Compare commits

..

177 Commits

Author SHA1 Message Date
github-actions[bot]
4ad27e9d72 chore: update versions (#2599)
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@6.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/react-apollo@10.0.1

### Patch Changes

-   @nhost/apollo@6.1.1
-   @nhost/react@3.3.1

## @nhost/react-urql@7.0.1

### Patch Changes

-   @nhost/react@3.3.1

## @nhost/stripe-graphql-js@1.1.1

### Patch Changes

-   7789469: chore: address linter errors and remove unnecessary imports

## @nhost/graphql-js@0.1.9

### Patch Changes

- 7789469: fix: resolve process is undefined error when running with
vitejs

## @nhost/nextjs@2.1.7

### Patch Changes

-   @nhost/react@3.3.1

## @nhost/nhost-js@3.0.9

### Patch Changes

-   Updated dependencies [7789469]
    -   @nhost/graphql-js@0.1.9

## @nhost/react@3.3.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/vue@2.3.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/dashboard@1.11.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings

### Patch Changes

-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

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

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1

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

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1

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

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-urql@7.0.1

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

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1

## @nhost-examples/cli@0.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

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

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost-examples/nextjs@0.2.1

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

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

### Patch Changes

-   @nhost/nhost-js@3.0.9

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

### Patch Changes

-   @nhost/nhost-js@3.0.9

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

### Patch Changes

-   @nhost/react@3.3.1

## @nhost-examples/serverless-functions@0.1.1

### Patch Changes

-   Updated dependencies [7789469]
    -   @nhost/stripe-graphql-js@1.1.1

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

### Patch Changes

-   7789469: chore: address linter errors and remove unnecessary imports
    -   @nhost/nhost-js@3.0.9
    -   @nhost/apollo@6.1.1
    -   @nhost/vue@2.3.1

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

### Patch Changes

-   @nhost/apollo@6.1.1
-   @nhost/vue@2.3.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-08 15:51:16 +01:00
Hassan Ben Jobrane
778946998a fix: graphql-js: resolve process is undefined error when running with vitejs (#2601)
fixes https://github.com/nhost/nhost/issues/2600
2024-03-08 15:23:13 +01:00
Hassan Ben Jobrane
6c11b75807 feat: dashboard: add update user displayName section in account settings (#2598)
fixes https://github.com/nhost/nhost/issues/1489
2024-03-07 17:23:35 +01:00
github-actions[bot]
2dc031d16c chore: update versions (#2592)
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-examples/react-apollo@0.5.0

### Minor Changes

- 08a7dd9: feat: add example workaround to the reset password ticket
expired issue

### Patch Changes

- f0a994a: fix: update allowedUrls and redirectTo to point to the
profile page

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

### Minor Changes

- 08a7dd9: feat: add example workaround to the reset password ticket
expired issue

### Patch Changes

- f0a994a: fix: update allowedUrls and redirectTo to point to the
profile page

## @nhost/docs@2.7.1

### Patch Changes

-   6cb2b63: feat: added nhost run env documentation
-   40bd3e4: fix: fixed wrong links in documentation

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-06 16:56:26 +01:00
Nicolas Bourdin
40bd3e4572 doc(link): fix wrong links in documentation (#2596)
Co-authored-by: Nicolas Bourdin <nicolas@epeak.co>
Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-03-06 14:50:32 +01:00
David Barroso
6cb2b6331a feat (docs): added nhost run env documentation (#2594) 2024-03-06 14:13:02 +01:00
Hassan Ben Jobrane
08a7dd9894 feat(examples): add reset password ticket expired workarounds in the examples (#2590)
fixes https://github.com/nhost/nhost/issues/2314
2024-03-05 15:48:46 +01:00
Hassan Ben Jobrane
f0a994a26e fix(examples): update allowedUrls and redirectTo to point to /profile (#2591) 2024-03-05 14:17:01 +01:00
Hassan Ben Jobrane
4fbd6bd4fa chore: fix release with missing changeset (#2588)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-04 16:51:57 +01:00
github-actions[bot]
67fc77486c chore: update versions (#2578)
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@6.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/google-translation@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/react-apollo@10.0.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/react@3.3.0

## @nhost/react-urql@7.0.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost/stripe-graphql-js@1.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/react@3.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/vue@2.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/nextjs@2.1.6

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost/dashboard@1.10.0

### Minor Changes

-   49a80c2: chore: update dependencies
-   150c04a: feat: add healthcheck config to run services

### Patch Changes

- e03f141: fix: allow insert, update and delete on tables in `auth` and
`storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/nextjs@2.1.6

## @nhost/docs@2.7.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost-examples/cli@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-urql@7.0.0
    -   @nhost/react@3.3.0

## @nhost-examples/docker-compose@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0
    -   @nhost/nextjs@2.1.6

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/sveltekit@0.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

- 4f3fb34: fix: set redirectTo when doing sign in with github and
include vercel previews in allowed redirect URLs
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost-examples/serverless-functions@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/stripe-graphql-js@1.1.0

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

- 4f3fb34: fix: set redirectTo when doing sign in with github and
include vercel previews in allowed redirect URLs
-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/vue@2.3.0
    -   @nhost/nhost-js@3.0.8

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

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/vue@2.3.0

## @nhost/docgen@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/sync-versions@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-03-04 16:16:06 +01:00
Hassan Ben Jobrane
4f3fb3446e fix: set redirectTo in oauth examples (#2586) 2024-03-04 15:33:24 +01:00
Hassan Ben Jobrane
49a80c22be chore: add changeset (#2584)
adds missing changeset for this PR
https://github.com/nhost/nhost/pull/2574
2024-03-04 13:52:38 +01:00
Hassan Ben Jobrane
28676f4cdc feat: dashboard: add min postgres version check to enable the ai service (#2576)
fixes https://github.com/nhost/nhost/issues/2439
2024-03-02 22:33:49 +01:00
Hassan Ben Jobrane
e03f14133c fix: dashboard: refactor database datagrid to allow insert/update/delete for tables auth and storage (#2577)
fixes https://github.com/nhost/nhost/issues/2476
2024-03-02 22:04:23 +01:00
Hassan Ben Jobrane
150c04a4f4 feat: dashboard: add healthcheck config to run services (#2575)
fixes https://github.com/nhost/nhost/issues/2410
2024-03-02 19:28:13 +01:00
github-actions[bot]
bccd67b1b1 [Scheduled] Update dependencies (#2574)
Dependencies updated

Note - If you see this PR and the checks haven't run, close and reopen
the PR. See
https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
Co-authored-by: dbarrosop <dbarrosop@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-03-02 18:40:03 +01:00
David Barroso
b14fd2f14c chore: fix role to assume in gen update dependencies (#2573) 2024-03-01 12:21:38 +01:00
github-actions[bot]
68b3d23cd9 chore: update versions (#2572)
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.9.0

### Minor Changes

-   d86e5c9: feat: add support for filtering the logs using a RegExp

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 17:54:02 +01:00
Hassan Ben Jobrane
d86e5c9c16 feat(dashboard): query services list from be and filter the logs using a regex (#2552)
fixes: https://github.com/nhost/nhost/issues/2391
2024-02-29 17:38:38 +01:00
github-actions[bot]
b2cc1411d7 chore: update versions (#2571)
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@6.0.8

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/react-apollo@9.0.3

### Patch Changes

-   @nhost/apollo@6.0.8
-   @nhost/react@3.2.3

## @nhost/react-urql@6.0.3

### Patch Changes

-   @nhost/react@3.2.3

## @nhost/graphql-js@0.1.8

### Patch Changes

- 407feea: fix: replace `jwt-decode` with `jose` to decode access tokens
in a non browser environment

## @nhost/nextjs@2.1.5

### Patch Changes

-   @nhost/react@3.2.3

## @nhost/nhost-js@3.0.8

### Patch Changes

-   Updated dependencies [407feea]
    -   @nhost/graphql-js@0.1.8

## @nhost/react@3.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/vue@2.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/dashboard@1.8.3

### Patch Changes

-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

## @nhost-examples/cli@0.1.9

### Patch Changes

-   @nhost/nhost-js@3.0.8

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

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3

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

### Patch Changes

-   @nhost/react@3.2.3

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

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-urql@6.0.3

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

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs@0.1.19

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

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

### Patch Changes

-   @nhost/nhost-js@3.0.8

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

### Patch Changes

-   @nhost/nhost-js@3.0.8

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

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3

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

### Patch Changes

-   @nhost/react@3.2.3

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

### Patch Changes

-   @nhost/nhost-js@3.0.8
-   @nhost/apollo@6.0.8
-   @nhost/vue@2.2.3

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

### Patch Changes

-   @nhost/apollo@6.0.8
-   @nhost/vue@2.2.3

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 15:43:48 +01:00
Hassan Ben Jobrane
407feeac37 fix: sdk: graphql-js: replace jwt-decode with jose to decode access tokens in both node and the browser (#2570) 2024-02-29 14:51:33 +01:00
github-actions[bot]
7b25c37c26 chore: update versions (#2569)
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.8.2

### Patch Changes

- 6df4f02: fix: use custom error toast and show correct message when
sending an invite

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 13:10:09 +01:00
Hassan Ben Jobrane
6df4f02e95 fix(dashboard): show correct message when sending invite fails (#2567) 2024-02-29 12:52:25 +01:00
github-actions[bot]
aaae98f019 chore: update versions (#2559)
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/docs@2.6.0

### Minor Changes

-   dc23dc0: fix: docs run references

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-25 23:02:36 -01:00
Nuno Pato
dc23dc0f49 fix: docs run references (#2558) 2024-02-25 22:47:38 -01:00
github-actions[bot]
82728da100 chore: update versions (#2556)
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@6.0.7

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/react-apollo@9.0.2

### Patch Changes

-   @nhost/apollo@6.0.7
-   @nhost/react@3.2.2

## @nhost/react-urql@6.0.2

### Patch Changes

-   @nhost/react@3.2.2

## @nhost/graphql-js@0.1.7

### Patch Changes

- 2d68fee: fix: resolve an issue where unauthenticated graphql requests
are not sent

## @nhost/nextjs@2.1.4

### Patch Changes

-   @nhost/react@3.2.2

## @nhost/nhost-js@3.0.7

### Patch Changes

-   Updated dependencies [2d68fee]
    -   @nhost/graphql-js@0.1.7

## @nhost/react@3.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/vue@2.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/dashboard@1.8.1

### Patch Changes

-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

## @nhost-examples/cli@0.1.8

### Patch Changes

-   @nhost/nhost-js@3.0.7

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

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2

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

### Patch Changes

-   @nhost/react@3.2.2

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

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-urql@6.0.2

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

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost-examples/nextjs@0.1.18

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

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

### Patch Changes

-   @nhost/nhost-js@3.0.7

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

### Patch Changes

-   @nhost/nhost-js@3.0.7

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

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2

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

### Patch Changes

-   @nhost/react@3.2.2

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

### Patch Changes

-   @nhost/nhost-js@3.0.7
-   @nhost/apollo@6.0.7
-   @nhost/vue@2.2.2

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

### Patch Changes

-   @nhost/apollo@6.0.7
-   @nhost/vue@2.2.2

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-23 21:14:11 +01:00
Hassan Ben Jobrane
2d68fee54c fix(graphql-js): allow graphql requests with no access token (#2555) 2024-02-23 21:09:45 +01:00
github-actions[bot]
35010353c7 chore: update versions (#2547)
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@6.0.6

### Patch Changes

-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT
    -   @nhost/nhost-js@3.0.6

## @nhost/react-apollo@9.0.1

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/react@3.2.1

## @nhost/react-urql@6.0.1

### Patch Changes

-   @nhost/react@3.2.1

## @nhost/graphql-js@0.1.6

### Patch Changes

-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT

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

### Patch Changes

- 7baee8a: fix(hasura-auth-js): replace `jwt-decode` with `jose` for
decoding access tokens that works on both the browser and Node.js
-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT

## @nhost/nextjs@2.1.3

### Patch Changes

-   @nhost/react@3.2.1

## @nhost/nhost-js@3.0.6

### Patch Changes

-   Updated dependencies [7baee8a]
-   Updated dependencies [e0ab6d9]
    -   @nhost/hasura-auth-js@2.3.1
    -   @nhost/graphql-js@0.1.6

## @nhost/react@3.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost/vue@2.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost/dashboard@1.8.0

### Minor Changes

- 713d53c: feat: add catch-all route for workspace/project - useful for
documentation

### Patch Changes

-   3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast`
component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid
header did not select all rows
    -   @nhost/react-apollo@9.0.1
    -   @nhost/nextjs@2.1.3

## @nhost-examples/cli@0.1.7

### Patch Changes

-   @nhost/nhost-js@3.0.6

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

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1

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

### Patch Changes

-   @nhost/react@3.2.1

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

### Patch Changes

-   @nhost/react@3.2.1
-   @nhost/react-urql@6.0.1

## @nhost-examples/docker-compose@0.1.1

### Patch Changes

-   aff059e: fix: timers

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

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost-examples/nextjs@0.1.17

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1
-   @nhost/nextjs@2.1.3

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

### Patch Changes

-   @nhost/nhost-js@3.0.6

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

### Patch Changes

-   @nhost/nhost-js@3.0.6

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

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1

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

### Patch Changes

-   @nhost/react@3.2.1

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

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/nhost-js@3.0.6
    -   @nhost/vue@2.2.1

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

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/vue@2.2.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-23 10:07:53 +01:00
David Barroso
aff059ec71 fix (examples/docker-compose): timers (#2553) 2024-02-23 10:04:20 +01:00
Nuno Pato
713d53cfc0 feat: dashboard: add catch-all route (#2545) 2024-02-22 17:59:24 -01:00
Hassan Ben Jobrane
e0ab6d9a37 fix: JWT expired bug (#2533)
fixes: https://github.com/nhost/nhost/issues/2348

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-02-22 18:44:43 +01:00
Hassan Ben Jobrane
7baee8a9cc fix(hasura-auth-js): use jose instead of jwt-decode to decode the accessToken and get the Hasura claims (#2550)
fixes https://github.com/nhost/nhost/issues/2513
2024-02-21 11:17:03 +01:00
Hassan Ben Jobrane
3db2999f60 fix(dashboard): refresh table list after running a SQL stmt using the editor (#2549)
fixes https://github.com/nhost/projects/issues/52
2024-02-20 13:40:46 +01:00
Hassan Ben Jobrane
3c4dd55045 fix(dashboard): handle Error alongside ApolloError properly in the ErrorToast component (#2548)
fixes https://github.com/nhost/nhost/issues/2525
2024-02-20 12:16:26 +01:00
Hassan Ben Jobrane
92b434e840 fix: refactor DataGridHeader component to allow for selecting all rows (#2546)
fixes https://github.com/nhost/nhost/issues/2526
2024-02-19 17:30:59 +01:00
github-actions[bot]
13d359602f chore: update versions (#2540)
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.7.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

## @nhost/docs@2.5.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

### Patch Changes

-   41617b9: feat: added elevated permissions docs
- 7db095f: chore: added a note about disk performance and CDN
information

## @nhost-examples/docker-compose@0.1.0

### Minor Changes

-   ed9df85: updated docker-compose.yaml and .env-example

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

### Patch Changes

-   c5c904b: fix: update signin methods settings

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-16 20:44:28 -01:00
Nuno Pato
0d8d0eb10f chore: update docs and fix dashboard references (#2543) 2024-02-16 18:21:30 -01:00
Seth Deegan
ed9df85778 Update docker-compose and .env-example (#2397)
The docker-compose example is severely outdated and the past
configuration used a docker image for the dashboard that did not allow
you to configure the URLs to the various API endpoints if you
self-hosted your own dashboard publicly.

The newest dashboard image allows you to do this so the docker-compose
has been updated to use this image and the env variables have been
updated accordingly.

Other variables have been updated in the docker-compose to support
self-hosting a public instance.

A commented traefik configuration in the docker-compose for the
dashboard service also allows the user to configure basic auth to
protect a publicly-facing dashboard.

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-16 08:52:58 +01:00
David Barroso
41617b970a feat (docs): added elevated permissions docs (#2519)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-02-15 16:00:44 +01:00
Hassan Ben Jobrane
c5c904b716 fix(vue-apollo): update signin methods settings (#2541) 2024-02-15 13:48:41 +01:00
David Barroso
7db095fe92 chore: docs: added a note about disk performance and CDN information (#2539)
Fixes #2504
2024-02-15 11:47:33 +01:00
github-actions[bot]
f33e07b191 chore: update versions (#2538)
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/hasura-auth-js@2.3.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

## @nhost/react@3.2.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/vue@2.2.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/apollo@6.0.5

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/react-apollo@9.0.0

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/apollo@6.0.5

## @nhost/react-urql@6.0.0

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost/nextjs@2.1.2

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost/nhost-js@3.0.5

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/hasura-auth-js@2.3.0

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

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0

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

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/vue@2.2.0
    -   @nhost/nhost-js@3.0.5
    -   @nhost/apollo@6.0.5

## @nhost/dashboard@1.6.9

### Patch Changes

-   @nhost/react-apollo@9.0.0
-   @nhost/nextjs@2.1.2

## @nhost-examples/cli@0.1.6

### Patch Changes

-   @nhost/nhost-js@3.0.5

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

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0

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

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

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

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-urql@6.0.0

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

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost-examples/nextjs@0.1.16

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0
    -   @nhost/nextjs@2.1.2

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

### Patch Changes

-   @nhost/nhost-js@3.0.5

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

### Patch Changes

-   @nhost/nhost-js@3.0.5

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

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

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

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/vue@2.2.0
    -   @nhost/apollo@6.0.5

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-14 15:12:34 +01:00
Hassan Ben Jobrane
017f1a6c7b feat: add elevate workflow to react-apollo and vue-apollo example projects (#2521)
part-2 of https://github.com/nhost/nhost/issues/2394

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-02-14 14:52:43 +01:00
github-actions[bot]
93957c8af3 chore: update versions (#2537)
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/hasura-storage-js@2.4.0

### Minor Changes

-   2505b2e: fix: fix headers sent with getPresignedUrl

## @nhost/apollo@6.0.4

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/react-apollo@8.0.1

### Patch Changes

-   @nhost/apollo@6.0.4
-   @nhost/react@3.1.1

## @nhost/react-urql@5.0.1

### Patch Changes

-   @nhost/react@3.1.1

## @nhost/nextjs@2.1.1

### Patch Changes

-   @nhost/react@3.1.1

## @nhost/nhost-js@3.0.4

### Patch Changes

-   Updated dependencies [2505b2e]
    -   @nhost/hasura-storage-js@2.4.0

## @nhost/react@3.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/vue@2.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/dashboard@1.6.8

### Patch Changes

-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

## @nhost-examples/cli@0.1.5

### Patch Changes

-   @nhost/nhost-js@3.0.4

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

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1

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

### Patch Changes

-   @nhost/react@3.1.1

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

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-urql@5.0.1

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

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost-examples/nextjs@0.1.15

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

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

### Patch Changes

-   @nhost/nhost-js@3.0.4

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

### Patch Changes

-   @nhost/nhost-js@3.0.4

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

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1

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

### Patch Changes

-   @nhost/react@3.1.1

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

### Patch Changes

-   @nhost/nhost-js@3.0.4
-   @nhost/apollo@6.0.4
-   @nhost/vue@2.1.1

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

### Patch Changes

-   @nhost/apollo@6.0.4
-   @nhost/vue@2.1.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-14 10:29:57 +01:00
Nuno Pato
2505b2e26b fix: fix headers sent with getPresignedUrl (#2535) 2024-02-13 23:33:09 -01:00
Nuno Pato
5f4b4d2acc chore: update dependencies (#2536)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-13 20:29:47 -01:00
github-actions[bot]
71a8ce4446 chore: update versions (#2524)
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/docs@2.4.0

### Minor Changes

-   791b729: fix: remove auth method

## @nhost/dashboard@1.6.7

### Patch Changes

-   5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-12 16:33:16 +01:00
Hassan Ben Jobrane
5ef5189898 fix(dashboard): resolve change plan modal cache issue (#2532)
related to https://github.com/nhost/nhost/issues/2530
2024-02-12 16:08:22 +01:00
Nuno Pato
791b7295fb fix: docs: remove auth method (#2475)
- https://github.com/nhost/nhost/issues/2474
2024-02-08 10:36:51 -01:00
github-actions[bot]
25bc4b7fd6 chore: update versions (#2501)
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/hasura-auth-js@2.2.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

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

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/nextjs@2.1.0

### Minor Changes

-   b19ffed: chore: update peerDependency to support nextjs 14

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost/react@3.1.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/vue@2.1.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/apollo@6.0.3

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/google-translation@0.0.8

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/react-apollo@8.0.0

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/apollo@6.0.3

## @nhost/react-urql@5.0.0

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost/stripe-graphql-js@1.0.7

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/nhost-js@3.0.3

### Patch Changes

-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
-   Updated dependencies [d3d1424]
    -   @nhost/hasura-auth-js@2.2.0
    -   @nhost/hasura-storage-js@2.3.0
    -   @nhost/graphql-js@0.1.5

## @nhost/docs@2.3.0

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies
- 2ae5ea8: fix: indicate that custom domains for postgres doesn't
require configuration

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

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

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

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-apollo@8.0.0

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

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/vue@2.1.0
    -   @nhost/apollo@6.0.3
    -   @nhost/nhost-js@3.0.3

## @nhost/dashboard@1.6.6

### Patch Changes

-   3ba485e: fix: added discord.com to connect-src
-   e5bab6a: chore: update dependencies
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

## @nhost-examples/cli@0.1.4

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

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

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-apollo@8.0.0

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

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

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

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-urql@5.0.0

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

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/nextjs@0.1.14

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

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

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/sveltekit@0.2.3

### Patch Changes

-   e5bab6a: chore: update dependencies

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

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost-examples/serverless-functions@0.0.11

### Patch Changes

-   8c34c69: chore: update nodemailer version to `6.9.9`
-   Updated dependencies [e5bab6a]
    -   @nhost/stripe-graphql-js@1.0.7

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

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/vue@2.1.0
    -   @nhost/apollo@6.0.3

## @nhost/docgen@0.1.13

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/sync-versions@0.0.10

### Patch Changes

-   e5bab6a: chore: update dependencies

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-06 14:41:47 +01:00
Hassan Ben Jobrane
da20159ec5 chore(examples): update auth version to 0.25.0 in nhost.toml (#2518) 2024-02-06 14:09:30 +01:00
David Barroso
2ae5ea8bc1 fix (docs): indicate that custom domains for postgres doesn't require configuration (#2506) 2024-02-06 11:54:18 +01:00
David Barroso
3ba485e582 fix (dashboard): added discord.com to connect-src (#2516) 2024-02-06 11:29:27 +01:00
David Barroso
e5bab6a061 chore: update dependencies (#2505)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-06 10:25:48 +01:00
David Barroso
be64353145 Create SECURITY.md (#2515) 2024-02-06 10:00:38 +01:00
Hassan Ben Jobrane
2f5913c78d fix(examples): revert back auth version to 0.24.1 (#2512) 2024-02-05 17:18:52 +01:00
Nuno Pato
757ddd901c chore: docs: use hyphen instead of underscore (#2511) 2024-02-05 13:46:13 -01:00
Hassan Ben Jobrane
1a61c658a7 feat: add elevate func to the SDKs and the react-apollo example project (#2500)
part-1 of https://github.com/nhost/nhost/issues/2394
2024-02-05 13:25:14 +01:00
Nuno Pato
d3d14245c7 feat: hasura-storage-js: add authenticated download of files (#2507) 2024-02-05 11:24:34 -01:00
Alexander Mart
53d2f9d3e0 doc: fix method name in example code at refresh-session.mdx doc page (#2468)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-02-03 15:54:08 +01:00
Hassan Ben Jobrane
8c34c69e79 chore: update nodemailer (#2510) 2024-02-02 20:31:29 +01:00
Jared Prather
b19ffed273 chore: Update peerDependency next to ^14.0.0 (#2354)
Fixes: #2351 

Summary of next 14 changes
[here](https://nextjs.org/docs/pages/building-your-application/upgrading/version-14#v14-summary)

---------

Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-30 18:25:02 +01:00
Nuno Pato
859efa988a fix: docs: small fixes (#2486) 2024-01-26 17:15:06 -01:00
github-actions[bot]
3202b6b897 chore: update versions (#2495)
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.6.5

### Patch Changes

- ba73bb4: fix: update ErrorToast component to show the internal graphql
error
- d5337ff: fix: utilize accumulator in the creation of validation schema
within data grid utils

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-26 18:32:57 +01:00
Hassan Ben Jobrane
ba73bb4003 fix(dashboard): show internal error in toast message (#2496) 2024-01-26 17:42:18 +01:00
Hassan Ben Jobrane
d5337ff5bd fix(dashboard): fix bug with validation schema for create record form (#2494) 2024-01-26 16:50:28 +01:00
github-actions[bot]
511ab19755 chore: update versions (#2492)
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/docs@2.2.0

### Minor Changes

- 5c9b8f0: feat: added docs regarding local development for Run services

## @nhost/dashboard@1.6.4

### Patch Changes

-   7c2a1c2: feat: show error and debug info in the error toast

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 17:23:36 +01:00
Hassan Ben Jobrane
7c2a1c29fd feat(dashboard): add custom error toast (#2463)
fixes https://github.com/nhost/nhost/issues/2435
2024-01-25 16:48:54 +01:00
David Barroso
5c9b8f0a3f feat (docs): added docs regarding local development for Run services (#2488) 2024-01-25 12:40:04 +01:00
github-actions[bot]
b3f1f5f6ea chore: update versions (#2491)
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.6.3

### Patch Changes

-   6b8aad5: fix: add bare nhost.run to CSP

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 12:14:56 +01:00
David Barroso
6b8aad5c84 fix(dashboard): add bare nhost.run to CSP (#2490) 2024-01-25 11:28:15 +01:00
github-actions[bot]
c36132c9bb chore: update versions (#2489)
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.6.2

### Patch Changes

-   b18edc0: feat: added CSP and X-Frame-Options

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 11:00:06 +01:00
David Barroso
b18edc0532 feat (dashboard): added CSP and X-Frame-Options (#2479) 2024-01-25 10:46:41 +01:00
David Barroso
1d55d3ea38 chore (general): added mintlify to docs devDependencies and manage node_modules with nix (#2487)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-01-24 10:43:59 +01:00
github-actions[bot]
fdc50b32d8 chore: update versions (#2484)
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@6.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/google-translation@0.0.7

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/react-apollo@7.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/react@3.0.2

## @nhost/react-urql@4.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost/stripe-graphql-js@1.0.6

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/graphql-js@0.1.5

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/nextjs@2.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost/nhost-js@3.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/hasura-storage-js@2.2.6
    -   @nhost/hasura-auth-js@2.1.11
    -   @nhost/graphql-js@0.1.5

## @nhost/react@3.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/vue@2.0.3

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/dashboard@1.6.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in
Dockerfile
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2

## @nhost-examples/cli@0.1.3

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/react@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-urql@4.0.2
    -   @nhost/react@3.0.2

## @nhost-examples/docker-compose@0.0.7

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/nextjs@0.1.13

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2
    -   @nhost/react@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/sveltekit@0.2.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/react@3.0.2

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost-examples/serverless-functions@0.0.10

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/stripe-graphql-js@1.0.6

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/nhost-js@3.0.2
    -   @nhost/vue@2.0.3

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

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/vue@2.0.3

## @nhost/docgen@0.1.12

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/sync-versions@0.0.9

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-23 20:04:39 +01:00
Hassan Ben Jobrane
3cdca8d4b3 chore: update sveltekit pnpm-lockl.yaml (#2485) 2024-01-23 19:18:44 +01:00
Hassan Ben Jobrane
c425c9f265 fix(quickstarts): use turbo to build nextjs-server-components and fix sveltekit lockfile (#2483) 2024-01-23 18:53:21 +01:00
Hassan Ben Jobrane
3b8473b168 chore: update pnpm and turbo versions in Dockerfile (#2482) 2024-01-23 16:51:14 +01:00
David Barroso
8d91f7103f chore: update deps and enable pnpm audit (#2466)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-23 13:58:48 +01:00
github-actions[bot]
11ce93d64b chore: update versions (#2478)
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.6.0

### Minor Changes

-   3ff1c2b53: fix: show upgrade option for pro projects

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-22 15:08:49 -01:00
Nuno Pato
3ff1c2b531 fix: dashboard: show upgrade option to pro projects (#2477) 2024-01-22 15:03:33 -01:00
github-actions[bot]
e4341c3706 chore: update versions (#2462)
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.5.0

### Minor Changes

-   c2ef17c0a: feat: add support for new Team plan

## @nhost/docs@2.1.0

### Minor Changes

-   65b6a48d5: feat: added graphite/cli documentation

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-22 11:31:49 -01:00
Nuno Pato
c2ef17c0a0 feat: dashboard: new Team plan (#2473) 2024-01-22 11:13:26 -01:00
David Barroso
1045ea0a46 fix(docs): set correct hostname for connecting to run service internally (#2471) 2024-01-17 12:34:01 +01:00
Nevada Le Master
5faaf36e26 chore: add maskedErrors param to CreateServerProps (#2129)
this PR addresses https://github.com/nhost/nhost/issues/1218, adding
`maskedErrors` param when creating Stripe and Google Translate GraphQL
Yoga servers

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-01-16 16:36:51 +01:00
David Barroso
65b6a48d51 feat(docs): added graphite/cli documentation (#2457)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-01-10 17:19:58 +01:00
github-actions[bot]
23e18fb734 chore: update versions (#2454)
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/docs@2.0.0

### Major Changes

-   6d08b3430: New Docs powered by Mintlify

## @nhost/dashboard@1.4.0

### Minor Changes

-   7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview
environments

### Patch Changes

- 3c3594898: fix: allow access to graphite when configured running in
local dashboard
-   32c246b7a: chore: update docs icon

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-10 14:59:31 +01:00
David Barroso
44be6dc0a5 feat (dashboard): set redirectTo during sign-in with twitter to support preview environments (#2461)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-10 14:48:58 +01:00
Hassan Ben Jobrane
3c35948986 fix: refactor plan check when accessing ai services (#2456)
fixes https://github.com/nhost/nhost/issues/2455
2024-01-10 12:47:34 +01:00
David Barroso
7883bbcbd1 feat (dashboard): don't show deprecated plans (#2458) 2024-01-09 16:36:27 +01:00
Nuno Pato
42fddcf790 Merge pull request #2425 from nhost/docs/new-version
chore(docs): new docs
2024-01-09 14:29:15 -01:00
Nuno Pato
5d1a444451 asd 2024-01-09 14:03:36 -01:00
Nuno Pato
98d17a3066 asd 2024-01-09 12:42:14 -01:00
Nuno Pato
f70f36be08 asd 2024-01-09 11:06:13 -01:00
Nuno Pato
50fe08624f Merge branch 'main' into docs/new-version 2024-01-09 10:16:04 -01:00
Nuno Pato
6cb7dd8203 asd 2024-01-08 23:45:49 -01:00
Hassan Ben Jobrane
f859159ef5 Merge pull request #2453 from nhost/chore/update-docs-icon
chore(dashboard): update docs icon
2024-01-08 15:14:37 +01:00
Hassan Ben Jobrane
32c246b7a9 chore: add changeset 2024-01-08 11:24:35 +01:00
Hassan Ben Jobrane
f004fd067a chore: update docs icons 2024-01-08 11:24:03 +01:00
David Barroso
82340b5d54 remove migration step from ai guide (#2450) 2024-01-06 13:05:41 +01:00
Nuno Pato
8fff3e06bd asd 2024-01-05 14:54:40 -01:00
Nuno Pato
527a661222 asd 2024-01-05 14:47:46 -01:00
Hassan Ben Jobrane
172fd8dfed Merge pull request #2448 from nhost/changeset-release/main
chore: update versions
2024-01-05 15:30:30 +01:00
github-actions[bot]
a99ca90279 chore: update versions 2024-01-05 14:19:10 +00:00
Hassan Ben Jobrane
5892fd7f01 Merge pull request #2451 from nhost/fix/graphite/version-setting
fix: remove hardcoded ai settings version
2024-01-05 15:17:07 +01:00
Hassan Ben Jobrane
0344cc9a6d fix: update filterOptions logic in service version selector 2024-01-05 13:56:53 +01:00
Hassan Ben Jobrane
2697e28cf2 Merge pull request #2452 from nhost/fix/default-allowed-roles
chore: change `Allowed Roles` to `Default Allowed Roles`
2024-01-04 17:10:27 +01:00
Hassan Ben Jobrane
54231b119f fix: remove filtering in software version selector 2024-01-04 16:58:19 +01:00
Hassan Ben Jobrane
7c977e7143 chore: add changeset 2024-01-04 11:52:51 +01:00
Hassan Ben Jobrane
7c3019389e chore: change Allowed Roles to Default Allowed Roles 2024-01-04 11:50:14 +01:00
Hassan Ben Jobrane
46f028b9fd chore: add changeset 2024-01-04 11:00:59 +01:00
Hassan Ben Jobrane
683e85b89f fix: remove hardcoded ai settings version 2024-01-04 10:59:00 +01:00
Hassan Ben Jobrane
b0f27c908d Merge pull request #2444 from nhost/chore/fix-graphql-codegen
chore(dashboard): use env variables for graphql codegen
2024-01-03 21:47:28 +01:00
Hassan Ben Jobrane
5f2618e183 chore: run pnpm codegen 2024-01-03 16:59:28 +01:00
Hassan Ben Jobrane
29037147f2 Merge pull request #2447 from nhost/fix/vue-sdk/constructor-params
fix(vue-sdk): include `ServiceUrls` in `NhostVueClientConstructorParams`
2024-01-03 16:09:57 +01:00
Hassan Ben Jobrane
95b630a621 chore: fix pnpm-lock.yaml 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
0fdfd8ad81 chore: run pnpm codegen 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
174b4165b3 chore: add changeset 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
04257bc09c chore: use env variables when running graphql codegen 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
184c341f05 chore: add changeset 2024-01-03 15:53:20 +01:00
Hassan Ben Jobrane
52fdce291f fix(vue-sdk): include ServiceUrls in NhostVueClientConstructorParams interface 2024-01-03 15:51:29 +01:00
Hassan Ben Jobrane
c43ff40e1f Merge pull request #2445 from nhost/changeset-release/main
chore: update versions
2024-01-03 14:20:46 +01:00
github-actions[bot]
4ec2f8f186 chore: update versions 2024-01-03 13:19:13 +00:00
Hassan Ben Jobrane
7ece80a39e Merge pull request #2442 from nhost/chore/remove-update-providers-notice
chore: remove backendUrl deprecation notice and update providers alert
2024-01-03 14:17:09 +01:00
Hassan Ben Jobrane
1327351e1b fix: increase ci e2e timeout 2024-01-03 12:48:41 +01:00
Hassan Ben Jobrane
1fbdf630a5 chore: run pnpm codegen 2024-01-03 11:58:54 +01:00
Nestor Manrique
93f573ea98 Merge pull request #2443 from nhost/feat/docs-for-run-services-health-checks
feat(docs): for run services health checks
2024-01-03 10:51:09 +01:00
Nestor Manrique
ac78629414 Remove vscode settings json 2024-01-03 10:23:47 +01:00
Nestor Manrique
3403744c22 wip 2024-01-03 10:09:02 +01:00
Hassan Ben Jobrane
cef11677f4 Merge pull request #2437 from nhost/fix/sveltekit-quickstart
fix(quickstarts): fix auth issue and too many redirects error
2024-01-02 21:40:08 +01:00
Nuno Pato
ddadf3399c Merge pull request #2441 from nhost/feat/docs-for-postgres-wal-settings
feat(docs): add postgres wal settings to docs
2024-01-02 18:52:11 -01:00
Nestor Manrique
c768341ce8 Adjust PR comments and run sections on product page 2024-01-02 16:34:49 +01:00
Nestor Manrique
1396cbe4c0 Add more details to healthcheck docs 2024-01-02 16:05:31 +01:00
Nestor Manrique
76761b4970 Add docs for run health checks config 2024-01-02 16:00:40 +01:00
Hassan Ben Jobrane
af33c21d10 chore: add changeset 2024-01-02 15:19:46 +01:00
Hassan Ben Jobrane
1b01d56e82 chore: remove all references to providersUpdated 2024-01-02 15:17:57 +01:00
Hassan Ben Jobrane
229acb1d60 chore: remove backendUrl deprication notice and update providers alert 2024-01-02 14:56:58 +01:00
Nestor Manrique
0bc9a41e51 Add postgres wal settings to docs 2024-01-02 14:55:26 +01:00
Hassan Ben Jobrane
b4dccd4496 chore: add changeset 2024-01-01 11:23:39 +01:00
Hassan Ben Jobrane
31683fa926 fix(quickstarts): fix auth issue and too many redirects error 2024-01-01 11:17:33 +01:00
Nuno Pato
7107089a29 asd 2023-12-24 11:10:50 -01:00
Hassan Ben Jobrane
e9d5d0a53e Merge pull request #2429 from nhost/changeset-release/main
chore: update versions
2023-12-22 22:53:18 +01:00
github-actions[bot]
4e0b132d20 chore: update versions 2023-12-22 21:35:18 +00:00
Hassan Ben Jobrane
425476759f Merge pull request #2428 from nhost/fix/dashboard-graphite-version
bug: dashboard: fix graphite default version
2023-12-22 22:33:11 +01:00
Nuno Pato
04784d880b asd 2023-12-22 20:08:09 -01:00
Nuno Pato
130131c488 fix graphite default version 2023-12-22 20:05:24 -01:00
David Barroso
a6c7300e14 asd 2023-12-22 16:34:25 +01:00
Nuno Pato
1a84610b74 asd 2023-12-22 14:34:00 -01:00
Nuno Pato
6c43529eff asd 2023-12-22 13:35:45 -01:00
Nuno Pato
63309cbcd6 asd 2023-12-22 13:24:47 -01:00
David Barroso
998b1d5963 asd 2023-12-22 15:21:08 +01:00
David Barroso
42d2a89de3 asd 2023-12-22 15:17:34 +01:00
David Barroso
731f094cf8 asd 2023-12-22 15:17:34 +01:00
David Barroso
3454605582 asd 2023-12-22 15:17:34 +01:00
David Barroso
e4479afab4 asd 2023-12-22 15:17:34 +01:00
David Barroso
6edae34bf0 asd 2023-12-22 15:17:34 +01:00
David Barroso
80b6464f60 asd 2023-12-22 15:17:34 +01:00
David Barroso
e3880dbe8a asd 2023-12-22 15:17:33 +01:00
David Barroso
ea991228e2 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
7cb568be52 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
dacaa7cad7 ads 2023-12-22 15:17:33 +01:00
Nuno Pato
30a688778e asd 2023-12-22 15:17:33 +01:00
Nuno Pato
d4f79c05b4 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
e10d313e37 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
77e8fb471c asd 2023-12-22 15:17:33 +01:00
Nuno Pato
f40a3f23ac asd 2023-12-22 15:17:33 +01:00
Nuno Pato
17dea7e60b asd 2023-12-22 15:17:33 +01:00
Nuno Pato
23527fc388 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
8ec6b85bac asd 2023-12-22 15:17:33 +01:00
Nuno Pato
b067838984 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
7553506e18 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
e58a9f1aaa asd 2023-12-22 15:17:33 +01:00
Nuno Pato
d4bfea963f asd 2023-12-22 15:17:33 +01:00
Nuno Pato
88779ad950 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
90929e9357 asd 2023-12-22 15:17:33 +01:00
David Barroso
2f4d5814ed asd 2023-12-22 15:17:33 +01:00
Nuno Pato
6d08b34309 new docs 2023-12-22 15:17:32 +01:00
1346 changed files with 47004 additions and 35534 deletions

22
.github/CODEOWNERS vendored
View File

@@ -1,14 +1,14 @@
# Documentation # Documentation
# https://help.github.com/en/articles/about-code-owners # https://help.github.com/en/articles/about-code-owners
/packages @szilarddoro /packages @nunopato @onehassan
/packages/docgen @szilarddoro /packages/docgen @nunopato @onehassan
/integrations/stripe-graphql-js @elitan /integrations/stripe-graphql-js @nunopato @onehassan
/.github @szilarddoro /.github @nunopato @onehassan
/dashboard/ @szilarddoro /dashboard/ @nunopato @onehassan
/docs/ @elitan /docs/ @nunopato @onehassan
/config/ @szilarddoro /config/ @nunopato @onehassan
/examples/ @szilarddoro /examples/ @nunopato @onehassan
/examples/codegen-react-apollo @elitan @szilarddoro /examples/codegen-react-apollo @nunopato @onehassan
/examples/codegen-react-query @elitan @szilarddoro /examples/codegen-react-query @nunopato @onehassan
/examples/react-apollo-crm @elitan @szilarddoro /examples/react-apollo-crm @nunopato @onehassan

View File

@@ -14,7 +14,7 @@ runs:
steps: steps:
- uses: pnpm/action-setup@v2.2.4 - uses: pnpm/action-setup@v2.2.4
with: with:
version: 8.6.2 version: 8.10.5
run_install: false run_install: false
- name: Get pnpm cache directory - name: Get pnpm cache directory
id: pnpm-cache-dir id: pnpm-cache-dir

1
.github/labeler.yml vendored
View File

@@ -4,7 +4,6 @@ dashboard:
documentation: documentation:
- any: - any:
- docs/**/* - docs/**/*
- '!docs/docs/reference/docgen/**/*'
examples: examples:
- examples/**/* - examples/**/*

23
.github/renovate.json vendored
View File

@@ -1,23 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"docker-compose": {
"enabled": true
},
"ignoreDeps": [
"pnpm",
"node",
"@types/node"
],
"labels": [
"dependencies"
],
"enabledManagers": [
"npm",
"dockerfile",
"docker-compose",
"github-actions"
]
}

View File

@@ -106,6 +106,8 @@ jobs:
# * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo # * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo
- name: Lint - name: Lint
run: pnpm run lint:all run: pnpm run lint:all
- name: Audit for vulnerabilities
run: pnpx audit-ci --config ./audit-ci.jsonc
e2e: e2e:
name: 'E2E (Package: ${{ matrix.package.path }})' name: 'E2E (Package: ${{ matrix.package.path }})'
@@ -146,7 +148,7 @@ jobs:
run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo # * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e tests - name: Run e2e tests
timeout-minutes: 15 timeout-minutes: 20
run: pnpm --filter="${{ matrix.package.name }}" run e2e run: pnpm --filter="${{ matrix.package.name }}" run e2e
- id: file-name - id: file-name
if: ${{ failure() }} if: ${{ failure() }}

View File

@@ -0,0 +1,82 @@
---
name: "gen: update depenendencies"
on:
schedule:
- cron: '0 2 1 * *'
jobs:
run:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
pull-requests: write
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure aws
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_PRODUCTION_CORE_ACCOUNT_ID }}:role/github-actions-nhost-${{ github.event.repository.name }}
aws-region: eu-central-1
- uses: nixbuild/nix-quick-install-action@v26
with:
nix_version: 2.16.2
nix_conf: |
experimental-features = nix-command flakes
sandbox = false
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
substituters = https://cache.nixos.org/?priority=40 s3://nhost-nix-cache?region=eu-central-1&priority=50
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= ${{ secrets.NIX_CACHE_PUB_KEY }}
- name: Cache nix store
uses: actions/cache@v4
with:
path: /nix
key: nix-update-deps-${{ hashFiles('flakes.nix', 'flake.lock') }}
- name: Update nix flakes
run: nix flake update
- name: Update dependencies
run: |
nix develop -c bash -c "
pnpm dedupe
pnpm update -r
pnpm dedupe
"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update dependencies
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
branch: automated/update-deps
delete-branch: true
title: '[Scheduled] Update dependencies'
body: |
Dependencies updated
Note - If you see this PR and the checks haven't run, close and reopen the PR. See https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs
labels: |
dependencies
draft: false
- name: "Cache nix store on s3"
run: |
echo ${{ secrets.NIX_CACHE_PRIV_KEY }} > cache-priv-key.pem
nix build .\#devShells.x86_64-linux.default
nix store sign --key-file cache-priv-key.pem --all
nix copy --to s3://nhost-nix-cache\?region=eu-central-1 .\#devShells.x86_64-linux.default
- run: rm cache-priv-key.pem
if: always()

4
.gitignore vendored
View File

@@ -19,11 +19,11 @@ logs/
coverage/ coverage/
dist/ dist/
umd/ umd/
node_modules/ node_modules
tmp/ tmp/
.pnpm-store .pnpm-store
.turbo .turbo
.env .env*
.secrets .secrets
out/ out/

1
.npmrc
View File

@@ -1 +1,2 @@
prefer-workspace-packages = true prefer-workspace-packages = true
auto-install-peers = false

View File

@@ -1,7 +0,0 @@
{
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"eslint.workingDirectories": ["./dashboard"],
"typescript.tsdk": "node_modules/typescript/lib"
}

7
SECURITY.md Normal file
View File

@@ -0,0 +1,7 @@
# Security Policy
## Reporting a Vulnerability
At Nhost, we take security vulnerabilities seriously and appreciate the assistance of the community in bringing any issues to our attention. If you discover a security vulnerability, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/nhost/nhost/security/advisories/new) tab.
Once you have submitted the report, we will promptly conduct a thorough investigation within 72 hours. In case we need further information, we may contact you for additional details. Rest assured that addressing the reported vulnerability in a timely manner is our top priority.

6
audit-ci.jsonc Normal file
View File

@@ -0,0 +1,6 @@
{
// $schema provides code completion hints to IDEs.
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"moderate": true,
"allowlist": ["trim-newlines"]
}

3
config/.husky/pre-commit Executable file → Normal file
View File

@@ -1,4 +1,7 @@
#!/bin/sh #!/bin/sh
#
[ -n "$CI" ] && exit 0
. "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/husky.sh"
pnpm dlx lint-staged --config config/.lintstagedrc.js pnpm dlx lint-staged --config config/.lintstagedrc.js

View File

@@ -16,3 +16,6 @@ NEXT_PUBLIC_STRIPE_PK=<nhost_stripe_public_key>
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL=<github_app_install_url> NEXT_PUBLIC_GITHUB_APP_INSTALL_URL=<github_app_install_url>
NEXT_PUBLIC_ANALYTICS_WRITE_KEY=<analytics_write_key> NEXT_PUBLIC_ANALYTICS_WRITE_KEY=<analytics_write_key>
NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET=<nhost_bragi_websocket> NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET=<nhost_bragi_websocket>
CODEGEN_GRAPHQL_URL=https://local.graphql.nhost.run/v1
CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret

View File

@@ -1,5 +1,188 @@
# @nhost/dashboard # @nhost/dashboard
## 1.11.0
### Minor Changes
- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2` to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings
### Patch Changes
- @nhost/react-apollo@10.0.1
- @nhost/nextjs@2.1.7
## 1.10.0
### Minor Changes
- 49a80c2: chore: update dependencies
- 150c04a: feat: add healthcheck config to run services
### Patch Changes
- e03f141: fix: allow insert, update and delete on tables in `auth` and `storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
- Updated dependencies [49a80c2]
- @nhost/react-apollo@10.0.0
- @nhost/nextjs@2.1.6
## 1.9.0
### Minor Changes
- d86e5c9: feat: add support for filtering the logs using a RegExp
## 1.8.3
### Patch Changes
- @nhost/react-apollo@9.0.3
- @nhost/nextjs@2.1.5
## 1.8.2
### Patch Changes
- 6df4f02: fix: use custom error toast and show correct message when sending an invite
## 1.8.1
### Patch Changes
- @nhost/react-apollo@9.0.2
- @nhost/nextjs@2.1.4
## 1.8.0
### Minor Changes
- 713d53c: feat: add catch-all route for workspace/project - useful for documentation
### Patch Changes
- 3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast` component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid header did not select all rows
- @nhost/react-apollo@9.0.1
- @nhost/nextjs@2.1.3
## 1.7.0
### Minor Changes
- 0d8d0eb: Update docs and dashboard references
## 1.6.9
### Patch Changes
- @nhost/react-apollo@9.0.0
- @nhost/nextjs@2.1.2
## 1.6.8
### Patch Changes
- @nhost/react-apollo@8.0.1
- @nhost/nextjs@2.1.1
## 1.6.7
### Patch Changes
- 5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug
## 1.6.6
### Patch Changes
- 3ba485e: fix: added discord.com to connect-src
- e5bab6a: chore: update dependencies
- Updated dependencies [b19ffed]
- Updated dependencies [e5bab6a]
- @nhost/nextjs@2.1.0
- @nhost/react-apollo@8.0.0
## 1.6.5
### Patch Changes
- ba73bb4: fix: update ErrorToast component to show the internal graphql error
- d5337ff: fix: utilize accumulator in the creation of validation schema within data grid utils
## 1.6.4
### Patch Changes
- 7c2a1c2: feat: show error and debug info in the error toast
## 1.6.3
### Patch Changes
- 6b8aad5: fix: add bare nhost.run to CSP
## 1.6.2
### Patch Changes
- b18edc0: feat: added CSP and X-Frame-Options
## 1.6.1
### Patch Changes
- 8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in Dockerfile
- Updated dependencies [8d91f71]
- @nhost/react-apollo@7.0.2
- @nhost/nextjs@2.0.2
## 1.6.0
### Minor Changes
- 3ff1c2b53: fix: show upgrade option for pro projects
## 1.5.0
### Minor Changes
- c2ef17c0a: feat: add support for new Team plan
## 1.4.0
### Minor Changes
- 7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview environments
### Patch Changes
- 3c3594898: fix: allow access to graphite when configured running in local dashboard
- 32c246b7a: chore: update docs icon
## 1.3.2
### Patch Changes
- 174b4165b: chore: use env variables when running graphql codegen
- 7c977e714: chore: change `Allowed Roles` to `Default Allowed Roles`
- 46f028b9f: fix: remove hardcoded ai version setting
## 1.3.1
### Patch Changes
- af33c21d1: chore: remove backendUrl deprecation notice and remove all references to `providersUpdated`
## 1.3.0
### Minor Changes
- 04784d880: Fix graphite's default version
## 1.2.0 ## 1.2.0
### Minor Changes ### Minor Changes

View File

@@ -3,7 +3,7 @@ RUN apk add --no-cache libc6-compat
RUN apk update RUN apk update
WORKDIR /app WORKDIR /app
RUN yarn global add turbo@1.10.11 RUN yarn global add turbo@1.11.3
COPY . . COPY . .
RUN turbo prune --scope="@nhost/dashboard" --docker RUN turbo prune --scope="@nhost/dashboard" --docker
@@ -29,7 +29,7 @@ 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_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_HASURA_API_URL __NEXT_PUBLIC_NHOST_HASURA_API_URL__
RUN yarn global add pnpm@8.6.2 RUN yarn global add pnpm@8.10.5
COPY .gitignore .gitignore COPY .gitignore .gitignore
COPY --from=pruner /app/out/json/ . COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/pnpm-*.yaml . COPY --from=pruner /app/out/pnpm-*.yaml .

View File

@@ -27,7 +27,7 @@ test('should be able to create then delete a personal access token', async () =>
const patName = faker.lorem.slug(3); const patName = faker.lorem.slug(3);
await page.getByRole('textbox', { name: /name/i }).fill(patName); await page.getByRole('textbox', { name: /name/i }).fill(patName);
await page.getByRole('button', { name: /expiration/i }).click(); await page.getByLabel('Expiration').click();
await page.getByRole('option', { name: /7 days/i }).click(); await page.getByRole('option', { name: /7 days/i }).click();
await page.getByRole('button', { name: /create/i }).click(); await page.getByRole('button', { name: /create/i }).click();

View File

@@ -138,7 +138,8 @@ test('should create a table with an identity column', async () => {
], ],
}); });
await page.getByRole('button', { name: /identity/i }).click(); // await page.getByRole('button', { name: /identity/i }).click();
await page.getByLabel('Identity').click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
// create table // create table
@@ -194,26 +195,18 @@ test('should create table with foreign key constraint', async () => {
await page.getByRole('button', { name: /add foreign key/i }).click(); await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table await page.locator('#columnName').click();
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click(); await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema // select reference schema
await page.getByRole('button', { name: /schema/i }).click(); await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click(); await page.getByRole('option', { name: /public/i }).click();
// select reference table // select reference table
await page.getByRole('button', { name: /table/i }).click(); await page.getByLabel('Table').click();
await page.getByRole('option', { name: firstTableName, exact: true }).click(); await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column await page.locator('#referencedColumn').click();
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click(); await page.getByRole('button', { name: /add/i }).click();

View File

@@ -113,27 +113,21 @@ test('should not be able to delete a table if other tables have foreign keys ref
await page.getByRole('button', { name: /add foreign key/i }).click(); await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table // select column in current table
await page await page.locator('#columnName').click();
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click(); await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema // select reference schema
await page.getByRole('button', { name: /schema/i }).click(); await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click(); await page.getByRole('option', { name: /public/i }).click();
// select reference table // select reference table
await page.getByRole('button', { name: /table/i }).click(); await page.getByLabel('Table').click();
await page.getByRole('option', { name: firstTableName, exact: true }).click(); await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column // select reference column
await page await page.locator('#referencedColumn').click();
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click(); await page.getByRole('button', { name: /add/i }).click();
await expect( await expect(

View File

@@ -93,7 +93,7 @@ test("should show the project's region and subdomain", async () => {
test('should not have a GitHub repository connected', async () => { test('should not have a GitHub repository connected', async () => {
await expect( await expect(
page.getByRole('button', { name: /connect to github/i }), page.getByRole('button', { name: /connect to github/i }).first(),
).toBeVisible(); ).toBeVisible();
}); });

View File

@@ -116,7 +116,8 @@ export async function prepareTable({
); );
// select the first column as primary key // select the first column as primary key
await page.getByRole('button', { name: /primary key/i }).click(); // await page.getByRole('button', { name: /primary key/i }).click();
await page.getByLabel('Primary Key').click();
await page.getByRole('option', { name: primaryKey, exact: true }).click(); await page.getByRole('option', { name: primaryKey, exact: true }).click();
} }

View File

@@ -1,7 +1,7 @@
schema: schema:
- https://local.graphql.nhost.run/v1: - ${CODEGEN_GRAPHQL_URL}:
headers: headers:
x-hasura-admin-secret: nhost-admin-secret x-hasura-admin-secret: ${CODEGEN_HASURA_ADMIN_SECRET}
generates: generates:
src/utils/__generated__/graphql.ts: src/utils/__generated__/graphql.ts:
documents: documents:

View File

@@ -1,5 +0,0 @@
query InitQuery {
root {
enableServices
}
}

View File

@@ -1,5 +0,0 @@
{
"projectId": 2596,
"token": "U2FsdGVkX19+V8BJnVR0xLEC+42OW5qZl/A0i6beAaRmJoIhFh5Yf6eIKBzLbV9h",
"outputDirectoryPath": "src/hypertune"
}

View File

@@ -4,6 +4,20 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
}); });
const { version } = require('./package.json'); const { version } = require('./package.json');
const cspHeader = `
default-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run;
script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.segment.com js.stripe.com;
connect-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run discord.com;
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data: avatars.githubusercontent.com s.gravatar.com *.nhost.run nhost.run;
font-src 'self' data:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
frame-src 'self' js.stripe.com;
`;
module.exports = withBundleAnalyzer({ module.exports = withBundleAnalyzer({
reactStrictMode: true, reactStrictMode: true,
swcMinify: false, swcMinify: false,
@@ -17,6 +31,19 @@ module.exports = withBundleAnalyzer({
eslint: { eslint: {
dirs: ['src'], dirs: ['src'],
}, },
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
],
},
];
},
async redirects() { async redirects() {
return [ return [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "1.2.0", "version": "1.11.0",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -10,67 +10,67 @@
"start": "next start", "start": "next start",
"lint": "next lint --max-warnings 0", "lint": "next lint --max-warnings 0",
"test": "vitest", "test": "vitest",
"codegen": "graphql-codegen --config graphql.config.yaml --errors-only", "codegen": "DOTENV_CONFIG_PATH=./.env.local graphql-codegen -r dotenv/config --config graphql.config.yaml --errors-only",
"codegen-graphite": "graphql-codegen --config graphite.graphql.config.yaml --errors-only", "codegen-graphite": "graphql-codegen --config graphite.graphql.config.yaml --errors-only",
"format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.", "format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.",
"storybook": "start-storybook -p 6006 -s public", "storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook", "build-storybook": "build-storybook",
"install-browsers": "pnpm dlx playwright@1.31.0 install --with-deps", "install-browsers": "pnpm playwright install && pnpm playwright install-deps",
"e2e": "pnpm install-browsers && pnpm dlx playwright@1.31.0 test" "e2e": "pnpm install-browsers && pnpm playwright test"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.7.10", "@apollo/client": "^3.9.5",
"@codemirror/lang-sql": "^6.5.4", "@codemirror/lang-sql": "^6.6.0",
"@emotion/cache": "^11.10.5", "@emotion/cache": "^11.11.0",
"@emotion/react": "^11.10.5", "@emotion/react": "^11.11.4",
"@emotion/server": "^11.4.0", "@emotion/server": "^11.11.0",
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.0", "@fontsource/inter": "^5.0.16",
"@fontsource/roboto-mono": "^5.0.0", "@fontsource/roboto-mono": "^5.0.16",
"@graphiql/react": "^0.18.0", "@graphiql/react": "^0.20.3",
"@graphiql/toolkit": "^0.8.2", "@graphiql/toolkit": "^0.9.1",
"@headlessui/react": "^1.6.5", "@headlessui/react": "^1.7.18",
"@heroicons/react": "^1.0.6", "@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.0.0", "@hookform/resolvers": "^3.3.4",
"@mui/base": "^5.0.0-alpha.106", "@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.10.14", "@mui/material": "^5.15.11",
"@mui/system": "^5.10.14", "@mui/system": "^5.15.11",
"@mui/x-date-pickers": "^5.0.8", "@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*", "@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*", "@nhost/react-apollo": "workspace:*",
"@segment/snippet": "^4.15.3", "@segment/snippet": "^4.16.2",
"@stripe/react-stripe-js": "^2.0.0", "@stripe/react-stripe-js": "^2.5.1",
"@stripe/stripe-js": "^1.35.0", "@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.7",
"@tanstack/react-query": "^4.16.1", "@tanstack/react-query": "^4.36.1",
"@tanstack/react-table": "^8.5.30", "@tanstack/react-table": "^8.13.2",
"@tanstack/react-virtual": "^3.0.0-beta.23", "@tanstack/react-virtual": "^3.1.3",
"@uiw/codemirror-theme-github": "^4.21.20", "@uiw/codemirror-theme-github": "^4.21.24",
"@uiw/react-codemirror": "^4.21.20", "@uiw/react-codemirror": "^4.21.24",
"analytics-node": "^6.2.0", "analytics-node": "^6.2.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"date-fns": "^2.29.3", "date-fns": "^2.30.0",
"generate-password": "^1.7.0", "framer-motion": "^10.18.0",
"graphiql": "^3.0.0", "generate-password": "^1.7.1",
"graphql": "^16.6.0", "graphiql": "^3.1.1",
"graphql-request": "^6.0.0", "graphql": "16.8.1",
"graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-ws": "^5.11.2", "graphql-ws": "^5.15.0",
"hypertune": "^1.4.4", "just-kebab-case": "^4.2.0",
"just-kebab-case": "^4.1.1",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"next": "^12.3.1", "next": "^14.1.0",
"next-seo": "^6.0.0", "next-seo": "^6.5.0",
"node-pg-format": "^1.3.5", "node-pg-format": "^1.3.5",
"pluralize": "^8.0.0", "pluralize": "^8.0.0",
"react": "18.2.0", "react": "18.2.0",
"react-children-utilities": "^2.9.0", "react-children-utilities": "^2.10.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-error-boundary": "^4.0.0", "react-error-boundary": "^4.0.13",
"react-hook-form": "^7.42.1", "react-hook-form": "^7.50.1",
"react-hot-toast": "^2.4.0", "react-hot-toast": "^2.4.1",
"react-intersection-observer": "^9.5.2", "react-intersection-observer": "^9.8.1",
"react-is": "18.2.0", "react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0", "react-loading-skeleton": "^2.2.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
@@ -82,87 +82,87 @@
"rehype-highlight": "^7.0.0", "rehype-highlight": "^7.0.0",
"remark-gfm": "^4.0.0", "remark-gfm": "^4.0.0",
"shell-quote": "^1.8.1", "shell-quote": "^1.8.1",
"slugify": "^1.6.5", "slugify": "^1.6.6",
"stripe": "^10.17.0", "stripe": "^10.17.0",
"tailwind-merge": "^1.8.0", "tailwind-merge": "^1.14.0",
"utility-types": "^3.10.0", "utility-types": "^3.11.0",
"validator": "^13.7.0", "validator": "^13.11.0",
"yup": "^1.0.2", "yup": "^1.3.3",
"yup-password": "^0.2.2" "yup-password": "^0.2.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.2", "@babel/core": "^7.24.0",
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^3.0.0", "@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/typescript": "^3.0.0", "@graphql-codegen/typescript": "^3.0.4",
"@graphql-codegen/typescript-operations": "^3.0.0", "@graphql-codegen/typescript-operations": "^3.0.4",
"@graphql-codegen/typescript-react-apollo": "^3.3.1", "@graphql-codegen/typescript-react-apollo": "^3.3.7",
"@next/bundle-analyzer": "^12.3.1", "@next/bundle-analyzer": "^12.3.4",
"@playwright/test": "1.31.0", "@playwright/test": "1.41.0",
"@storybook/addon-actions": "^6.5.14", "@storybook/addon-actions": "^6.5.16",
"@storybook/addon-essentials": "^6.5.14", "@storybook/addon-essentials": "^6.5.16",
"@storybook/addon-interactions": "^6.5.14", "@storybook/addon-interactions": "^6.5.16",
"@storybook/addon-links": "^6.5.14", "@storybook/addon-links": "^6.5.16",
"@storybook/addon-postcss": "^2.0.0", "@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-webpack5": "^6.5.14", "@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.14", "@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^6.5.14", "@storybook/react": "^7.6.17",
"@storybook/testing-library": "^0.2.0", "@storybook/testing-library": "^0.2.2",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@testing-library/dom": "^9.0.0", "@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.2.1",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.5.2",
"@types/ace": "^0.0.48", "@types/ace": "^0.0.48",
"@types/bcryptjs": "^2.4.2", "@types/bcryptjs": "^2.4.6",
"@types/jest": "^29.5.3", "@types/jest": "^29.5.12",
"@types/lodash.debounce": "^4.0.7", "@types/lodash.debounce": "^4.0.9",
"@types/node": "^16.11.7", "@types/node": "^16.18.86",
"@types/pluralize": "^0.0.30", "@types/pluralize": "^0.0.30",
"@types/react": "^18.2.14", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.6", "@types/react-dom": "^18.2.19",
"@types/react-table": "^7.7.12", "@types/react-table": "^7.7.19",
"@types/shell-quote": "^1.7.1", "@types/shell-quote": "^1.7.5",
"@types/testing-library__jest-dom": "^5.14.5", "@types/testing-library__jest-dom": "^5.14.9",
"@types/validator": "^13.7.10", "@types/validator": "^13.11.9",
"@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.15.0", "@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.0.0", "@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^0.32.0", "@vitest/coverage-v8": "^0.32.4",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.17",
"babel-loader": "^8.3.0", "babel-loader": "^8.3.0",
"babel-plugin-transform-remove-console": "^6.9.4", "babel-plugin-transform-remove-console": "^6.9.4",
"csstype": "^3.0.10", "csstype": "^3.1.3",
"dotenv": "^16.0.3", "dotenv": "^16.4.5",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"eslint": "^8.28.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-next": "^13.0.2", "eslint-config-next": "^13.5.6",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.10.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^22.0.0", "jsdom": "^22.1.0",
"lint-staged": ">=13", "lint-staged": "^15.2.2",
"msw": "^1.0.1", "msw": "^1.3.2",
"msw-storybook-addon": "^1.6.3", "msw-storybook-addon": "^1.10.0",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.2",
"postcss": "^8.4.19", "postcss": "^8.4.35",
"prettier": "^2.7.1", "prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.0", "prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.4.0", "prettier-plugin-tailwindcss": "^0.4.1",
"react-date-fns-hooks": "^0.9.4", "react-date-fns-hooks": "^0.9.4",
"require-from-string": "^2.0.2", "require-from-string": "^2.0.2",
"snake-case": "^3.0.4", "snake-case": "^3.0.4",
"storybook-addon-next-router": "^4.0.1", "storybook-addon-next-router": "^4.0.2",
"tailwindcss": "^3.1.2", "tailwindcss": "^3.4.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.0.0", "tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^4.0.2", "vite": "^5.1.4",
"vite-tsconfig-paths": "^4.0.3", "vite-tsconfig-paths": "^4.3.1",
"vitest": "^0.32.0" "vitest": "^0.32.4"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 6H10" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 8H10" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10H8" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.79289 13.5H3C2.86739 13.5 2.74021 13.4473 2.64645 13.3536C2.55268 13.2598 2.5 13.1326 2.5 13V3C2.5 2.86739 2.55268 2.74021 2.64645 2.64645C2.74021 2.55268 2.86739 2.5 3 2.5H13C13.1326 2.5 13.2598 2.55268 13.3536 2.64645C13.4473 2.74021 13.5 2.86739 13.5 3V9.79289C13.5 9.85855 13.4871 9.92357 13.4619 9.98423C13.4368 10.0449 13.4 10.1 13.3536 10.1464L10.1464 13.3536C10.1 13.4 10.0449 13.4368 9.98423 13.4619C9.92357 13.4871 9.85855 13.5 9.79289 13.5V13.5Z" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.4548 9.99948H10V13.4545" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 6H10" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 8H10" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10H8" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.79289 13.5H3C2.86739 13.5 2.74021 13.4473 2.64645 13.3536C2.55268 13.2598 2.5 13.1326 2.5 13V3C2.5 2.86739 2.55268 2.74021 2.64645 2.64645C2.74021 2.55268 2.86739 2.5 3 2.5H13C13.1326 2.5 13.2598 2.55268 13.3536 2.64645C13.4473 2.74021 13.5 2.86739 13.5 3V9.79289C13.5 9.85855 13.4871 9.92357 13.4619 9.98423C13.4368 10.0449 13.4 10.1 13.3536 10.1464L10.1464 13.3536C10.1 13.4 10.0449 13.4368 9.98423 13.4619C9.92357 13.4871 9.85855 13.5 9.79289 13.5V13.5Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.4548 9.99948H10V13.4545" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -4,9 +4,17 @@ import type { DetailedHTMLProps, HTMLProps } from 'react';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface ContactUsProps export interface ContactUsProps
extends DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> {} extends DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> {
isTeam?: boolean;
isOwner?: boolean;
}
export default function FeedbackForm({ className, ...props }: ContactUsProps) { export default function FeedbackForm({
className,
isTeam,
isOwner,
...props
}: ContactUsProps) {
return ( return (
<div <div
className={twMerge( className={twMerge(
@@ -19,6 +27,30 @@ export default function FeedbackForm({ className, ...props }: ContactUsProps) {
Contact us Contact us
</Text> </Text>
{isTeam && isOwner && (
<Text>
If this is a new Team project, or you need to manage members, reach
out to us on discord or via email at{' '}
<Link
href="mailto:support@nhost.io"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
support@nhost.io
</Link>{' '}
so we can have your dedicated channel set up.
</Text>
)}
{isTeam && !isOwner && (
<Text>
As part of a team plan you can reach out to us on the private channel
for this workspace. If you haven&apos;t been added to the channel, ask
the workspace owner to add you.
</Text>
)}
<Text> <Text>
To report issues with Nhost, please open a GitHub issue in the{' '} To report issues with Nhost, please open a GitHub issue in the{' '}
<Link <Link

View File

@@ -1,28 +0,0 @@
import { Alert } from '@/components/ui/v2/Alert';
import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
export default function DepricationNotice() {
const { currentProject } = useCurrentWorkspaceAndProject();
return (
!currentProject?.providersUpdated && (
<Alert severity="warning" className="grid place-content-center">
<Text color="warning" className="max-w-3xl text-sm">
On December 1st the old backend domain will cease to work. You need to
make sure your client is instantiated using the subdomain and region
and update your oauth2 settings. You can find more information{' '}
<a
target="_blank"
rel="noopener noreferrer"
className="underline"
href="https://github.com/nhost/nhost/discussions/2303"
>
here
</a>
.
</Text>
</Alert>
)
);
}

View File

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

View File

@@ -17,7 +17,7 @@ function NavLink(
ref: ForwardedRef<HTMLAnchorElement>, ref: ForwardedRef<HTMLAnchorElement>,
) { ) {
return ( return (
<NextLink href={href} passHref> <NextLink href={href} passHref legacyBehavior>
<Link className={twMerge('font-display', className)} ref={ref} {...props}> <Link className={twMerge('font-display', className)} ref={ref} {...props}>
{children} {children}
</Link> </Link>

View File

@@ -26,7 +26,7 @@ export default function ThemeSwitcher({
listbox: { className: 'min-w-0 w-full' }, listbox: { className: 'min-w-0 w-full' },
popper: { popper: {
disablePortal: false, disablePortal: false,
className: 'z-[10000] w-[270px] w-full', className: 'z-[10000] w-[270px]',
}, },
}} }}
> >

View File

@@ -26,7 +26,7 @@ export default function UpgradeToProBanner({
return ( return (
<Box <Box
sx={{ backgroundColor: 'primary.light' }} sx={{ backgroundColor: 'primary.light' }}
className="flex flex-col justify-between space-y-4 rounded-md p-4 lg:flex-row lg:items-center lg:space-y-0" className="flex flex-col justify-between p-4 space-y-4 rounded-md lg:flex-row lg:items-center lg:space-y-0"
> >
<div className="flex flex-col justify-between space-y-4"> <div className="flex flex-col justify-between space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -81,13 +81,13 @@ export default function UpgradeToProBanner({
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
underline="hover" underline="hover"
className="text-center font-medium" className="font-medium text-center"
sx={{ sx={{
color: 'text.secondary', color: 'text.secondary',
}} }}
> >
See all features See all features
<ArrowSquareOutIcon className="ml-1 h-4 w-4" /> <ArrowSquareOutIcon className="w-4 h-4 ml-1" />
</Link> </Link>
</div> </div>
</div> </div>
@@ -97,6 +97,7 @@ export default function UpgradeToProBanner({
width={300} width={300}
height={140} height={140}
objectFit="contain" objectFit="contain"
alt='Upgrade to Pro illustration'
/> />
</Box> </Box>
); );

View File

@@ -35,7 +35,7 @@ function InsertPlaceholderTableRow({
...props ...props
}: InsertPlaceholderTableRowProps) { }: InsertPlaceholderTableRowProps) {
return ( return (
<Box className="h-12 border-r-1 border-b-1" {...props}> <Box className="h-12 border-b-1 border-r-1" {...props}>
<Button <Button
onClick={onInsertRow} onClick={onInsertRow}
variant="borderless" variant="borderless"
@@ -209,7 +209,7 @@ export default function DataGridBody<T extends object>({
/> />
) : ( ) : (
<Box <Box
className="inline-flex h-12 items-center border-b-1 border-r-1 py-1.5 px-2 text-xs" className="inline-flex h-12 items-center border-b-1 border-r-1 px-2 py-1.5 text-xs"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
style={{ style={{
width: allowInsertColumn width: allowInsertColumn
@@ -281,8 +281,8 @@ export default function DataGridBody<T extends object>({
}} }}
className={twMerge( className={twMerge(
'h-12 font-display text-xs motion-safe:transition-colors', 'h-12 font-display text-xs motion-safe:transition-colors',
'border-r-1 border-b-1', 'border-b-1 border-r-1',
'scroll-mt-[57px] scroll-ml-8', 'scroll-ml-8 scroll-mt-[57px]',
column.id === 'selection' && column.id === 'selection' &&
'sticky left-0 z-20 justify-center px-0', 'sticky left-0 z-20 justify-center px-0',
)} )}
@@ -296,7 +296,7 @@ export default function DataGridBody<T extends object>({
})} })}
{allowInsertColumn && ( {allowInsertColumn && (
<Box className="h-12 w-25 border-r-1 border-b-1" /> <Box className="h-12 w-25 border-b-1 border-r-1" />
)} )}
</div> </div>

View File

@@ -8,7 +8,15 @@ import type {
DataBrowserGridCellProps, DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser'; } from '@/features/database/dataGrid/types/dataBrowser';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import type { FocusEvent, KeyboardEvent, MouseEvent } from 'react'; import type {
FocusEvent,
JSXElementConstructor,
KeyboardEvent,
MouseEvent,
ReactElement,
ReactNode,
ReactPortal,
} from 'react';
import { import {
Children, Children,
cloneElement, cloneElement,
@@ -308,7 +316,7 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
isEditable && isEditable &&
'focus-within:outline-none focus-within:ring-0 focus:ring-0', 'focus-within:outline-none focus-within:ring-0 focus:ring-0',
isSelected && 'shadow-outline', isSelected && 'shadow-outline',
isEditing ? 'p-0.5 shadow-outline-dark' : 'py-1.5 px-2', isEditing ? 'p-0.5 shadow-outline-dark' : 'px-2 py-1.5',
className, className,
)} )}
onFocus={handleFocus} onFocus={handleFocus}
@@ -320,20 +328,28 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
sx={{ backgroundColor: 'transparent' }} sx={{ backgroundColor: 'transparent' }}
{...props} {...props}
> >
{Children.map(children, (child) => { {Children.map(
if (!isValidElement(child)) { children,
return null; (
} child:
| ReactNode
| ReactPortal
| ReactElement<unknown, string | JSXElementConstructor<any>>,
) => {
if (!isValidElement(child)) {
return null;
}
return cloneElement(child, { return cloneElement(child, {
...child.props, ...child.props,
onSave: handleSave, onSave: handleSave,
optimisticValue, optimisticValue,
onOptimisticValueChange: setOptimisticValue, onOptimisticValueChange: setOptimisticValue,
temporaryValue, temporaryValue,
onTemporaryValueChange: setTemporaryValue, onTemporaryValueChange: setTemporaryValue,
}); });
})} },
)}
</Box> </Box>
); );

View File

@@ -96,45 +96,52 @@ export default function DataGridHeader<T extends object>({
}} }}
key={column.id} key={column.id}
> >
<Dropdown.Trigger {column.id === 'selection' ? (
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled ||
column.id === 'selection' ||
(column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span <span
{...headerProps} {...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2" className="relative grid w-full grid-flow-col items-center justify-between p-2"
> >
{column.render('Header')} {column.render('Header')}
{allowSort && (
<Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span> </span>
) : (
{allowResize && !column.disableResizing && ( <Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span <span
{...column.getResizerProps({ {...headerProps}
onClick: (event: Event) => event.stopPropagation(), className="relative grid w-full grid-flow-col items-center justify-between p-2"
})} >
className="absolute top-0 bottom-0 -right-0.5 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors" {column.render('Header')}
/>
)} {allowSort && (
</Dropdown.Trigger> <Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span>
{allowResize && !column.disableResizing && (
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
/>
)}
</Dropdown.Trigger>
)}
<Dropdown.Content <Dropdown.Content
menu menu

View File

@@ -13,6 +13,7 @@ import { Dropdown } from '@/components/ui/v2/Dropdown';
import { GraphiteIcon } from '@/components/ui/v2/icons/GraphiteIcon'; import { GraphiteIcon } from '@/components/ui/v2/icons/GraphiteIcon';
import { DevAssistant } from '@/features/ai/DevAssistant'; import { DevAssistant } from '@/features/ai/DevAssistant';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCurrentUserOwner';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform'; import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { ApplicationStatus } from '@/types/application'; import { ApplicationStatus } from '@/types/application';
import { getToastStyleProps } from '@/utils/constants/settings'; import { getToastStyleProps } from '@/utils/constants/settings';
@@ -37,6 +38,8 @@ export default function Header({ className, ...props }: HeaderProps) {
const { currentProject, refetch: refetchProject } = const { currentProject, refetch: refetchProject } =
useCurrentWorkspaceAndProject(); useCurrentWorkspaceAndProject();
const isOwner = useIsCurrentUserOwner();
const isProjectUpdating = const isProjectUpdating =
currentProject?.appStates[0]?.stateId === ApplicationStatus.Updating; currentProject?.appStates[0]?.stateId === ApplicationStatus.Updating;
@@ -114,7 +117,11 @@ export default function Header({ className, ...props }: HeaderProps) {
transformOrigin={{ vertical: 'top', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
> >
<ContactUs className="max-w-md" /> <ContactUs
className="max-w-md"
isTeam={currentProject?.plan?.name === 'Team'}
isOwner={isOwner}
/>
</Dropdown.Content> </Dropdown.Content>
</Dropdown.Root> </Dropdown.Root>
)} )}

View File

@@ -1,4 +1,3 @@
import DepricationNotice from '@/components/common/DepricationNotice/DepricationNotice';
import type { ProjectLayoutProps } from '@/components/layout/ProjectLayout'; import type { ProjectLayoutProps } from '@/components/layout/ProjectLayout';
import { ProjectLayout } from '@/components/layout/ProjectLayout'; import { ProjectLayout } from '@/components/layout/ProjectLayout';
import type { SettingsSidebarProps } from '@/components/layout/SettingsSidebar'; import type { SettingsSidebarProps } from '@/components/layout/SettingsSidebar';
@@ -50,7 +49,6 @@ export default function SettingsLayout({
> >
<RetryableErrorBoundary> <RetryableErrorBoundary>
<div className="flex flex-col space-y-2"> <div className="flex flex-col space-y-2">
<DepricationNotice />
{hasGitRepo && ( {hasGitRepo && (
<Alert <Alert
severity="warning" severity="warning"

View File

@@ -1,100 +0,0 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Alert } from '@/components/ui/v2/Alert';
import { Button } from '@/components/ui/v2/Button';
import { ArrowSquareOutIcon } from '@/components/ui/v2/icons/ArrowSquareOutIcon';
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings';
import { useConfirmProvidersUpdatedMutation } from '@/utils/__generated__/graphql';
import { useTheme } from '@mui/material';
import { useState } from 'react';
import toast from 'react-hot-toast';
export default function ProvidersUpdatedAlert() {
const theme = useTheme();
const { openAlertDialog } = useDialog();
const [confirmed, setConfirmed] = useState(true);
const { currentProject } = useCurrentWorkspaceAndProject();
const [confirmProvidersUpdated] = useConfirmProvidersUpdatedMutation({
variables: { id: currentProject?.id },
});
async function handleSubmitConfirmation() {
const confirmProvidersUpdatedPromise = confirmProvidersUpdated();
await toast.promise(
confirmProvidersUpdatedPromise,
{
loading: 'Confirming...',
success: 'Your settings have been updated successfully.',
error: 'An error occurred while trying to confirm the message.',
},
getToastStyleProps(),
);
setConfirmed(false);
}
function handleOpenConfirmationDialog() {
openAlertDialog({
title: 'Confirm all providers updated?',
payload: (
<Text variant="subtitle1" component="span">
Please make sure to update all providers before continuing. Your
sign-in flows might break if you don&apos;t.
</Text>
),
props: {
onPrimaryAction: handleSubmitConfirmation,
},
});
}
if (!confirmed) {
return null;
}
return (
<Alert
severity="warning"
className="grid items-center grid-flow-row gap-2 p-4 place-items-center lg:grid-flow-col lg:place-content-between"
>
<div className="grid grid-flow-row gap-1 text-left">
<Text className="font-semibold">
Please update the Redirect URL for all providers being used
</Text>
<Text className="text-sm+">
We are deprecating your project&apos;s old DNS name in favor of
individual DNS names for each service. Please make sure to update your
providers to use the new auth specific URL under <b>Redirect URL</b>{' '}
before the 1st of February 2023.{' '}
<Link
href="https://github.com/nhost/nhost/discussions/1319"
target="_blank"
rel="noopener noreferrer"
underline="hover"
className="font-medium"
>
Read the discussion here.
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
</Link>
</Text>
</div>
<Button
variant="borderless"
className={
theme.palette.mode === 'dark'
? 'text-white hover:bg-brown'
: 'text-black hover:bg-orange-300'
}
onClick={handleOpenConfirmationDialog}
>
I have updated all Redirect URLs
</Button>
</Alert>
);
}

View File

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

View File

@@ -8,9 +8,9 @@ import { Input, inputClasses } from '@/components/ui/v2/Input';
import { OptionBase } from '@/components/ui/v2/Option'; import { OptionBase } from '@/components/ui/v2/Option';
import { OptionGroupBase } from '@/components/ui/v2/OptionGroup'; import { OptionGroupBase } from '@/components/ui/v2/OptionGroup';
import type { StyledComponent } from '@emotion/styled'; import type { StyledComponent } from '@emotion/styled';
import type { UseAutocompleteProps } from '@mui/base/AutocompleteUnstyled'; import type { UseAutocompleteProps } from '@mui/base/useAutocomplete';
import { createFilterOptions } from '@mui/base/AutocompleteUnstyled'; import { createFilterOptions } from '@mui/base/useAutocomplete';
import PopperUnstyled from '@mui/base/PopperUnstyled'; import { Popper } from '@mui/base'
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { AutocompleteProps as MaterialAutocompleteProps } from '@mui/material/Autocomplete'; import type { AutocompleteProps as MaterialAutocompleteProps } from '@mui/material/Autocomplete';
import MaterialAutocomplete, { import MaterialAutocomplete, {
@@ -142,7 +142,7 @@ const StyledOptionBase = styled(OptionBase)(({ theme }) => ({
gap: theme.spacing(0.5), gap: theme.spacing(0.5),
})); }));
export const AutocompletePopper = styled(PopperUnstyled)(({ theme }) => ({ export const AutocompletePopper = styled(Popper)(({ theme }) => ({
zIndex: theme.zIndex.modal + 1, zIndex: theme.zIndex.modal + 1,
boxShadow: 'none', boxShadow: 'none',
minWidth: 320, minWidth: 320,

View File

@@ -1,9 +1,7 @@
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { import type { BoxProps as MaterialBoxProps } from '@mui/material/Box';
BoxProps as MaterialBoxProps,
BoxTypeMap,
} from '@mui/material/Box';
import MaterialBox from '@mui/material/Box'; import MaterialBox from '@mui/material/Box';
import { type BoxTypeMap } from '@mui/system';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';

View File

@@ -1,6 +1,6 @@
import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon'; import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon'; import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { ButtonProps } from './Button'; import type { ButtonProps } from './Button';
import Button from './Button'; import Button from './Button';
@@ -24,9 +24,9 @@ export default {
control: { type: 'radio' }, control: { type: 'radio' },
}, },
}, },
} as ComponentMeta<typeof Button>; } as Meta<typeof Button>;
const Template: ComponentStory<typeof Button> = function Template( const Template: StoryFn<ButtonProps> = function TemplateFunction(
args: ButtonProps, args: ButtonProps,
) { ) {
return <Button {...args} />; return <Button {...args} />;

View File

@@ -10,7 +10,7 @@ export interface ChipProps extends MaterialChipProps {
/** /**
* Custom component for the root node. * Custom component for the root node.
*/ */
component?: string | ElementType; component?: ElementType;
} }
const Chip = styled(MaterialChip)<ChipProps>(({ theme }) => ({ const Chip = styled(MaterialChip)<ChipProps>(({ theme }) => ({

View File

@@ -0,0 +1,164 @@
import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon';
import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastBackgroundColor } from '@/utils/constants/settings';
import { copy } from '@/utils/copy';
import type { ApolloError } from '@apollo/client';
import { useUserData } from '@nhost/nextjs';
import { AnimatePresence, motion } from 'framer-motion';
import { useRouter } from 'next/router';
import { useState } from 'react';
interface ErrorDetails {
info: {
projectId: string;
userId: string;
url?: string;
};
error: any;
}
const getInternalErrorMessage = (
error: Error | ApolloError | undefined,
): string | null => {
if (!error) {
return null;
}
if (error.name === 'ApolloError') {
// @ts-ignore
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as {
error: { message: string };
};
return internalError?.error?.message || null;
}
if (error instanceof Error) {
return error.message;
}
return null;
};
const errorToObject = (error: ApolloError | Error) => {
if (error.name === 'ApolloError') {
return error;
}
if (error instanceof Error) {
return {
name: error.name,
message: error.message,
stack: error.stack,
};
}
return {};
};
export default function ErrorToast({
isVisible,
errorMessage,
error,
close,
}: {
isVisible: boolean;
errorMessage: string;
error: ApolloError | Error;
close: () => void;
}) {
const userData = useUserData();
const { asPath } = useRouter();
const [showInfo, setShowInfo] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject();
const errorDetails: ErrorDetails = {
info: {
projectId: currentProject?.id,
userId: userData?.id || 'local',
url: asPath,
},
error: errorToObject(error),
};
const msg = getInternalErrorMessage(error) || errorMessage;
return (
<AnimatePresence>
{isVisible && (
<motion.div
style={{
backgroundColor: getToastBackgroundColor(),
}}
className="flex w-full max-w-xl flex-col space-y-4 rounded-lg p-4 text-white"
initial={{
opacity: 0,
y: 100,
}}
animate={{
opacity: 1,
scale: 1,
y: 0,
}}
exit={{
opacity: 0,
scale: 0,
y: 100,
}}
transition={{
bounce: 0.1,
}}
>
<div className="flex w-full flex-row items-center justify-between space-x-4">
<button onClick={close} type="button" aria-label="Close">
<XIcon className="h-4 w-4 text-white" />
</button>
<span>
{msg ?? 'An unkown error has occured, please try again later!'}
</span>
<button
type="button"
onClick={() => setShowInfo(!showInfo)}
className="flex flex-row items-center justify-center space-x-2 text-white"
>
<span>Info</span>
{showInfo ? (
<ChevronUpIcon className="h-3 w-3 text-white" />
) : (
<ChevronDownIcon className="h-3 w-3 text-white" />
)}
</button>
</div>
{showInfo && (
<div className="flex flex-col space-y-4">
<div className="relative flex flex-col">
<div className="relative flex max-h-[400px] w-full max-w-xl flex-row justify-between overflow-x-auto rounded-lg bg-black p-4">
<pre>{JSON.stringify(errorDetails, null, 2)}</pre>
</div>
<button
type="button"
aria-label="Copy error details"
className="absolute right-2 top-2"
onClick={(event) => {
event.stopPropagation();
copy(
JSON.stringify(errorDetails, null, 2),
'Error details',
);
}}
>
<CopyIcon className="h-4 w-4" />
</button>
</div>
</div>
)}
</motion.div>
)}
</AnimatePresence>
);
}

View File

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

View File

@@ -7,7 +7,7 @@ export interface HelperTextProps extends MaterialFormHelperTextProps {
/** /**
* Custom component for the root node. * Custom component for the root node.
*/ */
component?: string | ElementType; component?: ElementType;
} }
const HelperText = styled(MaterialFormHelperText)<HelperTextProps>({ const HelperText = styled(MaterialFormHelperText)<HelperTextProps>({

View File

@@ -1,41 +1,42 @@
import type { OptionUnstyledProps } from '@mui/base/OptionUnstyled'; import {
import OptionUnstyled, { Option as BaseOption,
optionUnstyledClasses, optionClasses as baseOptionClasses,
} from '@mui/base/OptionUnstyled'; type OptionProps as BaseOptionProps,
} from '@mui/base';
import { darken, styled } from '@mui/material'; import { darken, styled } from '@mui/material';
import type { ForwardedRef } from 'react'; import type { ForwardedRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import OptionBase from './OptionBase'; import OptionBase from './OptionBase';
export interface OptionProps<TValue extends {}> export interface OptionProps<TValue extends {}>
extends OptionUnstyledProps<TValue> {} extends BaseOptionProps<TValue> {}
const StyledOption = styled(OptionUnstyled)(({ theme }) => ({ const StyledOption = styled(BaseOption)(({ theme }) => ({
transition: theme.transitions.create(['background-color']), transition: theme.transitions.create(['background-color']),
color: theme.palette.text.primary, color: theme.palette.text.primary,
[`&.${optionUnstyledClasses.selected}`]: { [`&.${baseOptionClasses.selected}`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.1)} !important` ? `${darken(theme.palette.action.hover, 0.1)} !important`
: `${darken(theme.palette.action.hover, 0.05)} !important`, : `${darken(theme.palette.action.hover, 0.05)} !important`,
}, },
[`&.${optionUnstyledClasses.selected}:hover, &.${optionUnstyledClasses.selected}.${optionUnstyledClasses.highlighted}`]: [`&.${baseOptionClasses.selected}:hover, &.${baseOptionClasses.selected}.${baseOptionClasses.highlighted}`]:
{ {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.25)} !important` ? `${darken(theme.palette.action.hover, 0.25)} !important`
: `${darken(theme.palette.action.hover, 0.075)} !important`, : `${darken(theme.palette.action.hover, 0.075)} !important`,
}, },
[`&.${optionUnstyledClasses.highlighted}, &:hover`]: { [`&.${baseOptionClasses.highlighted}, &:hover`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.15)} !important` ? `${darken(theme.palette.action.hover, 0.15)} !important`
: `${theme.palette.action.hover} !important`, : `${theme.palette.action.hover} !important`,
}, },
[`&.${optionUnstyledClasses.disabled}`]: { [`&.${baseOptionClasses.disabled}`]: {
color: theme.palette.text.disabled, color: theme.palette.text.disabled,
}, },
[`&.${optionUnstyledClasses.disabled}:hover`]: { [`&.${baseOptionClasses.disabled}:hover`]: {
backgroundColor: 'transparent !important', backgroundColor: 'transparent !important',
}, },
})); }));

View File

@@ -1,11 +1,13 @@
import type { OptionGroupUnstyledProps } from '@mui/base/OptionGroupUnstyled'; import {
import OptionGroupUnstyled from '@mui/base/OptionGroupUnstyled'; OptionGroup as BaseOptionGroup,
type OptionGroupProps as BaseOptionGroupProps,
} from '@mui/base';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { ForwardedRef } from 'react'; import type { ForwardedRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import OptionGroupBase from './OptionGroupBase'; import OptionGroupBase from './OptionGroupBase';
export interface OptionGroupProps extends OptionGroupUnstyledProps {} export interface OptionGroupProps extends BaseOptionGroupProps {}
const StyledGroupRoot = styled('li')(({ theme }) => ({ const StyledGroupRoot = styled('li')(({ theme }) => ({
listStyle: 'none', listStyle: 'none',
@@ -25,7 +27,7 @@ function OptionGroup(
...externalSlots, ...externalSlots,
}; };
return <OptionGroupUnstyled {...props} ref={ref} slots={slots} />; return <BaseOptionGroup {...props} ref={ref} slots={slots} />;
} }
OptionGroup.displayName = 'NhostOptionGroup'; OptionGroup.displayName = 'NhostOptionGroup';

View File

@@ -1,5 +1,5 @@
import { Option } from '@/components/ui/v2/Option'; import { Option } from '@/components/ui/v2/Option';
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { SelectProps } from './Select'; import type { SelectProps } from './Select';
import Select from './Select'; import Select from './Select';
@@ -7,11 +7,9 @@ export default {
title: 'UI Library / Select', title: 'UI Library / Select',
component: Select, component: Select,
argTypes: {}, argTypes: {},
} as ComponentMeta<typeof Select>; } as Meta<typeof Select>;
const Template: ComponentStory<typeof Select> = function Template( const Template: StoryFn<SelectProps<any>> = function TemplateFunction(args) {
args: SelectProps<any>,
) {
return ( return (
<Select className="w-64" {...args}> <Select className="w-64" {...args}>
<Option value="value1">Value 1</Option> <Option value="value1">Value 1</Option>

View File

@@ -1,9 +1,9 @@
import type { FormControlProps } from '@/components/ui/v2/FormControl'; import type { FormControlProps } from '@/components/ui/v2/FormControl';
import { FormControl } from '@/components/ui/v2/FormControl'; import { FormControl } from '@/components/ui/v2/FormControl';
import PopperUnstyled from '@mui/base/PopperUnstyled'; import { Popper as BasePopper } from '@mui/base/Popper';
import type { SelectUnstyledProps } from '@mui/base/SelectUnstyled'; import type { SelectProps as BaseSelectProps } from '@mui/base/Select';
import SelectUnstyled from '@mui/base/SelectUnstyled'; import { Select as BaseSelect } from '@mui/base/Select';
import { styled } from '@mui/material'; import { styled } from '@mui/system';
import clsx from 'clsx'; import clsx from 'clsx';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
@@ -11,7 +11,7 @@ import type { ToggleButtonProps } from './ToggleButton';
import ToggleButton from './ToggleButton'; import ToggleButton from './ToggleButton';
export interface SelectProps<TValue extends {}> export interface SelectProps<TValue extends {}>
extends SelectUnstyledProps<TValue>, extends BaseSelectProps<TValue, false>,
Pick< Pick<
FormControlProps, FormControlProps,
| 'fullWidth' | 'fullWidth'
@@ -25,7 +25,7 @@ export interface SelectProps<TValue extends {}>
/** /**
* Props for component slots. * Props for component slots.
*/ */
slotProps?: SelectUnstyledProps<TValue>['slotProps'] & { slotProps?: BaseSelectProps<TValue, false>['slotProps'] & {
root?: Partial<PropsWithoutRef<ToggleButtonProps>>; root?: Partial<PropsWithoutRef<ToggleButtonProps>>;
label?: Partial<FormControlProps['labelProps']>; label?: Partial<FormControlProps['labelProps']>;
formControl?: Partial<FormControlProps>; formControl?: Partial<FormControlProps>;
@@ -59,8 +59,8 @@ const StyledListbox = styled('ul')(({ theme }) => ({
}, },
})); }));
const StyledPopper = styled(PopperUnstyled)` const StyledPopper = styled(BasePopper)`
z-index: 10; z-index: 9999;
`; `;
function Select<TValue>( function Select<TValue>(
@@ -80,7 +80,7 @@ function Select<TValue>(
}: SelectProps<TValue>, }: SelectProps<TValue>,
ref: ForwardedRef<HTMLButtonElement>, ref: ForwardedRef<HTMLButtonElement>,
) { ) {
const slots: SelectUnstyledProps<TValue>['slots'] = { const slots: BaseSelectProps<TValue, false>['slots'] = {
root: ToggleButton, root: ToggleButton,
popper: StyledPopper, popper: StyledPopper,
listbox: StyledListbox, listbox: StyledListbox,
@@ -107,7 +107,7 @@ function Select<TValue>(
htmlFor: props.id, htmlFor: props.id,
}} }}
> >
<SelectUnstyled <BaseSelect
aria-label={typeof label === 'string' ? label : undefined} aria-label={typeof label === 'string' ? label : undefined}
{...props} {...props}
className={clsx(error && 'error')} className={clsx(error && 'error')}
@@ -117,7 +117,6 @@ function Select<TValue>(
...slotProps, ...slotProps,
root: { root: {
...slotProps?.root, ...slotProps?.root,
placeholder,
}, },
listbox: { listbox: {
...slotProps?.listbox, ...slotProps?.listbox,
@@ -132,7 +131,7 @@ function Select<TValue>(
placeholder={placeholder} placeholder={placeholder}
> >
{children} {children}
</SelectUnstyled> </BaseSelect>
</FormControl> </FormControl>
); );
} }

View File

@@ -1,8 +1,10 @@
import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon'; import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon';
import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon'; import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon';
import type { ButtonUnstyledProps } from '@mui/base/ButtonUnstyled'; import {
import ButtonUnstyled from '@mui/base/ButtonUnstyled'; Button as ButtonUnstyled,
import { selectUnstyledClasses } from '@mui/base/SelectUnstyled'; type ButtonProps as ButtonUnstyledProps,
} from '@mui/base';
import { selectClasses as selectUnstyledClasses } from '@mui/base/Select';
import type { SxProps } from '@mui/material'; import type { SxProps } from '@mui/material';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { Theme } from '@mui/system'; import type { Theme } from '@mui/system';
@@ -24,6 +26,7 @@ export interface ToggleButtonProps
Omit<DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement>, 'as'> Omit<DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement>, 'as'>
>; >;
}; };
placeholder?: string;
} }
const StyledButton = styled(ButtonUnstyled)(({ theme }) => ({ const StyledButton = styled(ButtonUnstyled)(({ theme }) => ({

View File

@@ -1,4 +1,4 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { SwitchProps } from './Switch'; import type { SwitchProps } from './Switch';
import Switch from './Switch'; import Switch from './Switch';
@@ -6,9 +6,9 @@ export default {
title: 'UI Library / Switch', title: 'UI Library / Switch',
component: Switch, component: Switch,
argTypes: {}, argTypes: {},
} as ComponentMeta<typeof Switch>; } as Meta<typeof Switch>;
const Template: ComponentStory<typeof Switch> = function Template( const Template: StoryFn<SwitchProps> = function TemplateFunction(
args: SwitchProps, args: SwitchProps,
) { ) {
return <Switch label="Accept Rules" {...args} />; return <Switch label="Accept Rules" {...args} />;

View File

@@ -1,14 +1,15 @@
import type { FormControlLabelProps } from '@/components/ui/v2/FormControlLabel'; import type { FormControlLabelProps } from '@/components/ui/v2/FormControlLabel';
import { FormControlLabel } from '@/components/ui/v2/FormControlLabel'; import { FormControlLabel } from '@/components/ui/v2/FormControlLabel';
import SwitchUnstyled, { import {
switchUnstyledClasses, Switch as BaseSwitch,
} from '@mui/base/SwitchUnstyled'; switchClasses as baseSwitchClasses,
import type { SwitchUnstyledProps } from '@mui/base/SwitchUnstyled/SwitchUnstyled.types'; } from '@mui/base';
import type { SwitchProps as BaseSwitchProps } from '@mui/base/Switch';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
export interface SwitchProps extends SwitchUnstyledProps { export interface SwitchProps extends BaseSwitchProps {
/** /**
* Label to be displayed next to the checkbox. * Label to be displayed next to the checkbox.
*/ */
@@ -16,11 +17,11 @@ export interface SwitchProps extends SwitchUnstyledProps {
/** /**
* Props to be passed to the internal components. * Props to be passed to the internal components.
*/ */
slotProps?: SwitchUnstyledProps['slotProps'] & { slotProps?: BaseSwitchProps['slotProps'] & {
/** /**
* Props to be passed to the `Switch` component. * Props to be passed to the `Switch` component.
*/ */
root?: Partial<SwitchUnstyledProps>; root?: Partial<BaseSwitchProps>;
/** /**
* Props to be passed to the `FormControlLabel` component. * Props to be passed to the `FormControlLabel` component.
*/ */
@@ -35,23 +36,23 @@ const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
justifyContent: 'start', justifyContent: 'start',
})); }));
const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({ const StyledSwitch = styled(BaseSwitch)(({ theme }) => ({
position: 'relative', position: 'relative',
display: 'inline-block', display: 'inline-block',
width: '40px', width: '40px',
height: '24px', height: '24px',
cursor: 'pointer', cursor: 'pointer',
[`&.${switchUnstyledClasses.disabled}`]: { [`&.${baseSwitchClasses.disabled}`]: {
cursor: 'not-allowed', cursor: 'not-allowed',
[`& .${switchUnstyledClasses.track}`]: { [`& .${baseSwitchClasses.track}`]: {
backgroundColor: theme.palette.grey[200], backgroundColor: theme.palette.grey[200],
color: theme.palette.grey[200], color: theme.palette.grey[200],
}, },
}, },
[`& .${switchUnstyledClasses.track}`]: { [`& .${baseSwitchClasses.track}`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? theme.palette.grey[500] ? theme.palette.grey[500]
@@ -63,7 +64,7 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
position: 'absolute', position: 'absolute',
}, },
[` & .${switchUnstyledClasses.thumb}`]: { [` & .${baseSwitchClasses.thumb}`]: {
display: 'block', display: 'block',
width: '18px', width: '18px',
height: '18px', height: '18px',
@@ -77,24 +78,24 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
transitionDuration: '120ms', transitionDuration: '120ms',
}, },
[`&.${switchUnstyledClasses.focusVisible} .${switchUnstyledClasses.thumb}`]: { [`&.${baseSwitchClasses.focusVisible} .${baseSwitchClasses.thumb}`]: {
backgroundColor: theme.palette.action.focus, backgroundColor: theme.palette.action.focus,
boxShadow: '0 0 1px 8px rgba(0, 0, 0, 0.25)', boxShadow: '0 0 1px 8px rgba(0, 0, 0, 0.25)',
}, },
[`&.${switchUnstyledClasses.checked}`]: { [`&.${baseSwitchClasses.checked}`]: {
[`.${switchUnstyledClasses.thumb}`]: { [`.${baseSwitchClasses.thumb}`]: {
left: '19px', left: '19px',
top: '3px', top: '3px',
backgroundColor: theme.palette.common.white, backgroundColor: theme.palette.common.white,
}, },
[`.${switchUnstyledClasses.track}`]: { [`.${baseSwitchClasses.track}`]: {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
}, },
[`&.${switchUnstyledClasses.disabled}`]: { [`&.${baseSwitchClasses.disabled}`]: {
[`.${switchUnstyledClasses.track}`]: { [`.${baseSwitchClasses.track}`]: {
opacity: 0.5, opacity: 0.5,
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -104,7 +105,7 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
}, },
}, },
[`& .${switchUnstyledClasses.input}`]: { [`& .${baseSwitchClasses.input}`]: {
cursor: 'inherit', cursor: 'inherit',
position: 'absolute', position: 'absolute',
width: '100%', width: '100%',

View File

@@ -4,16 +4,14 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox'; import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { import {
useDeleteUserAccountMutation, useDeleteUserAccountMutation,
useGetAllWorkspacesAndProjectsQuery, useGetAllWorkspacesAndProjectsQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { type ApolloError } from '@apollo/client';
import { useSignOut, useUserData } from '@nhost/nextjs'; import { useSignOut, useUserData } from '@nhost/nextjs';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
function ConfirmDeleteAccountModal({ function ConfirmDeleteAccountModal({
@@ -44,30 +42,19 @@ function ConfirmDeleteAccountModal({
const onClickConfirm = async () => { const onClickConfirm = async () => {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(
deleteUserAccount(), async () => {
{ await deleteUserAccount();
loading: 'Deleting your account...', onDelete?.();
success: `The account has been deleted successfully.`, close();
error: (arg: ApolloError) => { },
// we need to get the internal error message from the GraphQL error {
const { internal } = arg.graphQLErrors[0]?.extensions || {}; loadingMessage: 'Deleting your account...',
const { message } = (internal as Record<string, any>)?.error || {}; successMessage: 'The account has been deleted successfully.',
errorMessage:
// we use the default Apollo error message if we can't find the 'An error occurred while deleting your account. Please try again.',
// internal error message
return (
message ||
arg.message ||
'An error occurred while deleting your account. Please try again.'
);
},
}, },
getToastStyleProps(),
); );
onDelete?.();
close();
}; };
return ( return (

View File

@@ -0,0 +1,85 @@
import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { Input } from '@/components/ui/v2/Input';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useUpdateUserDisplayNameMutation } from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useUserData } from '@nhost/nextjs';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
const validationSchema = Yup.object({
displayName: Yup.string()
.label('Display Name')
.required('This field is required.'),
});
export type DisplayNameSettingFormValues = Yup.InferType<
typeof validationSchema
>;
export default function DisplayNameSetting() {
const { id: userID, displayName } = useUserData();
const [updateUserDisplayName] = useUpdateUserDisplayNameMutation();
const form = useForm<DisplayNameSettingFormValues>({
reValidateMode: 'onSubmit',
defaultValues: {
displayName,
},
resolver: yupResolver(validationSchema),
});
const { register, formState } = form;
const isDirty = Object.keys(formState.dirtyFields).length > 0;
async function handleSubmit(formValues: DisplayNameSettingFormValues) {
await execPromiseWithErrorToast(
async () => {
await updateUserDisplayName({
variables: {
id: userID,
displayName: formValues.displayName,
},
});
form.reset({ displayName: formValues.displayName });
},
{
loadingMessage: 'Updating your display name...',
successMessage: 'Your display name has been updated successfully.',
errorMessage:
'An error occurred while trying to update your display name. Please try again.',
},
);
}
return (
<FormProvider {...form}>
<Form onSubmit={handleSubmit}>
<SettingsContainer
title="Update your display name"
slotProps={{
submitButton: {
disabled: !isDirty,
loading: formState.isSubmitting,
},
}}
className="grid grid-flow-row lg:grid-cols-5"
>
<Input
{...register('displayName')}
className="col-span-2"
type="text"
id="display-name"
label="Display Name"
fullWidth
helperText={formState.errors.displayName?.message}
error={Boolean(formState.errors.displayName)}
/>
</SettingsContainer>
</Form>
</FormProvider>
);
}

View File

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

View File

@@ -15,15 +15,13 @@ import { ListItem } from '@/components/ui/v2/ListItem';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { CreatePATForm } from '@/features/account/settings/components/CreatePATForm'; import { CreatePATForm } from '@/features/account/settings/components/CreatePATForm';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { import {
GetPersonalAccessTokensDocument, GetPersonalAccessTokensDocument,
useDeletePersonalAccessTokenMutation, useDeletePersonalAccessTokenMutation,
useGetPersonalAccessTokensQuery, useGetPersonalAccessTokensQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { Fragment } from 'react'; import { Fragment } from 'react';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function PATSettings() { export default function PATSettings() {
@@ -59,28 +57,20 @@ export default function PATSettings() {
async function handleDeletePAT({ async function handleDeletePAT({
id, id,
}: typeof availablePersonalAccessTokens[0]) { }: (typeof availablePersonalAccessTokens)[0]) {
const deletePATPromise = deletePAT({ variables: { patId: id } }); await execPromiseWithErrorToast(
() => deletePAT({ variables: { patId: id } }),
try { {
await toast.promise( loadingMessage: 'Deleting personal access token...',
deletePATPromise, successMessage: 'Personal access token has been deleted successfully.',
{ errorMessage:
loading: 'Deleting personal access token...', 'An error occurred while deleting the personal access token.',
success: 'Personal access token has been deleted successfully.', },
error: getServerError( );
'An error occurred while deleting the personal access token.',
),
},
getToastStyleProps(),
);
} catch {
// Note: The toast will handle the error.
}
} }
function handleConfirmDelete( function handleConfirmDelete(
originalPAT: typeof availablePersonalAccessTokens[0], originalPAT: (typeof availablePersonalAccessTokens)[0],
) { ) {
openAlertDialog({ openAlertDialog({
title: 'Delete Personal Access Token', title: 'Delete Personal Access Token',

View File

@@ -1,12 +1,10 @@
import { Form } from '@/components/form/Form'; import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useChangePassword } from '@nhost/nextjs'; import { useChangePassword } from '@nhost/nextjs';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -38,25 +36,19 @@ export default function PasswordSettings() {
const isDirty = Object.keys(formState.dirtyFields).length > 0; const isDirty = Object.keys(formState.dirtyFields).length > 0;
async function handleSubmit(formValues: PasswordSettingsFormValues) { async function handleSubmit(formValues: PasswordSettingsFormValues) {
try { await execPromiseWithErrorToast(
const changePasswordPromise = changePassword(formValues.newPassword); async () => {
// TODO fix changePassword should throw an error if something happens
await toast.promise( await changePassword(formValues.newPassword);
changePasswordPromise, form.reset();
{ },
loading: 'Changing password...', {
success: 'The password has been changed successfully.', loadingMessage: 'Changing password...',
error: getServerError( successMessage: 'The password has been changed successfully.',
'An error occurred while trying to update the password. Please try again.', errorMessage:
), 'An error occurred while trying to update the password. Please try again.',
}, },
getToastStyleProps(), );
);
form.reset();
} catch {
// Note: The error is handled by the toast.
}
} }
return ( return (

View File

@@ -0,0 +1,6 @@
mutation updateUserDisplayName($id: uuid!, $displayName: String!) {
updateUser(pk_columns: { id: $id }, _set: { displayName: $displayName }) {
id
displayName
}
}

View File

@@ -10,26 +10,17 @@ import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { GraphqlDataSourcesFormSection } from '@/features/ai/AssistantForm/components/GraphqlDataSourcesFormSection'; import { GraphqlDataSourcesFormSection } from '@/features/ai/AssistantForm/components/GraphqlDataSourcesFormSection';
import { WebhooksDataSourcesFormSection } from '@/features/ai/AssistantForm/components/WebhooksDataSourcesFormSection'; import { WebhooksDataSourcesFormSection } from '@/features/ai/AssistantForm/components/WebhooksDataSourcesFormSection';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getHasuraAdminSecret } from '@/utils/env';
import { removeTypename, type DeepRequired } from '@/utils/helpers'; import { removeTypename, type DeepRequired } from '@/utils/helpers';
import { import {
useInsertAssistantMutation, useInsertAssistantMutation,
useUpdateAssistantMutation, useUpdateAssistantMutation,
} from '@/utils/__generated__/graphite.graphql'; } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export const validationSchema = Yup.object({ export const validationSchema = Yup.object({
@@ -101,32 +92,15 @@ export default function AssistantForm({
}: AssistantFormProps) { }: AssistantFormProps) {
const { onDirtyStateChange } = useDialog(); const { onDirtyStateChange } = useDialog();
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [insertAssistantMutation] = useInsertAssistantMutation({ const [insertAssistantMutation] = useInsertAssistantMutation({
client, client: adminClient,
}); });
const [updateAssistantMutation] = useUpdateAssistantMutation({ client }); const [updateAssistantMutation] = useUpdateAssistantMutation({
client: adminClient,
});
const form = useForm<AssistantFormValues>({ const form = useForm<AssistantFormValues>({
defaultValues: initialData, defaultValues: initialData,
@@ -186,33 +160,18 @@ export default function AssistantForm({
const handleSubmit = async ( const handleSubmit = async (
values: DeepRequired<AssistantFormValues> & { assistantID: string }, values: DeepRequired<AssistantFormValues> & { assistantID: string },
) => { ) => {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
createOrUpdateAutoEmbeddings(values), await createOrUpdateAutoEmbeddings(values);
{ onSubmit?.();
loading: 'Configuring the Assistant...', },
success: `The Assistant has been configured successfully.`, {
error: (arg: ApolloError) => { loadingMessage: 'Configuring the Assistant...',
// we need to get the internal error message from the GraphQL error successMessage: 'The Assistant has been configured successfully.',
const { internal } = arg.graphQLErrors[0]?.extensions || {}; errorMessage:
const { message } = (internal as Record<string, any>)?.error || {}; 'An error occurred while configuring the Assistant. Please try again.',
},
// we use the default Apollo error message if we can't find the );
// internal error message
return (
message ||
arg.message ||
'An error occurred while configuring the Assistant. Please try again.'
);
},
},
getToastStyleProps(),
);
onSubmit?.();
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -8,25 +8,16 @@ import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getHasuraAdminSecret } from '@/utils/env';
import { import {
useInsertGraphiteAutoEmbeddingsConfigurationMutation, useInsertGraphiteAutoEmbeddingsConfigurationMutation,
useUpdateGraphiteAutoEmbeddingsConfigurationMutation, useUpdateGraphiteAutoEmbeddingsConfigurationMutation,
} from '@/utils/__generated__/graphite.graphql'; } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export const validationSchema = Yup.object({ export const validationSchema = Yup.object({
@@ -70,34 +61,17 @@ export default function AutoEmbeddingsForm({
}: AutoEmbeddingsFormProps) { }: AutoEmbeddingsFormProps) {
const { onDirtyStateChange } = useDialog(); const { onDirtyStateChange } = useDialog();
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [insertGraphiteAutoEmbeddingsConfiguration] = const [insertGraphiteAutoEmbeddingsConfiguration] =
useInsertGraphiteAutoEmbeddingsConfigurationMutation({ useInsertGraphiteAutoEmbeddingsConfigurationMutation({
client, client: adminClient,
}); });
const [updateGraphiteAutoEmbeddingsConfiguration] = const [updateGraphiteAutoEmbeddingsConfiguration] =
useUpdateGraphiteAutoEmbeddingsConfigurationMutation({ client }); useUpdateGraphiteAutoEmbeddingsConfigurationMutation({
client: adminClient,
});
const form = useForm<AutoEmbeddingsFormValues>({ const form = useForm<AutoEmbeddingsFormValues>({
defaultValues: initialData, defaultValues: initialData,
@@ -137,33 +111,18 @@ export default function AutoEmbeddingsForm({
}; };
const handleSubmit = async (values: AutoEmbeddingsFormValues) => { const handleSubmit = async (values: AutoEmbeddingsFormValues) => {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
createOrUpdateAutoEmbeddings(values), await createOrUpdateAutoEmbeddings(values);
{ onSubmit?.();
loading: 'Configuring the Auto-Embeddings...', },
success: `The Auto-Embeddings has been configured successfully.`, {
error: (arg: ApolloError) => { loadingMessage: 'Configuring the Auto-Embeddings...',
// we need to get the internal error message from the GraphQL error successMessage: 'The Auto-Embeddings has been configured successfully.',
const { internal } = arg.graphQLErrors[0]?.extensions || {}; errorMessage:
const { message } = (internal as Record<string, any>)?.error || {}; 'An error occurred while configuring the Auto-Embeddings. Please try again.',
},
// we use the default Apollo error message if we can't find the );
// internal error message
return (
message ||
arg.message ||
'An error occurred while configuring the Auto-Embeddings. Please try again.'
);
},
},
getToastStyleProps(),
);
onSubmit?.();
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -2,20 +2,11 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox'; import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getToastStyleProps } from '@/utils/constants/settings';
import { getHasuraAdminSecret } from '@/utils/env';
import { useDeleteAssistantMutation } from '@/utils/__generated__/graphite.graphql'; import { useDeleteAssistantMutation } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants'; import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DeleteAssistantModalProps { export interface DeleteAssistantModalProps {
@@ -32,29 +23,10 @@ export default function DeleteAssistantModal({
const [remove, setRemove] = useState(false); const [remove, setRemove] = useState(false);
const [loadingRemove, setLoadingRemove] = useState(false); const [loadingRemove, setLoadingRemove] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [deleteAssistantMutation] = useDeleteAssistantMutation({ const [deleteAssistantMutation] = useDeleteAssistantMutation({
client, client: adminClient,
}); });
const deleteAssistant = async () => { const deleteAssistant = async () => {
@@ -70,27 +42,12 @@ export default function DeleteAssistantModal({
async function handleClick() { async function handleClick() {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(deleteAssistant, {
deleteAssistant(), loadingMessage: 'Deleting the assistant...',
{ successMessage: 'The Assistant has been deleted successfully.',
loading: 'Deleting the assistant...', errorMessage:
success: `The Assistant has been deleted successfully.`, 'An error occurred while deleting the Assistant. Please try again.',
error: (arg: ApolloError) => { });
// we need to get the internal error message from the GraphQL error
const { internal } = arg.graphQLErrors[0]?.extensions || {};
const { message } = (internal as Record<string, any>)?.error || {};
// we use the default Apollo error message if we can't find the
// internal error message
return (
message ||
arg.message ||
'An error occurred while deleting the Assistant. Please try again.'
);
},
},
getToastStyleProps(),
);
} }
return ( return (

View File

@@ -4,18 +4,12 @@ import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { getToastStyleProps } from '@/utils/constants/settings';
import { getHasuraAdminSecret } from '@/utils/env'; import { getHasuraAdminSecret } from '@/utils/env';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useDeleteGraphiteAutoEmbeddingsConfigurationMutation } from '@/utils/__generated__/graphite.graphql'; import { useDeleteGraphiteAutoEmbeddingsConfigurationMutation } from '@/utils/__generated__/graphite.graphql';
import { import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { type AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings'; import { type AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DeleteAutoEmbeddingsModalProps { export interface DeleteAutoEmbeddingsModalProps {
@@ -71,27 +65,13 @@ export default function DeleteAutoEmbeddingsModal({
async function handleClick() { async function handleClick() {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(deleteAutoEmbeddingsConfig, {
deleteAutoEmbeddingsConfig(), loadingMessage: 'Deleting Auto-Embeddings Configuration...',
{ successMessage:
loading: 'Deleting Auto-Embeddings Configuration...', 'The Auto-Embeddings Configuration has been deleted successfully.',
success: `The Auto-Embeddings Configuration has been deleted successfully.`, errorMessage:
error: (arg: ApolloError) => { 'An error occurred while deleting the Auto-Embeddings Configuration. Please try again.',
// we need to get the internal error message from the GraphQL error });
const { internal } = arg.graphQLErrors[0]?.extensions || {};
const { message } = (internal as Record<string, any>)?.error || {};
// we use the default Apollo error message if we can't find the
// internal error message
return (
message ||
arg.message ||
'An error occurred while deleting the Auto-Embeddings Configuration. Please try again.'
);
},
},
getToastStyleProps(),
);
} }
return ( return (

View File

@@ -2,6 +2,7 @@ import { UpgradeToProBanner } from '@/components/common/UpgradeToProBanner';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert'; import { Alert } from '@/components/ui/v2/Alert';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { ErrorToast } from '@/components/ui/v2/ErrorToast';
import { IconButton } from '@/components/ui/v2/IconButton'; import { IconButton } from '@/components/ui/v2/IconButton';
import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon'; import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
@@ -15,7 +16,8 @@ import {
} from '@/features/ai/DevAssistant/state'; } from '@/features/ai/DevAssistant/state';
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings'; import { useIsGraphiteEnabled } from '@/features/projects/common/hooks/useIsGraphiteEnabled';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { import {
useSendDevMessageMutation, useSendDevMessageMutation,
useStartDevSessionMutation, useStartDevSessionMutation,
@@ -33,6 +35,7 @@ export type Message = Omit<
>; >;
export default function DevAssistant() { export default function DevAssistant() {
const isPlatform = useIsPlatform();
const { currentProject, currentWorkspace } = useCurrentWorkspaceAndProject(); const { currentProject, currentWorkspace } = useCurrentWorkspaceAndProject();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -45,6 +48,8 @@ export default function DevAssistant() {
const [startDevSession] = useStartDevSessionMutation({ client: adminClient }); const [startDevSession] = useStartDevSessionMutation({ client: adminClient });
const [sendDevMessage] = useSendDevMessageMutation({ client: adminClient }); const [sendDevMessage] = useSendDevMessageMutation({ client: adminClient });
const { isGraphiteEnabled } = useIsGraphiteEnabled();
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
@@ -117,11 +122,17 @@ export default function DevAssistant() {
setMessages(thread); setMessages(thread);
} catch (error) { } catch (error) {
toast.error( toast.custom(
'Failed to send the message to graphite. Please try again later.', (t) => (
<ErrorToast
isVisible={t.visible}
errorMessage="Failed to send the message. Please try again later."
error={error}
close={() => toast.dismiss()}
/>
),
{ {
style: getToastStyleProps().style, duration: Number.POSITIVE_INFINITY,
...getToastStyleProps().error,
}, },
); );
} finally { } finally {
@@ -141,7 +152,7 @@ export default function DevAssistant() {
} }
}; };
if (currentProject.plan.isFree) { if (isPlatform && currentProject?.plan?.isFree) {
return ( return (
<Box className="p-4"> <Box className="p-4">
<UpgradeToProBanner <UpgradeToProBanner
@@ -157,7 +168,12 @@ export default function DevAssistant() {
); );
} }
if (!currentProject.plan.isFree && !currentProject.config?.ai) { if (
(isPlatform &&
!currentProject?.plan?.isFree &&
!currentProject.config?.ai) ||
!isGraphiteEnabled
) {
return ( return (
<Box className="p-4"> <Box className="p-4">
<Alert className="grid w-full grid-flow-col place-content-between items-center gap-2"> <Alert className="grid w-full grid-flow-col place-content-between items-center gap-2">

View File

@@ -24,7 +24,7 @@ function PreComponent(
const { children } = props; const { children } = props;
return ( return (
<div className="group relative"> <div className="relative group">
<pre>{children}</pre> <pre>{children}</pre>
<IconButton <IconButton
sx={{ sx={{
@@ -34,13 +34,13 @@ function PreComponent(
}} }}
color="warning" color="warning"
variant="contained" variant="contained"
className="absolute top-2 right-2 hidden group-hover:flex" className="absolute hidden top-2 right-2 group-hover:flex"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
copy(onlyText(children), 'Snippet'); copy(onlyText(children), 'Snippet');
}} }}
> >
<CopyIcon className="h-5 w-5" /> <CopyIcon className="w-5 h-5" />
</IconButton> </IconButton>
</div> </div>
); );
@@ -53,7 +53,7 @@ export default function MessageBox({ message }: { message: Message }) {
return ( return (
<Box <Box
className="flex flex-col space-y-4 border-t p-4 first:border-t-0" className="flex flex-col p-4 space-y-4 border-t first:border-t-0"
sx={{ sx={{
backgroundColor: isUserMessage && 'background.default', backgroundColor: isUserMessage && 'background.default',
}} }}
@@ -67,7 +67,7 @@ export default function MessageBox({ message }: { message: Message }) {
) : ( ) : (
<> <>
<Avatar <Avatar
className="h-7 w-7 rounded-full" className="rounded-full h-7 w-7"
alt={user?.displayName} alt={user?.displayName}
src={user?.avatarUrl} src={user?.avatarUrl}
> >

View File

@@ -1,7 +1,6 @@
import { import messagesState, {
messagesState,
type ProjectMessage, type ProjectMessage,
} from '@/features/ai/DevAssistant/state'; } from '@/features/ai/DevAssistant/state/messages';
import { selectorFamily } from 'recoil'; import { selectorFamily } from 'recoil';
const projectMessagesState = selectorFamily<ProjectMessage[], string>({ const projectMessagesState = selectorFamily<ProjectMessage[], string>({

View File

@@ -5,7 +5,6 @@ import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert'; import { Alert } from '@/components/ui/v2/Alert';
import { filterOptions } from '@/components/ui/v2/Autocomplete';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon'; import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
@@ -23,7 +22,7 @@ import {
} from '@/generated/graphql'; } from '@/generated/graphql';
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common'; import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { getToastStyleProps } from '@/utils/constants/settings';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
@@ -31,6 +30,8 @@ import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { DisableAIServiceConfirmationDialog } from './DisableAIServiceConfirmationDialog'; import { DisableAIServiceConfirmationDialog } from './DisableAIServiceConfirmationDialog';
const MIN_POSTGRES_VERSION_SUPPORTING_AI = '14.6-20231018-1';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
version: Yup.object({ version: Yup.object({
label: Yup.string().required(), label: Yup.string().required(),
@@ -57,7 +58,9 @@ export default function AISettings() {
const [aiServiceEnabled, setAIServiceEnabled] = useState(true); const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
const { const {
data: { config: { ai } = {} } = {}, data: {
config: { ai, postgres: { version: postgresVersion } = {} } = {},
} = {},
loading: loadingAiSettings, loading: loadingAiSettings,
error: errorGettingAiSettings, error: errorGettingAiSettings,
} = useGetAiSettingsQuery({ } = useGetAiSettingsQuery({
@@ -95,8 +98,8 @@ export default function AISettings() {
reValidateMode: 'onSubmit', reValidateMode: 'onSubmit',
defaultValues: { defaultValues: {
version: { version: {
label: '0.1.0-beta4', label: ai?.version ?? availableVersions?.at(0)?.label,
value: '0.1.0-beta4', value: ai?.version ?? availableVersions?.at(0)?.value,
}, },
webhookSecret: '', webhookSecret: '',
organization: '', organization: '',
@@ -110,12 +113,17 @@ export default function AISettings() {
resolver: yupResolver(validationSchema), resolver: yupResolver(validationSchema),
}); });
const { register, formState, reset, watch } = form; const { register, formState, reset, watch, setValue } = form;
const aiSettingsFormValues = watch();
useEffect(() => { useEffect(() => {
if (ai) { if (ai) {
reset({ reset({
version: { label: ai?.version, value: ai?.version }, version: {
label: ai?.version,
value: ai?.version,
},
webhookSecret: ai?.webhookSecret, webhookSecret: ai?.webhookSecret,
synchPeriodMinutes: ai?.autoEmbeddings?.synchPeriodMinutes, synchPeriodMinutes: ai?.autoEmbeddings?.synchPeriodMinutes,
apiKey: ai?.openai?.apiKey, apiKey: ai?.openai?.apiKey,
@@ -130,10 +138,38 @@ export default function AISettings() {
setAIServiceEnabled(!!ai); setAIServiceEnabled(!!ai);
}, [ai, reset]); }, [ai, reset]);
useEffect(() => {
if (
!loadingGraphiteVersionsData &&
availableVersions.length > 0 &&
!ai &&
!aiSettingsFormValues.version.value
) {
setValue('version', availableVersions?.at(0));
}
}, [
ai,
setValue,
availableVersions,
aiSettingsFormValues,
loadingGraphiteVersionsData,
]);
const toggleAIService = async (enabled: boolean) => { const toggleAIService = async (enabled: boolean) => {
if (postgresVersion < MIN_POSTGRES_VERSION_SUPPORTING_AI) {
toast.error(
'In order to enable the AI service you need to update your database version to 14.6-20231018-1 or newer.',
{
style: getToastStyleProps().style,
...getToastStyleProps().error,
},
);
return;
}
setAIServiceEnabled(enabled); setAIServiceEnabled(enabled);
if (!enabled) { if (!enabled && ai) {
openDialog({ openDialog({
title: 'Confirm Disabling the AI service', title: 'Confirm Disabling the AI service',
component: ( component: (
@@ -161,9 +197,9 @@ export default function AISettings() {
} }
async function handleSubmit(formValues: AISettingsFormValues) { async function handleSubmit(formValues: AISettingsFormValues) {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfig({ await updateConfig({
variables: { variables: {
appId: currentProject.id, appId: currentProject.id,
config: { config: {
@@ -186,25 +222,19 @@ export default function AISettings() {
}, },
}, },
}, },
}), });
{
loading: `AI settings are being updated...`,
success: `AI settings has been updated successfully.`,
error: getServerError(
`An error occurred while trying to update the AI settings!`,
),
},
getToastStyleProps(),
);
form.reset(formValues); form.reset(formValues);
} catch { },
// Note: The toast will handle the error. {
} loadingMessage: 'AI settings are being updated...',
successMessage: 'AI settings has been updated successfully.',
errorMessage:
'An error occurred while trying to update the AI settings!',
},
);
} }
const aiSettingsFormValues = watch();
const getAIResourcesCost = () => { const getAIResourcesCost = () => {
const vCPUs = `${ const vCPUs = `${
aiSettingsFormValues.compute.cpu / RESOURCE_VCPU_MULTIPLIER aiSettingsFormValues.compute.cpu / RESOURCE_VCPU_MULTIPLIER
@@ -240,37 +270,54 @@ export default function AISettings() {
className="flex flex-col" className="flex flex-col"
> >
<Box className="space-y-4"> <Box className="space-y-4">
<Box className="space-y-2"> {availableVersions.length > 0 && (
<Box className="flex flex-row items-center space-x-2"> <Box className="space-y-2">
<Text className="text-lg font-semibold">Version</Text> <Box className="flex flex-row items-center space-x-2">
<Tooltip title="Version of the service to use."> <Text className="text-lg font-semibold">Version</Text>
<InfoIcon <Tooltip title="Version of the service to use.">
aria-label="Info" <InfoIcon
className="h-4 w-4" aria-label="Info"
color="primary" className="h-4 w-4"
/> color="primary"
</Tooltip> />
</Box> </Tooltip>
<ControlledAutocomplete </Box>
id="version" <ControlledAutocomplete
name="version" id="version"
filterOptions={(options, state) => { name="version"
if (state.inputValue === ai?.version) { autoHighlight
return options; isOptionEqualToValue={() => false}
filterOptions={(options, { inputValue }) => {
const inputValueLower = inputValue.toLowerCase();
const matched = [];
const otherOptions = [];
options.forEach((option) => {
const optionLabelLower = option.label.toLowerCase();
if (optionLabelLower.startsWith(inputValueLower)) {
matched.push(option);
} else {
otherOptions.push(option);
}
});
const result = [...matched, ...otherOptions];
return result;
}}
fullWidth
className="col-span-4"
options={availableVersions}
error={!!formState.errors?.version?.message}
helperText={formState.errors?.version?.message}
showCustomOption="auto"
customOptionLabel={(value) =>
`Use custom value: "${value}"`
} }
return filterOptions(options, state); />
}} </Box>
fullWidth )}
className="col-span-4"
options={availableVersions}
error={!!formState.errors?.version?.message}
helperText={formState.errors?.version?.message}
showCustomOption="auto"
customOptionLabel={(value) =>
`Use custom value: "${value}"`
}
/>
</Box>
<Box className="space-y-2"> <Box className="space-y-2">
<Box className="flex flex-row items-center space-x-2"> <Box className="flex flex-row items-center space-x-2">

View File

@@ -3,11 +3,9 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useUpdateConfigMutation } from '@/utils/__generated__/graphql'; import { useUpdateConfigMutation } from '@/utils/__generated__/graphql';
import type { ApolloError } from '@apollo/client';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DisableAIServiceConfirmationDialogProps { export interface DisableAIServiceConfirmationDialogProps {
@@ -34,37 +32,26 @@ export default function DisableAIServiceConfirmationDialog({
async function handleClick() { async function handleClick() {
setLoading(true); setLoading(true);
await toast.promise( await execPromiseWithErrorToast(
updateConfig({ async () => {
variables: { await updateConfig({
appId: currentProject.id, variables: {
config: { appId: currentProject.id,
ai: null, config: {
ai: null,
},
}, },
}, });
}),
{
loading: 'Disabling the AI service...',
success: () => {
onServiceDisabled();
closeDialog();
return `The service has been disabled.`;
},
error: (arg: ApolloError) => {
// we need to get the internal error message from the GraphQL error
const { internal } = arg.graphQLErrors[0]?.extensions || {};
const { message } = (internal as Record<string, any>)?.error || {};
// we use the default Apollo error message if we can't find the onServiceDisabled();
// internal error message closeDialog();
return ( },
message || {
arg.message || loadingMessage: 'Disabling the AI service...',
'An error occurred while disabling the AI service. Please try again later.' successMessage: 'The service has been disabled.',
); errorMessage:
}, 'An error occurred while disabling the AI service. Please try again later.',
}, },
getToastStyleProps(),
); );
} }

View File

@@ -1,5 +1,8 @@
query GetAISettings($appId: uuid!) { query GetAISettings($appId: uuid!) {
config(appID: $appId, resolve: false) { config(appID: $appId, resolve: false) {
postgres {
version
}
ai { ai {
version version
webhookSecret webhookSecret

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -103,21 +101,19 @@ export default function AllowedEmailDomainsSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Allowed email settings are being updated...`, },
success: `Allowed email settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Allowed email settings are being updated...',
`An error occurred while trying to update the project's allowed email settings.`, successMessage:
), 'Allowed email settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), "An error occurred while trying to update the project's allowed email settings.",
); },
} catch { );
// Note: The toast will handle the error
}
form.reset(values); form.reset(values);
}; };
@@ -134,7 +130,7 @@ export default function AllowedEmailDomainsSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#allowed-emails-and-domains" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-emails-and-domains"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -80,23 +78,19 @@ export default function AllowedRedirectURLsSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Allowed redirect URL settings are being updated...`, },
success: `Allowed redirect URL settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Allowed redirect URL settings are being updated...',
`An error occurred while trying to update the project's allowed redirect URL settings.`, successMessage:
), 'Allowed redirect URL settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), "An error occurred while trying to update the project's allowed redirect URL settings.",
); },
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -111,7 +105,7 @@ export default function AllowedRedirectURLsSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#allowed-redirect-urls" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-redirect-urls"
className="grid grid-flow-row px-4 lg:grid-cols-5" className="grid grid-flow-row px-4 lg:grid-cols-5"
> >
<Input <Input

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -73,23 +71,19 @@ export default function AnonymousSignInSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Anonymous sign-in settings are being updated...`, },
success: `Anonymous sign-in settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Anonymous sign-in settings are being updated...',
`An error occurred while trying to update Anonymous sign-in settings.`, successMessage:
), 'Anonymous sign-in settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), 'An error occurred while trying to update Anonymous sign-in settings.',
); },
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -13,13 +13,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -117,23 +115,18 @@ export default function AppleProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Apple settings are being updated...`, },
success: `Apple settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Apple settings are being updated...',
`An error occurred while trying to update the project's Apple settings.`, successMessage: 'Apple settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Apple settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -148,7 +141,7 @@ export default function AppleProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-apple" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-apple"
docsTitle="how to sign in users with Apple" docsTitle="how to sign in users with Apple"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -158,7 +151,7 @@ export default function AppleProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -3,7 +3,6 @@ import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete
import { Form } from '@/components/form/Form'; import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { filterOptions } from '@/components/ui/v2/Autocomplete';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { import {
GetAuthenticationSettingsDocument, GetAuthenticationSettingsDocument,
@@ -12,11 +11,9 @@ import {
useGetSoftwareVersionsQuery, useGetSoftwareVersionsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -96,23 +93,17 @@ export default function AuthServiceVersionSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Auth version is being updated...`, },
success: `Auth version has been updated successfully.`, {
error: getServerError( loadingMessage: 'Auth version is being updated...',
`An error occurred while trying to update Auth version.`, successMessage: 'Auth version has been updated successfully.',
), errorMessage: 'An error occurred while trying to update Auth version.',
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -129,17 +120,31 @@ export default function AuthServiceVersionSettings() {
}} }}
docsLink="https://github.com/nhost/hasura-auth/releases" docsLink="https://github.com/nhost/hasura-auth/releases"
docsTitle="the latest releases" docsTitle="the latest releases"
className="grid grid-flow-row gap-y-2 gap-x-4 px-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
> >
<ControlledAutocomplete <ControlledAutocomplete
id="version" id="version"
name="version" name="version"
filterOptions={(options, state) => { autoHighlight
if (state.inputValue === version) { isOptionEqualToValue={() => false}
return options; filterOptions={(options, { inputValue }) => {
} const inputValueLower = inputValue.toLowerCase();
const matched = [];
const otherOptions = [];
return filterOptions(options, state); options.forEach((option) => {
const optionLabelLower = option.label.toLowerCase();
if (optionLabelLower.startsWith(inputValueLower)) {
matched.push(option);
} else {
otherOptions.push(option);
}
});
const result = [...matched, ...otherOptions];
return result;
}} }}
fullWidth fullWidth
className="lg:col-span-2" className="lg:col-span-2"

View File

@@ -14,12 +14,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -106,23 +104,18 @@ export default function AzureADProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Azure AD settings are being updated...`, },
success: `Azure AD settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Azure AD settings are being updated...',
`An error occurred while trying to update the project's Azure AD settings.`, successMessage: 'Azure AD settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Azure AD settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -141,7 +134,7 @@ export default function AzureADProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid grid-flow-row grid-cols-2 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-row grid-cols-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function BitbucketProviderSettings() { export default function BitbucketProviderSettings() {
@@ -84,23 +82,18 @@ export default function BitbucketProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Bitbucket settings are being updated...`, },
success: `Bitbucket settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Bitbucket settings are being updated...',
`An error occurred while trying to update the project's Bitbucket settings.`, successMessage: 'Bitbucket settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Bitbucket settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -119,7 +112,7 @@ export default function BitbucketProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -110,23 +108,20 @@ export default function BlockedEmailSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Blocked email and domain settings are being updated...`, },
success: `Blocked email and domain settings have been updated successfully.`, {
error: getServerError( loadingMessage:
`An error occurred while trying to update the project's blocked email and domain settings.`, 'Blocked email and domain settings are being updated...',
), successMessage:
}, 'Blocked email and domain settings have been updated successfully.',
getToastStyleProps(), errorMessage:
); "An error occurred while trying to update the project's blocked email and domain settings.",
},
form.reset(values); );
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -141,7 +136,7 @@ export default function BlockedEmailSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#blocked-emails-and-domains" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-emails-and-domains"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -75,23 +73,18 @@ export default function ClientURLSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Client URL is being updated...`, },
success: `Client URL has been updated successfully.`, {
error: getServerError( loadingMessage: 'Client URL is being updated...',
`An error occurred while trying to update the project's Client URL.`, successMessage: 'Client URL has been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Client URL.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -106,7 +99,7 @@ export default function ClientURLSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#client-url" docsLink="https://docs.nhost.io/guides/auth/overview#client-url"
className="grid grid-flow-row lg:grid-cols-5" className="grid grid-flow-row lg:grid-cols-5"
> >
<Input <Input

View File

@@ -3,15 +3,13 @@ import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { import {
GetAuthenticationSettingsDocument, GetAuthenticationSettingsDocument,
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -71,23 +69,18 @@ export default function DisableNewUsersSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Disabling new user sign ups...`, },
success: `New user sign ups have been disabled successfully.`, {
error: getServerError( loadingMessage: 'Disabling new user sign ups...',
`An error occurred while trying to disable new user sign ups.`, successMessage: 'New user sign ups have been disabled successfully.',
), errorMessage:
}, 'An error occurred while trying to disable new user sign ups.',
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -96,7 +89,7 @@ export default function DisableNewUsersSettings() {
<SettingsContainer <SettingsContainer
title="Disable New Users" title="Disable New Users"
description="If set, newly registered users are disabled and won't be able to sign in." description="If set, newly registered users are disabled and won't be able to sign in."
docsLink="https://docs.nhost.io/authentication#disable-new-users" docsLink="https://docs.nhost.io/guides/auth/overview#disable-new-users"
switchId="disabled" switchId="disabled"
showSwitch showSwitch
slotProps={{ slotProps={{

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function DiscordProviderSettings() { export default function DiscordProviderSettings() {
@@ -87,23 +85,18 @@ export default function DiscordProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Discord settings are being updated...`, },
success: `Discord settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Discord settings are being updated...',
`An error occurred while trying to update the project's Discrod settings.`, successMessage: 'Discord settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Discrod settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function DiscordProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-discord" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-discord"
docsTitle="how to sign in users with Discord" docsTitle="how to sign in users with Discord"
icon="/assets/brands/discord.svg" icon="/assets/brands/discord.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -11,11 +11,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -85,23 +83,19 @@ export default function EmailAndPasswordSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Email and password sign-in settings are being updated...`, },
success: `Email and password sign-in settings have been updated successfully.`, {
error: getServerError( loadingMessage: `Email and password sign-in settings are being updated...`,
`An error occurred while trying to update email sign-in settings.`, successMessage:
), 'Email and password sign-in settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), 'An error occurred while trying to update email sign-in settings.',
); },
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -110,7 +104,7 @@ export default function EmailAndPasswordSettings() {
<SettingsContainer <SettingsContainer
title="Email and Password" title="Email and Password"
description="Allow users to sign in with email and password." description="Allow users to sign in with email and password."
docsLink="https://docs.nhost.io/authentication/sign-in-with-email-and-password" docsLink="https://docs.nhost.io/guides/auth/sign-in-email-password"
docsTitle="how to sign in users with email and password" docsTitle="how to sign in users with email and password"
className="grid grid-flow-row" className="grid grid-flow-row"
showSwitch showSwitch

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function FacebookProviderSettings() { export default function FacebookProviderSettings() {
@@ -87,23 +85,18 @@ export default function FacebookProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Facebook settings are being updated...`, },
success: `Facebook settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Facebook settings are being updated...',
`An error occurred while trying to update the project's Facebook settings.`, successMessage: 'Facebook settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Facebook settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function FacebookProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-facebook" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-facebook"
docsTitle="how to sign in users with Facebook" docsTitle="how to sign in users with Facebook"
icon="/assets/brands/facebook.svg" icon="/assets/brands/facebook.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,13 +18,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GitHubProviderSettings() { export default function GitHubProviderSettings() {
@@ -89,23 +87,18 @@ export default function GitHubProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `GitHub settings are being updated...`, },
success: `GitHub settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'GitHub settings are being updated...',
`An error occurred while trying to update the project's GitHub settings.`, successMessage: 'GitHub settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's GitHub settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -120,7 +113,7 @@ export default function GitHubProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-github" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-github"
docsTitle="how to sign in users with GitHub" docsTitle="how to sign in users with GitHub"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -130,7 +123,7 @@ export default function GitHubProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GitLabProviderSettings() { export default function GitLabProviderSettings() {
@@ -87,23 +85,18 @@ export default function GitLabProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `GitLab settings are being updated...`, },
success: `GitLab settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'GitLab settings are being updated...',
`An error occurred while trying to update the project's GitLab settings.`, successMessage: 'GitLab settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's GitLab settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -122,7 +115,7 @@ export default function GitLabProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GoogleProviderSettings() { export default function GoogleProviderSettings() {
@@ -87,23 +85,18 @@ export default function GoogleProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Google settings are being updated...`, },
success: `Google settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Google settings are being updated...',
`An error occurred while trying to update the project's Google settings.`, successMessage: 'Google settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Google settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function GoogleProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-google" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-google"
docsTitle="how to sign in users with Google" docsTitle="how to sign in users with Google"
icon="/assets/brands/google.svg" icon="/assets/brands/google.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -13,12 +13,10 @@ import {
import { import {
AUTH_GRAVATAR_DEFAULT, AUTH_GRAVATAR_DEFAULT,
AUTH_GRAVATAR_RATING, AUTH_GRAVATAR_RATING,
getToastStyleProps,
} from '@/utils/constants/settings'; } from '@/utils/constants/settings';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -89,23 +87,18 @@ export default function GravatarSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Gravatar settings are being updated...`, },
success: `Gravatar settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Gravatar settings are being updated...',
`An error occurred while trying to update the project's Gravatar settings.`, successMessage: 'Gravatar settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Gravatar settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -120,7 +113,7 @@ export default function GravatarSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#gravatar" docsLink="https://docs.nhost.io/guides/auth/overview#gravatar"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function LinkedInProviderSettings() { export default function LinkedInProviderSettings() {
@@ -87,23 +85,18 @@ export default function LinkedInProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `LinkedIn settings are being updated...`, },
success: `LinkedIn settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'LinkedIn settings are being updated...',
`An error occurred while trying to update the project's LinkedIn settings.`, successMessage: 'LinkedIn settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's LinkedIn settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function LinkedInProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-linkedin" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-linkedin"
docsTitle="how to sign in users with LinkedIn" docsTitle="how to sign in users with LinkedIn"
icon="/assets/brands/linkedin.svg" icon="/assets/brands/linkedin.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -76,23 +74,20 @@ export default function MFASettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Multi-factor authentication settings are being updated...`, },
success: `Multi-factor authentication settings have been updated successfully.`, {
error: getServerError( loadingMessage:
`An error occurred while trying to update the project's multi-factor authentication settings.`, 'Multi-factor authentication settings are being updated...',
), successMessage:
}, 'Multi-factor authentication settings have been updated successfully.',
getToastStyleProps(), errorMessage:
); "An error occurred while trying to update the project's multi-factor authentication settings.",
},
form.reset(values); );
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -107,7 +102,7 @@ export default function MFASettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#multi-factor-authentication" docsLink="https://docs.nhost.io/guides/auth/overview#multi-factor-authentication"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -73,23 +71,18 @@ export default function MagicLinkSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Magic Link settings are being updated...`, },
success: `Magic Link settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Magic Link settings are being updated...',
`An error occurred while trying to update the project's Magic Link settings.`, successMessage: 'Magic Link settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Magic Link settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -104,7 +97,7 @@ export default function MagicLinkSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-magic-link" docsLink="https://docs.nhost.io/guides/auth/sign-in-magic-link"
docsTitle="how to sign in users with Magic Link" docsTitle="how to sign in users with Magic Link"
switchId="enabled" switchId="enabled"
showSwitch showSwitch

View File

@@ -12,12 +12,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import Image from 'next/image'; import Image from 'next/image';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -112,23 +110,17 @@ export default function SMSSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `SMS settings are being updated...`, },
success: `SMS settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'SMS settings are being updated...',
`An error occurred while trying to update SMS settings.`, successMessage: 'SMS settings have been updated successfully.',
), errorMessage: 'An error occurred while trying to update SMS settings.',
}, },
getToastStyleProps(), );
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -145,10 +137,10 @@ export default function SMSSettings() {
}} }}
switchId="enabled" switchId="enabled"
showSwitch showSwitch
docsLink="https://docs.nhost.io/authentication/sign-in-with-phone-number-sms" docsLink="https://docs.nhost.io/guides/auth/sign-in-phone-number"
docsTitle="how to sign in users with a phone number (SMS)" docsTitle="how to sign in users with a phone number (SMS)"
className={twMerge( className={twMerge(
'grid grid-flow-col grid-cols-2 grid-rows-4 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-col grid-cols-2 grid-rows-4 gap-x-3 gap-y-4 px-4 py-2',
!authSmsPasswordlessEnabled && 'hidden', !authSmsPasswordlessEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -84,23 +82,18 @@ export default function SessionSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Session settings are being updated...`, },
success: `Session settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Session settings are being updated...',
`An error occurred while trying to update the project's session settings.`, successMessage: 'Session settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's session settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function SpotifyProviderSettings() { export default function SpotifyProviderSettings() {
@@ -87,23 +85,18 @@ export default function SpotifyProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Spotify settings are being updated...`, },
success: `Spotify settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Spotify settings are being updated...',
`An error occurred while trying to update the project's Spotify settings.`, successMessage: 'Spotify settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Spotify settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function SpotifyProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-spotify" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-spotify"
docsTitle="how to sign in users with Spotify" docsTitle="how to sign in users with Spotify"
icon="/assets/brands/spotify.svg" icon="/assets/brands/spotify.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function StravaProviderSettings() { export default function StravaProviderSettings() {
@@ -87,23 +85,18 @@ export default function StravaProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Strava settings are being updated...`, },
success: `Strava settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Strava settings are being updated...',
`An error occurred while trying to update the project's Strava settings.`, successMessage: 'Strava settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Strava settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -122,7 +115,7 @@ export default function StravaProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,13 +18,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function TwitchProviderSettings() { export default function TwitchProviderSettings() {
@@ -89,23 +87,18 @@ export default function TwitchProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Twitch settings are being updated...`, },
success: `Twitch settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Twitch settings are being updated...',
`An error occurred while trying to update the project's Twitch settings.`, successMessage: 'Twitch settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Twitch settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -120,7 +113,7 @@ export default function TwitchProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-twitch" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-twitch"
docsTitle="how to sign in users with Twitch" docsTitle="how to sign in users with Twitch"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -130,7 +123,7 @@ export default function TwitchProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -13,12 +13,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -98,23 +96,17 @@ export default function TwitterProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Twitter settings are being updated...`, },
success: `Twitter settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Twitter settings are being updated...',
`An error occurred while trying to update the project's Twitter settings.`, successMessage: 'Twitter settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's Twitter settings.`,
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -134,7 +126,7 @@ export default function TwitterProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -66,33 +64,29 @@ export default function WebAuthnSettings() {
config: { config: {
auth: { auth: {
method: { method: {
webauthn: {...values, webauthn: {
relyingParty: { ...values,
name: currentProject.name, relyingParty: {
}}, name: currentProject.name,
},
},
}, },
}, },
}, },
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `WebAuthn settings are being updated...`, },
success: `WebAuthn settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'WebAuthn settings are being updated...',
`An error occurred while trying to update the project's WebAuthn settings.`, successMessage: 'WebAuthn settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's WebAuthn settings.`,
}, },
getToastStyleProps(), );
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -107,7 +101,7 @@ export default function WebAuthnSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-security-keys" docsLink="https://docs.nhost.io/guides/auth/sign-in-webauthn"
docsTitle="how to sign in users with security keys" docsTitle="how to sign in users with security keys"
switchId="enabled" switchId="enabled"
showSwitch showSwitch

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function WindowsLiveProviderSettings() { export default function WindowsLiveProviderSettings() {
@@ -87,23 +85,17 @@ export default function WindowsLiveProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Windows Live settings are being updated...`, },
success: `Windows Live settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Windows Live settings are being updated...',
`An error occurred while trying to update the project's Windows Live settings.`, successMessage: 'Windows Live settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's Windows Live settings.`,
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -123,7 +115,7 @@ export default function WindowsLiveProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -14,12 +14,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -113,23 +111,18 @@ export default function WorkOsProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `WorkOS settings are being updated...`, },
success: `WorkOS settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'WorkOS settings are being updated...',
`An error occurred while trying to update the project's WorkOS settings.`, successMessage: 'WorkOS settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's WorkOS settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -144,13 +137,13 @@ export default function WorkOsProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-workos" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-workos"
docsTitle="how to sign in users with WorkOS" docsTitle="how to sign in users with WorkOS"
icon="/assets/brands/workos.svg" icon="/assets/brands/workos.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid grid-flow-row grid-cols-2 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-row grid-cols-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -6,12 +6,10 @@ import { Input } from '@/components/ui/v2/Input';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export interface CreateUserFormProps extends DialogFormProps { export interface CreateUserFormProps extends DialogFormProps {
@@ -77,9 +75,9 @@ export default function CreateUserForm({
async function handleCreateUser({ email, password }: CreateUserFormValues) { async function handleCreateUser({ email, password }: CreateUserFormValues) {
setCreateUserFormError(null); setCreateUserFormError(null);
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
fetch(signUpUrl, { await fetch(signUpUrl, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }), body: JSON.stringify({ email, password }),
@@ -95,21 +93,16 @@ export default function CreateUserForm({
} }
throw new Error(data?.message || 'Something went wrong.'); throw new Error(data?.message || 'Something went wrong.');
}), });
{
loading: 'Creating user...',
success: 'User has been created successfully.',
error: getServerError(
'An error occurred while trying to create the user.',
),
},
getToastStyleProps(),
);
onSubmit?.(); onSubmit?.();
} catch (error) { },
// Note: The error is already handled by the toast promise. {
} loadingMessage: 'Creating user...',
successMessage: 'User has been created successfully.',
errorMessage: 'An error occurred while trying to create the user.',
},
);
} }
return ( return (

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