Compare commits

..

11 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
94 changed files with 4366 additions and 3879 deletions

View File

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

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

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

View File

@@ -1,5 +1,26 @@
# @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

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,15 @@ import type {
DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser';
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 {
Children,
cloneElement,
@@ -308,7 +316,7 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
isEditable &&
'focus-within:outline-none focus-within:ring-0 focus:ring-0',
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,
)}
onFocus={handleFocus}
@@ -320,20 +328,28 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
sx={{ backgroundColor: 'transparent' }}
{...props}
>
{Children.map(children, (child: ReactNode | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>>) => {
if (!isValidElement(child)) {
return null;
}
{Children.map(
children,
(
child:
| ReactNode
| ReactPortal
| ReactElement<unknown, string | JSXElementConstructor<any>>,
) => {
if (!isValidElement(child)) {
return null;
}
return cloneElement(child, {
...child.props,
onSave: handleSave,
optimisticValue,
onOptimisticValueChange: setOptimisticValue,
temporaryValue,
onTemporaryValueChange: setTemporaryValue,
});
})}
return cloneElement(child, {
...child.props,
onSave: handleSave,
optimisticValue,
onOptimisticValueChange: setOptimisticValue,
temporaryValue,
onTemporaryValueChange: setTemporaryValue,
});
},
)}
</Box>
);

View File

@@ -1,6 +1,6 @@
import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon';
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 Button from './Button';
@@ -24,9 +24,9 @@ export default {
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,
) {
return <Button {...args} />;

View File

@@ -1,5 +1,5 @@
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 Select from './Select';
@@ -7,11 +7,9 @@ export default {
title: 'UI Library / Select',
component: Select,
argTypes: {},
} as ComponentMeta<typeof Select>;
} as Meta<typeof Select>;
const Template: ComponentStory<typeof Select> = function Template(
args: SelectProps<any>,
) {
const Template: StoryFn<SelectProps<any>> = function TemplateFunction(args) {
return (
<Select className="w-64" {...args}>
<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 Switch from './Switch';
@@ -6,9 +6,9 @@ export default {
title: 'UI Library / Switch',
component: Switch,
argTypes: {},
} as ComponentMeta<typeof Switch>;
} as Meta<typeof Switch>;
const Template: ComponentStory<typeof Switch> = function Template(
const Template: StoryFn<SwitchProps> = function TemplateFunction(
args: SwitchProps,
) {
return <Switch label="Accept Rules" {...args} />;

View File

@@ -21,13 +21,17 @@ import {
useUpdateConfigMutation,
} from '@/generated/graphql';
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
import { getToastStyleProps } from '@/utils/constants/settings';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup';
import { DisableAIServiceConfirmationDialog } from './DisableAIServiceConfirmationDialog';
const MIN_POSTGRES_VERSION_SUPPORTING_AI = '14.6-20231018-1';
const validationSchema = Yup.object({
version: Yup.object({
label: Yup.string().required(),
@@ -54,7 +58,9 @@ export default function AISettings() {
const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
const {
data: { config: { ai } = {} } = {},
data: {
config: { ai, postgres: { version: postgresVersion } = {} } = {},
} = {},
loading: loadingAiSettings,
error: errorGettingAiSettings,
} = useGetAiSettingsQuery({
@@ -150,6 +156,17 @@ export default function AISettings() {
]);
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);
if (!enabled && ai) {

View File

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

View File

@@ -275,7 +275,7 @@ export default function DataBrowserGrid({
() =>
columns
.map((column) => ({
...createDataGridColumn(column, isSchemaEditable),
...createDataGridColumn(column, true),
onCellEdit: async (variables: UpdateRecordVariables) => {
const result = await updateRow(variables);
await queryClient.invalidateQueries([currentTablePath]);
@@ -288,7 +288,6 @@ export default function DataBrowserGrid({
[
columns,
currentTablePath,
isSchemaEditable,
optimisticlyRemovedColumnId,
queryClient,
removableColumnId,
@@ -422,7 +421,7 @@ export default function DataBrowserGrid({
loading={status === 'loading'}
sortBy={sortBy}
className="pb-17 sm:pb-0"
onInsertRow={isSchemaEditable ? handleInsertRowClick : undefined}
onInsertRow={handleInsertRowClick}
onInsertColumn={isSchemaEditable ? handleInsertColumnClick : undefined}
onEditColumn={isSchemaEditable ? handleEditColumnClick : undefined}
onRemoveColumn={isSchemaEditable ? handleColumnRemoveClick : undefined}
@@ -445,7 +444,7 @@ export default function DataBrowserGrid({
onInsertColumnClick={
isSchemaEditable ? handleInsertColumnClick : undefined
}
onInsertRowClick={isSchemaEditable ? handleInsertRowClick : undefined}
onInsertRowClick={handleInsertRowClick}
paginationProps={{
currentPage: Math.max(currentPage, 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 { useDeleteRecordMutation } from '@/features/database/dataGrid/hooks/useDeleteRecordMutation';
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 { triggerToast } from '@/utils/toast';
import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useState } from 'react';
import type { Row } from 'react-table';
import { twMerge } from 'tailwind-merge';
@@ -58,11 +56,6 @@ export default function DataBrowserGridControls({
const { className: paginationClassName, ...restPaginationProps } =
paginationProps || ({} as DataGridPaginationProps);
const {
query: { schemaSlug },
} = useRouter();
const isSchemaEditable = !isSchemaLocked(schemaSlug as string);
const {
selectedFlatRows: selectedRows,
columns,
@@ -126,7 +119,7 @@ export default function DataBrowserGridControls({
numberOfSelectedRows > 0 ? 'justify-between' : 'justify-end',
)}
>
{isSchemaEditable && numberOfSelectedRows > 0 && (
{numberOfSelectedRows > 0 && (
<div className="grid grid-flow-col place-content-start items-center gap-2">
<Chip
size="small"

View File

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

View File

@@ -131,7 +131,7 @@ export default function LogsBody({ logsData, loading, error }: LogsBodyProps) {
count: rows.length,
getScrollElement: () => tableRef.current,
estimateSize: () => 63,
overscan: 5,
overscan: 50,
});
if (loading && !error) {
@@ -214,7 +214,7 @@ export default function LogsBody({ logsData, loading, error }: LogsBodyProps) {
<TableCell
key={cell.id}
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={{
width: cell.column.getSize() || 'auto',
minWidth: !cell.column.getSize() ? 300 : 'initial',

View File

@@ -52,7 +52,7 @@ function LogsDatePicker({
<Text
htmlFor={label}
component="label"
className="self-center text-sm+ font-normal"
className="min-w-14 self-center text-sm+ font-normal"
color="secondary"
>
{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 { Box } from '@/components/ui/v2/Box';
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 { Select } from '@/components/ui/v2/Select';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { LogsDatePicker } from '@/features/projects/logs/components/LogsDatePicker';
import type { LogsCustomInterval } from '@/features/projects/logs/utils/constants/intervals';
import { LOGS_AVAILABLE_INTERVALS } from '@/features/projects/logs/utils/constants/intervals';
import type { AvailableLogsService } from '@/features/projects/logs/utils/constants/services';
import { LOGS_AVAILABLE_SERVICES } from '@/features/projects/logs/utils/constants/services';
import { useGetRunServicesQuery } from '@/utils/__generated__/graphql';
import { LogsRangeSelector } from '@/features/projects/logs/components/LogsRangeSelector';
import { AvailableLogsService } from '@/features/projects/logs/utils/constants/services';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { useGetServiceLabelValuesQuery } from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { subMinutes } from 'date-fns';
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;
/**
* 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>
);
onSubmitFilterValues: (value: LogsFilterFormValues) => void;
}
export default function LogsHeader({
fromDate,
toDate,
service,
onFromDateChange,
onToDateChange,
onServiceChange,
loading,
onSubmitFilterValues,
...props
}: LogsHeaderProps) {
const { currentProject } = useCurrentWorkspaceAndProject();
const applicationCreationDate = new Date(currentProject.createdAt);
const [runServices, setRunServices] = useState<
{
label: string;
value: string;
}[]
const [serviceLabels, setServiceLabels] = useState<
{ label: string; value: string }[]
>([]);
const { data, loading } = useGetRunServicesQuery({
variables: {
appID: currentProject.id,
resolve: false,
limit: 1000,
offset: 0,
},
});
const { data, loading: loadingServiceLabelValues } =
useGetServiceLabelValuesQuery({
variables: { appID: currentProject.id },
});
useEffect(() => {
if (!loading) {
const services = data.app?.runServices ?? [];
if (!loadingServiceLabelValues) {
const labels = data.getServiceLabelValues ?? [];
setServiceLabels(labels.map((l) => ({ label: l, value: l })));
}
}, [loadingServiceLabelValues, data]);
setRunServices(
services
.filter((s) => !!s.config?.name)
.map((s) => ({
label: s.config.name,
value: `run-${s.config.name}`,
})),
useEffect(() => {
if (!loadingServiceLabelValues) {
const labels = data.getServiceLabelValues ?? [];
const labelMappings = {
'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]);
/**
* Will subtract the `customInterval` time in minutes from the current date.
*/
function handleIntervalChange({
minutesToDecreaseFromCurrentDate,
}: LogsCustomInterval) {
onFromDateChange(subMinutes(new Date(), minutesToDecreaseFromCurrentDate));
onToDateChange(new Date());
}
const form = useForm<LogsFilterFormValues>({
defaultValues: {
from: subMinutes(new Date(), MINUTES_TO_DECREASE_FROM_CURRENT_DATE),
to: new Date(),
regexFilter: '',
service: AvailableLogsService.ALL,
},
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 (
<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}
>
<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">
<div className="grid grid-flow-col items-center gap-3 md:justify-start">
<LogsDatePicker
label="From"
value={fromDate}
onChange={onFromDateChange}
minDate={applicationCreationDate}
maxDate={toDate || new Date()}
/>
<FormProvider {...form}>
<Form
onSubmit={handleSubmit}
className="grid w-full grid-flow-row items-center gap-2 md:w-[initial] md:grid-flow-col md:gap-3 lg:justify-end"
>
<Box className="flex flex-row space-x-2">
<ControlledSelect
{...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
fromDate={fromDate}
toDate={toDate}
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"
<Input
{...register('regexFilter')}
placeholder="Filter logs with a regular expression"
hideEmptyHelperText
slotProps={{
root: { className: 'min-h-[initial] h-9 leading-[initial]' },
}}
>
{[...LOGS_AVAILABLE_SERVICES, ...runServices].map(
({ value, label }) => (
<Option
key={value}
value={value}
className="text-sm+ font-medium"
>
{label}
</Option>
),
)}
</Select>
</Box>
</Box>
autoComplete="off"
fullWidth
className="min-w-80"
startAdornment={
<Tooltip
componentsProps={{
tooltip: {
sx: {
maxWidth: '30rem',
},
},
}}
title={
<div className="p-2 space-y-4">
<h2>Here are some useful regular expressions:</h2>
<ul className="pl-3 space-y-2 list-disc">
<li>
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
key={logInterval.label}
variant="outlined"
color="secondary"
className="self-center"
onClick={() => handleIntervalChange(logInterval)}
type="submit"
className="h-10"
startIcon={
loading ? (
<ActivityIndicator className="w-4 h-4" />
) : (
<SearchIcon />
)
}
disabled={loading}
>
{logInterval.label}
Search
</Button>
))}
</Box>
</Form>
</FormProvider>
</Box>
);
}

View File

@@ -1,2 +1 @@
export * from './LogsHeader';
export { default as LogsHeader } from './LogsHeader';
export { default as LogsHeader, type LogsFilterFormValues } 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 variant="contained" color="primary" onClick={handleApply}>
Apply
Set
</Button>
</Box>
</div>

View File

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

View File

@@ -38,6 +38,7 @@ import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { parse } from 'shell-quote';
import { HealthCheckFormSection } from './components/HealthCheckFormSection';
import { ServiceConfirmationDialog } from './components/ServiceConfirmationDialog';
import { ServiceDetailsDialog } from './components/ServiceDetailsDialog';
@@ -118,6 +119,13 @@ export default function ServiceForm({
type: item.type,
publish: item.publish,
})),
healthCheck: values.healthCheck
? {
port: values.healthCheck?.port,
initialDelaySeconds: values.healthCheck?.initialDelaySeconds,
probePeriodSeconds: values.healthCheck?.probePeriodSeconds,
}
: null,
};
return config;
@@ -375,6 +383,8 @@ export default function ServiceForm({
<StorageFormSection />
<HealthCheckFormSection />
{createServiceFormError && (
<Alert
severity="error"

View File

@@ -41,6 +41,13 @@ export const validationSchema = Yup.object({
})
.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>;

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
$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
service
timestamp
@@ -15,8 +22,14 @@ 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
service
timestamp

View File

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

View File

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

View File

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

View File

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

View File

@@ -196,6 +196,7 @@ export type ConfigAppSystemConfig = {
*/
export type ConfigAuth = {
__typename?: 'ConfigAuth';
elevatedPrivileges?: Maybe<ConfigAuthElevatedPrivileges>;
method?: Maybe<ConfigAuthMethod>;
redirections?: Maybe<ConfigAuthRedirections>;
/** Resources for the service */
@@ -219,6 +220,7 @@ export type ConfigAuthComparisonExp = {
_and?: InputMaybe<Array<ConfigAuthComparisonExp>>;
_not?: InputMaybe<ConfigAuthComparisonExp>;
_or?: InputMaybe<Array<ConfigAuthComparisonExp>>;
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesComparisonExp>;
method?: InputMaybe<ConfigAuthMethodComparisonExp>;
redirections?: InputMaybe<ConfigAuthRedirectionsComparisonExp>;
resources?: InputMaybe<ConfigResourcesComparisonExp>;
@@ -229,7 +231,28 @@ export type ConfigAuthComparisonExp = {
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 = {
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesInsertInput>;
method?: InputMaybe<ConfigAuthMethodInsertInput>;
redirections?: InputMaybe<ConfigAuthRedirectionsInsertInput>;
resources?: InputMaybe<ConfigResourcesInsertInput>;
@@ -808,6 +831,7 @@ export type ConfigAuthTotpUpdateInput = {
};
export type ConfigAuthUpdateInput = {
elevatedPrivileges?: InputMaybe<ConfigAuthElevatedPrivilegesUpdateInput>;
method?: InputMaybe<ConfigAuthMethodUpdateInput>;
redirections?: InputMaybe<ConfigAuthRedirectionsUpdateInput>;
resources?: InputMaybe<ConfigResourcesUpdateInput>;
@@ -5238,9 +5262,9 @@ export type AuthUserProviders_Bool_Exp = {
export enum AuthUserProviders_Constraint {
/** unique or primary key constraint on columns "id" */
UserProvidersPkey = 'user_providers_pkey',
/** unique or primary key constraint on columns "provider_id", "provider_user_id" */
/** unique or primary key constraint on columns "provider_user_id", "provider_id" */
UserProvidersProviderIdProviderUserIdKey = 'user_providers_provider_id_provider_user_id_key',
/** unique or primary key constraint on columns "provider_id", "user_id" */
/** unique or primary key constraint on columns "user_id", "provider_id" */
UserProvidersUserIdProviderIdKey = 'user_providers_user_id_provider_id_key'
}
@@ -15774,6 +15798,7 @@ export type Query_Root = {
runServiceConfig?: Maybe<ConfigRunServiceConfig>;
runServiceConfigRawJSON: Scalars['String'];
runServiceConfigs: Array<ConfigRunServiceConfigWithId>;
runServiceConfigsAll: Array<ConfigRunServiceConfigWithId>;
/** An array relationship */
runServices: Array<Run_Service>;
/** fetch aggregated fields from the table: "run_service" */
@@ -16755,6 +16780,12 @@ export type Query_RootRunServiceConfigRawJsonArgs = {
export type Query_RootRunServiceConfigsArgs = {
appID: Scalars['uuid'];
resolve: Scalars['Boolean'];
};
export type Query_RootRunServiceConfigsAllArgs = {
resolve: Scalars['Boolean'];
where?: InputMaybe<ConfigRunServiceConfigComparisonExp>;
};
@@ -21355,7 +21386,7 @@ export type WorkspaceMemberInvites_Bool_Exp = {
/** unique or primary key constraints on table "workspace_member_invites" */
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',
/** unique or primary key constraint on columns "id" */
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<{
appId: Scalars['uuid'];
@@ -22772,6 +22803,7 @@ export type GetProjectLogsQueryVariables = Exact<{
service?: InputMaybe<Scalars['String']>;
from?: InputMaybe<Scalars['Timestamp']>;
to?: InputMaybe<Scalars['Timestamp']>;
regexFilter?: InputMaybe<Scalars['String']>;
}>;
@@ -22781,11 +22813,19 @@ export type GetLogsSubscriptionSubscriptionVariables = Exact<{
appID: Scalars['String'];
service?: InputMaybe<Scalars['String']>;
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 GetServiceLabelValuesQueryVariables = Exact<{
appID: Scalars['String'];
}>;
export type GetServiceLabelValuesQuery = { __typename?: 'query_root', getServiceLabelValues: Array<string> };
export type DeletePaymentMethodMutationVariables = Exact<{
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<{
object: Run_Service_Insert_Input;
@@ -23524,6 +23564,9 @@ export type DeletePersonalAccessTokenMutationOptions = Apollo.BaseMutationOption
export const GetAiSettingsDocument = gql`
query GetAISettings($appId: uuid!) {
config(appID: $appId, resolve: false) {
postgres {
version
}
ai {
version
webhookSecret
@@ -25558,8 +25601,14 @@ export function refetchGetGithubRepositoriesQuery(variables?: GetGithubRepositor
return { query: GetGithubRepositoriesDocument, variables: variables }
}
export const GetProjectLogsDocument = gql`
query getProjectLogs($appID: String!, $service: String, $from: Timestamp, $to: Timestamp) {
logs(appID: $appID, service: $service, from: $from, to: $to) {
query getProjectLogs($appID: String!, $service: String, $from: Timestamp, $to: Timestamp, $regexFilter: String) {
logs(
appID: $appID
service: $service
from: $from
to: $to
regexFilter: $regexFilter
) {
log
service
timestamp
@@ -25583,6 +25632,7 @@ export const GetProjectLogsDocument = gql`
* service: // value for 'service'
* from: // value for 'from'
* to: // value for 'to'
* regexFilter: // value for 'regexFilter'
* },
* });
*/
@@ -25601,8 +25651,8 @@ export function refetchGetProjectLogsQuery(variables: GetProjectLogsQueryVariabl
return { query: GetProjectLogsDocument, variables: variables }
}
export const GetLogsSubscriptionDocument = gql`
subscription getLogsSubscription($appID: String!, $service: String, $from: Timestamp) {
logs(appID: $appID, service: $service, from: $from) {
subscription getLogsSubscription($appID: String!, $service: String, $from: Timestamp, $regexFilter: String) {
logs(appID: $appID, service: $service, from: $from, regexFilter: $regexFilter) {
log
service
timestamp
@@ -25625,6 +25675,7 @@ export const GetLogsSubscriptionDocument = gql`
* appID: // value for 'appID'
* service: // value for 'service'
* 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 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`
mutation deletePaymentMethod($paymentMethodId: uuid!) {
deletePaymentMethod(id: $paymentMethodId) {
@@ -26577,6 +26664,11 @@ export const GetRunServicesDocument = gql`
fqdn
}
}
healthCheck {
port
initialDelaySeconds
probePeriodSeconds
}
}
}
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.
*/
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

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

View File

@@ -1,5 +1,11 @@
# @nhost/docs
## 2.7.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 2.6.0
### Minor Changes

View File

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

View File

@@ -1,5 +1,15 @@
# @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

View File

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

View File

@@ -1,5 +1,17 @@
# @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

View File

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

View File

@@ -1,5 +1,16 @@
# @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

View File

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

View File

@@ -1,5 +1,17 @@
# @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

View File

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

View File

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

View File

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

View File

@@ -1,76 +1,7 @@
import { exec } from 'child_process'
import fetch from 'cross-fetch'
import { promisify } from 'util'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { describe, it } from 'vitest'
const promisifiedExec = promisify(exec)
describe(
'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 }
)
describe('Empty Test Suite', () => {
it('Empty Test', async () => {
// This test does nothing and will always pass
})
})

View File

@@ -1,5 +1,15 @@
# @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

View File

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

View File

@@ -1,5 +1,18 @@
# @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

View File

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

View File

@@ -1,5 +1,15 @@
# @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

View File

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

View File

@@ -1,5 +1,15 @@
# @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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,23 @@
# @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

View File

@@ -35,7 +35,7 @@ mode = 'required'
[auth.redirections]
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]
enabled = true

View File

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

View File

@@ -1,5 +1,16 @@
# @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

View File

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

View File

@@ -1,5 +1,16 @@
# @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
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# @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

View File

@@ -35,7 +35,7 @@ mode = 'required'
[auth.redirections]
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]
enabled = true

View File

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

View File

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

View File

@@ -1,5 +1,17 @@
# @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

View File

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

12
flake.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,17 @@
# @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

View File

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

View File

@@ -1,5 +1,16 @@
# @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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react",
"version": "3.2.3",
"version": "3.3.0",
"description": "Nhost React library",
"license": "MIT",
"keywords": [
@@ -70,7 +70,7 @@
},
"devDependencies": {
"@nhost/docgen": "workspace:*",
"@types/react": "^18.2.50",
"@types/react": "^18.2.61",
"react": "^18.2.0"
},
"peerDependencies": {

View File

@@ -1,5 +1,11 @@
# @nhost/sync-versions
## 0.1.0
### Minor Changes
- 49a80c2: chore: update dependencies
## 0.0.10
### Patch Changes

View File

@@ -2,7 +2,7 @@
"name": "@nhost/sync-versions",
"description": "Sync the versions of Nhost services in each of the packages of a pnpm workspace",
"private": true,
"version": "0.0.10",
"version": "0.1.0",
"license": "MIT",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
@@ -25,17 +25,17 @@
},
"bin": "dist/index.js",
"devDependencies": {
"@swc-node/register": "^1.6.8",
"@swc/core": "^1.3.107",
"@swc-node/register": "^1.8.0",
"@swc/core": "^1.4.2",
"@types/glob": "^8.1.0",
"@types/node": "^16.18.78",
"@types/node": "^16.18.86",
"@types/object-path": "^0.11.4",
"typescript": "^4.9.5"
},
"dependencies": {
"@pnpm/find-workspace-dir": "^6.0.2",
"@pnpm/find-workspace-dir": "^6.0.3",
"glob": "^10.3.10",
"object-path": "^0.11.8",
"yaml": "^2.3.4"
"yaml": "^2.4.0"
}
}

View File

@@ -1,5 +1,15 @@
# @nhost/vue
## 2.3.0
### Minor Changes
- 49a80c2: chore: update dependencies
### Patch Changes
- @nhost/nhost-js@3.0.8
## 2.2.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/vue",
"version": "2.2.3",
"version": "2.3.0",
"description": "Nhost Vue library",
"license": "MIT",
"keywords": [
@@ -66,7 +66,7 @@
},
"dependencies": {
"@nhost/nhost-js": "workspace:*",
"@vueuse/core": "^10.7.2",
"@vueuse/core": "^10.9.0",
"@xstate/vue": "^2.0.0",
"jwt-decode": "^3.1.2"
},
@@ -74,8 +74,8 @@
"@nhost/docgen": "workspace:*",
"@vitejs/plugin-vue": "^4.6.2",
"@xstate/inspect": "^0.8.0",
"vue": "^3.4.15",
"vue-router": "^4.2.5",
"vue": "^3.4.21",
"vue-router": "^4.3.0",
"ws": "^8.16.0",
"xstate": "^4.38.3"
}

6460
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff