Compare commits

..

26 Commits

Author SHA1 Message Date
github-actions[bot]
e2646cab55 chore: update versions (#2709)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.16.0

### Minor Changes

- c6d5c5c: feat: add toggle switch to enable/disable public access in
the database settings

## @nhost/docs@2.12.0

### Minor Changes

-   d5077c7: feat: added docs about how to connect to postgres

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-15 09:36:54 +01:00
David Barroso
d5077c7ca4 feat (docs): added docs about how to connect to postgres (#2708) 2024-05-15 10:15:23 +02:00
Hassan Ben Jobrane
c6d5c5cc8c feat: dashboard: add toggle switch to enable/disable database public access (#2707) 2024-05-15 09:12:06 +01:00
github-actions[bot]
f1d9b472d1 chore: update versions (#2704)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@7.0.2

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost/react-apollo@11.0.4

### Patch Changes

-   @nhost/apollo@7.0.2
-   @nhost/react@3.4.4

## @nhost/react-urql@8.0.4

### Patch Changes

-   @nhost/react@3.4.4

## @nhost/nextjs@2.1.13

### Patch Changes

-   @nhost/react@3.4.4

## @nhost/nhost-js@3.1.2

### Patch Changes

- 4c35171: fix: update docstring to correctly reflect usage of
nhost.unsetRole method
- 3cea460: chore: update docs links for nhost-js setRole and unsetRole
methods

## @nhost/react@3.4.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost/vue@2.5.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost/docs@2.11.0

### Minor Changes

-   c6dc7f4: chore: docs: add Nhost client reference

## @nhost/dashboard@1.15.2

### Patch Changes

-   @nhost/react-apollo@11.0.4
-   @nhost/nextjs@2.1.13

## @nhost-examples/cli@0.3.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost-examples/codegen-react-apollo@0.4.4

### Patch Changes

-   @nhost/react@3.4.4
-   @nhost/react-apollo@11.0.4

## @nhost-examples/codegen-react-query@0.4.4

### Patch Changes

-   @nhost/react@3.4.4

## @nhost-examples/codegen-react-urql@0.3.4

### Patch Changes

-   @nhost/react@3.4.4
-   @nhost/react-urql@8.0.4

## @nhost-examples/multi-tenant-one-to-many@2.2.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost-examples/nextjs@0.3.4

### Patch Changes

-   @nhost/react@3.4.4
-   @nhost/react-apollo@11.0.4
-   @nhost/nextjs@2.1.13

## @nhost-examples/node-storage@0.2.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost-examples/nextjs-server-components@0.4.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2

## @nhost-examples/react-apollo@0.8.4

### Patch Changes

-   @nhost/react@3.4.4
-   @nhost/react-apollo@11.0.4

## @nhost-examples/react-gqty@1.2.4

### Patch Changes

-   @nhost/react@3.4.4

## @nhost-examples/vue-apollo@0.6.4

### Patch Changes

-   Updated dependencies [4c35171]
-   Updated dependencies [3cea460]
    -   @nhost/nhost-js@3.1.2
    -   @nhost/apollo@7.0.2
    -   @nhost/vue@2.5.4

## @nhost-examples/vue-quickstart@0.2.4

### Patch Changes

-   @nhost/apollo@7.0.2
-   @nhost/vue@2.5.4

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-14 13:56:40 +01:00
Nuno Pato
c6dc7f44df chore: docs: add Nhost client reference (#2698) 2024-05-14 13:49:31 +01:00
Hassan Ben Jobrane
3cea460c36 chore: update docs links for nhost-js setRole and unsetRole methods (#2706) 2024-05-14 12:52:30 +01:00
Hassan Ben Jobrane
4c351714f5 fix(sdk): update docstring to accurately reflect usage of nhost.unsetRole method (#2703) 2024-05-14 10:54:41 +01:00
github-actions[bot]
3143d66a8e chore: update versions (#2701)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@7.0.1

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost/react-apollo@11.0.3

### Patch Changes

-   @nhost/apollo@7.0.1
-   @nhost/react@3.4.3

## @nhost/react-urql@8.0.3

### Patch Changes

-   @nhost/react@3.4.3

## @nhost/hasura-storage-js@2.5.1

### Patch Changes

- 8512a7f: fix: fix types StorageGetUrlParams and
StorageGetPresignedUrlParams to include missing StorageHeadersParam

## @nhost/nextjs@2.1.12

### Patch Changes

-   @nhost/react@3.4.3

## @nhost/nhost-js@3.1.1

### Patch Changes

-   Updated dependencies [8512a7f]
    -   @nhost/hasura-storage-js@2.5.1

## @nhost/react@3.4.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost/vue@2.5.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost/dashboard@1.15.1

### Patch Changes

-   @nhost/react-apollo@11.0.3
-   @nhost/nextjs@2.1.12

## @nhost-examples/cli@0.3.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost-examples/codegen-react-apollo@0.4.3

### Patch Changes

-   @nhost/react@3.4.3
-   @nhost/react-apollo@11.0.3

## @nhost-examples/codegen-react-query@0.4.3

### Patch Changes

-   @nhost/react@3.4.3

## @nhost-examples/codegen-react-urql@0.3.3

### Patch Changes

-   @nhost/react@3.4.3
-   @nhost/react-urql@8.0.3

## @nhost-examples/multi-tenant-one-to-many@2.2.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost-examples/nextjs@0.3.3

### Patch Changes

-   @nhost/react@3.4.3
-   @nhost/react-apollo@11.0.3
-   @nhost/nextjs@2.1.12

## @nhost-examples/node-storage@0.2.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost-examples/nextjs-server-components@0.4.3

### Patch Changes

-   @nhost/nhost-js@3.1.1

## @nhost-examples/react-apollo@0.8.3

### Patch Changes

-   @nhost/react@3.4.3
-   @nhost/react-apollo@11.0.3

## @nhost-examples/react-gqty@1.2.3

### Patch Changes

-   @nhost/react@3.4.3

## @nhost-examples/vue-apollo@0.6.3

### Patch Changes

-   @nhost/nhost-js@3.1.1
-   @nhost/apollo@7.0.1
-   @nhost/vue@2.5.3

## @nhost-examples/vue-quickstart@0.2.3

### Patch Changes

-   @nhost/apollo@7.0.1
-   @nhost/vue@2.5.3

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-13 21:58:21 +01:00
Hassan Ben Jobrane
8512a7f181 fix:(hasura-storage-js): add missing StorageHeadersParam to StorageGetUrlParams and StorageGetPresignedUrlParams (#2700) 2024-05-13 21:39:48 +01:00
github-actions[bot]
e503b8fe8b chore: update versions (#2691)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/graphql-js@0.2.0

### Minor Changes

- 304065a: feat: add `setHeaders` method enabling global configuration
of storage, graphql, and functions client headers, alongside added
support for passing specific headers with individual calls

## @nhost/hasura-storage-js@2.5.0

### Minor Changes

- 304065a: feat: add `setHeaders` method enabling global configuration
of storage, graphql, and functions client headers, alongside added
support for passing specific headers with individual calls

## @nhost/nhost-js@3.1.0

### Minor Changes

- 304065a: feat: add `setHeaders` method enabling global configuration
of storage, graphql, and functions client headers, alongside added
support for passing specific headers with individual calls

### Patch Changes

-   Updated dependencies [68e0622]
-   Updated dependencies [304065a]
    -   @nhost/hasura-auth-js@2.4.2
    -   @nhost/hasura-storage-js@2.5.0
    -   @nhost/graphql-js@0.2.0

## @nhost/apollo@7.0.0

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost/react-apollo@11.0.2

### Patch Changes

-   @nhost/apollo@7.0.0
-   @nhost/react@3.4.2

## @nhost/react-urql@8.0.2

### Patch Changes

-   @nhost/react@3.4.2

## @nhost/hasura-auth-js@2.4.2

### Patch Changes

- 68e0622: fix: resolved infinite loop occurring with requests to /token
when a user logs out in one tab while other tabs are open

## @nhost/nextjs@2.1.11

### Patch Changes

-   @nhost/react@3.4.2

## @nhost/react@3.4.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost/vue@2.5.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @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

## @nhost/docs@2.10.3

### Patch Changes

-   a58c5cf: fix: broken link

## @nhost-examples/cli@0.3.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost-examples/codegen-react-apollo@0.4.2

### Patch Changes

-   @nhost/react@3.4.2
-   @nhost/react-apollo@11.0.2

## @nhost-examples/codegen-react-query@0.4.2

### Patch Changes

-   @nhost/react@3.4.2

## @nhost-examples/codegen-react-urql@0.3.2

### Patch Changes

-   @nhost/react@3.4.2
-   @nhost/react-urql@8.0.2

## @nhost-examples/multi-tenant-one-to-many@2.2.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost-examples/nextjs@0.3.2

### Patch Changes

-   @nhost/react@3.4.2
-   @nhost/react-apollo@11.0.2
-   @nhost/nextjs@2.1.11

## @nhost-examples/node-storage@0.2.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost-examples/nextjs-server-components@0.4.2

### Patch Changes

-   Updated dependencies [304065a]
    -   @nhost/nhost-js@3.1.0

## @nhost-examples/react-apollo@0.8.2

### Patch Changes

-   @nhost/react@3.4.2
-   @nhost/react-apollo@11.0.2

## @nhost-examples/react-gqty@1.2.2

### Patch Changes

-   @nhost/react@3.4.2

## @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

## @nhost-examples/vue-quickstart@0.2.2

### Patch Changes

-   @nhost/apollo@7.0.0
-   @nhost/vue@2.5.2

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-13 13:52:42 +01:00
Hassan Ben Jobrane
304065ae22 feat: sdk: add setHeaders for setting global headers and make sure all client calls have a headers arg (#2697)
resolves https://github.com/nhost/nhost/issues/2696
2024-05-13 13:38:28 +01:00
Hassan Ben Jobrane
68e0622eb0 fix: broadcast signout event to all tabs (#2686)
fixes https://github.com/nhost/nhost/issues/2635
2024-05-09 11:20:39 +01:00
Hassan Ben Jobrane
70c6834636 chore: add e2e test project (#2688) 2024-05-08 12:52:11 +01:00
Johanna Blom
a7bde37bba feat (dashboard): send metadata in the edit form (#2689)
resolves #2684

---------

Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-05-08 13:36:03 +02:00
Hassan Ben Jobrane
1bc615beca fix(dashboard): improve error toast message handling (#2692) 2024-05-08 12:35:21 +01:00
David Barroso
a58c5cfc96 fix (docs): broken link (#2690) 2024-05-08 12:42:58 +02:00
Daniel Olofsson
c61228e45d Fixed typo in README.md (#2687) 2024-05-07 14:39:31 +02:00
github-actions[bot]
6cec04bd6f chore: update versions (#2680)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.14.0

### Minor Changes

-   a448d7d: feat: allow configuring postmark and delete SMTP settings

## @nhost/docs@2.10.2

### Patch Changes

-   9480489: fix: update docs performance info

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-25 13:13:32 +01:00
David Barroso
a448d7d182 feat (dashboard): allow configuring postmark and deleting SMTP settings (#2678)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-04-25 12:58:47 +01:00
David Barroso
948048940e fix (docs): update docs performance info (#2679)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-04-25 13:50:45 +02:00
github-actions[bot]
5e91221d5a chore: update versions (#2672)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@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

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-18 15:49:01 +01:00
Hassan Ben Jobrane
7278991a59 fix: dashboard: update graphql auto-embeddings configuration to use String type for model field (#2674) 2024-04-18 15:22:32 +01:00
Hassan Ben Jobrane
5924bc3248 fix: dashboard: include password in GetSmtpSettings query (#2673) 2024-04-18 15:14:02 +01:00
Hassan Ben Jobrane
c5ad634799 fix: dashboard: check for undefined router query on Safari when accessing base64config (#2671) 2024-04-18 10:04:18 +01:00
github-actions[bot]
426b93a19f chore: update versions (#2670)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.13.2

### Patch Changes

-   026f84f: fix: use configuration server URL from environment variable

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-17 14:15:04 +01:00
Hassan Ben Jobrane
026f84f466 fix: dashboard: use config server url from env variable (#2669)
related to https://github.com/nhost/cli/issues/862
2024-04-17 14:02:11 +01:00
160 changed files with 2877 additions and 824 deletions

View File

@@ -1,5 +1,57 @@
# @nhost/dashboard
## 1.16.0
### Minor Changes
- c6d5c5c: feat: add toggle switch to enable/disable public access in the database settings
## 1.15.2
### Patch Changes
- @nhost/react-apollo@11.0.4
- @nhost/nextjs@2.1.13
## 1.15.1
### Patch Changes
- @nhost/react-apollo@11.0.3
- @nhost/nextjs@2.1.12
## 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
- 026f84f: fix: use configuration server URL from environment variable
## 1.13.1
### Patch Changes

View File

@@ -28,6 +28,7 @@ ENV NEXT_PUBLIC_NHOST_STORAGE_URL __NEXT_PUBLIC_NHOST_STORAGE_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL __NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL __NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_API_URL __NEXT_PUBLIC_NHOST_HASURA_API_URL__
ENV NEXT_PUBLIC_NHOST_CONFIGSERVER_URL __NEXT_PUBLIC_NHOST_CONFIGSERVER_URL__
RUN yarn global add pnpm@8.10.5
COPY .gitignore .gitignore

View File

@@ -21,5 +21,6 @@ find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_STORAGE_URL__~${NEXT_
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__~${NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_API_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_CONFIGSERVER_URL__~${NEXT_PUBLIC_NHOST_CONFIGSERVER_URL}~g" {} +
exec "$@"

View File

@@ -0,0 +1,2 @@
.secrets
.nhost

View File

@@ -0,0 +1 @@
version: 3

View File

@@ -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>

View File

@@ -0,0 +1 @@
Потвърждение за смяна на имейл

View File

@@ -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>

View File

@@ -0,0 +1 @@
Потвърждаване на имейл

View File

@@ -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>

View File

@@ -0,0 +1 @@
Смяна на парола

View File

@@ -0,0 +1 @@
Вашият код е ${code}.

View File

@@ -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>

View File

@@ -0,0 +1 @@
Магически линк за вход

View File

@@ -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>

View File

@@ -0,0 +1 @@
Změna vaší emailové adresy

View File

@@ -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>

View File

@@ -0,0 +1 @@
Ověření vaší emailové adresy

View File

@@ -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>

View File

@@ -0,0 +1 @@
Obnova hesla

View File

@@ -0,0 +1 @@
Váš kód je ${code}.

View File

@@ -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>

View File

@@ -0,0 +1 @@
Bezpečný odkaz k přihlášení

View File

@@ -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>

View File

@@ -0,0 +1 @@
Change your email address

View File

@@ -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>

View File

@@ -0,0 +1 @@
Verify your email

View File

@@ -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>

View File

@@ -0,0 +1 @@
Reset your password

View File

@@ -0,0 +1 @@
Your code is ${code}.

View File

@@ -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>

View File

@@ -0,0 +1 @@
Secure sign-in link

View File

@@ -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>

View File

@@ -0,0 +1 @@
Cambiar dirección de correo electrónico

View File

@@ -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>

View File

@@ -0,0 +1 @@
Verifica tu correo electrónico

View File

@@ -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>

View File

@@ -0,0 +1 @@
Recuperar contraseña

View File

@@ -0,0 +1 @@
Tu código es ${code}.

View File

@@ -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>

View File

@@ -0,0 +1 @@
Enlace de acceso seguro

View File

@@ -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>

View File

@@ -0,0 +1 @@
Changez votre adresse courriel

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h2>V&eacute;rifiez votre courriel</h2>
<p>Utilisez ce lien pour v&eacute;rifier votre courriel :</p>
<p>
<a href="${link}">
V&eacute;rifier courriel
</a>
</p>
</body>
</html>

View File

@@ -0,0 +1 @@
Vérifier votre courriel

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h2>R&eacute;initialiser votre mot de passe</h2>
<p>Utilisez ce lien pour r&eacute;initialiser votre mot de passe :</p>
<p>
<a href="${link}">
R&eacute;initialiser mot de passe
</a>
</p>
</body>
</html>

View File

@@ -0,0 +1 @@
Réinitialiser votre mot de passe

View File

@@ -0,0 +1 @@
Votre code est ${code}.

View File

@@ -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&ccedil;on s&eacute;curisée :</p>
<p>
<a href="${link}">
Connexion
</a>
</p>
</body>
</html>

View File

@@ -0,0 +1 @@
Lien de connexion sécurisé

View File

@@ -0,0 +1,8 @@
${link},
${displayName},
${email},
${ticket},
${redirectTo},
${serverUrl},
${clientUrl},
${locale},

View File

@@ -0,0 +1 @@
${link}, ${displayName}, ${email}, ${ticket}, ${redirectTo}, ${serverUrl}, ${clientUrl}, ${locale}

View 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 }}'

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "1.13.1",
"version": "1.16.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",

View File

@@ -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) {

View File

@@ -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>
);
}

View File

@@ -0,0 +1 @@
export { default as DeleteSTMPSettings } from './DeleteSMTPSettings';

View File

@@ -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>
);
}

View File

@@ -0,0 +1,2 @@
export * from './PostmarkSettings';
export { default as PostmarkSettings } from './PostmarkSettings';

View File

@@ -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>
);
}

View File

@@ -0,0 +1,2 @@
export * from './SMTPSettings';
export { default as SMTPSettings } from './SMTPSettings';

View File

@@ -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">

View File

@@ -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 }),
},
},
});

View File

@@ -1,3 +1,7 @@
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 { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert';
@@ -7,11 +11,32 @@ import type { InputProps } from '@/components/ui/v2/Input';
import { Input } from '@/components/ui/v2/Input';
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
import { copy } from '@/utils/copy';
import { useGetPostgresSettingsQuery } from '@/utils/__generated__/graphql';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import {
useGetPostgresSettingsQuery,
useUpdateConfigMutation,
} from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
const databasePublicAccessValidationSchema = Yup.object({
enablePublicAccess: Yup.bool(),
});
type DatabasePublicAccessFormValues = Yup.InferType<
typeof databasePublicAccessValidationSchema
>;
export default function DatabaseConnectionInfo() {
const { openDialog } = useDialog();
const isPlatform = useIsPlatform();
const { maintenanceActive } = useUI();
const localMimirClient = useLocalMimirClient();
const { currentProject } = useCurrentWorkspaceAndProject();
const { data, loading, error } = useGetPostgresSettingsQuery({
@@ -19,6 +44,61 @@ export default function DatabaseConnectionInfo() {
fetchPolicy: 'cache-only',
});
const [updateConfig] = useUpdateConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}),
});
const enablePublicAccess =
!!data?.config?.postgres?.resources?.enablePublicAccess;
const form = useForm<DatabasePublicAccessFormValues>({
reValidateMode: 'onSubmit',
defaultValues: {
enablePublicAccess,
},
resolver: yupResolver(databasePublicAccessValidationSchema),
});
async function handleSubmit(formValues: DatabasePublicAccessFormValues) {
const updateConfigPromise = updateConfig({
variables: {
appId: currentProject.id,
config: {
postgres: {
resources: {
enablePublicAccess: formValues.enablePublicAccess,
},
},
},
},
});
await execPromiseWithErrorToast(
async () => {
await updateConfigPromise;
form.reset(formValues);
if (!isPlatform) {
openDialog({
title: 'Apply your changes',
component: <ApplyLocalSettingsDialog />,
props: {
PaperProps: {
className: 'max-w-2xl',
},
},
});
}
},
{
loadingMessage: 'Database settings are being updated...',
successMessage: 'Database settings have been updated successfully.',
errorMessage:
"An error occurred while trying to update the project's database settings.",
},
);
}
if (loading) {
return (
<ActivityIndicator
@@ -76,49 +156,72 @@ export default function DatabaseConnectionInfo() {
},
];
return (
<SettingsContainer
title="Connection Info"
description="Connect directly to the Postgres database with this information."
slotProps={{ footer: { className: 'hidden' } }}
className="grid grid-cols-6 gap-4 pb-2"
>
{settingsDatabaseCustomInputs.map(
({ name, label, className, value: inputValue }) => (
<Input
key={name}
label={label}
required
disabled
value={inputValue}
className={className}
slotProps={{ inputRoot: { className: '!pr-8 truncate' } }}
fullWidth
hideEmptyHelperText
endAdornment={
<InputAdornment position="end" className="absolute right-2">
<Button
sx={{ minWidth: 0, padding: 0 }}
color="secondary"
variant="borderless"
onClick={(e) => {
e.stopPropagation();
copy(inputValue as string, `${label}`);
}}
>
<CopyIcon className="h-4 w-4" />
</Button>
</InputAdornment>
}
/>
),
)}
const { formState } = form;
<Alert severity="info" className="col-span-6 text-left">
To connect to the Postgres database directly, generate a new password,
securely save it, and then modify your connection string with the newly
created password.
</Alert>
</SettingsContainer>
return (
<FormProvider {...form}>
<Form onSubmit={handleSubmit}>
<SettingsContainer
title="Public access"
description={
enablePublicAccess
? 'Connect directly to the Postgres database with this information.'
: 'Enable public access to your Postgres database.'
}
slotProps={{
submitButton: {
disabled: !formState.isDirty || maintenanceActive,
loading: formState.isSubmitting,
},
}}
className="grid grid-cols-6 gap-4 pb-2"
switchId="enablePublicAccess"
showSwitch
>
{enablePublicAccess && (
<>
{settingsDatabaseCustomInputs.map(
({ name, label, className, value: inputValue }) => (
<Input
key={name}
label={label}
required
disabled
value={inputValue}
className={className}
slotProps={{ inputRoot: { className: '!pr-8 truncate' } }}
fullWidth
hideEmptyHelperText
endAdornment={
<InputAdornment
position="end"
className="absolute right-2"
>
<Button
sx={{ minWidth: 0, padding: 0 }}
color="secondary"
variant="borderless"
onClick={(e) => {
e.stopPropagation();
copy(inputValue as string, `${label}`);
}}
>
<CopyIcon className="w-4 h-4" />
</Button>
</InputAdornment>
}
/>
),
)}
<Alert severity="info" className="col-span-6 text-left">
To connect to the Postgres database directly, generate a new
password, securely save it, and then modify your connection
string with the newly created password.
</Alert>
</>
)}
</SettingsContainer>
</Form>
</FormProvider>
);
}

View File

@@ -13,6 +13,7 @@ query GetPostgresSettings($appId: uuid!) {
storage {
capacity
}
enablePublicAccess
}
}
}

View File

@@ -12,6 +12,7 @@ query GetSmtpSettings($appId: uuid!) {
secure
sender
user
password
}
}
}

View File

@@ -6,6 +6,7 @@ mutation UpdateConfig($appId: uuid!, $config: ConfigConfigUpdateInput!) {
storage {
capacity
}
enablePublicAccess
}
}
ai {

View File

@@ -1,6 +1,6 @@
mutation insertGraphiteAutoEmbeddingsConfiguration(
$name: String
$model: embedding_model_enum
$model: String
$schemaName: String
$tableName: String
$columnName: String

View File

@@ -1,7 +1,7 @@
mutation updateGraphiteAutoEmbeddingsConfiguration(
$id: uuid!
$name: String
$model: embedding_model_enum
$model: String
$schemaName: String
$tableName: String
$columnName: String

View File

@@ -11,6 +11,7 @@ fragment RemoteAppGetUsers on users {
defaultRole
lastSeen
locale
metadata
roles {
id
role

View File

@@ -1,3 +1,4 @@
import { getConfigServerUrl } from '@/utils/env';
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { useMemo } from 'react';
@@ -11,7 +12,7 @@ export default function useLocalMimirClient() {
new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'https://local.dashboard.nhost.run/v1/configserver/graphql',
uri: getConfigServerUrl(),
}),
}),
[],

View File

@@ -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>
);
}

View File

@@ -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"

View File

@@ -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}

View File

@@ -1804,6 +1804,7 @@ export type ConfigPostgresInsertInput = {
export type ConfigPostgresResources = {
__typename?: 'ConfigPostgresResources';
compute?: Maybe<ConfigResourcesCompute>;
enablePublicAccess?: Maybe<Scalars['Boolean']>;
networking?: Maybe<ConfigNetworking>;
/** Number of replicas for a service */
replicas?: Maybe<Scalars['ConfigUint8']>;
@@ -1815,6 +1816,7 @@ export type ConfigPostgresResourcesComparisonExp = {
_not?: InputMaybe<ConfigPostgresResourcesComparisonExp>;
_or?: InputMaybe<Array<ConfigPostgresResourcesComparisonExp>>;
compute?: InputMaybe<ConfigResourcesComputeComparisonExp>;
enablePublicAccess?: InputMaybe<ConfigBooleanComparisonExp>;
networking?: InputMaybe<ConfigNetworkingComparisonExp>;
replicas?: InputMaybe<ConfigUint8ComparisonExp>;
storage?: InputMaybe<ConfigPostgresStorageComparisonExp>;
@@ -1822,6 +1824,7 @@ export type ConfigPostgresResourcesComparisonExp = {
export type ConfigPostgresResourcesInsertInput = {
compute?: InputMaybe<ConfigResourcesComputeInsertInput>;
enablePublicAccess?: InputMaybe<Scalars['Boolean']>;
networking?: InputMaybe<ConfigNetworkingInsertInput>;
replicas?: InputMaybe<Scalars['ConfigUint8']>;
storage?: InputMaybe<ConfigPostgresStorageInsertInput>;
@@ -1829,6 +1832,7 @@ export type ConfigPostgresResourcesInsertInput = {
export type ConfigPostgresResourcesUpdateInput = {
compute?: InputMaybe<ConfigResourcesComputeUpdateInput>;
enablePublicAccess?: InputMaybe<Scalars['Boolean']>;
networking?: InputMaybe<ConfigNetworkingUpdateInput>;
replicas?: InputMaybe<Scalars['ConfigUint8']>;
storage?: InputMaybe<ConfigPostgresStorageUpdateInput>;
@@ -2524,7 +2528,9 @@ export type ConfigSystemConfigPostgres = {
__typename?: 'ConfigSystemConfigPostgres';
connectionString: ConfigSystemConfigPostgresConnectionString;
database: Scalars['String'];
disk?: Maybe<ConfigSystemConfigPostgresDisk>;
enabled?: Maybe<Scalars['Boolean']>;
majorVersion?: Maybe<Scalars['String']>;
};
export type ConfigSystemConfigPostgresComparisonExp = {
@@ -2533,7 +2539,9 @@ export type ConfigSystemConfigPostgresComparisonExp = {
_or?: InputMaybe<Array<ConfigSystemConfigPostgresComparisonExp>>;
connectionString?: InputMaybe<ConfigSystemConfigPostgresConnectionStringComparisonExp>;
database?: InputMaybe<ConfigStringComparisonExp>;
disk?: InputMaybe<ConfigSystemConfigPostgresDiskComparisonExp>;
enabled?: InputMaybe<ConfigBooleanComparisonExp>;
majorVersion?: InputMaybe<ConfigStringComparisonExp>;
};
export type ConfigSystemConfigPostgresConnectionString = {
@@ -2568,16 +2576,44 @@ 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']>;
majorVersion?: InputMaybe<Scalars['String']>;
};
export type ConfigSystemConfigPostgresUpdateInput = {
connectionString?: InputMaybe<ConfigSystemConfigPostgresConnectionStringUpdateInput>;
database?: InputMaybe<Scalars['String']>;
disk?: InputMaybe<ConfigSystemConfigPostgresDiskUpdateInput>;
enabled?: InputMaybe<Scalars['Boolean']>;
majorVersion?: InputMaybe<Scalars['String']>;
};
export type ConfigSystemConfigUpdateInput = {
@@ -2659,14 +2695,6 @@ export type Metrics = {
value: Scalars['float64'];
};
export type StatsDailyLiveFreeApps = {
__typename?: 'StatsDailyLiveFreeApps';
avg: Scalars['Int'];
max: Scalars['Int'];
min: Scalars['Int'];
raw: Array<Scalars['Int']>;
};
export type StatsLiveApps = {
__typename?: 'StatsLiveApps';
appID: Array<Scalars['uuid']>;
@@ -11798,6 +11826,7 @@ export type Mutation_Root = {
billingUpdatePersistentVolume: Scalars['Boolean'];
billingUpdateReports: Scalars['Boolean'];
billingUploadReports: Scalars['Boolean'];
changeDatabaseVersion: Scalars['Boolean'];
/** delete single row from the table: "apps" */
deleteApp?: Maybe<Apps>;
/** delete single row from the table: "app_states" */
@@ -12483,6 +12512,14 @@ export type Mutation_RootBillingUpdateReportsArgs = {
};
/** mutation root */
export type Mutation_RootChangeDatabaseVersionArgs = {
appID: Scalars['uuid'];
force?: InputMaybe<Scalars['Boolean']>;
version: Scalars['String'];
};
/** mutation root */
export type Mutation_RootDeleteAppArgs = {
id: Scalars['uuid'];
@@ -15988,12 +16025,6 @@ export type Query_Root = {
softwareVersions: Array<Software_Versions>;
/** fetch aggregated fields from the table: "software_versions" */
softwareVersionsAggregate: Software_Versions_Aggregate;
/**
* Returns the per-day number of free live apps in the given time range, as well as the min, max and avg.
*
* Requests that returned a 4xx or 5xx status code are not counted as live traffic.
*/
statsDailyLiveFreeApps: StatsDailyLiveFreeApps;
/**
* Returns lists of apps that have some live traffic in the give time range.
* From defaults to 24 hours ago and to defaults to now.
@@ -16003,6 +16034,8 @@ export type Query_Root = {
statsLiveApps: StatsLiveApps;
systemConfig?: Maybe<ConfigSystemConfig>;
systemConfigs: Array<ConfigAppSystemConfig>;
/** Returns system logs for a given application */
systemLogs: Array<Log>;
/** fetch data from the table: "auth.users" using primary key columns */
user?: Maybe<Users>;
/** fetch data from the table: "auth.users" */
@@ -17051,12 +17084,6 @@ export type Query_RootSoftwareVersionsAggregateArgs = {
};
export type Query_RootStatsDailyLiveFreeAppsArgs = {
from?: InputMaybe<Scalars['Timestamp']>;
to?: InputMaybe<Scalars['Timestamp']>;
};
export type Query_RootStatsLiveAppsArgs = {
from?: InputMaybe<Scalars['Timestamp']>;
to?: InputMaybe<Scalars['Timestamp']>;
@@ -17073,6 +17100,14 @@ export type Query_RootSystemConfigsArgs = {
};
export type Query_RootSystemLogsArgs = {
action: Scalars['String'];
appID: Scalars['String'];
from?: InputMaybe<Scalars['Timestamp']>;
to?: InputMaybe<Scalars['Timestamp']>;
};
export type Query_RootUserArgs = {
id: Scalars['uuid'];
};
@@ -22662,7 +22697,7 @@ export type GetPostgresSettingsQueryVariables = Exact<{
}>;
export type GetPostgresSettingsQuery = { __typename?: 'query_root', systemConfig?: { __typename?: 'ConfigSystemConfig', postgres: { __typename?: 'ConfigSystemConfigPostgres', database: string } } | null, config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', postgres?: { __typename?: 'ConfigPostgres', version?: string | null, resources?: { __typename?: 'ConfigPostgresResources', storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null } | null } | null } | null };
export type GetPostgresSettingsQuery = { __typename?: 'query_root', systemConfig?: { __typename?: 'ConfigSystemConfig', postgres: { __typename?: 'ConfigSystemConfigPostgres', database: string } } | null, config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', postgres?: { __typename?: 'ConfigPostgres', version?: string | null, resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null } | null } | null } | null };
export type ResetDatabasePasswordMutationVariables = Exact<{
appId: Scalars['String'];
@@ -22886,7 +22921,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'];
@@ -22894,7 +22929,7 @@ export type UpdateConfigMutationVariables = Exact<{
}>;
export type UpdateConfigMutation = { __typename?: 'mutation_root', updateConfig: { __typename?: 'ConfigConfig', id: 'ConfigConfig', postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null } | null } | null, ai?: { __typename?: 'ConfigAI', version?: string | null, webhookSecret: string, autoEmbeddings?: { __typename?: 'ConfigAIAutoEmbeddings', synchPeriodMinutes?: any | null } | null, openai: { __typename?: 'ConfigAIOpenai', organization?: string | null, apiKey: string }, resources: { __typename?: 'ConfigAIResources', compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any } } } | null } };
export type UpdateConfigMutation = { __typename?: 'mutation_root', updateConfig: { __typename?: 'ConfigConfig', id: 'ConfigConfig', postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null } | null } | null, ai?: { __typename?: 'ConfigAI', version?: string | null, webhookSecret: string, autoEmbeddings?: { __typename?: 'ConfigAIAutoEmbeddings', synchPeriodMinutes?: any | null } | null, openai: { __typename?: 'ConfigAIOpenai', organization?: string | null, apiKey: string }, resources: { __typename?: 'ConfigAIResources', compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any } } } | null } };
export type UnpauseApplicationMutationVariables = Exact<{
appId: Scalars['uuid'];
@@ -23098,7 +23133,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 +23142,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 +23159,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 +23658,7 @@ export const RemoteAppGetUsersFragmentDoc = gql`
defaultRole
lastSeen
locale
metadata
roles {
id
role
@@ -24036,6 +24072,7 @@ export const GetPostgresSettingsDocument = gql`
storage {
capacity
}
enablePublicAccess
}
}
}
@@ -25353,6 +25390,7 @@ export const GetSmtpSettingsDocument = gql`
secure
sender
user
password
}
}
}
@@ -25398,6 +25436,7 @@ export const UpdateConfigDocument = gql`
storage {
capacity
}
enablePublicAccess
}
}
ai {

View File

@@ -87,3 +87,13 @@ export function getHasuraApiUrl() {
'https://local.hasura.nhost.run'
);
}
/**
* Custom URL of the config service.
*/
export function getConfigServerUrl() {
return (
process.env.NEXT_PUBLIC_NHOST_CONFIGSERVER_URL ||
'https://local.dashboard.nhost.run/v1/configserver/graphql'
);
}

View File

@@ -1,5 +1,29 @@
# @nhost/docs
## 2.12.0
### Minor Changes
- d5077c7: feat: added docs about how to connect to postgres
## 2.11.0
### Minor Changes
- c6dc7f4: chore: docs: add Nhost client reference
## 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

View File

@@ -0,0 +1,43 @@
---
title: Accessing the Database
description: How to access the database directly using the connection string
icon: key
---
In most cases you will not need to access the database directly, choosing to interact with the data via the Graphql API, however, if you need direct access to postgres you can access it via the connection string.
# Nhost Run
You can find details on how to connect to the database from an [Nhost Run](/product/run) service [here](/guides/run/networking#connecting-to-the-nhost-stack). If you don't know the password you can set a new password in the dashboard:
**Project Dashboard -> Settings -> Database**
![reset password](/images/guides/database/access/reset.png)
# Public Access
For security reasons, by default your database won't be accessible online. If you need to access it directly from the Internet, first you will need to enable public access (enabling public access will also show the connection details):
<Tabs>
<Tab title="Dashboard">
**Project Dashboard -> Settings -> Database**
![public access](/images/guides/database/access/public.png)
</Tab>
<Tab title="Config">
```toml
[postgres.resources]
enablePublicAccess = true
```
</Tab>
</Tabs>
<Note>
Public access to your database utilizes [pgbouncer](http://www.pgbouncer.org). As this pooler is shared infrastructure the pooler will still be available even if your database has no public access configured. The pooler will simply not have access to your database.
</Note>
# Functions
[Functions](/product/functions) run on a separate network, which means in order to access the database you will first need to [make it public](#public-access).

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

View File

@@ -96,7 +96,7 @@
},
{
"group": "Database",
"pages": ["guides/database/configuring-postgres", "guides/database/extensions", "guides/database/performance"]
"pages": ["guides/database/configuring-postgres", "guides/database/access", "guides/database/extensions", "guides/database/performance"]
},
{
"group": "AI",
@@ -298,6 +298,10 @@
"group": "JavaScript",
"icon": "js",
"pages": [
{
"group": "nhost-js",
"pages": ["reference/javascript/nhost-js/nhost-client", "reference/javascript/nhost-js/set-role", "reference/javascript/nhost-js/unset-role"]
},
{
"group": "Auth",
"pages": [
@@ -338,7 +342,10 @@
"reference/javascript/storage/get-public-url",
"reference/javascript/storage/delete",
"reference/javascript/storage/set-access-token",
"reference/javascript/storage/set-admin-secret"
"reference/javascript/storage/set-admin-secret",
"reference/javascript/storage/set-headers",
"reference/javascript/storage/unset-headers",
"reference/javascript/storage/get-headers"
]
},
{
@@ -347,7 +354,10 @@
"reference/javascript/graphql/nhost-graphql-client",
"reference/javascript/graphql/get-url",
"reference/javascript/graphql/set-access-token",
"reference/javascript/graphql/request"
"reference/javascript/graphql/request",
"reference/javascript/graphql/set-headers",
"reference/javascript/graphql/unset-headers",
"reference/javascript/graphql/get-headers"
]
},
{

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/docs",
"version": "2.10.1",
"version": "2.12.0",
"private": true,
"scripts": {
"start": "mintlify dev"

View File

@@ -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.

View File

@@ -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>

View File

@@ -0,0 +1,10 @@
---
title: getHeaders()
sidebarTitle: getHeaders()
---
Use `nhost.graphql.getHeaders` to get the global headers sent with all graphql requests
```ts
nhost.graphql.getHeaders()
```

View File

@@ -0,0 +1,20 @@
---
title: setHeaders()
sidebarTitle: setHeaders()
---
Use `nhost.graphql.setHeaders` to set global headers to be sent in all subsequent graphql requests
```ts
nhost.graphql.setHeaders({
'x-hasura-role': 'admin'
})
```
## Parameters
---
**<span className="parameter-name">headers</span>** <span className="optional-status">optional</span> <code>Record&lt;string, string&gt;</code>
---

View File

@@ -0,0 +1,11 @@
---
title: unsetHeaders()
sidebarTitle: unsetHeaders()
---
Use `nhost.graphql.unsetHeaders` to remove global headers sent with all requests, except for the role header to preserve
the role set by 'setRole' method.
```ts
nhost.graphql.unsetHeaders()
```

View File

@@ -0,0 +1,51 @@
---
title: NhostClient
description: The Nhost client is the entry point to Nhost services.
---
# `NhostClient`
```ts
// Create a new Nhost client from subdomain and region.
const nhost = new NhostClient({ subdomain, region })
```
```ts
// Create a new Nhost client from individual service URLs (custom domains, self-hosting, etc).
const nhost = new NhostClient({
authUrl: 'my-auth-service-url',
storageUrl: 'my-storage-service-url',
graphqlUrl: 'my-graphql-service-url',
functionsUrl: 'my-functions-service-url'
})
```
```ts
// Create a new Nhost client for local development.
const nhost = new NhostClient({ subdomain: 'local' })
```
## Parameters
---
**<span className="parameter-name">\_\_namedParameters</span>** <span className="optional-status">required</span> [`NhostClientConstructorParams`](/reference/javascript/nhost-js/types/nhost-client-constructor-params)
| Property | Type | Required | Notes |
| :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------ | :------: | :--------------------------------------------------------------------------------------------------------------------------------------- |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>adminSecret</span> | <code>string</code> | | When set, the admin secret is sent as a header, `x-hasura-admin-secret`, for all requests to GraphQL, Storage, and Serverless Functions. |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>functionsUrl</span> | <code>string</code> | | |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>storageUrl</span> | <code>string</code> | | |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>graphqlUrl</span> | <code>string</code> | | |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>authUrl</span> | <code>string</code> | | |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>region</span> | <code>string</code> | | Project region (e.g. `eu-central-1`) Project region is not required during local development (when `subdomain` is `localhost`) |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>subdomain</span> | <code>string</code> | | Project subdomain (e.g. `ieingiwnginwnfnegqwvdqwdwq`) Use `localhost` during local development |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>devTools</span> | <code>boolean</code> | | Activate devTools e.g. the ability to connect to the xstate inspector |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>autoSignIn</span> | <code>boolean</code> | | When set to true, will parse the url on startup to check if it contains a refresh token to start the session with |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>autoRefreshToken</span> | <code>boolean</code> | | When set to true, will automatically refresh token before it expires |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>clientStorage</span> | [`ClientStorage`](/reference/javascript/nhost-js/types/client-storage) | | Object where the refresh token will be persisted and read locally. |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>clientStorageType</span> | [`ClientStorageType`](/reference/javascript/nhost-js/types/client-storage-type) | | Define a way to get information about the refresh token and its exipration date. |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>refreshIntervalTime</span> | <code>number</code> | | Time interval until token refreshes, in seconds |
| <span className="parameter-name"><span className="light-grey">\_\_namedParameters.</span>start</span> | <code>boolean</code> | | |
---

View File

@@ -0,0 +1,29 @@
---
title: setRole()
sidebarTitle: setRole()
---
Use `nhost.setRole` to set the user role for all subsequent GraphQL, storage, and functions calls.
Underneath, this method sets the `x-hasura-role` header on the graphql, storage,
and functions clients.
```ts
nhost.graphql.setHeaders({ 'x-hasura-role': role })
nhost.storage.setHeaders({ 'x-hasura-role': role })
nhost.functions.setHeaders({ 'x-hasura-role': role })
```
Note: Exercise caution when mixing the use of `setRole` along with `setHeaders` when setting the
`x-hasura-role` header, as the last call will override any previous ones.
```ts
nhost.setRole('admin')
```
## Parameters
---
**<span className="parameter-name">role</span>** <span className="optional-status">required</span> <code>string</code>
---

View File

@@ -0,0 +1,18 @@
---
title: ClientStorageType
sidebarTitle: ClientStorageType
description: No description provided.
---
# `ClientStorageType`
```ts
type ClientStorageType =
| 'capacitor'
| 'custom'
| 'expo-secure-storage'
| 'localStorage'
| 'react-native'
| 'web'
| 'cookie'
```

View File

@@ -0,0 +1,55 @@
---
title: ClientStorage
sidebarTitle: ClientStorage
description: No description provided.
---
# `ClientStorage`
## Parameters
---
**<span className="parameter-name">customSet</span>** <span className="optional-status">optional</span> <code>(key: string, value: null &#124; string) =&gt; void &#124; Promise&lt;void&gt;</code>
---
**<span className="parameter-name">customGet</span>** <span className="optional-status">optional</span> <code>(key: string) =&gt; null &#124; string &#124; Promise&lt;null &#124; string&gt;</code>
---
**<span className="parameter-name">deleteItemAsync</span>** <span className="optional-status">optional</span> <code>(key: string) =&gt; void</code>
---
**<span className="parameter-name">getItemAsync</span>** <span className="optional-status">optional</span> <code>(key: string) =&gt; any</code>
---
**<span className="parameter-name">setItemAsync</span>** <span className="optional-status">optional</span> <code>(key: string, value: string) =&gt; void</code>
---
**<span className="parameter-name">remove</span>** <span className="optional-status">optional</span> <code>(options: &#123; key: string &#125;) =&gt; void</code>
---
**<span className="parameter-name">get</span>** <span className="optional-status">optional</span> <code>(options: &#123; key: string &#125;) =&gt; any</code>
---
**<span className="parameter-name">set</span>** <span className="optional-status">optional</span> <code>(options: &#123; key: string, value: string &#125;) =&gt; void</code>
---
**<span className="parameter-name">removeItem</span>** <span className="optional-status">optional</span> <code>(key: string) =&gt; void</code>
---
**<span className="parameter-name">getItem</span>** <span className="optional-status">optional</span> <code>(key: string) =&gt; any</code>
---
**<span className="parameter-name">setItem</span>** <span className="optional-status">optional</span> <code>(\_key: string, \_value: string) =&gt; void</code>
---

View File

@@ -0,0 +1,118 @@
---
title: NhostClientConstructorParams
sidebarTitle: NhostClientConstructorParams
description: No description provided.
---
# `NhostClientConstructorParams`
## Parameters
---
**<span className="parameter-name">start</span>** <span className="optional-status">optional</span> <code>boolean</code>
---
**<span className="parameter-name">refreshIntervalTime</span>** <span className="optional-status">optional</span> <code>number</code>
Time interval until token refreshes, in seconds
---
**<span className="parameter-name">clientStorageType</span>** <span className="optional-status">optional</span> [`ClientStorageType`](/reference/javascript/nhost-js/types/client-storage-type)
Define a way to get information about the refresh token and its exipration date.
**`@default`**
`web`
---
**<span className="parameter-name">clientStorage</span>** <span className="optional-status">optional</span> [`ClientStorage`](/reference/javascript/nhost-js/types/client-storage)
Object where the refresh token will be persisted and read locally.
Recommended values:
- `'web'` and `'cookies'`: no value is required
- `'react-native'`: `import Storage from @react-native-async-storage/async-storage`
- `'cookies'`: `localStorage`
- `'custom'`: an object that defines the following methods:
- `setItem` or `setItemAsync`
- `getItem` or `getItemAsync`
- `removeItem`
- `'capacitor'`: `import { Storage } from @capacitor/storage`
- `'expo-secure-store'`: `import * as SecureStore from 'expo-secure-store'`
| Property | Type | Required | Notes |
| :-------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- | :------: | :---- |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>setItem</span> | <code>(\_key: string, \_value: string) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>getItem</span> | <code>(key: string) =&gt; any</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>removeItem</span> | <code>(key: string) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>set</span> | <code>(options: &#123; key: string, value: string &#125;) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>get</span> | <code>(options: &#123; key: string &#125;) =&gt; any</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>remove</span> | <code>(options: &#123; key: string &#125;) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>setItemAsync</span> | <code>(key: string, value: string) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>getItemAsync</span> | <code>(key: string) =&gt; any</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>deleteItemAsync</span> | <code>(key: string) =&gt; void</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>customGet</span> | <code>(key: string) =&gt; null &#124; string &#124; Promise&lt;null &#124; string&gt;</code> | | |
| <span className="parameter-name"><span className="light-grey">clientStorage.</span>customSet</span> | <code>(key: string, value: null &#124; string) =&gt; void &#124; Promise&lt;void&gt;</code> | | |
---
**<span className="parameter-name">autoRefreshToken</span>** <span className="optional-status">optional</span> <code>boolean</code>
When set to true, will automatically refresh token before it expires
---
**<span className="parameter-name">autoSignIn</span>** <span className="optional-status">optional</span> <code>boolean</code>
When set to true, will parse the url on startup to check if it contains a refresh token to start the session with
---
**<span className="parameter-name">devTools</span>** <span className="optional-status">optional</span> <code>boolean</code>
Activate devTools e.g. the ability to connect to the xstate inspector
---
**<span className="parameter-name">subdomain</span>** <span className="optional-status">optional</span> <code>string</code>
Project subdomain (e.g. `ieingiwnginwnfnegqwvdqwdwq`)
Use `localhost` during local development
---
**<span className="parameter-name">region</span>** <span className="optional-status">optional</span> <code>string</code>
Project region (e.g. `eu-central-1`)
Project region is not required during local development (when `subdomain` is `localhost`)
---
**<span className="parameter-name">authUrl</span>** <span className="optional-status">optional</span> <code>string</code>
---
**<span className="parameter-name">graphqlUrl</span>** <span className="optional-status">optional</span> <code>string</code>
---
**<span className="parameter-name">storageUrl</span>** <span className="optional-status">optional</span> <code>string</code>
---
**<span className="parameter-name">functionsUrl</span>** <span className="optional-status">optional</span> <code>string</code>
---
**<span className="parameter-name">adminSecret</span>** <span className="optional-status">optional</span> <code>string</code>
When set, the admin secret is sent as a header, `x-hasura-admin-secret`,
for all requests to GraphQL, Storage, and Serverless Functions.
---

View File

@@ -0,0 +1,14 @@
---
title: unsetRole()
sidebarTitle: unsetRole()
---
Use `nhost.unsetRole` to unset the user role for all subsequent graphql, storage and functions calls.
Underneath, this method removes the `x-hasura-role` header from the graphql, storage and functions clients.
Note: Exercise caution when mixing the use of `unsetRole` along with `setHeaders` when setting the
`x-hasura-role` header, as the last call will override any previous ones.
```ts
nhost.unsetRole()
```

View File

@@ -22,6 +22,6 @@ const { file, error } = await nhost.storage.download({ fileId: '<File-ID>' })
| <span className="parameter-name"><span className="light-grey">params.</span>quality</span> | <code>number</code> | | Image quality, between 1 and 100, 100 being the best quality |
| <span className="parameter-name"><span className="light-grey">params.</span>height</span> | <code>number</code> | | Image height, in pixels |
| <span className="parameter-name"><span className="light-grey">params.</span>width</span> | <code>number</code> | | Image width, in pixels |
| <span className="parameter-name"><span className="light-grey">params.</span>headers</span> | <code>Record&lt;string, string&gt;</code> | | Optional headers to be sent with the request |
| <span className="parameter-name"><span className="light-grey">params.</span>headers</span> | <code>Record&lt;string, string&gt;</code> | | |
---

View File

@@ -0,0 +1,10 @@
---
title: getHeaders()
sidebarTitle: getHeaders()
---
Use `nhost.storage.getHeaders` to get global headers sent with all storage requests.
```ts
nhost.storage.getHeaders()
```

View File

@@ -24,12 +24,13 @@ console.log('expiration: ', presignedUrl.expiration)
**<span className="parameter-name">params</span>** <span className="optional-status">required</span> [`StorageGetPresignedUrlParams`](/reference/javascript/storage/types/storage-get-presigned-url-params)
| Property | Type | Required | Notes |
| :----------------------------------------------------------------------------------------- | :------------------ | :------: | :----------------------------------------------------------- |
| <span className="parameter-name"><span className="light-grey">params.</span>fileId</span> | <code>string</code> | ✔️ | |
| <span className="parameter-name"><span className="light-grey">params.</span>blur</span> | <code>number</code> | | Image blur, between 0 and 100 |
| <span className="parameter-name"><span className="light-grey">params.</span>quality</span> | <code>number</code> | | Image quality, between 1 and 100, 100 being the best quality |
| <span className="parameter-name"><span className="light-grey">params.</span>height</span> | <code>number</code> | | Image height, in pixels |
| <span className="parameter-name"><span className="light-grey">params.</span>width</span> | <code>number</code> | | Image width, in pixels |
| Property | Type | Required | Notes |
| :----------------------------------------------------------------------------------------- | :---------------------------------------- | :------: | :----------------------------------------------------------- |
| <span className="parameter-name"><span className="light-grey">params.</span>fileId</span> | <code>string</code> | ✔️ | |
| <span className="parameter-name"><span className="light-grey">params.</span>blur</span> | <code>number</code> | | Image blur, between 0 and 100 |
| <span className="parameter-name"><span className="light-grey">params.</span>quality</span> | <code>number</code> | | Image quality, between 1 and 100, 100 being the best quality |
| <span className="parameter-name"><span className="light-grey">params.</span>height</span> | <code>number</code> | | Image height, in pixels |
| <span className="parameter-name"><span className="light-grey">params.</span>width</span> | <code>number</code> | | Image width, in pixels |
| <span className="parameter-name"><span className="light-grey">params.</span>headers</span> | <code>Record&lt;string, string&gt;</code> | | |
---

View File

@@ -0,0 +1,22 @@
---
title: setHeaders()
sidebarTitle: setHeaders()
---
Use `nhost.storage.setHeaders` to set global headers to be sent for all subsequent storage requests.
```ts
nhost.storage.setHeaders({
'x-hasura-role': 'admin'
})
```
## Parameters
---
**<span className="parameter-name">headers</span>** <span className="optional-status">optional</span> <code>Record&lt;string, string&gt;</code>
key value headers object
---

View File

@@ -10,6 +10,10 @@ description: No description provided.
---
**<span className="parameter-name">headers</span>** <span className="optional-status">optional</span> <code>Record&lt;string, string&gt;</code>
---
**<span className="parameter-name">fileId</span>** <span className="optional-status">required</span> <code>string</code>
---

View File

@@ -10,6 +10,10 @@ description: No description provided.
---
**<span className="parameter-name">headers</span>** <span className="optional-status">optional</span> <code>Record&lt;string, string&gt;</code>
---
**<span className="parameter-name">fileId</span>** <span className="optional-status">required</span> <code>string</code>
---

View File

@@ -40,6 +40,4 @@ Image width, in pixels
**<span className="parameter-name">headers</span>** <span className="optional-status">optional</span> <code>Record&lt;string, string&gt;</code>
Optional headers to be sent with the request
---

Some files were not shown because too many files have changed in this diff Show More