Compare commits
11 Commits
@nhost/rea
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fbd6bd4fa | ||
|
|
67fc77486c | ||
|
|
4f3fb3446e | ||
|
|
49a80c22be | ||
|
|
28676f4cdc | ||
|
|
e03f14133c | ||
|
|
150c04a4f4 | ||
|
|
bccd67b1b1 | ||
|
|
b14fd2f14c | ||
|
|
68b3d23cd9 | ||
|
|
d86e5c9c16 |
@@ -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
3
config/.husky/pre-commit
Executable file → Normal file
@@ -1,4 +1,7 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
[ -n "$CI" ] && exit 0
|
||||
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
pnpm dlx lint-staged --config config/.lintstagedrc.js
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ''),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
|
||||
@@ -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} />;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} />;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
query GetAISettings($appId: uuid!) {
|
||||
config(appID: $appId, resolve: false) {
|
||||
postgres {
|
||||
version
|
||||
}
|
||||
ai {
|
||||
version
|
||||
webhookSecret
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ')})`,
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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'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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './LogsHeader';
|
||||
export { default as LogsHeader } from './LogsHeader';
|
||||
export { default as LogsHeader, type LogsFilterFormValues } from './LogsHeader';
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as LogsRangeSelector } from './LogsRangeSelector';
|
||||
@@ -89,7 +89,7 @@ function LogsTimePicker({
|
||||
</Button>
|
||||
|
||||
<Button variant="contained" color="primary" onClick={handleApply}>
|
||||
Apply
|
||||
Set
|
||||
</Button>
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as HealthCheckFormSection } from './HealthCheckFormSection';
|
||||
@@ -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
|
||||
|
||||
3
dashboard/src/gql/logs/getServiceLabelValues.gql
Normal file
3
dashboard/src/gql/logs/getServiceLabelValues.gql
Normal file
@@ -0,0 +1,3 @@
|
||||
query getServiceLabelValues($appID: String!) {
|
||||
getServiceLabelValues(appID: $appID)
|
||||
}
|
||||
@@ -40,6 +40,11 @@ query getRunServices(
|
||||
fqdn
|
||||
}
|
||||
}
|
||||
healthCheck {
|
||||
port
|
||||
initialDelaySeconds
|
||||
probePeriodSeconds
|
||||
}
|
||||
}
|
||||
}
|
||||
runServices_aggregate {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
110
dashboard/src/utils/__generated__/graphql.ts
generated
110
dashboard/src/utils/__generated__/graphql.ts
generated
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 2.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 2.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/docker-compose
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/docker-compose",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"e2e": "vitest run"
|
||||
|
||||
@@ -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
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
---
|
||||
|
||||
## 0.3.0
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 0.2.3
|
||||
### Patch Changes
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
12
flake.lock
generated
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:*"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/google-translation
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/stripe-graphql-js
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
12
package.json
12
package.json
@@ -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"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docgen
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 0.1.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 2.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [49a80c2]
|
||||
- @nhost/react@3.3.0
|
||||
|
||||
## 2.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "2.1.5",
|
||||
"version": "2.1.6",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/sync-versions
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 49a80c2: chore: update dependencies
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
6460
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user