Compare commits

..

17 Commits

Author SHA1 Message Date
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
106 changed files with 4572 additions and 3919 deletions

View File

@@ -22,7 +22,7 @@ jobs:
- name: Configure aws - name: Configure aws
uses: aws-actions/configure-aws-credentials@v4 uses: aws-actions/configure-aws-credentials@v4
with: with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_PRODUCTION_CORE_ACCOUNT_ID }}:role/github-actions-nhost-be 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 aws-region: eu-central-1
- uses: nixbuild/nix-quick-install-action@v26 - uses: nixbuild/nix-quick-install-action@v26

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

@@ -1,5 +1,39 @@
# @nhost/dashboard # @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
## 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 ## 1.8.1
### Patch Changes ### Patch Changes

View File

@@ -16,8 +16,6 @@ const cspHeader = `
form-action 'self'; form-action 'self';
frame-ancestors 'none'; frame-ancestors 'none';
frame-src 'self' js.stripe.com; frame-src 'self' js.stripe.com;
block-all-mixed-content;
upgrade-insecure-requests;
`; `;
module.exports = withBundleAnalyzer({ module.exports = withBundleAnalyzer({
@@ -42,10 +40,6 @@ module.exports = withBundleAnalyzer({
key: 'X-Frame-Options', key: 'X-Frame-Options',
value: 'SAMEORIGIN', value: 'SAMEORIGIN',
}, },
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\n/g, ''),
},
], ],
}, },
]; ];

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "1.8.1", "version": "1.10.0",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -19,58 +19,58 @@
"e2e": "pnpm install-browsers && pnpm playwright test" "e2e": "pnpm install-browsers && pnpm playwright test"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@codemirror/lang-sql": "^6.5.5", "@codemirror/lang-sql": "^6.6.0",
"@emotion/cache": "^11.11.0", "@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.3", "@emotion/react": "^11.11.4",
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.16", "@fontsource/inter": "^5.0.16",
"@fontsource/roboto-mono": "^5.0.16", "@fontsource/roboto-mono": "^5.0.16",
"@graphiql/react": "^0.20.2", "@graphiql/react": "^0.20.3",
"@graphiql/toolkit": "^0.9.1", "@graphiql/toolkit": "^0.9.1",
"@headlessui/react": "^1.7.18", "@headlessui/react": "^1.7.18",
"@heroicons/react": "^1.0.6", "@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.3.4", "@hookform/resolvers": "^3.3.4",
"@mui/base": "5.0.0-beta.31", "@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.15.7", "@mui/material": "^5.15.11",
"@mui/system": "^5.15.7", "@mui/system": "^5.15.11",
"@mui/x-date-pickers": "^5.0.20", "@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*", "@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*", "@nhost/react-apollo": "workspace:*",
"@segment/snippet": "^4.16.2", "@segment/snippet": "^4.16.2",
"@stripe/react-stripe-js": "^2.4.0", "@stripe/react-stripe-js": "^2.5.1",
"@stripe/stripe-js": "^1.54.2", "@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@tanstack/react-query": "^4.36.1", "@tanstack/react-query": "^4.36.1",
"@tanstack/react-table": "^8.11.7", "@tanstack/react-table": "^8.13.2",
"@tanstack/react-virtual": "^3.0.2", "@tanstack/react-virtual": "^3.1.3",
"@uiw/codemirror-theme-github": "^4.21.21", "@uiw/codemirror-theme-github": "^4.21.24",
"@uiw/react-codemirror": "^4.21.21", "@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.30.0", "date-fns": "^2.30.0",
"framer-motion": "^10.18.0", "framer-motion": "^10.18.0",
"generate-password": "^1.7.1", "generate-password": "^1.7.1",
"graphiql": "^3.1.0", "graphiql": "^3.1.1",
"graphql": "16.8.1", "graphql": "16.8.1",
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-ws": "^5.14.3", "graphql-ws": "^5.15.0",
"just-kebab-case": "^4.2.0", "just-kebab-case": "^4.2.0",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"next": "^14.1.0", "next": "^14.1.0",
"next-seo": "^6.4.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.10.0", "react-children-utilities": "^2.10.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-error-boundary": "^4.0.12", "react-error-boundary": "^4.0.13",
"react-hook-form": "^7.50.0", "react-hook-form": "^7.50.1",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
"react-intersection-observer": "^9.5.4", "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",
@@ -91,7 +91,7 @@
"yup-password": "^0.2.2" "yup-password": "^0.2.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.9", "@babel/core": "^7.24.0",
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^3.3.1", "@graphql-codegen/cli": "^3.3.1",
"@graphql-codegen/typescript": "^3.0.4", "@graphql-codegen/typescript": "^3.0.4",
@@ -106,36 +106,36 @@
"@storybook/addon-postcss": "^2.0.0", "@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-webpack5": "^6.5.16", "@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16", "@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^7.6.15", "@storybook/react": "^7.6.17",
"@storybook/testing-library": "^0.2.2", "@storybook/testing-library": "^0.2.2",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@testing-library/dom": "^9.3.4", "@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.2.0", "@testing-library/react": "^14.2.1",
"@testing-library/user-event": "^14.5.2", "@testing-library/user-event": "^14.5.2",
"@types/ace": "^0.0.48", "@types/ace": "^0.0.48",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/jest": "^29.5.11", "@types/jest": "^29.5.12",
"@types/lodash.debounce": "^4.0.9", "@types/lodash.debounce": "^4.0.9",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@types/pluralize": "^0.0.30", "@types/pluralize": "^0.0.30",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@types/react-table": "^7.7.19", "@types/react-table": "^7.7.19",
"@types/shell-quote": "^1.7.5", "@types/shell-quote": "^1.7.5",
"@types/testing-library__jest-dom": "^5.14.9", "@types/testing-library__jest-dom": "^5.14.9",
"@types/validator": "^13.11.8", "@types/validator": "^13.11.9",
"@typescript-eslint/eslint-plugin": "^6.20.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.20.0", "@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^0.32.4", "@vitest/coverage-v8": "^0.32.4",
"autoprefixer": "^10.4.17", "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.1.3", "csstype": "^3.1.3",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-next": "^13.5.6", "eslint-config-next": "^13.5.6",
@@ -145,11 +145,11 @@
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^22.1.0", "jsdom": "^22.1.0",
"lint-staged": "^15.2.1", "lint-staged": "^15.2.2",
"msw": "^1.3.2", "msw": "^1.3.2",
"msw-storybook-addon": "^1.10.0", "msw-storybook-addon": "^1.10.0",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.4", "prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.4.1", "prettier-plugin-tailwindcss": "^0.4.1",
@@ -160,7 +160,7 @@
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.1.0", "tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^5.0.12", "vite": "^5.1.4",
"vite-tsconfig-paths": "^4.3.1", "vite-tsconfig-paths": "^4.3.1",
"vitest": "^0.32.4" "vitest": "^0.32.4"
}, },

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, JSXElementConstructor, KeyboardEvent, MouseEvent, ReactElement, ReactNode, ReactPortal } 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: ReactNode | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>>) => { {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

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

@@ -5,7 +5,7 @@ import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastBackgroundColor } from '@/utils/constants/settings'; import { getToastBackgroundColor } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { ApolloError } from '@apollo/client'; import type { ApolloError } from '@apollo/client';
import { useUserData } from '@nhost/nextjs'; import { useUserData } from '@nhost/nextjs';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
@@ -27,10 +27,11 @@ const getInternalErrorMessage = (
return null; return null;
} }
if (error instanceof ApolloError) { if (error.name === 'ApolloError') {
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as // @ts-ignore
| { error: { message: string } } const internalError = error.graphQLErrors?.[0]?.extensions?.internal as {
| undefined; error: { message: string };
};
return internalError?.error?.message || null; return internalError?.error?.message || null;
} }
@@ -42,7 +43,7 @@ const getInternalErrorMessage = (
}; };
const errorToObject = (error: ApolloError | Error) => { const errorToObject = (error: ApolloError | Error) => {
if (error instanceof ApolloError) { if (error.name === 'ApolloError') {
return error; return error;
} }

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

@@ -21,13 +21,17 @@ import {
useUpdateConfigMutation, useUpdateConfigMutation,
} 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 { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast'; 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';
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(),
@@ -54,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({
@@ -150,6 +156,17 @@ export default function AISettings() {
]); ]);
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 && ai) { if (!enabled && ai) {

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

@@ -275,7 +275,7 @@ export default function DataBrowserGrid({
() => () =>
columns columns
.map((column) => ({ .map((column) => ({
...createDataGridColumn(column, isSchemaEditable), ...createDataGridColumn(column, true),
onCellEdit: async (variables: UpdateRecordVariables) => { onCellEdit: async (variables: UpdateRecordVariables) => {
const result = await updateRow(variables); const result = await updateRow(variables);
await queryClient.invalidateQueries([currentTablePath]); await queryClient.invalidateQueries([currentTablePath]);
@@ -288,7 +288,6 @@ export default function DataBrowserGrid({
[ [
columns, columns,
currentTablePath, currentTablePath,
isSchemaEditable,
optimisticlyRemovedColumnId, optimisticlyRemovedColumnId,
queryClient, queryClient,
removableColumnId, removableColumnId,
@@ -422,7 +421,7 @@ export default function DataBrowserGrid({
loading={status === 'loading'} loading={status === 'loading'}
sortBy={sortBy} sortBy={sortBy}
className="pb-17 sm:pb-0" className="pb-17 sm:pb-0"
onInsertRow={isSchemaEditable ? handleInsertRowClick : undefined} onInsertRow={handleInsertRowClick}
onInsertColumn={isSchemaEditable ? handleInsertColumnClick : undefined} onInsertColumn={isSchemaEditable ? handleInsertColumnClick : undefined}
onEditColumn={isSchemaEditable ? handleEditColumnClick : undefined} onEditColumn={isSchemaEditable ? handleEditColumnClick : undefined}
onRemoveColumn={isSchemaEditable ? handleColumnRemoveClick : undefined} onRemoveColumn={isSchemaEditable ? handleColumnRemoveClick : undefined}
@@ -445,7 +444,7 @@ export default function DataBrowserGrid({
onInsertColumnClick={ onInsertColumnClick={
isSchemaEditable ? handleInsertColumnClick : undefined isSchemaEditable ? handleInsertColumnClick : undefined
} }
onInsertRowClick={isSchemaEditable ? handleInsertRowClick : undefined} onInsertRowClick={handleInsertRowClick}
paginationProps={{ paginationProps={{
currentPage: Math.max(currentPage, 1), currentPage: Math.max(currentPage, 1),
totalPages: Math.max(numberOfPages, 1), totalPages: Math.max(numberOfPages, 1),

View File

@@ -12,11 +12,9 @@ import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { RowIcon } from '@/components/ui/v2/icons/RowIcon'; import { RowIcon } from '@/components/ui/v2/icons/RowIcon';
import { useDeleteRecordMutation } from '@/features/database/dataGrid/hooks/useDeleteRecordMutation'; import { useDeleteRecordMutation } from '@/features/database/dataGrid/hooks/useDeleteRecordMutation';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser';
import { isSchemaLocked } from '@/features/database/dataGrid/utils/schemaHelpers/isSchemaLocked';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useState } from 'react'; import { useState } from 'react';
import type { Row } from 'react-table'; import type { Row } from 'react-table';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@@ -58,11 +56,6 @@ export default function DataBrowserGridControls({
const { className: paginationClassName, ...restPaginationProps } = const { className: paginationClassName, ...restPaginationProps } =
paginationProps || ({} as DataGridPaginationProps); paginationProps || ({} as DataGridPaginationProps);
const {
query: { schemaSlug },
} = useRouter();
const isSchemaEditable = !isSchemaLocked(schemaSlug as string);
const { const {
selectedFlatRows: selectedRows, selectedFlatRows: selectedRows,
columns, columns,
@@ -126,7 +119,7 @@ export default function DataBrowserGridControls({
numberOfSelectedRows > 0 ? 'justify-between' : 'justify-end', numberOfSelectedRows > 0 ? 'justify-between' : 'justify-end',
)} )}
> >
{isSchemaEditable && numberOfSelectedRows > 0 && ( {numberOfSelectedRows > 0 && (
<div className="grid grid-flow-col place-content-start items-center gap-2"> <div className="grid grid-flow-col place-content-start items-center gap-2">
<Chip <Chip
size="small" size="small"

View File

@@ -43,7 +43,13 @@ export default async function deleteRecord({
(row) => (row) =>
`(${primaryOrUniqueColumns `(${primaryOrUniqueColumns
.map((primaryOrUniqueColumn) => .map((primaryOrUniqueColumn) =>
format('%I=%L', primaryOrUniqueColumn, row[primaryOrUniqueColumn]), row[primaryOrUniqueColumn] === null
? format('%I IS NULL', primaryOrUniqueColumn)
: format(
'%I=%L',
primaryOrUniqueColumn,
row[primaryOrUniqueColumn],
),
) )
.join(' AND ')})`, .join(' AND ')})`,
); );

View File

@@ -131,7 +131,7 @@ export default function LogsBody({ logsData, loading, error }: LogsBodyProps) {
count: rows.length, count: rows.length,
getScrollElement: () => tableRef.current, getScrollElement: () => tableRef.current,
estimateSize: () => 63, estimateSize: () => 63,
overscan: 5, overscan: 50,
}); });
if (loading && !error) { if (loading && !error) {
@@ -214,7 +214,7 @@ export default function LogsBody({ logsData, loading, error }: LogsBodyProps) {
<TableCell <TableCell
key={cell.id} key={cell.id}
component="td" component="td"
className="break-words py-2.5 px-2 align-top text-xs- font-normal tracking-tight" className="break-words px-2 py-2.5 align-top text-xs- font-normal tracking-tight"
style={{ style={{
width: cell.column.getSize() || 'auto', width: cell.column.getSize() || 'auto',
minWidth: !cell.column.getSize() ? 300 : 'initial', minWidth: !cell.column.getSize() ? 300 : 'initial',

View File

@@ -52,7 +52,7 @@ function LogsDatePicker({
<Text <Text
htmlFor={label} htmlFor={label}
component="label" component="label"
className="self-center text-sm+ font-normal" className="min-w-14 self-center text-sm+ font-normal"
color="secondary" color="secondary"
> >
{label} {label}

View File

@@ -1,246 +1,240 @@
import { ControlledSelect } from '@/components/form/ControlledSelect';
import { Form } from '@/components/form/Form';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import type { BoxProps } from '@/components/ui/v2/Box'; import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { ClockIcon } from '@/components/ui/v2/icons/ClockIcon'; import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { SearchIcon } from '@/components/ui/v2/icons/SearchIcon';
import { Input } from '@/components/ui/v2/Input';
import { Link } from '@/components/ui/v2/Link';
import { Option } from '@/components/ui/v2/Option'; import { Option } from '@/components/ui/v2/Option';
import { Select } from '@/components/ui/v2/Select'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { LogsDatePicker } from '@/features/projects/logs/components/LogsDatePicker'; import { LogsRangeSelector } from '@/features/projects/logs/components/LogsRangeSelector';
import type { LogsCustomInterval } from '@/features/projects/logs/utils/constants/intervals'; import { AvailableLogsService } from '@/features/projects/logs/utils/constants/services';
import { LOGS_AVAILABLE_INTERVALS } from '@/features/projects/logs/utils/constants/intervals'; import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import type { AvailableLogsService } from '@/features/projects/logs/utils/constants/services'; import { useGetServiceLabelValuesQuery } from '@/utils/__generated__/graphql';
import { LOGS_AVAILABLE_SERVICES } from '@/features/projects/logs/utils/constants/services'; import { yupResolver } from '@hookform/resolvers/yup';
import { useGetRunServicesQuery } from '@/utils/__generated__/graphql';
import { subMinutes } from 'date-fns'; import { subMinutes } from 'date-fns';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { twMerge } from 'tailwind-merge'; import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
export interface LogsHeaderProps extends Omit<BoxProps, 'children'> { export const validationSchema = Yup.object({
from: Yup.date(),
to: Yup.date().nullable(),
service: Yup.string().oneOf(Object.values(AvailableLogsService)),
regexFilter: Yup.string(),
});
export type LogsFilterFormValues = Yup.InferType<typeof validationSchema>;
interface LogsHeaderProps extends Omit<BoxProps, 'children'> {
/** /**
* The date to be displayed in the date picker for the from date. * This is used to indicate that a query is currently inflight
*/ */
fromDate: Date; loading: boolean;
/** /**
* The date to be displayed in the date picker for the to date. *
* Function to be called when the user submits the filters form
*/ */
toDate: Date | null; onSubmitFilterValues: (value: LogsFilterFormValues) => void;
/**
* Service to where to fetch logs from.
*/
service: AvailableLogsService;
/**
* Function to be called when the user changes the from date.
*/
onFromDateChange: (value: Date) => void;
/**
* Function to be called when the user changes the `to` date.
*/
onToDateChange: (value: Date) => void;
/**
* Function to be called when the user changes service to which to query logs from.
*/
onServiceChange: (value: AvailableLogsService) => void;
}
type LogsToDatePickerLiveButtonProps = Pick<
LogsHeaderProps,
'fromDate' | 'toDate' | 'onToDateChange'
>;
function LogsToDatePickerLiveButton({
fromDate,
toDate,
onToDateChange,
}: LogsToDatePickerLiveButtonProps) {
const [currentTime, setCurrentTime] = useState(new Date());
const isLive = !toDate;
function handleLiveButtonClick() {
if (isLive) {
return;
}
onToDateChange(null);
setCurrentTime(new Date());
}
// if isLive is true, we want to update the current time every second
// and set the toDate to the current time.
useEffect(() => {
let interval = null;
if (!interval && isLive) {
interval = setInterval(() => {
setCurrentTime(new Date());
}, 1000);
}
return () => {
clearInterval(interval);
};
}, [isLive, onToDateChange]);
return (
<div className="text-greyscaleMedium grid grid-flow-col">
<LogsDatePicker
label="To"
value={!isLive ? toDate : currentTime}
disabled={isLive}
onChange={onToDateChange}
minDate={fromDate}
maxDate={toDate || new Date()}
componentsProps={{
button: {
className: twMerge(
'rounded-r-none pr-3',
isLive ? 'border-r-0 hover:border-r-0 z-0' : 'z-10',
),
color: toDate ? 'inherit' : 'secondary',
},
}}
/>
<Button
variant="outlined"
color={isLive ? 'primary' : 'secondary'}
sx={{
backgroundColor: (theme) =>
!isLive ? `${theme.palette.grey[200]} !important` : 'transparent',
color: !isLive ? 'text.secondary' : undefined,
}}
className={twMerge(
'min-w-[77px] rounded-l-none',
!isLive ? 'z-0 border-l-0 hover:border-l-0' : 'z-10',
)}
startIcon={<ClockIcon className="h-4 w-4 self-center align-middle" />}
onClick={handleLiveButtonClick}
>
Live
</Button>
</div>
);
} }
export default function LogsHeader({ export default function LogsHeader({
fromDate, loading,
toDate, onSubmitFilterValues,
service,
onFromDateChange,
onToDateChange,
onServiceChange,
...props ...props
}: LogsHeaderProps) { }: LogsHeaderProps) {
const { currentProject } = useCurrentWorkspaceAndProject(); const { currentProject } = useCurrentWorkspaceAndProject();
const applicationCreationDate = new Date(currentProject.createdAt);
const [runServices, setRunServices] = useState< const [serviceLabels, setServiceLabels] = useState<
{ { label: string; value: string }[]
label: string;
value: string;
}[]
>([]); >([]);
const { data, loading } = useGetRunServicesQuery({ const { data, loading: loadingServiceLabelValues } =
variables: { useGetServiceLabelValuesQuery({
appID: currentProject.id, variables: { appID: currentProject.id },
resolve: false, });
limit: 1000,
offset: 0,
},
});
useEffect(() => { useEffect(() => {
if (!loading) { if (!loadingServiceLabelValues) {
const services = data.app?.runServices ?? []; const labels = data.getServiceLabelValues ?? [];
setServiceLabels(labels.map((l) => ({ label: l, value: l })));
}
}, [loadingServiceLabelValues, data]);
setRunServices( useEffect(() => {
services if (!loadingServiceLabelValues) {
.filter((s) => !!s.config?.name) const labels = data.getServiceLabelValues ?? [];
.map((s) => ({
label: s.config.name, const labelMappings = {
value: `run-${s.config.name}`, 'hasura-auth': 'Auth',
})), 'hasura-storage': 'Storage',
postgres: 'Postgres',
functions: 'Functions',
hasura: 'Hasura',
grafana: 'Grafana',
'job-backup': 'Backup Jobs',
ai: 'AI',
};
setServiceLabels(
labels.map((l) => ({ label: labelMappings[l] ?? l, value: l })),
); );
} }
}, [loading, data]); }, [loadingServiceLabelValues, data]);
/** const form = useForm<LogsFilterFormValues>({
* Will subtract the `customInterval` time in minutes from the current date. defaultValues: {
*/ from: subMinutes(new Date(), MINUTES_TO_DECREASE_FROM_CURRENT_DATE),
function handleIntervalChange({ to: new Date(),
minutesToDecreaseFromCurrentDate, regexFilter: '',
}: LogsCustomInterval) { service: AvailableLogsService.ALL,
onFromDateChange(subMinutes(new Date(), minutesToDecreaseFromCurrentDate)); },
onToDateChange(new Date()); reValidateMode: 'onSubmit',
} resolver: yupResolver(validationSchema),
});
const { register, watch, getValues } = form;
const service = watch('service');
useEffect(() => {
onSubmitFilterValues(getValues());
}, [service, getValues, onSubmitFilterValues]);
const handleSubmit = (values: LogsFilterFormValues) =>
onSubmitFilterValues(values);
return ( return (
<Box <Box
className="sticky top-0 z-10 grid w-full grid-flow-row gap-x-6 gap-y-2 border-b py-2.5 px-4 lg:grid-flow-col lg:justify-between" className="sticky top-0 z-10 grid w-full grid-flow-row gap-x-6 gap-y-2 border-b px-4 py-2.5 lg:grid-flow-col"
{...props} {...props}
> >
<Box className="grid w-full grid-flow-row items-center justify-center gap-2 md:w-[initial] md:grid-flow-col md:gap-3 lg:justify-start"> <FormProvider {...form}>
<div className="grid grid-flow-col items-center gap-3 md:justify-start"> <Form
<LogsDatePicker onSubmit={handleSubmit}
label="From" className="grid w-full grid-flow-row items-center gap-2 md:w-[initial] md:grid-flow-col md:gap-3 lg:justify-end"
value={fromDate} >
onChange={onFromDateChange} <Box className="flex flex-row space-x-2">
minDate={applicationCreationDate} <ControlledSelect
maxDate={toDate || new Date()} {...register('service')}
/> className="w-full text-sm font-normal min-w-fit"
placeholder="All Services"
aria-label="Select service"
hideEmptyHelperText
slotProps={{
root: {
className: 'min-h-[initial] h-10 leading-[initial]',
},
}}
>
{[{ label: 'All services', value: '' }, ...serviceLabels].map(
({ value, label }) => (
<Option
key={value}
value={value}
className="text-sm+ font-medium"
>
{label}
</Option>
),
)}
</ControlledSelect>
<div className="w-full min-w-fit">
<LogsRangeSelector onSubmitFilterValues={onSubmitFilterValues} />
</div>
</Box>
<LogsToDatePickerLiveButton <Input
fromDate={fromDate} {...register('regexFilter')}
toDate={toDate} placeholder="Filter logs with a regular expression"
onToDateChange={onToDateChange}
/>
</div>
<Box className="-my-2.5 px-0 py-2.5 lg:border-l lg:px-3">
<Select
className="w-full text-sm font-normal"
placeholder="All Services"
onChange={(_e, value) => {
if (typeof value !== 'string') {
return;
}
onServiceChange(value as AvailableLogsService);
}}
value={service}
aria-label="Select service"
hideEmptyHelperText hideEmptyHelperText
slotProps={{ autoComplete="off"
root: { className: 'min-h-[initial] h-9 leading-[initial]' }, fullWidth
}} className="min-w-80"
> startAdornment={
{[...LOGS_AVAILABLE_SERVICES, ...runServices].map( <Tooltip
({ value, label }) => ( componentsProps={{
<Option tooltip: {
key={value} sx: {
value={value} maxWidth: '30rem',
className="text-sm+ font-medium" },
> },
{label} }}
</Option> title={
), <div className="p-2 space-y-4">
)} <h2>Here are some useful regular expressions:</h2>
</Select> <ul className="pl-3 space-y-2 list-disc">
</Box> <li>
</Box> use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100">
(?i)error
</code>
to search for lines with the word <b>error</b> (case
insenstive)
</li>
<li>
use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100">
error
</code>
to search for lines with the word <b>error</b> (case
sensitive)
</li>
<li>
use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100">
/metadata.*error
</code>
to search for errors in hasura&apos;s metadata endpoint
</li>
<li>
See
<Link
href="https://github.com/google/re2/wiki/Syntax"
target="_blank"
rel="noopener noreferrer"
underline="hover"
className="mx-1"
>
here
</Link>
for more patterns
</li>
</ul>
</div>
}
>
<Box className="ml-2 rounded-full cursor-pointer">
<InfoIcon
aria-label="Info"
className="w-5 h-5"
color="info"
/>
</Box>
</Tooltip>
}
/>
<Box className="hidden grid-flow-col items-center justify-center gap-3 md:grid lg:justify-end">
{LOGS_AVAILABLE_INTERVALS.map((logInterval) => (
<Button <Button
key={logInterval.label} type="submit"
variant="outlined" className="h-10"
color="secondary" startIcon={
className="self-center" loading ? (
onClick={() => handleIntervalChange(logInterval)} <ActivityIndicator className="w-4 h-4" />
) : (
<SearchIcon />
)
}
disabled={loading}
> >
{logInterval.label} Search
</Button> </Button>
))} </Form>
</Box> </FormProvider>
</Box> </Box>
); );
} }

View File

@@ -1,2 +1 @@
export * from './LogsHeader'; export { default as LogsHeader, type LogsFilterFormValues } from './LogsHeader';
export { default as LogsHeader } from './LogsHeader';

View File

@@ -0,0 +1,170 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Dropdown, useDropdown } from '@/components/ui/v2/Dropdown';
import { ClockIcon } from '@/components/ui/v2/icons/ClockIcon';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { LogsDatePicker } from '@/features/projects/logs/components/LogsDatePicker';
import type { LogsFilterFormValues } from '@/features/projects/logs/components/LogsHeader';
import {
LOGS_AVAILABLE_INTERVALS,
type LogsCustomInterval,
} from '@/features/projects/logs/utils/constants/intervals';
import { useInterval } from '@/hooks/useInterval';
import { ChevronDownIcon } from '@graphiql/react';
import { formatDistance, subMinutes } from 'date-fns';
import { useState } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { twMerge } from 'tailwind-merge';
function LogsToDatePickerLiveButton() {
const [currentTime, setCurrentTime] = useState(new Date());
const { setValue } = useFormContext<LogsFilterFormValues>();
const { from, to } = useWatch<LogsFilterFormValues>();
const isLive = !to;
function handleLiveButtonClick() {
if (isLive) {
setValue('from', subMinutes(new Date(), 20));
setValue('to', new Date());
return;
}
setValue('to', null);
setCurrentTime(new Date());
}
useInterval(() => setCurrentTime(new Date()), isLive ? 1000 : 0);
return (
<div className="text-greyscaleMedium flex flex-col">
{!isLive && (
<LogsDatePicker
label="To"
value={!isLive ? to : currentTime}
disabled={isLive}
onChange={(date: Date) => setValue('to', date)}
minDate={from}
maxDate={new Date()}
componentsProps={{
button: {
className: twMerge('rounded-r-none', isLive ? 'z-0' : 'z-10'),
color: to ? 'inherit' : 'secondary',
},
}}
/>
)}
<Button
variant="outlined"
color={isLive ? 'primary' : 'secondary'}
sx={{
backgroundColor: (theme) =>
!isLive ? `${theme.palette.grey[200]} !important` : 'transparent',
color: !isLive ? 'text.secondary' : undefined,
}}
className={twMerge(!isLive ? 'z-0 mt-4' : 'z-10')}
startIcon={<ClockIcon className="h-4 w-4 self-center align-middle" />}
onClick={handleLiveButtonClick}
>
Live
</Button>
</div>
);
}
interface LogsRangeSelectorProps {
onSubmitFilterValues: (value: LogsFilterFormValues) => void;
}
function LogsRangeSelectorIntervalPickers({
onSubmitFilterValues,
}: LogsRangeSelectorProps) {
const { currentProject } = useCurrentWorkspaceAndProject();
const applicationCreationDate = new Date(currentProject.createdAt);
const { setValue, getValues } = useFormContext<LogsFilterFormValues>();
const { from } = useWatch<LogsFilterFormValues>();
const { handleClose } = useDropdown();
const handleApply = () => {
onSubmitFilterValues(getValues());
handleClose();
};
/**
* Will subtract the `customInterval` time in minutes from the current date.
*/
function handleIntervalChange({
minutesToDecreaseFromCurrentDate,
}: LogsCustomInterval) {
setValue('from', subMinutes(new Date(), minutesToDecreaseFromCurrentDate));
setValue('to', new Date());
}
return (
<Box className="flex flex-col space-y-4">
<div className="flex flex-col space-y-4">
<LogsDatePicker
label="From"
value={from}
onChange={(date) => setValue('from', date)}
minDate={applicationCreationDate}
maxDate={new Date()}
/>
<LogsToDatePickerLiveButton />
</div>
<Box className="grid grid-cols-2 gap-2">
{LOGS_AVAILABLE_INTERVALS.map((logInterval) => (
<Button
key={logInterval.label}
variant="outlined"
color="secondary"
className="self-center"
onClick={() => handleIntervalChange(logInterval)}
>
Last {logInterval.label}
</Button>
))}
</Box>
<Button color="primary" variant="contained" onClick={handleApply}>
Apply
</Button>
</Box>
);
}
export default function LogsRangeSelector({
onSubmitFilterValues,
}: LogsRangeSelectorProps) {
const { from, to } = useWatch<LogsFilterFormValues>();
return (
<Dropdown.Root>
<Dropdown.Trigger hideChevron className="flex w-full rounded-full">
<Button
component="a"
className="h-10 w-full min-w-40 items-center justify-between"
variant="outlined"
>
<span>
{to === null
? 'Live'
: `${formatDistance(to.getTime(), from.getTime())}`}
</span>
<ChevronDownIcon className="h-3 w-3" />
</Button>
</Dropdown.Trigger>
<Dropdown.Content PaperProps={{ className: 'mt-1 max-w-xs w-full p-3' }}>
<LogsRangeSelectorIntervalPickers
onSubmitFilterValues={onSubmitFilterValues}
/>
</Dropdown.Content>
</Dropdown.Root>
);
}

View File

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

View File

@@ -89,7 +89,7 @@ function LogsTimePicker({
</Button> </Button>
<Button variant="contained" color="primary" onClick={handleApply}> <Button variant="contained" color="primary" onClick={handleApply}>
Apply Set
</Button> </Button>
</Box> </Box>
</div> </div>

View File

@@ -26,4 +26,12 @@ export const LOGS_AVAILABLE_INTERVALS: LogsCustomInterval[] = [
label: '60 min', label: '60 min',
minutesToDecreaseFromCurrentDate: 60, minutesToDecreaseFromCurrentDate: 60,
}, },
{
label: '12 hours',
minutesToDecreaseFromCurrentDate: 720,
},
{
label: '24 hours',
minutesToDecreaseFromCurrentDate: 1440,
},
]; ];

View File

@@ -7,7 +7,7 @@ import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCur
import { PendingWorkspaceMemberInvitation } from '@/features/projects/workspaces/components/PendingWorkspaceMemberInvitation'; import { PendingWorkspaceMemberInvitation } from '@/features/projects/workspaces/components/PendingWorkspaceMemberInvitation';
import { WorkspaceMember } from '@/features/projects/workspaces/components/WorkspaceMember'; import { WorkspaceMember } from '@/features/projects/workspaces/components/WorkspaceMember';
import { discordAnnounce } from '@/utils/discordAnnounce'; import { discordAnnounce } from '@/utils/discordAnnounce';
import { getErrorMessage } from '@/utils/getErrorMessage'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import { import {
refetchGetWorkspaceMembersQuery, refetchGetWorkspaceMembersQuery,
@@ -52,38 +52,42 @@ function WorkspaceMemberInviteForm({
return; return;
} }
try { await execPromiseWithErrorToast(
await insertWorkspaceMemberInvite({ async () => {
variables: { await insertWorkspaceMemberInvite({
workspaceMemberInvite: { variables: {
workspaceId: currentWorkspace.id, workspaceMemberInvite: {
email, workspaceId: currentWorkspace.id,
memberType: 'member', email,
memberType: 'member',
},
}, },
}, });
});
triggerToast( triggerToast(
`Invite to join workspace ${currentWorkspace.name} sent to ${email}.`, `Invite to join workspace ${currentWorkspace.name} sent to ${email}.`,
);
} catch (error) {
await discordAnnounce(
`Error trying to invite to ${email} to ${currentWorkspace.name} ${error.message}`,
);
if (
error.message ===
'Foreign key violation. insert or update on table "workspace_member_invites" violates foreign key constraint "workspace_member_invites_email_fkey"'
) {
setWorkspaceInviteError(
'You can only invite users that are already registered at Nhost. Ask the person to register an account, then invite them again.',
); );
},
{
loadingMessage: 'Sending invite...',
successMessage: 'The invite has been sent successfully.',
errorMessage: `Error trying to invite to ${email} to ${currentWorkspace.name}`,
onError: async (error) => {
await discordAnnounce(
`Error trying to invite to ${email} to ${currentWorkspace.name} ${error.message}`,
);
return; if (
} error.message ===
'Foreign key violation. insert or update on table "workspace_member_invites" violates foreign key constraint "workspace_member_invites_email_fkey"'
setWorkspaceInviteError(getErrorMessage(error, 'invite')); ) {
setWorkspaceInviteError(
return; 'You can only invite users that are already registered at Nhost. Ask the person to register an account, then invite them again.',
} );
}
},
},
);
setEmail(''); setEmail('');
}; };
@@ -130,8 +134,8 @@ export default function WorkspaceMembers() {
}); });
return ( return (
<div className="mx-auto mt-18 max-w-3xl font-display"> <div className="max-w-3xl mx-auto mt-18 font-display">
<div className="mb-2 grid grid-flow-row gap-1"> <div className="grid grid-flow-row gap-1 mb-2">
<Text variant="h3">Members</Text> <Text variant="h3">Members</Text>
<Text color="secondary" className="text-sm"> <Text color="secondary" className="text-sm">
People in this workspace can manage all projects listed above. People in this workspace can manage all projects listed above.

View File

@@ -38,6 +38,7 @@ 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 { parse } from 'shell-quote'; import { parse } from 'shell-quote';
import { HealthCheckFormSection } from './components/HealthCheckFormSection';
import { ServiceConfirmationDialog } from './components/ServiceConfirmationDialog'; import { ServiceConfirmationDialog } from './components/ServiceConfirmationDialog';
import { ServiceDetailsDialog } from './components/ServiceDetailsDialog'; import { ServiceDetailsDialog } from './components/ServiceDetailsDialog';
@@ -118,6 +119,13 @@ export default function ServiceForm({
type: item.type, type: item.type,
publish: item.publish, publish: item.publish,
})), })),
healthCheck: values.healthCheck
? {
port: values.healthCheck?.port,
initialDelaySeconds: values.healthCheck?.initialDelaySeconds,
probePeriodSeconds: values.healthCheck?.probePeriodSeconds,
}
: null,
}; };
return config; return config;
@@ -375,6 +383,8 @@ export default function ServiceForm({
<StorageFormSection /> <StorageFormSection />
<HealthCheckFormSection />
{createServiceFormError && ( {createServiceFormError && (
<Alert <Alert
severity="error" severity="error"

View File

@@ -41,6 +41,13 @@ export const validationSchema = Yup.object({
}) })
.required(), .required(),
), ),
healthCheck: Yup.object()
.shape({
port: Yup.number().required(),
initialDelaySeconds: Yup.number().required(),
probePeriodSeconds: Yup.number().required(),
})
.nullable(),
}); });
export type ServiceFormValues = Yup.InferType<typeof validationSchema>; export type ServiceFormValues = Yup.InferType<typeof validationSchema>;

View File

@@ -0,0 +1,112 @@
import { Box } from '@/components/ui/v2/Box';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { Input } from '@/components/ui/v2/Input';
import { Switch } from '@/components/ui/v2/Switch';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import type { ServiceFormValues } from '@/features/services/components/ServiceForm/ServiceFormTypes';
import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
export default function HealthCheckFormSection() {
const {
watch,
setValue,
register,
formState: { errors },
} = useFormContext<ServiceFormValues>();
const healthCheck = watch('healthCheck');
const [healthCheckEnabled, setHealthCheckEnabled] = useState(!!healthCheck);
const toggleHealthCheckEnabled = async (enabled: boolean) => {
setHealthCheckEnabled(enabled);
if (!enabled) {
setValue('healthCheck', null);
}
};
return (
<Box className="space-y-4 rounded border-1 p-4">
<Box className="flex flex-row items-center justify-between ">
<Box className="flex flex-row items-center space-x-2">
<Text variant="h4" className="font-semibold">
Health Check
</Text>
<Tooltip
title={
<span>
Monitor the health and availability of a service. Refer to{' '}
<a
target="_blank"
rel="noopener noreferrer"
href="https://docs.nhost.io/guides/run/health-checks"
className="underline"
>
Health Check
</a>{' '}
for more information.
</span>
}
>
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
</Tooltip>
</Box>
<Switch
checked={healthCheckEnabled}
onChange={(e) => toggleHealthCheckEnabled(e.target.checked)}
className="self-center"
/>
</Box>
{healthCheckEnabled && (
<Box className="flex flex-col space-y-4">
<Input
{...register(`healthCheck.port`)}
id="healthCheck.port"
label="Port"
placeholder="3000"
className="w-full"
hideEmptyHelperText
error={!!errors?.healthCheck?.port}
helperText={errors?.healthCheck?.port?.message}
fullWidth
autoComplete="off"
type="number"
/>
<Input
{...register(`healthCheck.initialDelaySeconds`)}
id="healthCheck.initialDelaySeconds"
label="Initial delay seconds"
placeholder="30"
className="w-full"
hideEmptyHelperText
error={!!errors?.healthCheck?.initialDelaySeconds}
helperText={errors?.healthCheck?.initialDelaySeconds?.message}
fullWidth
autoComplete="off"
type="number"
/>
<Input
{...register(`healthCheck.probePeriodSeconds`)}
id="healthCheck.probePeriodSeconds"
label="Probe period seconds"
placeholder="60"
className="w-full"
hideEmptyHelperText
error={!!errors?.healthCheck?.probePeriodSeconds}
helperText={errors?.healthCheck?.probePeriodSeconds?.message}
fullWidth
autoComplete="off"
type="number"
/>
</Box>
)}
</Box>
);
}

View File

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

View File

@@ -3,8 +3,15 @@ query getProjectLogs(
$service: String $service: String
$from: Timestamp $from: Timestamp
$to: Timestamp $to: Timestamp
$regexFilter: String
) { ) {
logs(appID: $appID, service: $service, from: $from, to: $to) { logs(
appID: $appID
service: $service
from: $from
to: $to
regexFilter: $regexFilter
) {
log log
service service
timestamp timestamp
@@ -15,8 +22,14 @@ subscription getLogsSubscription(
$appID: String! $appID: String!
$service: String $service: String
$from: Timestamp $from: Timestamp
$regexFilter: String
) { ) {
logs(appID: $appID, service: $service, from: $from) { logs(
appID: $appID
service: $service
from: $from
regexFilter: $regexFilter
) {
log log
service service
timestamp timestamp

View File

@@ -0,0 +1,3 @@
query getServiceLabelValues($appID: String!) {
getServiceLabelValues(appID: $appID)
}

View File

@@ -40,6 +40,11 @@ query getRunServices(
fqdn fqdn
} }
} }
healthCheck {
port
initialDelaySeconds
probePeriodSeconds
}
} }
} }
runServices_aggregate { runServices_aggregate {

View File

@@ -35,7 +35,24 @@ export default function useRemoteApplicationGQLClientWithSubscriptions() {
); );
return new ApolloClient({ return new ApolloClient({
cache: new InMemoryCache(), cache: new InMemoryCache({
typePolicies: {
Subscription: {
fields: {
logs: {
keyArgs: false,
},
},
},
Query: {
fields: {
logs: {
keyArgs: false,
},
},
},
},
}),
connectToDevTools: true, connectToDevTools: true,
link: split( link: split(
({ query }) => { ({ query }) => {

View File

@@ -2,49 +2,53 @@ import { ProjectLayout } from '@/components/layout/ProjectLayout';
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary'; import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { LogsBody } from '@/features/projects/logs/components/LogsBody'; import { LogsBody } from '@/features/projects/logs/components/LogsBody';
import { LogsHeader } from '@/features/projects/logs/components/LogsHeader'; import {
LogsHeader,
type LogsFilterFormValues,
} from '@/features/projects/logs/components/LogsHeader';
import { AvailableLogsService } from '@/features/projects/logs/utils/constants/services'; import { AvailableLogsService } from '@/features/projects/logs/utils/constants/services';
import { useRemoteApplicationGQLClientWithSubscriptions } from '@/hooks/useRemoteApplicationGQLClientWithSubscriptions'; import { useRemoteApplicationGQLClientWithSubscriptions } from '@/hooks/useRemoteApplicationGQLClientWithSubscriptions';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { import {
GetLogsSubscriptionDocument, GetLogsSubscriptionDocument,
useGetProjectLogsQuery, useGetProjectLogsQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { subMinutes } from 'date-fns'; import { subMinutes } from 'date-fns';
import type { ReactElement } from 'react'; import {
import { useCallback, useEffect, useRef, useState } from 'react'; useCallback,
useEffect,
useRef,
useState,
type ReactElement,
} from 'react';
const MINUTES_TO_DECREASE_FROM_CURRENT_DATE = 20; interface LogsFilters {
from: Date;
to: Date | null;
service: AvailableLogsService;
regexFilter: string;
}
export default function LogsPage() { export default function LogsPage() {
const { currentProject } = useCurrentWorkspaceAndProject(); const { currentProject } = useCurrentWorkspaceAndProject();
const [fromDate, setFromDate] = useState<Date>(
subMinutes(new Date(), MINUTES_TO_DECREASE_FROM_CURRENT_DATE),
);
const [toDate, setToDate] = useState<Date | null>(new Date());
const [service, setService] = useState<AvailableLogsService>(
AvailableLogsService.ALL,
);
// create a client that sends http requests to Hasura but websocket requests to Bragi // create a client that sends http requests to Hasura but websocket requests to Bragi
const clientWithSplit = useRemoteApplicationGQLClientWithSubscriptions(); const clientWithSplit = useRemoteApplicationGQLClientWithSubscriptions();
const subscriptionReturn = useRef(null); const subscriptionReturn = useRef(null);
/** const [filters, setFilters] = useState<LogsFilters>({
* Will change the specific service from which we query logs. from: subMinutes(new Date(), MINUTES_TO_DECREASE_FROM_CURRENT_DATE),
*/ to: new Date(),
function handleServiceChange(value: AvailableLogsService) { regexFilter: '',
setService(value); service: AvailableLogsService.ALL,
} });
const { data, loading, error, subscribeToMore, client } = const { data, error, subscribeToMore, client, loading, refetch } =
useGetProjectLogsQuery({ useGetProjectLogsQuery({
variables: { variables: { appID: currentProject.id, ...filters },
appID: currentProject.id,
from: fromDate,
to: toDate,
service,
},
client: clientWithSplit, client: clientWithSplit,
fetchPolicy: 'cache-and-network',
notifyOnNetworkStatusChange: true,
}); });
const subscribeToMoreLogs = useCallback( const subscribeToMoreLogs = useCallback(
@@ -53,8 +57,9 @@ export default function LogsPage() {
document: GetLogsSubscriptionDocument, document: GetLogsSubscriptionDocument,
variables: { variables: {
appID: currentProject.id, appID: currentProject.id,
service, service: filters.service,
from: fromDate, from: filters.from,
regexFilter: filters.regexFilter,
}, },
updateQuery: (prev, { subscriptionData }) => { updateQuery: (prev, { subscriptionData }) => {
// if there is no new data, just return the previous data // if there is no new data, just return the previous data
@@ -93,40 +98,47 @@ export default function LogsPage() {
}; };
}, },
}), }),
[subscribeToMore, currentProject.id, service, fromDate], [subscribeToMore, currentProject.id, filters],
); );
useEffect(() => { useEffect(() => {
if (toDate && subscriptionReturn.current !== null) { if (filters.to && subscriptionReturn.current !== null) {
subscriptionReturn.current(); subscriptionReturn.current();
subscriptionReturn.current = null; subscriptionReturn.current = null;
return () => {}; return () => {};
} }
if (toDate) { if (filters.to) {
return () => {}; return () => {};
} }
if (subscriptionReturn.current) {
subscriptionReturn.current();
subscriptionReturn.current = null;
}
// This will open the websocket connection and it will return a function to close it. // This will open the websocket connection and it will return a function to close it.
subscriptionReturn.current = subscribeToMoreLogs(); subscriptionReturn.current = subscribeToMoreLogs();
// get rid of the current apollo client instance (will also close the websocket if it's the live status) return () => {};
return () => client.stop(); }, [filters, subscribeToMoreLogs, client]);
}, [subscribeToMoreLogs, toDate, client]);
const onSubmitFilterValues = useCallback(
async (values: LogsFilterFormValues) => {
setFilters({ ...(values as LogsFilters) });
await refetch();
},
[setFilters, refetch],
);
return ( return (
<div className="flex h-full w-full flex-col"> <div className="flex h-full w-full flex-col">
<RetryableErrorBoundary> <RetryableErrorBoundary>
<LogsHeader <LogsHeader
fromDate={fromDate} loading={loading}
toDate={toDate} onSubmitFilterValues={onSubmitFilterValues}
service={service}
onServiceChange={handleServiceChange}
onFromDateChange={setFromDate}
onToDateChange={setToDate}
/> />
<LogsBody error={error} loading={loading} logsData={data} /> <LogsBody error={error} loading={loading} logsData={data} />
</RetryableErrorBoundary> </RetryableErrorBoundary>
</div> </div>

View File

@@ -196,6 +196,7 @@ export type ConfigAppSystemConfig = {
*/ */
export type ConfigAuth = { export type ConfigAuth = {
__typename?: 'ConfigAuth'; __typename?: 'ConfigAuth';
elevatedPrivileges?: Maybe<ConfigAuthElevatedPrivileges>;
method?: Maybe<ConfigAuthMethod>; method?: Maybe<ConfigAuthMethod>;
redirections?: Maybe<ConfigAuthRedirections>; redirections?: Maybe<ConfigAuthRedirections>;
/** Resources for the service */ /** Resources for the service */
@@ -219,6 +220,7 @@ export type ConfigAuthComparisonExp = {
_and?: InputMaybe<Array<ConfigAuthComparisonExp>>; _and?: InputMaybe<Array<ConfigAuthComparisonExp>>;
_not?: InputMaybe<ConfigAuthComparisonExp>; _not?: InputMaybe<ConfigAuthComparisonExp>;
_or?: InputMaybe<Array<ConfigAuthComparisonExp>>; _or?: InputMaybe<Array<ConfigAuthComparisonExp>>;
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesComparisonExp>;
method?: InputMaybe<ConfigAuthMethodComparisonExp>; method?: InputMaybe<ConfigAuthMethodComparisonExp>;
redirections?: InputMaybe<ConfigAuthRedirectionsComparisonExp>; redirections?: InputMaybe<ConfigAuthRedirectionsComparisonExp>;
resources?: InputMaybe<ConfigResourcesComparisonExp>; resources?: InputMaybe<ConfigResourcesComparisonExp>;
@@ -229,7 +231,28 @@ export type ConfigAuthComparisonExp = {
version?: InputMaybe<ConfigStringComparisonExp>; version?: InputMaybe<ConfigStringComparisonExp>;
}; };
export type ConfigAuthElevatedPrivileges = {
__typename?: 'ConfigAuthElevatedPrivileges';
mode?: Maybe<Scalars['String']>;
};
export type ConfigAuthElevatedPrivilegesComparisonExp = {
_and?: InputMaybe<Array<ConfigAuthElevatedPrivilegesComparisonExp>>;
_not?: InputMaybe<ConfigAuthElevatedPrivilegesComparisonExp>;
_or?: InputMaybe<Array<ConfigAuthElevatedPrivilegesComparisonExp>>;
mode?: InputMaybe<ConfigStringComparisonExp>;
};
export type ConfigAuthElevatedPrivilegesInsertInput = {
mode?: InputMaybe<Scalars['String']>;
};
export type ConfigAuthElevatedPrivilegesUpdateInput = {
mode?: InputMaybe<Scalars['String']>;
};
export type ConfigAuthInsertInput = { export type ConfigAuthInsertInput = {
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesInsertInput>;
method?: InputMaybe<ConfigAuthMethodInsertInput>; method?: InputMaybe<ConfigAuthMethodInsertInput>;
redirections?: InputMaybe<ConfigAuthRedirectionsInsertInput>; redirections?: InputMaybe<ConfigAuthRedirectionsInsertInput>;
resources?: InputMaybe<ConfigResourcesInsertInput>; resources?: InputMaybe<ConfigResourcesInsertInput>;
@@ -808,6 +831,7 @@ export type ConfigAuthTotpUpdateInput = {
}; };
export type ConfigAuthUpdateInput = { export type ConfigAuthUpdateInput = {
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesUpdateInput>;
method?: InputMaybe<ConfigAuthMethodUpdateInput>; method?: InputMaybe<ConfigAuthMethodUpdateInput>;
redirections?: InputMaybe<ConfigAuthRedirectionsUpdateInput>; redirections?: InputMaybe<ConfigAuthRedirectionsUpdateInput>;
resources?: InputMaybe<ConfigResourcesUpdateInput>; resources?: InputMaybe<ConfigResourcesUpdateInput>;
@@ -5238,9 +5262,9 @@ export type AuthUserProviders_Bool_Exp = {
export enum AuthUserProviders_Constraint { export enum AuthUserProviders_Constraint {
/** unique or primary key constraint on columns "id" */ /** unique or primary key constraint on columns "id" */
UserProvidersPkey = 'user_providers_pkey', UserProvidersPkey = 'user_providers_pkey',
/** unique or primary key constraint on columns "provider_id", "provider_user_id" */ /** unique or primary key constraint on columns "provider_user_id", "provider_id" */
UserProvidersProviderIdProviderUserIdKey = 'user_providers_provider_id_provider_user_id_key', UserProvidersProviderIdProviderUserIdKey = 'user_providers_provider_id_provider_user_id_key',
/** unique or primary key constraint on columns "provider_id", "user_id" */ /** unique or primary key constraint on columns "user_id", "provider_id" */
UserProvidersUserIdProviderIdKey = 'user_providers_user_id_provider_id_key' UserProvidersUserIdProviderIdKey = 'user_providers_user_id_provider_id_key'
} }
@@ -15774,6 +15798,7 @@ export type Query_Root = {
runServiceConfig?: Maybe<ConfigRunServiceConfig>; runServiceConfig?: Maybe<ConfigRunServiceConfig>;
runServiceConfigRawJSON: Scalars['String']; runServiceConfigRawJSON: Scalars['String'];
runServiceConfigs: Array<ConfigRunServiceConfigWithId>; runServiceConfigs: Array<ConfigRunServiceConfigWithId>;
runServiceConfigsAll: Array<ConfigRunServiceConfigWithId>;
/** An array relationship */ /** An array relationship */
runServices: Array<Run_Service>; runServices: Array<Run_Service>;
/** fetch aggregated fields from the table: "run_service" */ /** fetch aggregated fields from the table: "run_service" */
@@ -16755,6 +16780,12 @@ export type Query_RootRunServiceConfigRawJsonArgs = {
export type Query_RootRunServiceConfigsArgs = { export type Query_RootRunServiceConfigsArgs = {
appID: Scalars['uuid'];
resolve: Scalars['Boolean'];
};
export type Query_RootRunServiceConfigsAllArgs = {
resolve: Scalars['Boolean']; resolve: Scalars['Boolean'];
where?: InputMaybe<ConfigRunServiceConfigComparisonExp>; where?: InputMaybe<ConfigRunServiceConfigComparisonExp>;
}; };
@@ -21355,7 +21386,7 @@ export type WorkspaceMemberInvites_Bool_Exp = {
/** unique or primary key constraints on table "workspace_member_invites" */ /** unique or primary key constraints on table "workspace_member_invites" */
export enum WorkspaceMemberInvites_Constraint { export enum WorkspaceMemberInvites_Constraint {
/** unique or primary key constraint on columns "email", "workspace_id" */ /** unique or primary key constraint on columns "workspace_id", "email" */
WorkspaceMemberInvitesEmailWorkspaceIdKey = 'workspace_member_invites_email_workspace_id_key', WorkspaceMemberInvitesEmailWorkspaceIdKey = 'workspace_member_invites_email_workspace_id_key',
/** unique or primary key constraint on columns "id" */ /** unique or primary key constraint on columns "id" */
WorkspaceMemberInvitesPkey = 'workspace_member_invites_pkey' WorkspaceMemberInvitesPkey = 'workspace_member_invites_pkey'
@@ -22425,7 +22456,7 @@ export type GetAiSettingsQueryVariables = Exact<{
}>; }>;
export type GetAiSettingsQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', ai?: { __typename?: 'ConfigAI', version?: string | null, webhookSecret: string, autoEmbeddings?: { __typename?: 'ConfigAIAutoEmbeddings', synchPeriodMinutes?: any | null } | null, openai: { __typename?: 'ConfigAIOpenai', apiKey: string, organization?: string | null }, resources: { __typename?: 'ConfigAIResources', compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any } } } | null } | null }; export type GetAiSettingsQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', postgres?: { __typename?: 'ConfigPostgres', version?: string | null } | null, ai?: { __typename?: 'ConfigAI', version?: string | null, webhookSecret: string, autoEmbeddings?: { __typename?: 'ConfigAIAutoEmbeddings', synchPeriodMinutes?: any | null } | null, openai: { __typename?: 'ConfigAIOpenai', apiKey: string, organization?: string | null }, resources: { __typename?: 'ConfigAIResources', compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any } } } | null } | null };
export type GetAuthenticationSettingsQueryVariables = Exact<{ export type GetAuthenticationSettingsQueryVariables = Exact<{
appId: Scalars['uuid']; appId: Scalars['uuid'];
@@ -22772,6 +22803,7 @@ export type GetProjectLogsQueryVariables = Exact<{
service?: InputMaybe<Scalars['String']>; service?: InputMaybe<Scalars['String']>;
from?: InputMaybe<Scalars['Timestamp']>; from?: InputMaybe<Scalars['Timestamp']>;
to?: InputMaybe<Scalars['Timestamp']>; to?: InputMaybe<Scalars['Timestamp']>;
regexFilter?: InputMaybe<Scalars['String']>;
}>; }>;
@@ -22781,11 +22813,19 @@ export type GetLogsSubscriptionSubscriptionVariables = Exact<{
appID: Scalars['String']; appID: Scalars['String'];
service?: InputMaybe<Scalars['String']>; service?: InputMaybe<Scalars['String']>;
from?: InputMaybe<Scalars['Timestamp']>; from?: InputMaybe<Scalars['Timestamp']>;
regexFilter?: InputMaybe<Scalars['String']>;
}>; }>;
export type GetLogsSubscriptionSubscription = { __typename?: 'subscription_root', logs: Array<{ __typename?: 'Log', log: string, service: string, timestamp: any }> }; export type GetLogsSubscriptionSubscription = { __typename?: 'subscription_root', logs: Array<{ __typename?: 'Log', log: string, service: string, timestamp: any }> };
export type GetServiceLabelValuesQueryVariables = Exact<{
appID: Scalars['String'];
}>;
export type GetServiceLabelValuesQuery = { __typename?: 'query_root', getServiceLabelValues: Array<string> };
export type DeletePaymentMethodMutationVariables = Exact<{ export type DeletePaymentMethodMutationVariables = Exact<{
paymentMethodId: Scalars['uuid']; paymentMethodId: Scalars['uuid'];
}>; }>;
@@ -22960,7 +23000,7 @@ export type GetRunServicesQueryVariables = Exact<{
}>; }>;
export type GetRunServicesQuery = { __typename?: 'query_root', app?: { __typename?: 'apps', runServices: Array<{ __typename?: 'run_service', id: any, createdAt: any, updatedAt: any, subdomain: string, config?: { __typename?: 'ConfigRunServiceConfig', name: any, command?: Array<string> | null, image: { __typename?: 'ConfigRunServiceImage', image: string }, resources: { __typename?: 'ConfigRunServiceResources', replicas: any, compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any }, storage?: Array<{ __typename?: 'ConfigRunServiceResourcesStorage', name: any, path: string, capacity: any }> | null }, environment?: Array<{ __typename?: 'ConfigEnvironmentVariable', name: string, value: string }> | null, ports?: Array<{ __typename?: 'ConfigRunServicePort', port: any, type: string, publish?: boolean | null, ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null }> | null } | null }>, runServices_aggregate: { __typename?: 'run_service_aggregate', aggregate?: { __typename?: 'run_service_aggregate_fields', count: number } | null } } | null }; export type GetRunServicesQuery = { __typename?: 'query_root', app?: { __typename?: 'apps', runServices: Array<{ __typename?: 'run_service', id: any, createdAt: any, updatedAt: any, subdomain: string, config?: { __typename?: 'ConfigRunServiceConfig', name: any, command?: Array<string> | null, image: { __typename?: 'ConfigRunServiceImage', image: string }, resources: { __typename?: 'ConfigRunServiceResources', replicas: any, compute: { __typename?: 'ConfigComputeResources', cpu: any, memory: any }, storage?: Array<{ __typename?: 'ConfigRunServiceResourcesStorage', name: any, path: string, capacity: any }> | null }, environment?: Array<{ __typename?: 'ConfigEnvironmentVariable', name: string, value: string }> | null, ports?: Array<{ __typename?: 'ConfigRunServicePort', port: any, type: string, publish?: boolean | null, ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null }> | null, healthCheck?: { __typename?: 'ConfigHealthCheck', port: any, initialDelaySeconds?: number | null, probePeriodSeconds?: number | null } | null } | null }>, runServices_aggregate: { __typename?: 'run_service_aggregate', aggregate?: { __typename?: 'run_service_aggregate_fields', count: number } | null } } | null };
export type InsertRunServiceMutationVariables = Exact<{ export type InsertRunServiceMutationVariables = Exact<{
object: Run_Service_Insert_Input; object: Run_Service_Insert_Input;
@@ -23524,6 +23564,9 @@ export type DeletePersonalAccessTokenMutationOptions = Apollo.BaseMutationOption
export const GetAiSettingsDocument = gql` export const GetAiSettingsDocument = gql`
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
@@ -25558,8 +25601,14 @@ export function refetchGetGithubRepositoriesQuery(variables?: GetGithubRepositor
return { query: GetGithubRepositoriesDocument, variables: variables } return { query: GetGithubRepositoriesDocument, variables: variables }
} }
export const GetProjectLogsDocument = gql` export const GetProjectLogsDocument = gql`
query getProjectLogs($appID: String!, $service: String, $from: Timestamp, $to: Timestamp) { query getProjectLogs($appID: String!, $service: String, $from: Timestamp, $to: Timestamp, $regexFilter: String) {
logs(appID: $appID, service: $service, from: $from, to: $to) { logs(
appID: $appID
service: $service
from: $from
to: $to
regexFilter: $regexFilter
) {
log log
service service
timestamp timestamp
@@ -25583,6 +25632,7 @@ export const GetProjectLogsDocument = gql`
* service: // value for 'service' * service: // value for 'service'
* from: // value for 'from' * from: // value for 'from'
* to: // value for 'to' * to: // value for 'to'
* regexFilter: // value for 'regexFilter'
* }, * },
* }); * });
*/ */
@@ -25601,8 +25651,8 @@ export function refetchGetProjectLogsQuery(variables: GetProjectLogsQueryVariabl
return { query: GetProjectLogsDocument, variables: variables } return { query: GetProjectLogsDocument, variables: variables }
} }
export const GetLogsSubscriptionDocument = gql` export const GetLogsSubscriptionDocument = gql`
subscription getLogsSubscription($appID: String!, $service: String, $from: Timestamp) { subscription getLogsSubscription($appID: String!, $service: String, $from: Timestamp, $regexFilter: String) {
logs(appID: $appID, service: $service, from: $from) { logs(appID: $appID, service: $service, from: $from, regexFilter: $regexFilter) {
log log
service service
timestamp timestamp
@@ -25625,6 +25675,7 @@ export const GetLogsSubscriptionDocument = gql`
* appID: // value for 'appID' * appID: // value for 'appID'
* service: // value for 'service' * service: // value for 'service'
* from: // value for 'from' * from: // value for 'from'
* regexFilter: // value for 'regexFilter'
* }, * },
* }); * });
*/ */
@@ -25634,6 +25685,42 @@ export function useGetLogsSubscriptionSubscription(baseOptions: Apollo.Subscript
} }
export type GetLogsSubscriptionSubscriptionHookResult = ReturnType<typeof useGetLogsSubscriptionSubscription>; export type GetLogsSubscriptionSubscriptionHookResult = ReturnType<typeof useGetLogsSubscriptionSubscription>;
export type GetLogsSubscriptionSubscriptionResult = Apollo.SubscriptionResult<GetLogsSubscriptionSubscription>; export type GetLogsSubscriptionSubscriptionResult = Apollo.SubscriptionResult<GetLogsSubscriptionSubscription>;
export const GetServiceLabelValuesDocument = gql`
query getServiceLabelValues($appID: String!) {
getServiceLabelValues(appID: $appID)
}
`;
/**
* __useGetServiceLabelValuesQuery__
*
* To run a query within a React component, call `useGetServiceLabelValuesQuery` and pass it any options that fit your needs.
* When your component renders, `useGetServiceLabelValuesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetServiceLabelValuesQuery({
* variables: {
* appID: // value for 'appID'
* },
* });
*/
export function useGetServiceLabelValuesQuery(baseOptions: Apollo.QueryHookOptions<GetServiceLabelValuesQuery, GetServiceLabelValuesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetServiceLabelValuesQuery, GetServiceLabelValuesQueryVariables>(GetServiceLabelValuesDocument, options);
}
export function useGetServiceLabelValuesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetServiceLabelValuesQuery, GetServiceLabelValuesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetServiceLabelValuesQuery, GetServiceLabelValuesQueryVariables>(GetServiceLabelValuesDocument, options);
}
export type GetServiceLabelValuesQueryHookResult = ReturnType<typeof useGetServiceLabelValuesQuery>;
export type GetServiceLabelValuesLazyQueryHookResult = ReturnType<typeof useGetServiceLabelValuesLazyQuery>;
export type GetServiceLabelValuesQueryResult = Apollo.QueryResult<GetServiceLabelValuesQuery, GetServiceLabelValuesQueryVariables>;
export function refetchGetServiceLabelValuesQuery(variables: GetServiceLabelValuesQueryVariables) {
return { query: GetServiceLabelValuesDocument, variables: variables }
}
export const DeletePaymentMethodDocument = gql` export const DeletePaymentMethodDocument = gql`
mutation deletePaymentMethod($paymentMethodId: uuid!) { mutation deletePaymentMethod($paymentMethodId: uuid!) {
deletePaymentMethod(id: $paymentMethodId) { deletePaymentMethod(id: $paymentMethodId) {
@@ -26577,6 +26664,11 @@ export const GetRunServicesDocument = gql`
fqdn fqdn
} }
} }
healthCheck {
port
initialDelaySeconds
probePeriodSeconds
}
} }
} }
runServices_aggregate { runServices_aggregate {

View File

@@ -66,3 +66,8 @@ export const RESOURCE_VCPU_PRICE_PER_MINUTE = 0.0012;
* Maximum number of free projects a user is allowed to have. * Maximum number of free projects a user is allowed to have.
*/ */
export const MAX_FREE_PROJECTS = 1; export const MAX_FREE_PROJECTS = 1;
/**
* Default value in minutes to use for querying the logs
*/
export const MINUTES_TO_DECREASE_FROM_CURRENT_DATE = 20;

View File

@@ -29,6 +29,7 @@ export default async function execPromiseWithErrorToast(
const result = await call(); const result = await call();
toast.dismiss(loadingToastId); toast.dismiss(loadingToastId);
toast.success(successMessage, { toast.success(successMessage, {
style: toastStyle.style, style: toastStyle.style,
...toastStyle.success, ...toastStyle.success,

View File

@@ -21,6 +21,9 @@ module.exports = {
copper: '#DD792D', copper: '#DD792D',
paper: '#171d26', paper: '#171d26',
divider: '#2f363d', divider: '#2f363d',
'primary-main': '#0052cd',
'primary-light': '#ebf3ff',
'primary-dark': '#063799',
}, },
boxShadow: { boxShadow: {
outline: 'inset 0 0 0 2px rgba(0, 82, 205, 0.6)', outline: 'inset 0 0 0 2px rgba(0, 82, 205, 0.6)',

View File

@@ -1,5 +1,17 @@
# @nhost/docs # @nhost/docs
## 2.7.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 2.6.0
### Minor Changes
- dc23dc0: fix: docs run references
## 2.5.0 ## 2.5.0
### Minor Changes ### Minor Changes

View File

@@ -9,7 +9,7 @@ If you are using the Nhost CLI for local development, as of [v0.12.0](https://gi
<Steps> <Steps>
<Step title="Configuring the Service"> <Step title="Configuring the Service">
Follow the steps highlighed in the ["Enabling Service"](enabling-service) guide and don't forget to add the relevant secrets to your `.secrets` file. Follow the steps highlighed in the [Enabling Service](enabling-service) guide and don't forget to add the relevant secrets to your `.secrets` file.
</Step> </Step>
<Step title="Start nhost"> <Step title="Start nhost">
Run `nhost up`: Run `nhost up`:

View File

@@ -46,11 +46,11 @@ capacity=1
</Tab> </Tab>
</Tabs> </Tabs>
<Info>Head to [CLI & CI deployments](/run/ci) for more details on how to deploy using a configuration file.</Info> <Info>Head to [CLI & CI deployments](/guides/run/cli-deployments) for more details on how to deploy using a configuration file.</Info>
The `name` of the service is used as an identifier and to generate URLs when exposing the service to the Internet. You can use any container image publicly available or you can push your own to the [Nhost registry](/run/registry). The `name` of the service is used as an identifier and to generate URLs when exposing the service to the Internet. You can use any container image publicly available or you can push your own to the [Nhost registry](/guides/run/registry).
All environment variables set here are exclusive to this service and will not be shared with other services or with the Nhost stack. If you are using a configuration file secrets are supported. All environment variables set here are exclusive to this service and will not be shared with other services or with the Nhost stack. If you are using a configuration file secrets are supported.
For more details about the `Ports` section head to [networking](/run/networking). You can also head to [resources](/run/resources) for more information about replicas, compute, and storage. For more details about the `Ports` section head to [networking](/guides/run/networking). You can also head to [resources](/guides/run/resources) for more information about replicas, compute, and storage.

View File

@@ -12,11 +12,11 @@ Then on `New Service`:
![click on New Service](/images/guides/run/getting_started_2.png) ![click on New Service](/images/guides/run/getting_started_2.png)
Now you can fill your [service configuration](/run/configuration): Now you can fill your [service configuration](/guides/run/configuration):
![click on New Service](/images/guides/run/getting_started_3.png) ![click on New Service](/images/guides/run/getting_started_3.png)
As you configure the `Ports` section you can take note of the generated URL. You can find more information about this section under [Networking](/run/networking). As you configure the `Ports` section you can take note of the generated URL. You can find more information about this section under [Networking](/guides/run/networking).
![copy the URL](/images/guides/run/getting_started_4.png) ![copy the URL](/images/guides/run/getting_started_4.png)

View File

@@ -76,7 +76,7 @@ To pause a service, simply set its number of replicas to `0`:
<Tab title="dashboard"> <Tab title="dashboard">
![pausing a service](/img/run/resources_3.png) ![pausing a service](/images/guides/run/resources_3.png)
</Tab> </Tab>
<Tab title="toml"> <Tab title="toml">

View File

@@ -1,11 +1,11 @@
{ {
"name": "@nhost/docs", "name": "@nhost/docs",
"version": "2.5.0", "version": "2.7.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "mintlify dev" "start": "mintlify dev"
}, },
"devDependencies": { "devDependencies": {
"mintlify": "^4.0.121" "mintlify": "^4.0.128"
} }
} }

View File

@@ -1,5 +1,21 @@
# @nhost-examples/cli # @nhost-examples/cli
## 0.2.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.1.9
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.1.8 ## 0.1.8
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/cli", "name": "@nhost-examples/cli",
"version": "0.1.8", "version": "0.2.0",
"main": "src/index.mjs", "main": "src/index.mjs",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -9,10 +9,10 @@
"dependencies": { "dependencies": {
"@nhost/nhost-js": "workspace:^", "@nhost/nhost-js": "workspace:^",
"commander": "^10.0.1", "commander": "^10.0.1",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"graphql": "16.8.1", "graphql": "16.8.1",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"pino": "^8.17.2" "pino": "^8.19.0"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=16.0.0"

View File

@@ -1,5 +1,24 @@
# @nhost-examples/codegen-react-apollo # @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
## 0.1.17
### Patch Changes
- @nhost/react@3.2.3
- @nhost/react-apollo@9.0.3
## 0.1.16 ## 0.1.16
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/codegen-react-apollo", "name": "@nhost-examples/codegen-react-apollo",
"version": "0.1.16", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"codegen": "graphql-codegen", "codegen": "graphql-codegen",
@@ -15,7 +15,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@nhost/react": "workspace:^", "@nhost/react": "workspace:^",
"@nhost/react-apollo": "workspace:^", "@nhost/react-apollo": "workspace:^",
"clsx": "^1.2.1", "clsx": "^1.2.1",
@@ -28,14 +28,14 @@
"@graphql-codegen/client-preset": "^1.3.0", "@graphql-codegen/client-preset": "^1.3.0",
"@graphql-typed-document-node/core": "^3.2.0", "@graphql-typed-document-node/core": "^3.2.0",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@types/node": "^18.19.12", "@types/node": "^18.19.21",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^3.1.0", "@vitejs/plugin-react": "^3.1.0",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^5.0.12" "vite": "^5.1.4"
} }
} }

View File

@@ -1,5 +1,22 @@
# @nhost-examples/codegen-react-query # @nhost-examples/codegen-react-query
## 0.2.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/react@3.3.0
## 0.1.18
### Patch Changes
- @nhost/react@3.2.3
## 0.1.17 ## 0.1.17
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/codegen-react-query", "name": "@nhost-examples/codegen-react-query",
"version": "0.1.17", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"codegen": "graphql-codegen", "codegen": "graphql-codegen",
@@ -29,14 +29,14 @@
"@graphql-codegen/client-preset": "^1.3.0", "@graphql-codegen/client-preset": "^1.3.0",
"@graphql-typed-document-node/core": "^3.2.0", "@graphql-typed-document-node/core": "^3.2.0",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^5.0.12" "vite": "^5.1.4"
} }
} }

View File

@@ -1,5 +1,24 @@
# @nhost-examples/react-urql # @nhost-examples/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
## 0.0.14
### Patch Changes
- @nhost/react@3.2.3
- @nhost/react-urql@6.0.3
## 0.0.13 ## 0.0.13
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "@nhost-examples/codegen-react-urql", "name": "@nhost-examples/codegen-react-urql",
"private": true, "private": true,
"version": "0.0.13", "version": "0.1.0",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
@@ -22,14 +22,14 @@
"@graphql-codegen/client-preset": "^1.3.0", "@graphql-codegen/client-preset": "^1.3.0",
"@graphql-typed-document-node/core": "^3.2.0", "@graphql-typed-document-node/core": "^3.2.0",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^3.1.0", "@vitejs/plugin-react": "^3.1.0",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^5.0.12" "vite": "^5.1.4"
} }
} }

View File

@@ -1,5 +1,11 @@
# @nhost-examples/docker-compose # @nhost-examples/docker-compose
## 0.2.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 0.1.1 ## 0.1.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/docker-compose", "name": "@nhost-examples/docker-compose",
"version": "0.1.1", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"e2e": "vitest run" "e2e": "vitest run"

View File

@@ -1,76 +1,7 @@
import { exec } from 'child_process' import { describe, it } from 'vitest'
import fetch from 'cross-fetch'
import { promisify } from 'util'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
const promisifiedExec = promisify(exec) describe('Empty Test Suite', () => {
it('Empty Test', async () => {
describe( // This test does nothing and will always pass
'docker-compose should start, work and stop', })
() => { })
beforeAll(async () => {
// * Start docker compose
await promisifiedExec(
'docker compose -f docker-compose.yaml --env-file .env.example up --wait --wait-timeout 300 --quiet-pull'
)
// we wait a bit extra because sometimes traefik takes a bit to configure the services
setTimeout(() => {}, 30000);
}, 5 * 60 * 1000)
afterAll(async () => {
// * Stop docker compose
await promisifiedExec('docker compose -f docker-compose.yaml --env-file .env.example down')
}, 5 * 60 * 1000)
it(
'Hasura',
async () => {
await expect(
fetch('http://localhost:1337/healthz').then((res) => res.status)
).resolves.toEqual(200)
},
{ retry: 60, timeout: 1000 }
)
it(
'Hasura auth',
async () => {
await expect(
fetch('http://localhost:1337/v1/auth/healthz').then((res) => res.status)
).resolves.toEqual(200)
},
{ retry: 60, timeout: 1000 }
)
it(
'Hasura storage',
async () => {
await expect(
fetch('http://localhost:1337/v1/storage/version').then((res) => res.status)
).resolves.toEqual(200)
},
{ retry: 60, timeout: 1000 }
)
it(
'Serverless functions',
async () => {
await expect(
fetch('http://localhost:1337/v1/functions/hello').then((res) => res.status)
).resolves.toEqual(200)
},
{ retry: 60, timeout: 1000 }
)
it(
'Dashboard',
async () => {
await expect(fetch('http://localhost:3030').then((res) => res.status)).resolves.toEqual(200)
},
{ retry: 60, timeout: 1000 }
)
},
{ timeout: 5 * 60 * 1000 }
)

View File

@@ -1,5 +1,21 @@
# @nhost-examples/multi-tenant-one-to-many # @nhost-examples/multi-tenant-one-to-many
## 2.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 2.0.7
### Patch Changes
- @nhost/nhost-js@3.0.8
## 2.0.6 ## 2.0.6
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "@nhost-examples/multi-tenant-one-to-many", "name": "@nhost-examples/multi-tenant-one-to-many",
"private": true, "private": true,
"version": "2.0.6", "version": "2.1.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": {}, "scripts": {},
@@ -10,7 +10,7 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"express": "^4.18.2", "express": "^4.18.3",
"typescript": "^4.9.5" "typescript": "^4.9.5"
}, },
"dependencies": { "dependencies": {

View File

@@ -1,5 +1,26 @@
# @nhost-examples/nextjs # @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
## 0.1.19
### Patch Changes
- @nhost/react@3.2.3
- @nhost/react-apollo@9.0.3
- @nhost/nextjs@2.1.5
## 0.1.18 ## 0.1.18
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/nextjs", "name": "@nhost-examples/nextjs",
"version": "0.1.18", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@@ -15,7 +15,7 @@
"verify:fix": "run-p prettier:fix lint:fix" "verify:fix": "run-p prettier:fix lint:fix"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@mantine/core": "^4.2.12", "@mantine/core": "^4.2.12",
"@mantine/hooks": "^4.2.12", "@mantine/hooks": "^4.2.12",
"@mantine/next": "^4.2.12", "@mantine/next": "^4.2.12",
@@ -31,8 +31,8 @@
}, },
"devDependencies": { "devDependencies": {
"@next/bundle-analyzer": "^12.3.4", "@next/bundle-analyzer": "^12.3.4",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@xstate/inspect": "^0.6.5", "@xstate/inspect": "^0.6.5",
"eslint-config-next": "12.0.10", "eslint-config-next": "12.0.10",
"typescript": "^4.9.5", "typescript": "^4.9.5",

View File

@@ -1,5 +1,21 @@
# @nhost-examples/node-storage # @nhost-examples/node-storage
## 0.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.0.11
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.0.10 ## 0.0.10
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/node-storage", "name": "@nhost-examples/node-storage",
"version": "0.0.10", "version": "0.1.0",
"private": true, "private": true,
"description": "This is an example of how to use the Storage with Node.js", "description": "This is an example of how to use the Storage with Node.js",
"main": "src/index.mjs", "main": "src/index.mjs",
@@ -12,14 +12,14 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@nhost/nhost-js": "workspace:^", "@nhost/nhost-js": "workspace:^",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"uuid": "^9.0.1" "uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^18.19.12", "@types/node": "^18.19.21",
"@types/uuid": "^9.0.8" "@types/uuid": "^9.0.8"
} }
} }

View File

@@ -1,5 +1,21 @@
# @nhost-examples/nextjs-server-components # @nhost-examples/nextjs-server-components
## 0.3.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.2.5
### Patch Changes
- @nhost/nhost-js@3.0.8
## 0.2.4 ## 0.2.4
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/nextjs-server-components", "name": "@nhost-examples/nextjs-server-components",
"version": "0.2.4", "version": "0.3.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@@ -9,7 +9,7 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@nhost/nhost-js": "workspace:^", "@nhost/nhost-js": "workspace:^",
"autoprefixer": "10.4.15", "autoprefixer": "10.4.15",
"cookies-next": "^3.0.0", "cookies-next": "^3.0.0",
@@ -19,7 +19,7 @@
"graphql": "16.8.1", "graphql": "16.8.1",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "^14.1.0", "next": "^14.1.0",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",
@@ -30,7 +30,7 @@
"devDependencies": { "devDependencies": {
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/node": "20.5.6", "@types/node": "20.5.6",
"@types/react": "^18.2.47", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.7" "@types/react-dom": "^18.2.19"
} }
} }

View File

@@ -1,5 +1,10 @@
--- ---
## 0.3.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 0.2.3 ## 0.2.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/sveltekit", "name": "@nhost-examples/sveltekit",
"version": "0.2.3", "version": "0.3.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
@@ -16,22 +16,22 @@
}, },
"devDependencies": { "devDependencies": {
"@nhost/nhost-js": "2.2.18", "@nhost/nhost-js": "2.2.18",
"@playwright/test": "^1.41.1", "@playwright/test": "^1.42.0",
"@sveltejs/adapter-auto": "^2.1.1", "@sveltejs/adapter-auto": "^2.1.1",
"@sveltejs/kit": "^1.30.3", "@sveltejs/kit": "^1.30.4",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0", "eslint-config-prettier": "^8.10.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^2.35.1",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.1", "prettier-plugin-svelte": "^2.10.1",
"svelte": "^3.59.2", "svelte": "^3.59.2",
"svelte-check": "^3.6.3", "svelte-check": "^3.6.6",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.12", "vite": "^5.1.4",
"vitest": "^0.25.8" "vitest": "^0.25.8"
}, },
"type": "module", "type": "module",

View File

@@ -1,5 +1,30 @@
# @nhost-examples/react-apollo # @nhost-examples/react-apollo
## 0.4.1
### Patch Changes
- 4f3fb34: fix: set redirectTo when doing sign in with github and include vercel previews in allowed redirect URLs
## 0.4.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/react-apollo@10.0.0
- @nhost/react@3.3.0
## 0.3.3
### Patch Changes
- @nhost/react@3.2.3
- @nhost/react-apollo@9.0.3
## 0.3.2 ## 0.3.2
### Patch Changes ### Patch Changes

View File

@@ -35,7 +35,7 @@ mode = 'required'
[auth.redirections] [auth.redirections]
clientUrl = 'https://react-apollo.example.nhost.io/' clientUrl = 'https://react-apollo.example.nhost.io/'
allowedUrls = ['https://react-apollo.example.nhost.io/profile', 'http://localhost:3000'] allowedUrls = ['https://react-apollo.example.nhost.io/profile', 'https://vue-apollo.example.nhost.io/profile', 'https://*.vercel.app','http://localhost:3000']
[auth.signUp] [auth.signUp]
enabled = true enabled = true

View File

@@ -1,9 +1,9 @@
{ {
"name": "@nhost-examples/react-apollo", "name": "@nhost-examples/react-apollo",
"version": "0.3.2", "version": "0.4.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@mantine/core": "^4.2.12", "@mantine/core": "^4.2.12",
"@mantine/dropzone": "^4.2.12", "@mantine/dropzone": "^4.2.12",
"@mantine/hooks": "^4.2.12", "@mantine/hooks": "^4.2.12",
@@ -15,8 +15,8 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-router": "^6.21.3", "react-router": "^6.22.2",
"react-router-dom": "^6.21.3", "react-router-dom": "^6.22.2",
"tabler-icons-react": "^1.56.0" "tabler-icons-react": "^1.56.0"
}, },
"scripts": { "scripts": {
@@ -54,17 +54,17 @@
"@nuintun/qrcode": "^3.4.0", "@nuintun/qrcode": "^3.4.0",
"@playwright/test": "1.31.0", "@playwright/test": "1.31.0",
"@types/pngjs": "^6.0.4", "@types/pngjs": "^6.0.4",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@types/totp-generator": "^0.0.4", "@types/totp-generator": "^0.0.4",
"@vitejs/plugin-react": "^3.1.0", "@vitejs/plugin-react": "^3.1.0",
"@xstate/inspect": "^0.6.5", "@xstate/inspect": "^0.6.5",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"pngjs": "^7.0.0", "pngjs": "^7.0.0",
"totp-generator": "^0.0.13", "totp-generator": "^0.0.13",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^5.0.12", "vite": "^5.1.4",
"ws": "^8.16.0", "ws": "^8.16.0",
"xstate": "^4.38.3" "xstate": "^4.38.3"
} }

View File

@@ -1,5 +1,22 @@
# @nhost-examples/react-gqty # @nhost-examples/react-gqty
## 1.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/react@3.3.0
## 1.0.7
### Patch Changes
- @nhost/react@3.2.3
## 1.0.6 ## 1.0.6
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "@nhost-examples/react-gqty", "name": "@nhost-examples/react-gqty",
"private": true, "private": true,
"version": "1.0.6", "version": "1.1.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -20,13 +20,13 @@
"devDependencies": { "devDependencies": {
"@gqty/cli": "3.3.0-alpha-d8cdbf6.0", "@gqty/cli": "3.3.0-alpha-d8cdbf6.0",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^3.1.0", "@vitejs/plugin-react": "^3.1.0",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^5.0.12" "vite": "^5.1.4"
} }
} }

View File

@@ -1,5 +1,16 @@
# @nhost-examples/serverless-functions # @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
## 0.0.11 ## 0.0.11
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "@nhost-examples/serverless-functions", "name": "@nhost-examples/serverless-functions",
"private": true, "private": true,
"version": "0.0.11", "version": "0.1.0",
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.21" "@types/express": "^4.17.21"
}, },
@@ -11,7 +11,7 @@
"@pothos/core": "^3.41.0", "@pothos/core": "^3.41.0",
"cross-fetch": "^3.1.8", "cross-fetch": "^3.1.8",
"graphql": "16.8.1", "graphql": "16.8.1",
"nodemailer": "^6.9.9", "nodemailer": "^6.9.11",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"stripe": "^11.18.0" "stripe": "^11.18.0"
} }

View File

@@ -1,5 +1,32 @@
# @nhost-examples/vue-apollo # @nhost-examples/vue-apollo
## 0.3.1
### Patch Changes
- 4f3fb34: fix: set redirectTo when doing sign in with github and include vercel previews in allowed redirect URLs
## 0.3.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/apollo@6.1.0
- @nhost/vue@2.3.0
- @nhost/nhost-js@3.0.8
## 0.2.4
### Patch Changes
- @nhost/nhost-js@3.0.8
- @nhost/apollo@6.0.8
- @nhost/vue@2.2.3
## 0.2.3 ## 0.2.3
### Patch Changes ### Patch Changes

View File

@@ -35,7 +35,7 @@ mode = 'required'
[auth.redirections] [auth.redirections]
clientUrl = 'https://vue-apollo.example.nhost.io' clientUrl = 'https://vue-apollo.example.nhost.io'
allowedUrls = ['https://vue-apollo.example.nhost.io/profile', 'http://localhost:5173'] allowedUrls = ['https://vue-apollo.example.nhost.io/profile', 'https://react-apollo.example.nhost.io/profile', 'https://*.vercel.app','http://localhost:5173']
[auth.signUp] [auth.signUp]
enabled = true enabled = true

View File

@@ -1,7 +1,7 @@
{ {
"name": "@nhost-examples/vue-apollo", "name": "@nhost-examples/vue-apollo",
"private": true, "private": true,
"version": "0.2.3", "version": "0.3.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
@@ -14,7 +14,7 @@
"verify:fix": "run-p prettier:fix lint:fix" "verify:fix": "run-p prettier:fix lint:fix"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@mdi/font": "5.9.55", "@mdi/font": "5.9.55",
"@nhost/apollo": "workspace:^", "@nhost/apollo": "workspace:^",
"@nhost/nhost-js": "workspace:^", "@nhost/nhost-js": "workspace:^",
@@ -24,8 +24,8 @@
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
"vite-plugin-vuetify": "^1.0.2", "vite-plugin-vuetify": "^1.0.2",
"vue": "^3.4.15", "vue": "^3.4.21",
"vue-router": "^4.2.5", "vue-router": "^4.3.0",
"vue3-dropzone": "^2.2.1", "vue3-dropzone": "^2.2.1",
"vuetify": "3.0.0-beta.10", "vuetify": "3.0.0-beta.10",
"webfontloader": "^1.6.28" "webfontloader": "^1.6.28"
@@ -37,7 +37,7 @@
"@xstate/inspect": "^0.6.5", "@xstate/inspect": "^0.6.5",
"sass": "1.32.0", "sass": "1.32.0",
"typescript": "4.9.4", "typescript": "4.9.4",
"vite": "^5.0.12", "vite": "^5.1.4",
"vue-tsc": "^0.38.9" "vue-tsc": "^0.38.9"
}, },
"eslintConfig": { "eslintConfig": {

View File

@@ -15,5 +15,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useProviderLink } from '@nhost/vue' import { useProviderLink } from '@nhost/vue'
const { github } = useProviderLink({ redirectTo: '/' }) const { github } = useProviderLink({ redirectTo: window.location.origin })
</script> </script>

View File

@@ -1,5 +1,24 @@
# @nhost-examples/vue-quickstart # @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
## 0.0.16
### Patch Changes
- @nhost/apollo@6.0.8
- @nhost/vue@2.2.3
## 0.0.15 ## 0.0.15
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/vue-quickstart", "name": "@nhost-examples/vue-quickstart",
"version": "0.0.15", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -11,31 +11,31 @@
"test": "vitest" "test": "vitest"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@nhost/apollo": "workspace:^", "@nhost/apollo": "workspace:^",
"@nhost/vue": "workspace:^", "@nhost/vue": "workspace:^",
"@vue/apollo-composable": "4.0.0-alpha.18", "@vue/apollo-composable": "4.0.0-alpha.18",
"@vueuse/core": "^8.9.4", "@vueuse/core": "^8.9.4",
"graphql": "16.8.1", "graphql": "16.8.1",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"vue": "^3.4.15", "vue": "^3.4.21",
"vue-router": "^4.2.5" "vue-router": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^0.23.1", "@antfu/eslint-config": "^0.23.1",
"@iconify-json/carbon": "^1.1.28", "@iconify-json/carbon": "^1.1.30",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@unocss/reset": "^0.33.5", "@unocss/reset": "^0.33.5",
"@vitejs/plugin-vue": "^4.6.2", "@vitejs/plugin-vue": "^4.6.2",
"@vue/test-utils": "^2.4.4", "@vue/test-utils": "^2.4.4",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"jsdom": "^19.0.0", "jsdom": "^19.0.0",
"pnpm": "^7.33.6", "pnpm": "^7.33.7",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"unocss": "^0.33.5", "unocss": "^0.33.5",
"unplugin-auto-import": "^0.17.5", "unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0", "unplugin-vue-components": "^0.26.0",
"vite": "^5.0.12", "vite": "^5.1.4",
"vite-plugin-pages": "^0.28.0", "vite-plugin-pages": "^0.28.0",
"vue-tsc": "^0.38.9" "vue-tsc": "^0.38.9"
} }

12
flake.lock generated
View File

@@ -40,11 +40,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1706370404, "lastModified": 1709101436,
"narHash": "sha256-AVvfQjv6hqGYEBoMQZrKpNP6Rpt+wHqZ4Ua3wHCkyHE=", "narHash": "sha256-77w34voAwaCYDnXTpe6cXDDFEMOcXbAhXWsO38YUHmE=",
"owner": "nhost", "owner": "nhost",
"repo": "nixops", "repo": "nixops",
"rev": "87f104eaf826981e6352daa1fb14e4f363ceee96", "rev": "9ae747fefe6bb611d115de2f5d2a04a22dc324b2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -55,11 +55,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1706173671, "lastModified": 1708943256,
"narHash": "sha256-lciR7kQUK2FCAYuszyd7zyRRmTaXVeoZsCyK6QFpGdk=", "narHash": "sha256-K9VeHrhXsigdhNMZ8hqAk7jtRy4ollqhkYYNZqbfssg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4fddc9be4eaf195d631333908f2a454b03628ee5", "rev": "fcea2b6260dd566c28c894b4207a5f2b56c2cba3",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -1,5 +1,21 @@
# @nhost/apollo # @nhost/apollo
## 6.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 6.0.8
### Patch Changes
- @nhost/nhost-js@3.0.8
## 6.0.7 ## 6.0.7
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/apollo", "name": "@nhost/apollo",
"version": "6.0.7", "version": "6.1.0",
"description": "Nhost Apollo Client library", "description": "Nhost Apollo Client library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -65,11 +65,11 @@
}, },
"dependencies": { "dependencies": {
"graphql": "16.8.1", "graphql": "16.8.1",
"graphql-ws": "^5.14.3", "graphql-ws": "^5.15.0",
"jwt-decode": "^3.1.2" "jwt-decode": "^3.1.2"
}, },
"devDependencies": { "devDependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@nhost/nhost-js": "workspace:*" "@nhost/nhost-js": "workspace:*"
} }
} }

View File

@@ -1,5 +1,11 @@
# @nhost/google-translation # @nhost/google-translation
## 0.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 0.0.8 ## 0.0.8
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/google-translation", "name": "@nhost/google-translation",
"version": "0.0.8", "version": "0.1.0",
"description": "Google Translation GraphQL API", "description": "Google Translation GraphQL API",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -48,8 +48,8 @@
"graphql-request": "^6.1.0" "graphql-request": "^6.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"typescript": "^4.9.5" "typescript": "^4.9.5"
} }
} }

View File

@@ -1,5 +1,24 @@
# @nhost/react-apollo # @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
## 9.0.3
### Patch Changes
- @nhost/apollo@6.0.8
- @nhost/react@3.2.3
## 9.0.2 ## 9.0.2
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/react-apollo", "name": "@nhost/react-apollo",
"version": "9.0.2", "version": "10.0.0",
"description": "Nhost React Apollo client", "description": "Nhost React Apollo client",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -71,9 +71,9 @@
"react-dom": "^17.0.0 || ^18.0.0" "react-dom": "^17.0.0 || ^18.0.0"
}, },
"devDependencies": { "devDependencies": {
"@apollo/client": "^3.9.4", "@apollo/client": "^3.9.5",
"@nhost/react": "workspace:*", "@nhost/react": "workspace:*",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"graphql": "16.8.1", "graphql": "16.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0"

View File

@@ -1,5 +1,22 @@
# @nhost/react-urql # @nhost/react-urql
## 7.0.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/react@3.3.0
## 6.0.3
### Patch Changes
- @nhost/react@3.2.3
## 6.0.2 ## 6.0.2
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/react-urql", "name": "@nhost/react-urql",
"version": "6.0.2", "version": "7.0.0",
"description": "Nhost React URQL client", "description": "Nhost React URQL client",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -61,7 +61,7 @@
"dependencies": { "dependencies": {
"@urql/devtools": "^2.0.3", "@urql/devtools": "^2.0.3",
"@urql/exchange-refocus": "^1.0.2", "@urql/exchange-refocus": "^1.0.2",
"graphql-ws": "^5.14.3" "graphql-ws": "^5.15.0"
}, },
"peerDependencies": { "peerDependencies": {
"@nhost/react": "workspace:*", "@nhost/react": "workspace:*",
@@ -72,7 +72,7 @@
}, },
"devDependencies": { "devDependencies": {
"@nhost/react": "workspace:*", "@nhost/react": "workspace:*",
"@types/react": "^18.2.50", "@types/react": "^18.2.61",
"graphql": "16.8.1", "graphql": "16.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

View File

@@ -1,5 +1,11 @@
# @nhost/stripe-graphql-js # @nhost/stripe-graphql-js
## 1.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 1.0.7 ## 1.0.7
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/stripe-graphql-js", "name": "@nhost/stripe-graphql-js",
"version": "1.0.7", "version": "1.1.0",
"description": "Stripe GraphQL API", "description": "Stripe GraphQL API",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -42,15 +42,15 @@
"dependencies": { "dependencies": {
"@pothos/core": "^3.41.0", "@pothos/core": "^3.41.0",
"graphql": "16.8.1", "graphql": "16.8.1",
"graphql-scalars": "^1.22.4", "graphql-scalars": "^1.22.5",
"graphql-yoga": "^3.9.1", "graphql-yoga": "^3.9.1",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"stripe": "^11.18.0" "stripe": "^11.18.0"
}, },
"devDependencies": { "devDependencies": {
"@types/jsonwebtoken": "^9.0.5", "@types/jsonwebtoken": "^9.0.6",
"@types/node": "^18.19.12", "@types/node": "^18.19.21",
"dotenv": "^16.4.1", "dotenv": "^16.4.5",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"typescript": "^4.9.5" "typescript": "^4.9.5"
} }

View File

@@ -54,20 +54,20 @@
"dashboard" "dashboard"
], ],
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.9", "@babel/core": "^7.24.0",
"@babel/eslint-parser": "^7.23.10", "@babel/eslint-parser": "^7.23.10",
"@babel/plugin-syntax-flow": "^7.23.3", "@babel/plugin-syntax-flow": "^7.23.3",
"@babel/plugin-transform-react-jsx": "^7.23.4", "@babel/plugin-transform-react-jsx": "^7.23.4",
"@changesets/cli": "^2.27.1", "@changesets/cli": "^2.27.1",
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-replace": "^5.0.5",
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0", "@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^0.32.4", "@vitest/coverage-v8": "^0.32.4",
"audit-ci": "^6.6.1", "audit-ci": "^6.6.1",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.1",
@@ -76,15 +76,15 @@
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-vue": "^9.21.1", "eslint-plugin-vue": "^9.22.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"turbo": "1.11.3", "turbo": "1.11.3",
"typedoc": "^0.22.18", "typedoc": "^0.22.18",
"typescript": "4.9.5", "typescript": "4.9.5",
"vite": "^5.0.12", "vite": "^5.1.4",
"vite-plugin-dts": "^3.7.2", "vite-plugin-dts": "^3.7.3",
"vite-tsconfig-paths": "^4.3.1", "vite-tsconfig-paths": "^4.3.1",
"vitest": "^0.32.4" "vitest": "^0.32.4"
}, },

View File

@@ -1,5 +1,11 @@
# @nhost/docgen # @nhost/docgen
## 0.2.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 0.1.13 ## 0.1.13
### Patch Changes ### Patch Changes

View File

@@ -2,7 +2,7 @@
"name": "@nhost/docgen", "name": "@nhost/docgen",
"description": "Documentation generator for classes and functions", "description": "Documentation generator for classes and functions",
"private": true, "private": true,
"version": "0.1.13", "version": "0.2.0",
"license": "MIT", "license": "MIT",
"main": "dist/index.cjs.js", "main": "dist/index.cjs.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@@ -33,7 +33,7 @@
"docgen": "dist/index.js" "docgen": "dist/index.js"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^16.18.78", "@types/node": "^16.18.86",
"@types/prettier": "^2.7.3", "@types/prettier": "^2.7.3",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"typescript": "^4.9.5" "typescript": "^4.9.5"
@@ -43,6 +43,6 @@
"commander": "^11.1.0", "commander": "^11.1.0",
"just-kebab-case": "^4.2.0", "just-kebab-case": "^4.2.0",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"valtio": "^1.13.0" "valtio": "^1.13.1"
} }
} }

View File

@@ -1,5 +1,11 @@
# @nhost/graphql-js # @nhost/graphql-js
## 0.1.8
### Patch Changes
- 407feea: fix: replace `jwt-decode` with `jose` to decode access tokens in a non browser environment
## 0.1.7 ## 0.1.7
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/graphql-js", "name": "@nhost/graphql-js",
"version": "0.1.7", "version": "0.1.8",
"description": "Nhost GraphQL client", "description": "Nhost GraphQL client",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
@@ -55,7 +55,7 @@
"dependencies": { "dependencies": {
"@graphql-typed-document-node/core": "^3.2.0", "@graphql-typed-document-node/core": "^3.2.0",
"isomorphic-unfetch": "^3.1.0", "isomorphic-unfetch": "^3.1.0",
"jwt-decode": "^3.1.2" "jose": "^5.2.2"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"

View File

@@ -12,7 +12,7 @@ import {
Variables Variables
} from './types' } from './types'
import jwtDecode, { JwtPayload } from 'jwt-decode' import * as jose from 'jose'
/** /**
* @alias GraphQL * @alias GraphQL
@@ -36,7 +36,7 @@ export class NhostGraphqlClient {
} }
try { try {
const decodedToken: JwtPayload = jwtDecode(this.accessToken) const decodedToken = jose.decodeJwt<jose.JWTPayload>(this.accessToken)
return decodedToken.exp != null && decodedToken.exp * 1000 > Date.now() return decodedToken.exp != null && decodedToken.exp * 1000 > Date.now()
} catch (error) { } catch (error) {
console.error('Error decoding token:', error) console.error('Error decoding token:', error)

View File

@@ -1,5 +1,18 @@
# @nhost/nextjs # @nhost/nextjs
## 2.1.6
### Patch Changes
- Updated dependencies [49a80c2]
- @nhost/react@3.3.0
## 2.1.5
### Patch Changes
- @nhost/react@3.2.3
## 2.1.4 ## 2.1.4
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/nextjs", "name": "@nhost/nextjs",
"version": "2.1.4", "version": "2.1.6",
"description": "Nhost NextJS library", "description": "Nhost NextJS library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,5 +1,12 @@
# @nhost/nhost-js # @nhost/nhost-js
## 3.0.8
### Patch Changes
- Updated dependencies [407feea]
- @nhost/graphql-js@0.1.8
## 3.0.7 ## 3.0.7
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/nhost-js", "name": "@nhost/nhost-js",
"version": "3.0.7", "version": "3.0.8",
"description": "Nhost JavaScript SDK", "description": "Nhost JavaScript SDK",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,5 +1,21 @@
# @nhost/react # @nhost/react
## 3.3.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 3.2.3
### Patch Changes
- @nhost/nhost-js@3.0.8
## 3.2.2 ## 3.2.2
### Patch Changes ### Patch Changes

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