Compare commits
15 Commits
@nhost/das
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e503b8fe8b | ||
|
|
304065ae22 | ||
|
|
68e0622eb0 | ||
|
|
70c6834636 | ||
|
|
a7bde37bba | ||
|
|
1bc615beca | ||
|
|
a58c5cfc96 | ||
|
|
c61228e45d | ||
|
|
6cec04bd6f | ||
|
|
a448d7d182 | ||
|
|
948048940e | ||
|
|
5e91221d5a | ||
|
|
7278991a59 | ||
|
|
5924bc3248 | ||
|
|
c5ad634799 |
@@ -1,5 +1,31 @@
|
||||
# @nhost/dashboard
|
||||
|
||||
## 1.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- a7bde37: feat: send metadata in the edit form
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1bc615b: feat: improve error message handling in `ErrorToast` component
|
||||
- @nhost/react-apollo@11.0.2
|
||||
- @nhost/nextjs@2.1.11
|
||||
|
||||
## 1.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- a448d7d: feat: allow configuring postmark and delete SMTP settings
|
||||
|
||||
## 1.13.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 5924bc3: fix: include password in `GetSmtpSettings` query
|
||||
- c5ad634: fix: resolved an issue where one-click install links were broken on Safari
|
||||
- 7278991: fix: update graphql auto-embeddings configuration to use String type for model field
|
||||
|
||||
## 1.13.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
2
dashboard/e2e/e2e-tests-project/.gitignore
vendored
Normal file
2
dashboard/e2e/e2e-tests-project/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.secrets
|
||||
.nhost
|
||||
1
dashboard/e2e/e2e-tests-project/nhost/config.yaml
Normal file
1
dashboard/e2e/e2e-tests-project/nhost/config.yaml
Normal file
@@ -0,0 +1 @@
|
||||
version: 3
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Потвърдете смяната на вашия имейл</h2>
|
||||
<p>Използвайте посочения линк, за да повърдите смяната на имейл:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Смени имейл
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Потвърждение за смяна на имейл
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Потвърдете вашия имейл</h2>
|
||||
<p>Използвайте посочения линк, за да потвърдите вашия имейл:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Потвърдете имейл
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Потвърждаване на имейл
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Смяна на парола</h2>
|
||||
<p>Използвайте посочения линк, за да смените вашата парола:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Смяна на парола
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Смяна на парола
|
||||
@@ -0,0 +1 @@
|
||||
Вашият код е ${code}.
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Магически линк за вход</h2>
|
||||
<p>Използвайте посочения линк за защитен и бърз вход:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Вход
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Магически линк за вход
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Potvrzení změny emailové adresy</h2>
|
||||
<p>Použijte tento odkaz k potvrzení změny emailové adresy:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Změnit email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Změna vaší emailové adresy
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Ověření emailové adresy</h2>
|
||||
<p>Použijte tento odkaz k ověření vaší emailové adresy:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Ověřit emailovou adresu
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Ověření vaší emailové adresy
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Obnova hesla</h2>
|
||||
<p>Použijte tento odkaz k obnovení vašeho hesla:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Obnova hesla
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Obnova hesla
|
||||
@@ -0,0 +1 @@
|
||||
Váš kód je ${code}.
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Magický odkaz</h2>
|
||||
<p>Použijte tento odkaz k bezpečnému přihlášení:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Přihlášení
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Bezpečný odkaz k přihlášení
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Confirm Email Change</h2>
|
||||
<p>Use this link to confirm changing email:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Change email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Change your email address
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Verify Email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Verify your email
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Reset password
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Reset your password
|
||||
@@ -0,0 +1 @@
|
||||
Your code is ${code}.
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Magic Link</h2>
|
||||
<p>Use this link to securely sign in:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Sign In
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Secure sign-in link
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Confirmar cambio de correo electrónico</h2>
|
||||
<p>Utiliza el siguiente enlace para confirmar el cambio de correo:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Cambiar correo electrónico
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Cambiar dirección de correo electrónico
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Verificar correo electrónico</h2>
|
||||
<p>Utilza el siguiente enlace para verificar tu correo:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Verificar correo electrónico
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Verifica tu correo electrónico
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Recuperar contraseña</h2>
|
||||
<p>Utiliza el siguiente enlace para recuperar tu contraseña:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Recuperar contraseña
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Recuperar contraseña
|
||||
@@ -0,0 +1 @@
|
||||
Tu código es ${code}.
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Enlace mágico</h2>
|
||||
<p>Utiliza este enlace para iniciar sesión de forma segura:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Iniciar sesión
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Enlace de acceso seguro
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Confirmer changement de courriel</h2>
|
||||
<p>Utilisez ce lien pour confirmer le changement de courriel :</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Changer courriel
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Changez votre adresse courriel
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Vérifiez votre courriel</h2>
|
||||
<p>Utilisez ce lien pour vérifier votre courriel :</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Vérifier courriel
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Vérifier votre courriel
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Réinitialiser votre mot de passe</h2>
|
||||
<p>Utilisez ce lien pour réinitialiser votre mot de passe :</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Réinitialiser mot de passe
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Réinitialiser votre mot de passe
|
||||
@@ -0,0 +1 @@
|
||||
Votre code est ${code}.
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Lien magique</h2>
|
||||
<p>Utilisez ce lien pour vous connecter de façon sécurisée :</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Connexion
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Lien de connexion sécurisé
|
||||
@@ -0,0 +1,8 @@
|
||||
${link},
|
||||
${displayName},
|
||||
${email},
|
||||
${ticket},
|
||||
${redirectTo},
|
||||
${serverUrl},
|
||||
${clientUrl},
|
||||
${locale},
|
||||
@@ -0,0 +1 @@
|
||||
${link}, ${displayName}, ${email}, ${ticket}, ${redirectTo}, ${serverUrl}, ${clientUrl}, ${locale}
|
||||
151
dashboard/e2e/e2e-tests-project/nhost/nhost.toml
Normal file
151
dashboard/e2e/e2e-tests-project/nhost/nhost.toml
Normal file
@@ -0,0 +1,151 @@
|
||||
[global]
|
||||
|
||||
[hasura]
|
||||
version = 'v2.33.4-ce'
|
||||
adminSecret = '{{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }}'
|
||||
webhookSecret = '{{ secrets.NHOST_WEBHOOK_SECRET }}'
|
||||
|
||||
[[hasura.jwtSecrets]]
|
||||
type = 'HS256'
|
||||
key = '{{ secrets.HASURA_GRAPHQL_JWT_SECRET }}'
|
||||
|
||||
[hasura.settings]
|
||||
corsDomain = ['*']
|
||||
devMode = true
|
||||
enableAllowList = false
|
||||
enableConsole = true
|
||||
enableRemoteSchemaPermissions = false
|
||||
enabledAPIs = ['metadata', 'graphql', 'pgdump', 'config']
|
||||
liveQueriesMultiplexedRefetchInterval = 1000
|
||||
stringifyNumericTypes = false
|
||||
|
||||
[hasura.logs]
|
||||
level = 'warn'
|
||||
|
||||
[hasura.events]
|
||||
httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.24.1'
|
||||
|
||||
[auth.elevatedPrivileges]
|
||||
mode = 'disabled'
|
||||
|
||||
[auth.redirections]
|
||||
clientUrl = 'http://localhost:3000'
|
||||
|
||||
[auth.signUp]
|
||||
enabled = true
|
||||
disableNewUsers = false
|
||||
|
||||
[auth.user]
|
||||
[auth.user.roles]
|
||||
default = 'user'
|
||||
allowed = ['user', 'me']
|
||||
|
||||
[auth.user.locale]
|
||||
default = 'en'
|
||||
allowed = ['en']
|
||||
|
||||
[auth.user.gravatar]
|
||||
enabled = true
|
||||
default = 'blank'
|
||||
rating = 'g'
|
||||
|
||||
[auth.user.email]
|
||||
|
||||
[auth.user.emailDomains]
|
||||
|
||||
[auth.session]
|
||||
[auth.session.accessToken]
|
||||
expiresIn = 900
|
||||
|
||||
[auth.session.refreshToken]
|
||||
expiresIn = 2592000
|
||||
|
||||
[auth.method]
|
||||
[auth.method.anonymous]
|
||||
enabled = false
|
||||
|
||||
[auth.method.emailPasswordless]
|
||||
enabled = false
|
||||
|
||||
[auth.method.emailPassword]
|
||||
hibpEnabled = false
|
||||
emailVerificationRequired = true
|
||||
passwordMinLength = 9
|
||||
|
||||
[auth.method.smsPasswordless]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth]
|
||||
[auth.method.oauth.apple]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.azuread]
|
||||
tenant = 'common'
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.bitbucket]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.discord]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.facebook]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.github]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.gitlab]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.google]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.linkedin]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.spotify]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.strava]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.twitch]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.twitter]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.windowslive]
|
||||
enabled = false
|
||||
|
||||
[auth.method.oauth.workos]
|
||||
enabled = false
|
||||
|
||||
[auth.method.webauthn]
|
||||
enabled = false
|
||||
|
||||
[auth.method.webauthn.attestation]
|
||||
timeout = 60000
|
||||
|
||||
[auth.totp]
|
||||
enabled = false
|
||||
|
||||
[postgres]
|
||||
version = '14.6-20240129-1'
|
||||
|
||||
[provider]
|
||||
|
||||
[storage]
|
||||
version = '0.6.0'
|
||||
|
||||
[observability]
|
||||
[observability.grafana]
|
||||
adminPassword = '{{ secrets.GRAFANA_ADMIN_PASSWORD }}'
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/dashboard",
|
||||
"version": "1.13.2",
|
||||
"version": "1.15.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
|
||||
@@ -29,10 +29,10 @@ const getInternalErrorMessage = (
|
||||
|
||||
if (error.name === 'ApolloError') {
|
||||
// @ts-ignore
|
||||
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as {
|
||||
error: { message: string };
|
||||
};
|
||||
return internalError?.error?.message || null;
|
||||
const graphqlError = error.graphQLErrors?.[0];
|
||||
const graphqlExtensionsError = graphqlError?.extensions?.internal
|
||||
?.error as { message: string };
|
||||
return graphqlError.message || graphqlExtensionsError?.message || null;
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import { useUI } from '@/components/common/UIProvider';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { Box } from '@/components/ui/v2/Box';
|
||||
import { Button } from '@/components/ui/v2/Button';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import {
|
||||
GetSmtpSettingsDocument,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { useState } from 'react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
function ConfirmDeleteSMTPSettingsModal({
|
||||
close,
|
||||
onDelete,
|
||||
}: {
|
||||
onDelete?: () => Promise<any>;
|
||||
close: () => void;
|
||||
}) {
|
||||
const onClickDelete = async () => {
|
||||
await onDelete();
|
||||
close();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={twMerge('w-full rounded-lg p-6 text-left')}>
|
||||
<div className="grid grid-flow-row gap-4">
|
||||
<Text variant="h3" component="h2">
|
||||
Delete SMTP Settings?
|
||||
</Text>
|
||||
|
||||
<Text>This will reset all your SMTP and Postmark settings.</Text>
|
||||
|
||||
<div className="grid grid-flow-row gap-2">
|
||||
<Button color="error" onClick={onClickDelete}>
|
||||
Delete
|
||||
</Button>
|
||||
|
||||
<Button variant="outlined" color="secondary" onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default function DeleteSMTPSettings() {
|
||||
const { openDialog, closeDialog } = useDialog();
|
||||
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { maintenanceActive } = useUI();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||
|
||||
const [updateConfig] = useUpdateConfigMutation({
|
||||
refetchQueries: [GetSmtpSettingsDocument],
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const deleteSMTPSettings = async () => {
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: currentProject.id,
|
||||
config: {
|
||||
provider: {
|
||||
smtp: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setLoading(true);
|
||||
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await updateConfigPromise;
|
||||
|
||||
if (!isPlatform) {
|
||||
openDialog({
|
||||
title: 'Apply your changes',
|
||||
component: <ApplyLocalSettingsDialog />,
|
||||
props: {
|
||||
PaperProps: {
|
||||
className: 'max-w-2xl',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
loadingMessage: 'SMTP settings are being deleted...',
|
||||
successMessage: 'SMTP settings have been deleted successfully.',
|
||||
errorMessage:
|
||||
'An error occurred while trying to delete the SMTP settings.',
|
||||
},
|
||||
);
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const confirmDeleteSMTPSettings = async () => {
|
||||
openDialog({
|
||||
component: (
|
||||
<ConfirmDeleteSMTPSettingsModal
|
||||
close={closeDialog}
|
||||
onDelete={deleteSMTPSettings}
|
||||
/>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsContainer
|
||||
title="Delete SMTP Settings"
|
||||
description="Delete SMTP settings and revert to default values"
|
||||
className="px-0"
|
||||
slotProps={{
|
||||
submitButton: { className: 'hidden' },
|
||||
footer: { className: 'hidden' },
|
||||
}}
|
||||
>
|
||||
<Box className="grid grid-flow-row border-t-1">
|
||||
<Button
|
||||
color="error"
|
||||
className="mx-4 mt-4 justify-self-end"
|
||||
onClick={confirmDeleteSMTPSettings}
|
||||
disabled={loading || maintenanceActive}
|
||||
loading={loading}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Box>
|
||||
</SettingsContainer>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as DeleteSTMPSettings } from './DeleteSMTPSettings';
|
||||
@@ -0,0 +1,149 @@
|
||||
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import { useUI } from '@/components/common/UIProvider';
|
||||
import { Form } from '@/components/form/Form';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import {
|
||||
GetSmtpSettingsDocument,
|
||||
useGetSmtpSettingsQuery,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const validationSchema = yup
|
||||
.object({
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
password: yup.string().label('Password').required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type PostmarkFormValues = yup.InferType<typeof validationSchema>;
|
||||
|
||||
export default function PostmarkSettings() {
|
||||
const { openDialog } = useDialog();
|
||||
const isPlatform = useIsPlatform();
|
||||
const { maintenanceActive } = useUI();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||
|
||||
const { data } = useGetSmtpSettingsQuery({
|
||||
variables: { appId: currentProject?.id },
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const { sender, password } = data?.config?.provider?.smtp || {};
|
||||
|
||||
const [updateConfig] = useUpdateConfigMutation({
|
||||
refetchQueries: [GetSmtpSettingsDocument],
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const form = useForm<PostmarkFormValues>({
|
||||
reValidateMode: 'onSubmit',
|
||||
resolver: yupResolver(validationSchema),
|
||||
defaultValues: {
|
||||
password: '',
|
||||
sender: '',
|
||||
},
|
||||
values: {
|
||||
password: password || '',
|
||||
sender: sender || '',
|
||||
},
|
||||
mode: 'onSubmit',
|
||||
criteriaMode: 'all',
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors, isDirty, isSubmitting },
|
||||
} = form;
|
||||
|
||||
const handleEditPostmarkSettings = async (values: PostmarkFormValues) => {
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: currentProject.id,
|
||||
config: {
|
||||
provider: {
|
||||
smtp: { method: 'LOGIN', host: 'postmark', ...values },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await updateConfigPromise;
|
||||
|
||||
if (!isPlatform) {
|
||||
openDialog({
|
||||
title: 'Apply your changes',
|
||||
component: <ApplyLocalSettingsDialog />,
|
||||
props: {
|
||||
PaperProps: {
|
||||
className: 'max-w-2xl',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
loadingMessage: 'Postmark settings are being updated...',
|
||||
successMessage: 'Postmark settings have been updated successfully.',
|
||||
errorMessage:
|
||||
'An error occurred while trying to update your Postmark settings.',
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<Form onSubmit={handleEditPostmarkSettings}>
|
||||
<SettingsContainer
|
||||
title="Postmark Settings"
|
||||
description="Configure postmark's native integration to send emails from your email domain."
|
||||
submitButtonText="Save"
|
||||
className="grid grid-cols-9 gap-4"
|
||||
slotProps={{
|
||||
submitButton: {
|
||||
disabled: !isDirty || maintenanceActive,
|
||||
loading: isSubmitting,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
{...register('sender')}
|
||||
id="sender"
|
||||
name="sender"
|
||||
label="From Email"
|
||||
placeholder="noreply@nhost.app"
|
||||
className="lg:col-span-4"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.sender)}
|
||||
helperText={errors.sender?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...register('password')}
|
||||
id="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
placeholder="Enter password"
|
||||
className="lg:col-span-5"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.password)}
|
||||
helperText={errors.password?.message}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</Form>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './PostmarkSettings';
|
||||
export { default as PostmarkSettings } from './PostmarkSettings';
|
||||
@@ -0,0 +1,238 @@
|
||||
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import { useUI } from '@/components/common/UIProvider';
|
||||
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
||||
import { Form } from '@/components/form/Form';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import {
|
||||
GetSmtpSettingsDocument,
|
||||
useGetSmtpSettingsQuery,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { type Optional } from 'utility-types';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const smtpValidationSchema = yup
|
||||
.object({
|
||||
secure: yup.bool().label('SMTP Secure'),
|
||||
host: yup
|
||||
.string()
|
||||
.label('SMTP Host')
|
||||
.matches(
|
||||
/((https?):\/\/)?(www\.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#[a-zA-Z0-9#]+?)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/,
|
||||
'SMTP Host must be a valid URL',
|
||||
)
|
||||
.required(),
|
||||
port: yup
|
||||
.number()
|
||||
.typeError('The SMTP port should contain only numbers.')
|
||||
.required(),
|
||||
user: yup.string().label('Username').required(),
|
||||
password: yup.string().label('Password'),
|
||||
method: yup.string().required(),
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type SmtpFormValues = yup.InferType<typeof smtpValidationSchema>;
|
||||
|
||||
export default function SMTPSettings() {
|
||||
const { maintenanceActive } = useUI();
|
||||
const { openDialog } = useDialog();
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||
|
||||
const { data } = useGetSmtpSettingsQuery({
|
||||
variables: { appId: currentProject?.id },
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const { secure, host, port, user, method, sender, password } =
|
||||
data?.config?.provider?.smtp || {};
|
||||
|
||||
const form = useForm<Optional<SmtpFormValues, 'password'>>({
|
||||
reValidateMode: 'onSubmit',
|
||||
resolver: yupResolver(smtpValidationSchema),
|
||||
defaultValues: {
|
||||
secure: false,
|
||||
host: '',
|
||||
port: undefined,
|
||||
user: '',
|
||||
password: '',
|
||||
method: '',
|
||||
sender: '',
|
||||
},
|
||||
values: {
|
||||
secure: secure || false,
|
||||
host: host || '',
|
||||
port,
|
||||
user: user || '',
|
||||
password: password || '',
|
||||
method: method || '',
|
||||
sender: sender || '',
|
||||
},
|
||||
mode: 'onSubmit',
|
||||
criteriaMode: 'all',
|
||||
});
|
||||
|
||||
const {
|
||||
register: registerSmtp,
|
||||
formState: { errors, isDirty, isSubmitting },
|
||||
} = form;
|
||||
|
||||
const [updateConfig] = useUpdateConfigMutation({
|
||||
refetchQueries: [GetSmtpSettingsDocument],
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const handleEditSMTPSettings = async (values: SmtpFormValues) => {
|
||||
const { password: newPassword, ...valuesWithoutPassword } = values;
|
||||
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: currentProject.id,
|
||||
config: {
|
||||
provider: {
|
||||
smtp: newPassword ? values : valuesWithoutPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await updateConfigPromise;
|
||||
|
||||
if (!isPlatform) {
|
||||
openDialog({
|
||||
title: 'Apply your changes',
|
||||
component: <ApplyLocalSettingsDialog />,
|
||||
props: {
|
||||
PaperProps: {
|
||||
className: 'max-w-2xl',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
loadingMessage: 'SMTP settings are being updated...',
|
||||
successMessage: 'SMTP settings have been updated successfully.',
|
||||
errorMessage:
|
||||
'An error occurred while trying to update the SMTP settings.',
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<Form onSubmit={handleEditSMTPSettings}>
|
||||
<SettingsContainer
|
||||
title="SMTP Settings"
|
||||
description="Configure your SMTP settings to send emails from your email domain."
|
||||
submitButtonText="Save"
|
||||
className="grid grid-cols-9 gap-4"
|
||||
slotProps={{
|
||||
submitButton: {
|
||||
disabled: !isDirty || maintenanceActive,
|
||||
loading: isSubmitting,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
{...registerSmtp('sender')}
|
||||
id="sender"
|
||||
name="sender"
|
||||
label="From Email"
|
||||
placeholder="noreply@nhost.app"
|
||||
className="lg:col-span-4"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.sender)}
|
||||
helperText={errors.sender?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...registerSmtp('host')}
|
||||
id="host"
|
||||
name="host"
|
||||
label="SMTP Host"
|
||||
className="lg:col-span-4"
|
||||
placeholder="e.g. smtp.sendgrid.net"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.host)}
|
||||
helperText={errors.host?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...registerSmtp('port')}
|
||||
id="port"
|
||||
name="port"
|
||||
label="Port"
|
||||
type="number"
|
||||
placeholder="587"
|
||||
className="lg:col-span-1"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.port)}
|
||||
helperText={errors.port?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...registerSmtp('user')}
|
||||
id="user"
|
||||
label="SMTP Username"
|
||||
placeholder="SMTP Username"
|
||||
className="lg:col-span-4"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.user)}
|
||||
helperText={errors.user?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...registerSmtp('password')}
|
||||
id="password"
|
||||
label="SMTP Password"
|
||||
type="password"
|
||||
placeholder="Enter SMTP password"
|
||||
className="lg:col-span-5"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.password)}
|
||||
helperText={errors.password?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...registerSmtp('method')}
|
||||
id="method"
|
||||
name="method"
|
||||
label="SMTP Auth Method"
|
||||
placeholder="LOGIN"
|
||||
hideEmptyHelperText
|
||||
className="lg:col-span-4"
|
||||
fullWidth
|
||||
error={Boolean(errors.method)}
|
||||
helperText={errors.method?.message}
|
||||
/>
|
||||
|
||||
<ControlledCheckbox
|
||||
name="secure"
|
||||
id="secure"
|
||||
label="Use SSL"
|
||||
className="lg:col-span-9"
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</Form>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './SMTPSettings';
|
||||
export { default as SMTPSettings } from './SMTPSettings';
|
||||
@@ -31,9 +31,10 @@ import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useTheme } from '@mui/material';
|
||||
import { format } from 'date-fns';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import debounce from 'lodash.debounce';
|
||||
import Image from 'next/image';
|
||||
import type { RemoteAppUser } from 'pages/[workspaceSlug]/[appSlug]/users';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
@@ -76,6 +77,21 @@ export const EditUserFormValidationSchema = Yup.object({
|
||||
locale: Yup.string(),
|
||||
defaultRole: Yup.string(),
|
||||
roles: Yup.array().of(Yup.boolean()),
|
||||
metadata: Yup.string().test(
|
||||
'is-valid-json',
|
||||
'Metadata must be valid JSON or empty',
|
||||
(value) => {
|
||||
if (value === '') {
|
||||
return true;
|
||||
} // Allow empty string as valid input
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
export type EditUserFormValues = Yup.InferType<
|
||||
@@ -116,14 +132,55 @@ export default function EditUserForm({
|
||||
locale: user.locale,
|
||||
defaultRole: user.defaultRole,
|
||||
roles: roles.map((role) => Object.values(role)[0]),
|
||||
metadata: user?.metadata ? JSON.stringify(user.metadata, null, 2) : '',
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
clearErrors,
|
||||
formState: { errors, dirtyFields, isSubmitting, isValidating },
|
||||
} = form;
|
||||
|
||||
const handleMetadataError = useMemo(() => {
|
||||
const debouncedSetError = debounce((value) => {
|
||||
try {
|
||||
JSON.parse(value);
|
||||
// Only set an error if JSON parsing fails
|
||||
} catch (error) {
|
||||
setError('metadata', {
|
||||
type: 'manual',
|
||||
message: 'Invalid JSON format',
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
|
||||
return {
|
||||
call: debouncedSetError,
|
||||
cancel: debouncedSetError.cancel, // lodash debounce provides a cancel method to stop the delayed function
|
||||
};
|
||||
}, [setError]);
|
||||
|
||||
const handleMetadataChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
if (value === '') {
|
||||
clearErrors('metadata'); // Clear errors when the input is explicitly cleared
|
||||
handleMetadataError.cancel(); // Cancel any debounced error checks
|
||||
} else {
|
||||
try {
|
||||
JSON.parse(value);
|
||||
clearErrors('metadata'); // Clear errors when valid JSON is entered
|
||||
handleMetadataError.cancel(); // Cancel pending debounced error checks
|
||||
} catch (error) {
|
||||
handleMetadataError.call(value); // Call the debounced error setter
|
||||
}
|
||||
}
|
||||
},
|
||||
[clearErrors, handleMetadataError],
|
||||
);
|
||||
|
||||
const isDirty = Object.keys(dirtyFields).length > 0;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -467,6 +524,28 @@ export default function EditUserForm({
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
<Box component="section" className="grid grid-flow-row gap-8 p-6">
|
||||
<Input
|
||||
{...register('metadata', { onChange: handleMetadataChange })}
|
||||
id="metadata"
|
||||
label="Metadata"
|
||||
variant="inline"
|
||||
hideEmptyHelperText
|
||||
error={!!errors.metadata}
|
||||
fullWidth
|
||||
multiline
|
||||
inputProps={{
|
||||
className: 'resize-y min-h-[130px]',
|
||||
}}
|
||||
helperText={
|
||||
errors.metadata
|
||||
? errors.metadata.message
|
||||
: 'Enter valid JSON. This can be a number, boolean, array, or object.'
|
||||
}
|
||||
maxRows={100}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box className="grid w-full flex-shrink-0 snap-end grid-flow-col justify-between gap-3 place-self-end border-t-1 p-2">
|
||||
|
||||
@@ -113,6 +113,9 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
|
||||
phoneNumber: values.phoneNumber,
|
||||
phoneNumberVerified: values.phoneNumberVerified,
|
||||
locale: values.locale,
|
||||
...(values?.metadata !== undefined && values.metadata !== ''
|
||||
? { metadata: JSON.parse(values.metadata) }
|
||||
: { metadata: null }),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ query GetSmtpSettings($appId: uuid!) {
|
||||
secure
|
||||
sender
|
||||
user
|
||||
password
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mutation insertGraphiteAutoEmbeddingsConfiguration(
|
||||
$name: String
|
||||
$model: embedding_model_enum
|
||||
$model: String
|
||||
$schemaName: String
|
||||
$tableName: String
|
||||
$columnName: String
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mutation updateGraphiteAutoEmbeddingsConfiguration(
|
||||
$id: uuid!
|
||||
$name: String
|
||||
$model: embedding_model_enum
|
||||
$model: String
|
||||
$schemaName: String
|
||||
$tableName: String
|
||||
$columnName: String
|
||||
|
||||
@@ -11,6 +11,7 @@ fragment RemoteAppGetUsers on users {
|
||||
defaultRole
|
||||
lastSeen
|
||||
locale
|
||||
metadata
|
||||
roles {
|
||||
id
|
||||
role
|
||||
|
||||
@@ -1,100 +1,35 @@
|
||||
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import { useUI } from '@/components/common/UIProvider';
|
||||
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
||||
import { Form } from '@/components/form/Form';
|
||||
import { Container } from '@/components/layout/Container';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { Option } from '@/components/ui/v2/Option';
|
||||
import { Select } from '@/components/ui/v2/Select';
|
||||
import DeleteSMTPSettings from '@/features/authentication/settings/components/DeleteSMTPSettings/DeleteSMTPSettings';
|
||||
import { PostmarkSettings } from '@/features/authentication/settings/components/PostmarkSettings';
|
||||
import { SMTPSettings } from '@/features/authentication/settings/components/SMTPSettings';
|
||||
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import {
|
||||
GetSmtpSettingsDocument,
|
||||
useGetSmtpSettingsQuery,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import type { ReactElement } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import type { Optional } from 'utility-types';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const smtpValidationSchema = yup
|
||||
.object({
|
||||
secure: yup.bool().label('SMTP Secure'),
|
||||
host: yup
|
||||
.string()
|
||||
.label('SMTP Host')
|
||||
.matches(
|
||||
/((https?):\/\/)?(www.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/,
|
||||
'SMTP Host must be a valid URL',
|
||||
)
|
||||
.required(),
|
||||
port: yup
|
||||
.number()
|
||||
.typeError('The SMTP port should contain only numbers.')
|
||||
.required(),
|
||||
user: yup.string().label('Username').required(),
|
||||
password: yup.string().label('Password'),
|
||||
method: yup.string().required(),
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type SmtpFormValues = yup.InferType<typeof smtpValidationSchema>;
|
||||
import { useGetSmtpSettingsQuery } from '@/utils/__generated__/graphql';
|
||||
import { useEffect, useState, type ReactElement } from 'react';
|
||||
|
||||
export default function SMTPSettingsPage() {
|
||||
const { openDialog } = useDialog();
|
||||
const isPlatform = useIsPlatform();
|
||||
const { maintenanceActive } = useUI();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||
|
||||
const [mode, setMode] = useState('postmark');
|
||||
|
||||
const { data, loading, error } = useGetSmtpSettingsQuery({
|
||||
variables: { appId: currentProject?.id },
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const { secure, host, port, user, method, sender } =
|
||||
data?.config?.provider?.smtp || {};
|
||||
const { host } = data?.config?.provider?.smtp || {};
|
||||
|
||||
const form = useForm<Optional<SmtpFormValues, 'password'>>({
|
||||
reValidateMode: 'onSubmit',
|
||||
resolver: yupResolver(smtpValidationSchema),
|
||||
defaultValues: {
|
||||
secure: false,
|
||||
host: '',
|
||||
port: undefined,
|
||||
user: '',
|
||||
method: '',
|
||||
sender: '',
|
||||
},
|
||||
values: {
|
||||
secure: secure || false,
|
||||
host: host || '',
|
||||
port,
|
||||
user: user || '',
|
||||
method: method || '',
|
||||
sender: sender || '',
|
||||
},
|
||||
mode: 'onSubmit',
|
||||
criteriaMode: 'all',
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors, isDirty, isSubmitting },
|
||||
} = form;
|
||||
|
||||
const [updateConfig] = useUpdateConfigMutation({
|
||||
refetchQueries: [GetSmtpSettingsDocument],
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
useEffect(() => {
|
||||
setMode(host !== 'postmark' ? 'smtp' : 'postmark');
|
||||
}, [host]);
|
||||
|
||||
if (isPlatform && currentProject?.plan?.isFree) {
|
||||
return (
|
||||
@@ -121,151 +56,29 @@ export default function SMTPSettingsPage() {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const handleEditSMTPSettings = async (values: SmtpFormValues) => {
|
||||
const { password, ...valuesWithoutPassword } = values;
|
||||
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: currentProject.id,
|
||||
config: {
|
||||
provider: {
|
||||
smtp: password ? values : valuesWithoutPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await updateConfigPromise;
|
||||
|
||||
if (!isPlatform) {
|
||||
openDialog({
|
||||
title: 'Apply your changes',
|
||||
component: <ApplyLocalSettingsDialog />,
|
||||
props: {
|
||||
PaperProps: {
|
||||
className: 'max-w-2xl',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
loadingMessage: 'SMTP settings are being updated...',
|
||||
successMessage: 'SMTP settings have been updated successfully.',
|
||||
errorMessage:
|
||||
'An error occurred while trying to update the SMTP settings.',
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container
|
||||
className="grid max-w-5xl grid-flow-row gap-4 bg-transparent"
|
||||
rootClassName="bg-transparent"
|
||||
>
|
||||
<FormProvider {...form}>
|
||||
<Form onSubmit={handleEditSMTPSettings}>
|
||||
<SettingsContainer
|
||||
title="SMTP Settings"
|
||||
description="Configure your SMTP settings to send emails from your email domain."
|
||||
submitButtonText="Save"
|
||||
className="grid grid-cols-9 gap-4"
|
||||
slotProps={{
|
||||
submitButton: {
|
||||
disabled: !isDirty || maintenanceActive,
|
||||
loading: isSubmitting,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
{...register('sender')}
|
||||
id="sender"
|
||||
name="sender"
|
||||
label="From Email"
|
||||
placeholder="noreply@nhost.app"
|
||||
className="lg:col-span-4"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.sender)}
|
||||
helperText={errors.sender?.message}
|
||||
/>
|
||||
<Select
|
||||
slotProps={{
|
||||
popper: { disablePortal: false, className: 'z-[10000]' },
|
||||
}}
|
||||
value={mode}
|
||||
onChange={(_, value) => setMode(value as string)}
|
||||
fullWidth
|
||||
>
|
||||
<Option key="smtp" value="smtp">
|
||||
SMTP
|
||||
</Option>
|
||||
<Option key="postmark" value="postmark">
|
||||
Postmark
|
||||
</Option>
|
||||
</Select>
|
||||
|
||||
<Input
|
||||
{...register('host')}
|
||||
id="host"
|
||||
name="host"
|
||||
label="SMTP Host"
|
||||
className="lg:col-span-4"
|
||||
placeholder="e.g. smtp.sendgrid.net"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.host)}
|
||||
helperText={errors.host?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...register('port')}
|
||||
id="port"
|
||||
name="port"
|
||||
label="Port"
|
||||
type="number"
|
||||
placeholder="587"
|
||||
className="lg:col-span-1"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.port)}
|
||||
helperText={errors.port?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...register('user')}
|
||||
id="user"
|
||||
label="SMTP Username"
|
||||
placeholder="SMTP Username"
|
||||
className="lg:col-span-4"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.user)}
|
||||
helperText={errors.user?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...register('password')}
|
||||
id="password"
|
||||
label="SMTP Password"
|
||||
type="password"
|
||||
placeholder="Enter SMTP password"
|
||||
className="lg:col-span-5"
|
||||
hideEmptyHelperText
|
||||
fullWidth
|
||||
error={Boolean(errors.password)}
|
||||
helperText={errors.password?.message}
|
||||
/>
|
||||
|
||||
<Input
|
||||
{...register('method')}
|
||||
id="method"
|
||||
name="method"
|
||||
label="SMTP Auth Method"
|
||||
placeholder="LOGIN"
|
||||
hideEmptyHelperText
|
||||
className="lg:col-span-4"
|
||||
fullWidth
|
||||
error={Boolean(errors.method)}
|
||||
helperText={errors.method?.message}
|
||||
/>
|
||||
|
||||
<ControlledCheckbox
|
||||
name="secure"
|
||||
id="secure"
|
||||
label="Use SSL"
|
||||
className="lg:col-span-9"
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</Form>
|
||||
</FormProvider>
|
||||
{mode === 'postmark' ? <PostmarkSettings /> : <SMTPSettings />}
|
||||
<DeleteSMTPSettings />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,11 @@ export default function SelectWorkspaceAndProject() {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
checkConfigFromQuery(router.query?.config as string);
|
||||
const config = router.query?.config as string;
|
||||
|
||||
if (config) {
|
||||
checkConfigFromQuery(router.query?.config as string);
|
||||
}
|
||||
}, [checkConfigFromQuery, router.query]);
|
||||
|
||||
const goToServices = async (project: {
|
||||
@@ -133,7 +137,7 @@ export default function SelectWorkspaceAndProject() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex w-full justify-center">
|
||||
<div className="flex justify-center w-full">
|
||||
<ActivityIndicator
|
||||
delay={500}
|
||||
label="Loading workspaces and projects..."
|
||||
@@ -156,7 +160,7 @@ export default function SelectWorkspaceAndProject() {
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div className="mb-2 flex w-full">
|
||||
<div className="flex w-full mb-2">
|
||||
<Input
|
||||
placeholder="Search..."
|
||||
onChange={handleFilterChange}
|
||||
@@ -166,11 +170,11 @@ export default function SelectWorkspaceAndProject() {
|
||||
</div>
|
||||
<RetryableErrorBoundary>
|
||||
{projectsToDisplay.length === 0 ? (
|
||||
<Box className="h-import py-2">
|
||||
<Box className="py-2 h-import">
|
||||
<Text variant="subtitle2">No results found.</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<List className="h-import overflow-y-auto">
|
||||
<List className="overflow-y-auto h-import">
|
||||
{projectsToDisplay.map((project, index) => (
|
||||
<Fragment key={project.value}>
|
||||
<ListItem.Root
|
||||
@@ -186,7 +190,7 @@ export default function SelectWorkspaceAndProject() {
|
||||
}
|
||||
>
|
||||
<ListItem.Avatar>
|
||||
<span className="inline-block h-6 w-6 overflow-hidden rounded-md">
|
||||
<span className="inline-block w-6 h-6 overflow-hidden rounded-md">
|
||||
<Image
|
||||
src="/logos/new.svg"
|
||||
alt="Nhost Logo"
|
||||
|
||||
389
dashboard/src/utils/__generated__/graphite.graphql.ts
generated
389
dashboard/src/utils/__generated__/graphite.graphql.ts
generated
@@ -16,9 +16,7 @@ export type Scalars = {
|
||||
bigint: any;
|
||||
bytea: any;
|
||||
citext: any;
|
||||
embedding_model_enum: any;
|
||||
jsonb: any;
|
||||
timestamp: any;
|
||||
timestamptz: any;
|
||||
timestampz: any;
|
||||
uuid: any;
|
||||
@@ -1547,9 +1545,9 @@ export type AuthUserProviders_Bool_Exp = {
|
||||
export enum AuthUserProviders_Constraint {
|
||||
/** unique or primary key constraint on columns "id" */
|
||||
UserProvidersPkey = 'user_providers_pkey',
|
||||
/** unique or primary key constraint on columns "provider_id", "provider_user_id" */
|
||||
/** unique or primary key constraint on columns "provider_user_id", "provider_id" */
|
||||
UserProvidersProviderIdProviderUserIdKey = 'user_providers_provider_id_provider_user_id_key',
|
||||
/** unique or primary key constraint on columns "provider_id", "user_id" */
|
||||
/** unique or primary key constraint on columns "user_id", "provider_id" */
|
||||
UserProvidersUserIdProviderIdKey = 'user_providers_user_id_provider_id_key'
|
||||
}
|
||||
|
||||
@@ -2684,19 +2682,6 @@ export enum Cursor_Ordering {
|
||||
Desc = 'DESC'
|
||||
}
|
||||
|
||||
/** Boolean expression to compare columns of type "embedding_model_enum". All fields are combined with logical 'AND'. */
|
||||
export type Embedding_Model_Enum_Comparison_Exp = {
|
||||
_eq?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_gt?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_gte?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_in?: InputMaybe<Array<Scalars['embedding_model_enum']>>;
|
||||
_is_null?: InputMaybe<Scalars['Boolean']>;
|
||||
_lt?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_lte?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_neq?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
_nin?: InputMaybe<Array<Scalars['embedding_model_enum']>>;
|
||||
};
|
||||
|
||||
/** columns and relationships of "storage.files" */
|
||||
export type Files = {
|
||||
__typename?: 'files';
|
||||
@@ -3297,7 +3282,7 @@ export type GraphiteAutoEmbeddingsConfiguration = {
|
||||
createdAt: Scalars['timestamptz'];
|
||||
id: Scalars['uuid'];
|
||||
lastRun?: Maybe<Scalars['timestamptz']>;
|
||||
model: Scalars['embedding_model_enum'];
|
||||
model: Scalars['String'];
|
||||
mutation?: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
query?: Maybe<Scalars['String']>;
|
||||
@@ -3337,7 +3322,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Bool_Exp = {
|
||||
createdAt?: InputMaybe<Timestamptz_Comparison_Exp>;
|
||||
id?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
lastRun?: InputMaybe<Timestamptz_Comparison_Exp>;
|
||||
model?: InputMaybe<Embedding_Model_Enum_Comparison_Exp>;
|
||||
model?: InputMaybe<String_Comparison_Exp>;
|
||||
mutation?: InputMaybe<String_Comparison_Exp>;
|
||||
name?: InputMaybe<String_Comparison_Exp>;
|
||||
query?: InputMaybe<String_Comparison_Exp>;
|
||||
@@ -3352,7 +3337,7 @@ export enum GraphiteAutoEmbeddingsConfiguration_Constraint {
|
||||
AutoEmbeddingsConfigurationNameKey = 'auto_embeddings_configuration_name_key',
|
||||
/** unique or primary key constraint on columns "id" */
|
||||
AutoEmbeddingsConfigurationPkey = 'auto_embeddings_configuration_pkey',
|
||||
/** unique or primary key constraint on columns "table_name", "column_name", "schema_name" */
|
||||
/** unique or primary key constraint on columns "column_name", "schema_name", "table_name" */
|
||||
AutoEmbeddingsConfigurationSchemaNameTableNameColumnKey = 'auto_embeddings_configuration_schema_name_table_name_column_key'
|
||||
}
|
||||
|
||||
@@ -3362,7 +3347,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Insert_Input = {
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
lastRun?: InputMaybe<Scalars['timestamptz']>;
|
||||
model?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
model?: InputMaybe<Scalars['String']>;
|
||||
mutation?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
@@ -3378,7 +3363,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Max_Fields = {
|
||||
createdAt?: Maybe<Scalars['timestamptz']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
lastRun?: Maybe<Scalars['timestamptz']>;
|
||||
model?: Maybe<Scalars['embedding_model_enum']>;
|
||||
model?: Maybe<Scalars['String']>;
|
||||
mutation?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
query?: Maybe<Scalars['String']>;
|
||||
@@ -3394,7 +3379,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Min_Fields = {
|
||||
createdAt?: Maybe<Scalars['timestamptz']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
lastRun?: Maybe<Scalars['timestamptz']>;
|
||||
model?: Maybe<Scalars['embedding_model_enum']>;
|
||||
model?: Maybe<Scalars['String']>;
|
||||
mutation?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
query?: Maybe<Scalars['String']>;
|
||||
@@ -3471,7 +3456,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Set_Input = {
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
lastRun?: InputMaybe<Scalars['timestamptz']>;
|
||||
model?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
model?: InputMaybe<Scalars['String']>;
|
||||
mutation?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
@@ -3494,7 +3479,7 @@ export type GraphiteAutoEmbeddingsConfiguration_Stream_Cursor_Value_Input = {
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
lastRun?: InputMaybe<Scalars['timestamptz']>;
|
||||
model?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
model?: InputMaybe<Scalars['String']>;
|
||||
mutation?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
@@ -3898,10 +3883,6 @@ export type Mutation_Root = {
|
||||
deleteVirus?: Maybe<Virus>;
|
||||
/** delete data from the table: "storage.virus" */
|
||||
deleteViruses?: Maybe<Virus_Mutation_Response>;
|
||||
/** delete data from the table: "todos" */
|
||||
delete_todos?: Maybe<Todos_Mutation_Response>;
|
||||
/** delete single row from the table: "todos" */
|
||||
delete_todos_by_pk?: Maybe<Todos>;
|
||||
graphite?: Maybe<GraphiteMutation>;
|
||||
/** insert a single row into the table: "auth.providers" */
|
||||
insertAuthProvider?: Maybe<AuthProviders>;
|
||||
@@ -3955,10 +3936,6 @@ export type Mutation_Root = {
|
||||
insertVirus?: Maybe<Virus>;
|
||||
/** insert data into the table: "storage.virus" */
|
||||
insertViruses?: Maybe<Virus_Mutation_Response>;
|
||||
/** insert data into the table: "todos" */
|
||||
insert_todos?: Maybe<Todos_Mutation_Response>;
|
||||
/** insert a single row into the table: "todos" */
|
||||
insert_todos_one?: Maybe<Todos>;
|
||||
/** update single row of the table: "auth.providers" */
|
||||
updateAuthProvider?: Maybe<AuthProviders>;
|
||||
/** update single row of the table: "auth.provider_requests" */
|
||||
@@ -4033,12 +4010,6 @@ export type Mutation_Root = {
|
||||
update_buckets_many?: Maybe<Array<Maybe<Buckets_Mutation_Response>>>;
|
||||
/** update multiples rows of table: "storage.files" */
|
||||
update_files_many?: Maybe<Array<Maybe<Files_Mutation_Response>>>;
|
||||
/** update data of the table: "todos" */
|
||||
update_todos?: Maybe<Todos_Mutation_Response>;
|
||||
/** update single row of the table: "todos" */
|
||||
update_todos_by_pk?: Maybe<Todos>;
|
||||
/** update multiples rows of table: "todos" */
|
||||
update_todos_many?: Maybe<Array<Maybe<Todos_Mutation_Response>>>;
|
||||
/** update multiples rows of table: "auth.users" */
|
||||
update_users_many?: Maybe<Array<Maybe<Users_Mutation_Response>>>;
|
||||
/** update multiples rows of table: "storage.virus" */
|
||||
@@ -4304,18 +4275,6 @@ export type Mutation_RootDeleteVirusesArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootDelete_TodosArgs = {
|
||||
where: Todos_Bool_Exp;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootDelete_Todos_By_PkArgs = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootInsertAuthProviderArgs = {
|
||||
object: AuthProviders_Insert_Input;
|
||||
@@ -4498,20 +4457,6 @@ export type Mutation_RootInsertVirusesArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootInsert_TodosArgs = {
|
||||
objects: Array<Todos_Insert_Input>;
|
||||
on_conflict?: InputMaybe<Todos_On_Conflict>;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootInsert_Todos_OneArgs = {
|
||||
object: Todos_Insert_Input;
|
||||
on_conflict?: InputMaybe<Todos_On_Conflict>;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootUpdateAuthProviderArgs = {
|
||||
_set?: InputMaybe<AuthProviders_Set_Input>;
|
||||
@@ -4816,26 +4761,6 @@ export type Mutation_RootUpdate_Files_ManyArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootUpdate_TodosArgs = {
|
||||
_set?: InputMaybe<Todos_Set_Input>;
|
||||
where: Todos_Bool_Exp;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootUpdate_Todos_By_PkArgs = {
|
||||
_set?: InputMaybe<Todos_Set_Input>;
|
||||
pk_columns: Todos_Pk_Columns_Input;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootUpdate_Todos_ManyArgs = {
|
||||
updates: Array<Todos_Updates>;
|
||||
};
|
||||
|
||||
|
||||
/** mutation root */
|
||||
export type Mutation_RootUpdate_Users_ManyArgs = {
|
||||
updates: Array<Users_Updates>;
|
||||
@@ -4944,12 +4869,6 @@ export type Query_Root = {
|
||||
graphiteAutoEmbeddingsConfigurationAggregate: GraphiteAutoEmbeddingsConfiguration_Aggregate;
|
||||
/** fetch data from the table: "graphite.auto_embeddings_configuration" */
|
||||
graphiteAutoEmbeddingsConfigurations: Array<GraphiteAutoEmbeddingsConfiguration>;
|
||||
/** fetch data from the table: "todos" */
|
||||
todos: Array<Todos>;
|
||||
/** fetch aggregated fields from the table: "todos" */
|
||||
todos_aggregate: Todos_Aggregate;
|
||||
/** fetch data from the table: "todos" using primary key columns */
|
||||
todos_by_pk?: Maybe<Todos>;
|
||||
/** fetch data from the table: "auth.users" using primary key columns */
|
||||
user?: Maybe<Users>;
|
||||
/** fetch data from the table: "auth.users" */
|
||||
@@ -5264,29 +5183,6 @@ export type Query_RootGraphiteAutoEmbeddingsConfigurationsArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootTodosArgs = {
|
||||
distinct_on?: InputMaybe<Array<Todos_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Todos_Order_By>>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootTodos_AggregateArgs = {
|
||||
distinct_on?: InputMaybe<Array<Todos_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Todos_Order_By>>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootTodos_By_PkArgs = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootUserArgs = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
@@ -5438,14 +5334,6 @@ export type Subscription_Root = {
|
||||
graphiteAutoEmbeddingsConfigurationStream: Array<GraphiteAutoEmbeddingsConfiguration>;
|
||||
/** fetch data from the table: "graphite.auto_embeddings_configuration" */
|
||||
graphiteAutoEmbeddingsConfigurations: Array<GraphiteAutoEmbeddingsConfiguration>;
|
||||
/** fetch data from the table: "todos" */
|
||||
todos: Array<Todos>;
|
||||
/** fetch aggregated fields from the table: "todos" */
|
||||
todos_aggregate: Todos_Aggregate;
|
||||
/** fetch data from the table: "todos" using primary key columns */
|
||||
todos_by_pk?: Maybe<Todos>;
|
||||
/** fetch data from the table in a streaming manner: "todos" */
|
||||
todos_stream: Array<Todos>;
|
||||
/** fetch data from the table: "auth.users" using primary key columns */
|
||||
user?: Maybe<Users>;
|
||||
/** fetch data from the table: "auth.users" */
|
||||
@@ -5855,36 +5743,6 @@ export type Subscription_RootGraphiteAutoEmbeddingsConfigurationsArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type Subscription_RootTodosArgs = {
|
||||
distinct_on?: InputMaybe<Array<Todos_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Todos_Order_By>>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
export type Subscription_RootTodos_AggregateArgs = {
|
||||
distinct_on?: InputMaybe<Array<Todos_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Todos_Order_By>>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
export type Subscription_RootTodos_By_PkArgs = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
|
||||
|
||||
export type Subscription_RootTodos_StreamArgs = {
|
||||
batch_size: Scalars['Int'];
|
||||
cursor: Array<InputMaybe<Todos_Stream_Cursor_Input>>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
export type Subscription_RootUserArgs = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
@@ -5944,19 +5802,6 @@ export type Subscription_RootVirusesAggregateArgs = {
|
||||
where?: InputMaybe<Virus_Bool_Exp>;
|
||||
};
|
||||
|
||||
/** Boolean expression to compare columns of type "timestamp". All fields are combined with logical 'AND'. */
|
||||
export type Timestamp_Comparison_Exp = {
|
||||
_eq?: InputMaybe<Scalars['timestamp']>;
|
||||
_gt?: InputMaybe<Scalars['timestamp']>;
|
||||
_gte?: InputMaybe<Scalars['timestamp']>;
|
||||
_in?: InputMaybe<Array<Scalars['timestamp']>>;
|
||||
_is_null?: InputMaybe<Scalars['Boolean']>;
|
||||
_lt?: InputMaybe<Scalars['timestamp']>;
|
||||
_lte?: InputMaybe<Scalars['timestamp']>;
|
||||
_neq?: InputMaybe<Scalars['timestamp']>;
|
||||
_nin?: InputMaybe<Array<Scalars['timestamp']>>;
|
||||
};
|
||||
|
||||
/** Boolean expression to compare columns of type "timestamptz". All fields are combined with logical 'AND'. */
|
||||
export type Timestamptz_Comparison_Exp = {
|
||||
_eq?: InputMaybe<Scalars['timestamptz']>;
|
||||
@@ -5970,208 +5815,6 @@ export type Timestamptz_Comparison_Exp = {
|
||||
_nin?: InputMaybe<Array<Scalars['timestamptz']>>;
|
||||
};
|
||||
|
||||
/** columns and relationships of "todos" */
|
||||
export type Todos = {
|
||||
__typename?: 'todos';
|
||||
/** An object relationship */
|
||||
attachment?: Maybe<Files>;
|
||||
createdAt: Scalars['timestamp'];
|
||||
done: Scalars['Boolean'];
|
||||
file_id?: Maybe<Scalars['uuid']>;
|
||||
id: Scalars['uuid'];
|
||||
title: Scalars['String'];
|
||||
updatedAt: Scalars['timestamptz'];
|
||||
/** An object relationship */
|
||||
user: Users;
|
||||
user_id: Scalars['uuid'];
|
||||
};
|
||||
|
||||
/** aggregated selection of "todos" */
|
||||
export type Todos_Aggregate = {
|
||||
__typename?: 'todos_aggregate';
|
||||
aggregate?: Maybe<Todos_Aggregate_Fields>;
|
||||
nodes: Array<Todos>;
|
||||
};
|
||||
|
||||
/** aggregate fields of "todos" */
|
||||
export type Todos_Aggregate_Fields = {
|
||||
__typename?: 'todos_aggregate_fields';
|
||||
count: Scalars['Int'];
|
||||
max?: Maybe<Todos_Max_Fields>;
|
||||
min?: Maybe<Todos_Min_Fields>;
|
||||
};
|
||||
|
||||
|
||||
/** aggregate fields of "todos" */
|
||||
export type Todos_Aggregate_FieldsCountArgs = {
|
||||
columns?: InputMaybe<Array<Todos_Select_Column>>;
|
||||
distinct?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
/** Boolean expression to filter rows from the table "todos". All fields are combined with a logical 'AND'. */
|
||||
export type Todos_Bool_Exp = {
|
||||
_and?: InputMaybe<Array<Todos_Bool_Exp>>;
|
||||
_not?: InputMaybe<Todos_Bool_Exp>;
|
||||
_or?: InputMaybe<Array<Todos_Bool_Exp>>;
|
||||
attachment?: InputMaybe<Files_Bool_Exp>;
|
||||
createdAt?: InputMaybe<Timestamp_Comparison_Exp>;
|
||||
done?: InputMaybe<Boolean_Comparison_Exp>;
|
||||
file_id?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
id?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
title?: InputMaybe<String_Comparison_Exp>;
|
||||
updatedAt?: InputMaybe<Timestamptz_Comparison_Exp>;
|
||||
user?: InputMaybe<Users_Bool_Exp>;
|
||||
user_id?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
};
|
||||
|
||||
/** unique or primary key constraints on table "todos" */
|
||||
export enum Todos_Constraint {
|
||||
/** unique or primary key constraint on columns "id" */
|
||||
TodosPkey = 'todos_pkey'
|
||||
}
|
||||
|
||||
/** input type for inserting data into table "todos" */
|
||||
export type Todos_Insert_Input = {
|
||||
attachment?: InputMaybe<Files_Obj_Rel_Insert_Input>;
|
||||
createdAt?: InputMaybe<Scalars['timestamp']>;
|
||||
done?: InputMaybe<Scalars['Boolean']>;
|
||||
file_id?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
title?: InputMaybe<Scalars['String']>;
|
||||
updatedAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
user?: InputMaybe<Users_Obj_Rel_Insert_Input>;
|
||||
user_id?: InputMaybe<Scalars['uuid']>;
|
||||
};
|
||||
|
||||
/** aggregate max on columns */
|
||||
export type Todos_Max_Fields = {
|
||||
__typename?: 'todos_max_fields';
|
||||
createdAt?: Maybe<Scalars['timestamp']>;
|
||||
file_id?: Maybe<Scalars['uuid']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
title?: Maybe<Scalars['String']>;
|
||||
updatedAt?: Maybe<Scalars['timestamptz']>;
|
||||
user_id?: Maybe<Scalars['uuid']>;
|
||||
};
|
||||
|
||||
/** aggregate min on columns */
|
||||
export type Todos_Min_Fields = {
|
||||
__typename?: 'todos_min_fields';
|
||||
createdAt?: Maybe<Scalars['timestamp']>;
|
||||
file_id?: Maybe<Scalars['uuid']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
title?: Maybe<Scalars['String']>;
|
||||
updatedAt?: Maybe<Scalars['timestamptz']>;
|
||||
user_id?: Maybe<Scalars['uuid']>;
|
||||
};
|
||||
|
||||
/** response of any mutation on the table "todos" */
|
||||
export type Todos_Mutation_Response = {
|
||||
__typename?: 'todos_mutation_response';
|
||||
/** number of rows affected by the mutation */
|
||||
affected_rows: Scalars['Int'];
|
||||
/** data from the rows affected by the mutation */
|
||||
returning: Array<Todos>;
|
||||
};
|
||||
|
||||
/** on_conflict condition type for table "todos" */
|
||||
export type Todos_On_Conflict = {
|
||||
constraint: Todos_Constraint;
|
||||
update_columns?: Array<Todos_Update_Column>;
|
||||
where?: InputMaybe<Todos_Bool_Exp>;
|
||||
};
|
||||
|
||||
/** Ordering options when selecting data from "todos". */
|
||||
export type Todos_Order_By = {
|
||||
attachment?: InputMaybe<Files_Order_By>;
|
||||
createdAt?: InputMaybe<Order_By>;
|
||||
done?: InputMaybe<Order_By>;
|
||||
file_id?: InputMaybe<Order_By>;
|
||||
id?: InputMaybe<Order_By>;
|
||||
title?: InputMaybe<Order_By>;
|
||||
updatedAt?: InputMaybe<Order_By>;
|
||||
user?: InputMaybe<Users_Order_By>;
|
||||
user_id?: InputMaybe<Order_By>;
|
||||
};
|
||||
|
||||
/** primary key columns input for table: todos */
|
||||
export type Todos_Pk_Columns_Input = {
|
||||
id: Scalars['uuid'];
|
||||
};
|
||||
|
||||
/** select columns of table "todos" */
|
||||
export enum Todos_Select_Column {
|
||||
/** column name */
|
||||
CreatedAt = 'createdAt',
|
||||
/** column name */
|
||||
Done = 'done',
|
||||
/** column name */
|
||||
FileId = 'file_id',
|
||||
/** column name */
|
||||
Id = 'id',
|
||||
/** column name */
|
||||
Title = 'title',
|
||||
/** column name */
|
||||
UpdatedAt = 'updatedAt',
|
||||
/** column name */
|
||||
UserId = 'user_id'
|
||||
}
|
||||
|
||||
/** input type for updating data in table "todos" */
|
||||
export type Todos_Set_Input = {
|
||||
createdAt?: InputMaybe<Scalars['timestamp']>;
|
||||
done?: InputMaybe<Scalars['Boolean']>;
|
||||
file_id?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
title?: InputMaybe<Scalars['String']>;
|
||||
updatedAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
user_id?: InputMaybe<Scalars['uuid']>;
|
||||
};
|
||||
|
||||
/** Streaming cursor of the table "todos" */
|
||||
export type Todos_Stream_Cursor_Input = {
|
||||
/** Stream column input with initial value */
|
||||
initial_value: Todos_Stream_Cursor_Value_Input;
|
||||
/** cursor ordering */
|
||||
ordering?: InputMaybe<Cursor_Ordering>;
|
||||
};
|
||||
|
||||
/** Initial value of the column from where the streaming should start */
|
||||
export type Todos_Stream_Cursor_Value_Input = {
|
||||
createdAt?: InputMaybe<Scalars['timestamp']>;
|
||||
done?: InputMaybe<Scalars['Boolean']>;
|
||||
file_id?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
title?: InputMaybe<Scalars['String']>;
|
||||
updatedAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
user_id?: InputMaybe<Scalars['uuid']>;
|
||||
};
|
||||
|
||||
/** update columns of table "todos" */
|
||||
export enum Todos_Update_Column {
|
||||
/** column name */
|
||||
CreatedAt = 'createdAt',
|
||||
/** column name */
|
||||
Done = 'done',
|
||||
/** column name */
|
||||
FileId = 'file_id',
|
||||
/** column name */
|
||||
Id = 'id',
|
||||
/** column name */
|
||||
Title = 'title',
|
||||
/** column name */
|
||||
UpdatedAt = 'updatedAt',
|
||||
/** column name */
|
||||
UserId = 'user_id'
|
||||
}
|
||||
|
||||
export type Todos_Updates = {
|
||||
/** sets the columns of the filtered rows to the given values */
|
||||
_set?: InputMaybe<Todos_Set_Input>;
|
||||
/** filter the rows which have to be updated */
|
||||
where: Todos_Bool_Exp;
|
||||
};
|
||||
|
||||
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
|
||||
export type Users = {
|
||||
__typename?: 'users';
|
||||
@@ -7150,11 +6793,11 @@ export type GetGraphiteAutoEmbeddingsConfigurationsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetGraphiteAutoEmbeddingsConfigurationsQuery = { __typename?: 'query_root', graphiteAutoEmbeddingsConfigurations: Array<{ __typename?: 'graphiteAutoEmbeddingsConfiguration', id: any, name: string, model: any, schemaName: string, tableName: string, columnName: string, query?: string | null, mutation?: string | null, createdAt: any, updatedAt: any }>, graphiteAutoEmbeddingsConfigurationAggregate: { __typename?: 'graphiteAutoEmbeddingsConfiguration_aggregate', aggregate?: { __typename?: 'graphiteAutoEmbeddingsConfiguration_aggregate_fields', count: number } | null } };
|
||||
export type GetGraphiteAutoEmbeddingsConfigurationsQuery = { __typename?: 'query_root', graphiteAutoEmbeddingsConfigurations: Array<{ __typename?: 'graphiteAutoEmbeddingsConfiguration', id: any, name: string, model: string, schemaName: string, tableName: string, columnName: string, query?: string | null, mutation?: string | null, createdAt: any, updatedAt: any }>, graphiteAutoEmbeddingsConfigurationAggregate: { __typename?: 'graphiteAutoEmbeddingsConfiguration_aggregate', aggregate?: { __typename?: 'graphiteAutoEmbeddingsConfiguration_aggregate_fields', count: number } | null } };
|
||||
|
||||
export type InsertGraphiteAutoEmbeddingsConfigurationMutationVariables = Exact<{
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
model?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
model?: InputMaybe<Scalars['String']>;
|
||||
schemaName?: InputMaybe<Scalars['String']>;
|
||||
tableName?: InputMaybe<Scalars['String']>;
|
||||
columnName?: InputMaybe<Scalars['String']>;
|
||||
@@ -7168,7 +6811,7 @@ export type InsertGraphiteAutoEmbeddingsConfigurationMutation = { __typename?: '
|
||||
export type UpdateGraphiteAutoEmbeddingsConfigurationMutationVariables = Exact<{
|
||||
id: Scalars['uuid'];
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
model?: InputMaybe<Scalars['embedding_model_enum']>;
|
||||
model?: InputMaybe<Scalars['String']>;
|
||||
schemaName?: InputMaybe<Scalars['String']>;
|
||||
tableName?: InputMaybe<Scalars['String']>;
|
||||
columnName?: InputMaybe<Scalars['String']>;
|
||||
@@ -7177,7 +6820,7 @@ export type UpdateGraphiteAutoEmbeddingsConfigurationMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateGraphiteAutoEmbeddingsConfigurationMutation = { __typename?: 'mutation_root', updateGraphiteAutoEmbeddingsConfiguration?: { __typename?: 'graphiteAutoEmbeddingsConfiguration', id: any, name: string, model: any, schemaName: string, tableName: string, columnName: string, query?: string | null, mutation?: string | null } | null };
|
||||
export type UpdateGraphiteAutoEmbeddingsConfigurationMutation = { __typename?: 'mutation_root', updateGraphiteAutoEmbeddingsConfiguration?: { __typename?: 'graphiteAutoEmbeddingsConfiguration', id: any, name: string, model: string, schemaName: string, tableName: string, columnName: string, query?: string | null, mutation?: string | null } | null };
|
||||
|
||||
export type SendDevMessageMutationVariables = Exact<{
|
||||
sessionId: Scalars['String'];
|
||||
@@ -7489,7 +7132,7 @@ export function refetchGetGraphiteAutoEmbeddingsConfigurationsQuery(variables: G
|
||||
return { query: GetGraphiteAutoEmbeddingsConfigurationsDocument, variables: variables }
|
||||
}
|
||||
export const InsertGraphiteAutoEmbeddingsConfigurationDocument = gql`
|
||||
mutation insertGraphiteAutoEmbeddingsConfiguration($name: String, $model: embedding_model_enum, $schemaName: String, $tableName: String, $columnName: String, $query: String, $mutation: String) {
|
||||
mutation insertGraphiteAutoEmbeddingsConfiguration($name: String, $model: String, $schemaName: String, $tableName: String, $columnName: String, $query: String, $mutation: String) {
|
||||
insertGraphiteAutoEmbeddingsConfiguration(
|
||||
object: {name: $name, model: $model, schemaName: $schemaName, tableName: $tableName, columnName: $columnName, query: $query, mutation: $mutation}
|
||||
) {
|
||||
@@ -7530,7 +7173,7 @@ export type InsertGraphiteAutoEmbeddingsConfigurationMutationHookResult = Return
|
||||
export type InsertGraphiteAutoEmbeddingsConfigurationMutationResult = Apollo.MutationResult<InsertGraphiteAutoEmbeddingsConfigurationMutation>;
|
||||
export type InsertGraphiteAutoEmbeddingsConfigurationMutationOptions = Apollo.BaseMutationOptions<InsertGraphiteAutoEmbeddingsConfigurationMutation, InsertGraphiteAutoEmbeddingsConfigurationMutationVariables>;
|
||||
export const UpdateGraphiteAutoEmbeddingsConfigurationDocument = gql`
|
||||
mutation updateGraphiteAutoEmbeddingsConfiguration($id: uuid!, $name: String, $model: embedding_model_enum, $schemaName: String, $tableName: String, $columnName: String, $query: String, $mutation: String) {
|
||||
mutation updateGraphiteAutoEmbeddingsConfiguration($id: uuid!, $name: String, $model: String, $schemaName: String, $tableName: String, $columnName: String, $query: String, $mutation: String) {
|
||||
updateGraphiteAutoEmbeddingsConfiguration(
|
||||
pk_columns: {id: $id}
|
||||
_set: {name: $name, model: $model, schemaName: $schemaName, tableName: $tableName, columnName: $columnName, query: $query, mutation: $mutation}
|
||||
|
||||
38
dashboard/src/utils/__generated__/graphql.ts
generated
38
dashboard/src/utils/__generated__/graphql.ts
generated
@@ -2524,6 +2524,7 @@ export type ConfigSystemConfigPostgres = {
|
||||
__typename?: 'ConfigSystemConfigPostgres';
|
||||
connectionString: ConfigSystemConfigPostgresConnectionString;
|
||||
database: Scalars['String'];
|
||||
disk?: Maybe<ConfigSystemConfigPostgresDisk>;
|
||||
enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
@@ -2533,6 +2534,7 @@ export type ConfigSystemConfigPostgresComparisonExp = {
|
||||
_or?: InputMaybe<Array<ConfigSystemConfigPostgresComparisonExp>>;
|
||||
connectionString?: InputMaybe<ConfigSystemConfigPostgresConnectionStringComparisonExp>;
|
||||
database?: InputMaybe<ConfigStringComparisonExp>;
|
||||
disk?: InputMaybe<ConfigSystemConfigPostgresDiskComparisonExp>;
|
||||
enabled?: InputMaybe<ConfigBooleanComparisonExp>;
|
||||
};
|
||||
|
||||
@@ -2568,15 +2570,41 @@ export type ConfigSystemConfigPostgresConnectionStringUpdateInput = {
|
||||
storage?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresDisk = {
|
||||
__typename?: 'ConfigSystemConfigPostgresDisk';
|
||||
iops?: Maybe<Scalars['ConfigUint32']>;
|
||||
tput?: Maybe<Scalars['ConfigUint32']>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresDiskComparisonExp = {
|
||||
_and?: InputMaybe<Array<ConfigSystemConfigPostgresDiskComparisonExp>>;
|
||||
_not?: InputMaybe<ConfigSystemConfigPostgresDiskComparisonExp>;
|
||||
_or?: InputMaybe<Array<ConfigSystemConfigPostgresDiskComparisonExp>>;
|
||||
iops?: InputMaybe<ConfigUint32ComparisonExp>;
|
||||
tput?: InputMaybe<ConfigUint32ComparisonExp>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresDiskInsertInput = {
|
||||
iops?: InputMaybe<Scalars['ConfigUint32']>;
|
||||
tput?: InputMaybe<Scalars['ConfigUint32']>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresDiskUpdateInput = {
|
||||
iops?: InputMaybe<Scalars['ConfigUint32']>;
|
||||
tput?: InputMaybe<Scalars['ConfigUint32']>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresInsertInput = {
|
||||
connectionString: ConfigSystemConfigPostgresConnectionStringInsertInput;
|
||||
database: Scalars['String'];
|
||||
disk?: InputMaybe<ConfigSystemConfigPostgresDiskInsertInput>;
|
||||
enabled?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type ConfigSystemConfigPostgresUpdateInput = {
|
||||
connectionString?: InputMaybe<ConfigSystemConfigPostgresConnectionStringUpdateInput>;
|
||||
database?: InputMaybe<Scalars['String']>;
|
||||
disk?: InputMaybe<ConfigSystemConfigPostgresDiskUpdateInput>;
|
||||
enabled?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
@@ -22886,7 +22914,7 @@ export type GetSmtpSettingsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetSmtpSettingsQuery = { __typename?: 'query_root', config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', provider?: { __typename: 'ConfigProvider', id: 'ConfigProvider', smtp?: { __typename?: 'ConfigSmtp', host: string, method: string, port: any, secure: boolean, sender: string, user: string } | null } | null } | null };
|
||||
export type GetSmtpSettingsQuery = { __typename?: 'query_root', config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', provider?: { __typename: 'ConfigProvider', id: 'ConfigProvider', smtp?: { __typename?: 'ConfigSmtp', host: string, method: string, port: any, secure: boolean, sender: string, user: string, password: string } | null } | null } | null };
|
||||
|
||||
export type UpdateConfigMutationVariables = Exact<{
|
||||
appId: Scalars['uuid'];
|
||||
@@ -23098,7 +23126,7 @@ export type GetRemoteAppMetricsQueryVariables = Exact<{ [key: string]: never; }>
|
||||
|
||||
export type GetRemoteAppMetricsQuery = { __typename?: 'query_root', filesAggregate: { __typename?: 'files_aggregate', aggregate?: { __typename?: 'files_aggregate_fields', count: number, sum?: { __typename?: 'files_sum_fields', size?: number | null } | null } | null }, usersAggregate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null } };
|
||||
|
||||
export type RemoteAppGetUsersFragment = { __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> };
|
||||
export type RemoteAppGetUsersFragment = { __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, metadata?: any | null, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> };
|
||||
|
||||
export type RemoteAppGetUsersQueryVariables = Exact<{
|
||||
where: Users_Bool_Exp;
|
||||
@@ -23107,7 +23135,7 @@ export type RemoteAppGetUsersQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type RemoteAppGetUsersQuery = { __typename?: 'query_root', users: Array<{ __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> }>, filteredUsersAggreggate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null }, usersAggregate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null } };
|
||||
export type RemoteAppGetUsersQuery = { __typename?: 'query_root', users: Array<{ __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, metadata?: any | null, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> }>, filteredUsersAggreggate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null }, usersAggregate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null } };
|
||||
|
||||
export type RemoteAppGetUsersCustomQueryVariables = Exact<{
|
||||
where: Users_Bool_Exp;
|
||||
@@ -23124,7 +23152,7 @@ export type RemoteAppGetUsersWholeQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type RemoteAppGetUsersWholeQuery = { __typename?: 'query_root', users: Array<{ __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> }>, usersAggregate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null } };
|
||||
export type RemoteAppGetUsersWholeQuery = { __typename?: 'query_root', users: Array<{ __typename?: 'users', id: any, createdAt: any, displayName: string, avatarUrl: string, email?: any | null, emailVerified: boolean, phoneNumber?: string | null, phoneNumberVerified: boolean, disabled: boolean, defaultRole: string, lastSeen?: any | null, locale: string, metadata?: any | null, roles: Array<{ __typename?: 'authUserRoles', id: any, role: string }>, userProviders: Array<{ __typename?: 'authUserProviders', id: any, providerId: string }> }>, usersAggregate: { __typename?: 'users_aggregate', aggregate?: { __typename?: 'users_aggregate_fields', count: number } | null } };
|
||||
|
||||
export type TotalUsersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -23623,6 +23651,7 @@ export const RemoteAppGetUsersFragmentDoc = gql`
|
||||
defaultRole
|
||||
lastSeen
|
||||
locale
|
||||
metadata
|
||||
roles {
|
||||
id
|
||||
role
|
||||
@@ -25353,6 +25382,7 @@ export const GetSmtpSettingsDocument = gql`
|
||||
secure
|
||||
sender
|
||||
user
|
||||
password
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 2.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a58c5cf: fix: broken link
|
||||
|
||||
## 2.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9480489: fix: update docs performance info
|
||||
|
||||
## 2.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "2.10.1",
|
||||
"version": "2.10.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "mintlify dev"
|
||||
|
||||
@@ -74,19 +74,4 @@ To setup dedicated resources for your project, you can either use the Dashboard
|
||||
|
||||
## Disk Performance
|
||||
|
||||
Services may require a disk provisioned to store data. For instance, [postgres](/guides/database/configuring-postgres#configuration-example) comes with a disk provisioned by default and [Nhost Run](/product/run) may [too](/guides/run/resources#storage). For these cases we provisioned SSD disks with the following performance:
|
||||
|
||||
- Baseline: 3000 IOPS
|
||||
- Baseline: 125Mbps of thoughput
|
||||
- Every 50GB: +350 IOPS and +15Mbps of throughput
|
||||
|
||||
For example, the following disk sizes will have the following performance:
|
||||
|
||||
| Size | IOPS | Throughput |
|
||||
| ---- | ---- | ---------- |
|
||||
| 1 | 3000| 125 |
|
||||
| 10 | 3000| 125 |
|
||||
| 49 | 3000| 125 |
|
||||
| 50 | 3350| 140 |
|
||||
| 100 | 3700 | 155 |
|
||||
| 300 | 5100 | 215 |
|
||||
By default disks are provisioned with a capacity for 3000 IOPS and 125 Mbps of throughput. If you need higher performance don't hesitate to contact us.
|
||||
|
||||
@@ -50,7 +50,7 @@ In addition, thanks to [pgvector](https://github.com/pgvector/pgvector) you can
|
||||
<CardGroup cols={4}>
|
||||
<Card title="Enabling Service" icon="square-1" href="../guides/ai/enabling-service">
|
||||
</Card>
|
||||
<Card title="Local Development" icon="square-2" href="../guides/ai/local_development">
|
||||
<Card title="Local Development" icon="square-2" href="../guides/ai/local-development">
|
||||
</Card>
|
||||
<Card title="Auto-Embeddings" icon="square-3" href="../guides/ai/auto-embeddings">
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/cli
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/cli",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"main": "src/index.mjs",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/codegen-react-apollo
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
- @nhost/react-apollo@11.0.2
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-apollo",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/codegen-react-query
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-query",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/react-urql
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
- @nhost/react-urql@8.0.2
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-urql",
|
||||
"private": true,
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
|
||||
@@ -23,7 +23,7 @@ The following endpoints are now exposed:
|
||||
- `http://localhost:3030`: Nhost Dashboard
|
||||
- `http://localhost:1337`: Hasura Console
|
||||
- `http://localhost:8025`: Mailhog SMTP testing dashboard
|
||||
- `http://localhost:9090`: Traefik dashboad
|
||||
- `http://localhost:9090`: Traefik dashboard
|
||||
|
||||
## Running the Nhost dashboard locally
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/multi-tenant-one-to-many
|
||||
|
||||
## 2.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
|
||||
## 2.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/multi-tenant-one-to-many",
|
||||
"private": true,
|
||||
"version": "2.2.1",
|
||||
"version": "2.2.2",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @nhost-examples/nextjs
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
- @nhost/react-apollo@11.0.2
|
||||
- @nhost/nextjs@2.1.11
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/node-storage
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/node-storage",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"private": true,
|
||||
"description": "This is an example of how to use the Storage with Node.js",
|
||||
"main": "src/index.mjs",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/nextjs-server-components
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs-server-components",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/react-apollo
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
- @nhost/react-apollo@11.0.2
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-apollo",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.9.9",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/react-gqty
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.4.2
|
||||
|
||||
## 1.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-gqty",
|
||||
"private": true,
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @nhost-examples/vue-apollo
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
- @nhost/apollo@7.0.0
|
||||
- @nhost/vue@2.5.2
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-apollo",
|
||||
"private": true,
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/vue-quickstart
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@7.0.0
|
||||
- @nhost/vue@2.5.2
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-quickstart",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 7.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [304065a]
|
||||
- @nhost/nhost-js@3.1.0
|
||||
|
||||
## 6.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "6.2.1",
|
||||
"version": "7.0.0",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user