Compare commits
76 Commits
@nhost/rea
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43705b992d | ||
|
|
2e999e8715 | ||
|
|
0370696d5c | ||
|
|
f62131d55a | ||
|
|
86d077ac00 | ||
|
|
200e9f774c | ||
|
|
bc1235de3b | ||
|
|
fce58ebaea | ||
|
|
452e281120 | ||
|
|
9a338e54c9 | ||
|
|
baeebf980d | ||
|
|
ac92c6ee61 | ||
|
|
1ddaf680c0 | ||
|
|
c6e6194d8e | ||
|
|
83deea8b45 | ||
|
|
acbaabcf85 | ||
|
|
3534501f37 | ||
|
|
27bc23cbbc | ||
|
|
6450223558 | ||
|
|
a62a85a777 | ||
|
|
ae24f83953 | ||
|
|
fc60d7a782 | ||
|
|
6be8a998df | ||
|
|
ea091f6251 | ||
|
|
8175c052f7 | ||
|
|
e6605a6ed0 | ||
|
|
1cba0e6492 | ||
|
|
179c90fcdb | ||
|
|
85f0f943a1 | ||
|
|
c4c23fde31 | ||
|
|
e0b94c3e90 | ||
|
|
113d638532 | ||
|
|
d87448916f | ||
|
|
af4292658c | ||
|
|
f735bcd2ea | ||
|
|
66fb74af86 | ||
|
|
791eac30bb | ||
|
|
da4ad889d7 | ||
|
|
9ef111760c | ||
|
|
c2706c7d97 | ||
|
|
683b8768c4 | ||
|
|
6d9df237a8 | ||
|
|
220ae37aa7 | ||
|
|
d0d94d9239 | ||
|
|
aed3d1f147 | ||
|
|
d07bf08e45 | ||
|
|
f2183250d2 | ||
|
|
d2bb5ecfae | ||
|
|
02d0db0cf0 | ||
|
|
441005d5c3 | ||
|
|
eea8708549 | ||
|
|
5f3f9390aa | ||
|
|
1c5b0560ed | ||
|
|
1bfdf21b99 | ||
|
|
efd522a38a | ||
|
|
55c35fa9c5 | ||
|
|
d42c27ae99 | ||
|
|
927be4a2c9 | ||
|
|
e44352abbd | ||
|
|
f9289f3c32 | ||
|
|
8ff06e5637 | ||
|
|
49e4633bca | ||
|
|
7ae7a7206c | ||
|
|
43d7e7babf | ||
|
|
463a51ce7c | ||
|
|
86e9d9d47f | ||
|
|
f99b72cd7c | ||
|
|
0dc2f3ff29 | ||
|
|
d0f8081101 | ||
|
|
84ebfb79d0 | ||
|
|
3c78d0ef46 | ||
|
|
ad28bf2166 | ||
|
|
dbd3ded515 | ||
|
|
5399fac211 | ||
|
|
52e3127a34 | ||
|
|
a529b654bc |
@@ -2,20 +2,7 @@
|
|||||||
"$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
|
"$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
|
||||||
"changelog": "@changesets/cli/changelog",
|
"changelog": "@changesets/cli/changelog",
|
||||||
"commit": false,
|
"commit": false,
|
||||||
"linked": [
|
"linked": [],
|
||||||
[
|
|
||||||
"@nhost/nextjs",
|
|
||||||
"@nhost/react",
|
|
||||||
"@nhost/vue",
|
|
||||||
"@nhost/nhost-js",
|
|
||||||
"@nhost/hasura-auth-js",
|
|
||||||
"@nhost/hasura-storage-js"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@nhost/react-apollo",
|
|
||||||
"@nhost/apollo"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"access": "restricted",
|
"access": "restricted",
|
||||||
"baseBranch": "main",
|
"baseBranch": "main",
|
||||||
"updateInternalDependencies": "patch",
|
"updateInternalDependencies": "patch",
|
||||||
|
|||||||
2
.github/actions/nhost-cli/action.yaml
vendored
2
.github/actions/nhost-cli/action.yaml
vendored
@@ -38,7 +38,7 @@ runs:
|
|||||||
uses: nick-fields/retry@v2
|
uses: nick-fields/retry@v2
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 3
|
timeout_minutes: 3
|
||||||
max_attempts: 3
|
max_attempts: 10
|
||||||
command: bash <(curl --silent -L https://raw.githubusercontent.com/nhost/cli/main/get.sh) ${{ inputs.version }}
|
command: bash <(curl --silent -L https://raw.githubusercontent.com/nhost/cli/main/get.sh) ${{ inputs.version }}
|
||||||
- name: Set custom configuration
|
- name: Set custom configuration
|
||||||
if: ${{ inputs.config }}
|
if: ${{ inputs.config }}
|
||||||
|
|||||||
@@ -1,5 +1,41 @@
|
|||||||
# @nhost/dashboard
|
# @nhost/dashboard
|
||||||
|
|
||||||
|
## 0.9.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/nextjs@1.13.2
|
||||||
|
- @nhost/react-apollo@4.13.2
|
||||||
|
|
||||||
|
## 0.9.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- dbd3ded5: fix(dashboard): workspaces creation, new form, correct redirects.
|
||||||
|
|
||||||
|
## 0.9.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 85f0f943: fix(dashboard): don't break the table creation process
|
||||||
|
|
||||||
|
## 0.9.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- Updated dependencies [927be4a2]
|
||||||
|
- @nhost/nextjs@1.13.1
|
||||||
|
- @nhost/react-apollo@4.13.1
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- d0f80811: fix(dashboard): don't show error when signing out the user
|
||||||
|
|
||||||
## 0.9.0
|
## 0.9.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ RUN apk add --no-cache libc6-compat
|
|||||||
RUN apk update
|
RUN apk update
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN yarn global add turbo
|
RUN yarn global add turbo@1
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN turbo prune --scope="@nhost/dashboard" --docker
|
RUN turbo prune --scope="@nhost/dashboard" --docker
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/dashboard",
|
"name": "@nhost/dashboard",
|
||||||
"version": "0.9.0",
|
"version": "0.9.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
@@ -105,14 +105,14 @@
|
|||||||
"@types/node": "^16.11.7",
|
"@types/node": "^16.11.7",
|
||||||
"@types/pluralize": "^0.0.29",
|
"@types/pluralize": "^0.0.29",
|
||||||
"@types/react": "18.0.25",
|
"@types/react": "18.0.25",
|
||||||
"@types/react-dom": "18.0.9",
|
"@types/react-dom": "18.0.10",
|
||||||
"@types/react-table": "^7.7.12",
|
"@types/react-table": "^7.7.12",
|
||||||
"@types/testing-library__jest-dom": "^5.14.5",
|
"@types/testing-library__jest-dom": "^5.14.5",
|
||||||
"@types/validator": "^13.7.10",
|
"@types/validator": "^13.7.10",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||||
"@typescript-eslint/parser": "^5.43.0",
|
"@typescript-eslint/parser": "^5.43.0",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
"@vitest/coverage-c8": "^0.26.0",
|
"@vitest/coverage-c8": "^0.27.0",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"babel-loader": "^8.3.0",
|
"babel-loader": "^8.3.0",
|
||||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
"typescript": "^4.8.4",
|
"typescript": "^4.8.4",
|
||||||
"vite": "^4.0.2",
|
"vite": "^4.0.2",
|
||||||
"vite-tsconfig-paths": "^4.0.3",
|
"vite-tsconfig-paths": "^4.0.3",
|
||||||
"vitest": "^0.26.2",
|
"vitest": "^0.27.0",
|
||||||
"webpack": "^5.75.0"
|
"webpack": "^5.75.0"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
|
|
||||||
import { Alert } from '@/ui/Alert';
|
|
||||||
import Button from '@/ui/v2/Button';
|
|
||||||
import Input from '@/ui/v2/Input';
|
|
||||||
import Text from '@/ui/v2/Text';
|
|
||||||
import { discordAnnounce } from '@/utils/discordAnnounce';
|
|
||||||
import { inputErrorMessages } from '@/utils/getErrorMessage';
|
|
||||||
import { slugifyString } from '@/utils/helpers';
|
|
||||||
import { triggerToast } from '@/utils/toast';
|
|
||||||
import { useUpdateWorkspaceMutation } from '@/utils/__generated__/graphql';
|
|
||||||
import router from 'next/router';
|
|
||||||
import type { ChangeEvent } from 'react';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
|
|
||||||
type ChangeWorkspaceNameProps = {
|
|
||||||
close: VoidFunction;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ChangeWorkspaceName({
|
|
||||||
close,
|
|
||||||
}: ChangeWorkspaceNameProps) {
|
|
||||||
const { currentWorkspace } = useCurrentWorkspaceAndApplication();
|
|
||||||
const [newWorkspaceName, setNewWorkspaceName] = useState(
|
|
||||||
currentWorkspace.name,
|
|
||||||
);
|
|
||||||
const [workspaceError, setWorkspaceError] = useState<string>('');
|
|
||||||
|
|
||||||
const [updateWorkspace, { loading: mutationLoading, error: mutationError }] =
|
|
||||||
useUpdateWorkspaceMutation({
|
|
||||||
refetchQueries: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleChange(event: ChangeEvent<HTMLInputElement>) {
|
|
||||||
inputErrorMessages(
|
|
||||||
event.target.value,
|
|
||||||
setNewWorkspaceName,
|
|
||||||
setWorkspaceError,
|
|
||||||
'Workspace',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const name = newWorkspaceName;
|
|
||||||
const slug = slugifyString(name);
|
|
||||||
|
|
||||||
if (slug.length < 4 || slug.length > 32) {
|
|
||||||
setWorkspaceError('Slug should be within 4 and 32 characters.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateWorkspace({
|
|
||||||
variables: {
|
|
||||||
id: currentWorkspace.id,
|
|
||||||
workspace: {
|
|
||||||
name,
|
|
||||||
slug,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
close();
|
|
||||||
triggerToast('Workspace name changed');
|
|
||||||
} catch (error) {
|
|
||||||
await discordAnnounce(
|
|
||||||
`Error trying to remove workspace: ${currentWorkspace.id} - ${error.message}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await router.push(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-modal px-6 py-6 text-left">
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<Text variant="h3" component="h2">
|
|
||||||
Change Workspace Name
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="mt-4 grid grid-flow-row gap-2">
|
|
||||||
<Input
|
|
||||||
id="workspaceName"
|
|
||||||
label="New Workspace Name"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={newWorkspaceName}
|
|
||||||
placeholder="New workspace name"
|
|
||||||
fullWidth
|
|
||||||
autoFocus
|
|
||||||
autoComplete="off"
|
|
||||||
helperText={`https://app.nhost.io/${slugifyString(
|
|
||||||
newWorkspaceName || '',
|
|
||||||
)}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{workspaceError && <Alert severity="error">{workspaceError}</Alert>}
|
|
||||||
|
|
||||||
{mutationError && (
|
|
||||||
<Alert severity="error">{mutationError.toString()}</Alert>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-6 grid grid-flow-row gap-2">
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
disabled={mutationLoading || !!workspaceError}
|
|
||||||
>
|
|
||||||
Save Changes
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button variant="outlined" color="secondary" onClick={close}>
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -52,9 +52,9 @@ function ControlledAutocomplete(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
|
inputValue={typeof field.value === 'string' ? field.value : undefined}
|
||||||
{...props}
|
{...props}
|
||||||
{...field}
|
{...field}
|
||||||
inputValue={typeof field.value === 'string' ? field.value : undefined}
|
|
||||||
ref={mergeRefs([field.ref, ref])}
|
ref={mergeRefs([field.ref, ref])}
|
||||||
onChange={(event, options, reason, details) => {
|
onChange={(event, options, reason, details) => {
|
||||||
setValue?.(controllerProps?.name || name, options, {
|
setValue?.(controllerProps?.name || name, options, {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { createContext } from 'react';
|
|||||||
* Available dialog types.
|
* Available dialog types.
|
||||||
*/
|
*/
|
||||||
export type DialogType =
|
export type DialogType =
|
||||||
|
| 'EDIT_WORKSPACE_NAME'
|
||||||
| 'CREATE_RECORD'
|
| 'CREATE_RECORD'
|
||||||
| 'CREATE_COLUMN'
|
| 'CREATE_COLUMN'
|
||||||
| 'EDIT_COLUMN'
|
| 'EDIT_COLUMN'
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import RetryableErrorBoundary from '@/components/common/RetryableErrorBoundary';
|
import RetryableErrorBoundary from '@/components/common/RetryableErrorBoundary';
|
||||||
import CreateForeignKeyForm from '@/components/dataBrowser/CreateForeignKeyForm';
|
import CreateForeignKeyForm from '@/components/dataBrowser/CreateForeignKeyForm';
|
||||||
import EditForeignKeyForm from '@/components/dataBrowser/EditForeignKeyForm';
|
import EditForeignKeyForm from '@/components/dataBrowser/EditForeignKeyForm';
|
||||||
|
import EditWorkspaceNameForm from '@/components/home/EditWorkspaceNameForm';
|
||||||
import CreateEnvironmentVariableForm from '@/components/settings/environmentVariables/CreateEnvironmentVariableForm';
|
import CreateEnvironmentVariableForm from '@/components/settings/environmentVariables/CreateEnvironmentVariableForm';
|
||||||
import EditEnvironmentVariableForm from '@/components/settings/environmentVariables/EditEnvironmentVariableForm';
|
import EditEnvironmentVariableForm from '@/components/settings/environmentVariables/EditEnvironmentVariableForm';
|
||||||
import EditJwtSecretForm from '@/components/settings/environmentVariables/EditJwtSecretForm';
|
import EditJwtSecretForm from '@/components/settings/environmentVariables/EditJwtSecretForm';
|
||||||
@@ -366,6 +367,10 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
|
|||||||
<RetryableErrorBoundary
|
<RetryableErrorBoundary
|
||||||
errorMessageProps={{ className: 'pt-0 pb-5 px-6' }}
|
errorMessageProps={{ className: 'pt-0 pb-5 px-6' }}
|
||||||
>
|
>
|
||||||
|
{activeDialogType === 'EDIT_WORKSPACE_NAME' && (
|
||||||
|
<EditWorkspaceNameForm {...sharedDialogProps} />
|
||||||
|
)}
|
||||||
|
|
||||||
{activeDialogType === 'CREATE_FOREIGN_KEY' && (
|
{activeDialogType === 'CREATE_FOREIGN_KEY' && (
|
||||||
<CreateForeignKeyForm {...sharedDialogProps} />
|
<CreateForeignKeyForm {...sharedDialogProps} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { ChangePasswordModal } from '@/components/applications/ChangePasswordModal';
|
import { ChangePasswordModal } from '@/components/applications/ChangePasswordModal';
|
||||||
import { useWorkspaceContext } from '@/context/workspace-context';
|
|
||||||
import { useUserDataContext } from '@/context/workspace1-context';
|
|
||||||
import { Avatar } from '@/ui/Avatar';
|
import { Avatar } from '@/ui/Avatar';
|
||||||
import { Modal } from '@/ui/Modal';
|
import { Modal } from '@/ui/Modal';
|
||||||
import Button from '@/ui/v2/Button';
|
import Button from '@/ui/v2/Button';
|
||||||
import { Dropdown, useDropdown } from '@/ui/v2/Dropdown';
|
import { Dropdown, useDropdown } from '@/ui/v2/Dropdown';
|
||||||
import Text from '@/ui/v2/Text';
|
import Text from '@/ui/v2/Text';
|
||||||
import { emptyWorkspace } from '@/utils/helpers';
|
|
||||||
import { nhost } from '@/utils/nhost';
|
import { nhost } from '@/utils/nhost';
|
||||||
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { useUserData } from '@nhost/nextjs';
|
import { useUserData } from '@nhost/nextjs';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@@ -22,9 +20,8 @@ function AccountMenuContent({
|
|||||||
}: AccountMenuContentProps) {
|
}: AccountMenuContentProps) {
|
||||||
const user = useUserData();
|
const user = useUserData();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const client = useApolloClient();
|
||||||
const [clicked, setClicked] = useState(false);
|
const [clicked, setClicked] = useState(false);
|
||||||
const { setWorkspaceContext } = useWorkspaceContext();
|
|
||||||
const { setUserContext } = useUserDataContext();
|
|
||||||
const { handleClose } = useDropdown();
|
const { handleClose } = useDropdown();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -34,10 +31,9 @@ function AccountMenuContent({
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
className="absolute top-6 right-4 grid grid-flow-col items-center gap-1 self-start font-medium"
|
className="absolute top-6 right-4 grid grid-flow-col items-center gap-1 self-start font-medium"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setWorkspaceContext(emptyWorkspace());
|
|
||||||
setUserContext({ workspaces: [] });
|
|
||||||
nhost.auth.signOut();
|
|
||||||
router.push('/signin');
|
router.push('/signin');
|
||||||
|
await nhost.auth.signOut();
|
||||||
|
await client.resetStore();
|
||||||
}}
|
}}
|
||||||
aria-label="Sign Out"
|
aria-label="Sign Out"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ export default function BaseColumnForm({
|
|||||||
variant="inline"
|
variant="inline"
|
||||||
className="col-span-8 py-3"
|
className="col-span-8 py-3"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
@@ -272,6 +273,7 @@ export default function BaseColumnForm({
|
|||||||
error={Boolean(errors.comment)}
|
error={Boolean(errors.comment)}
|
||||||
variant="inline"
|
variant="inline"
|
||||||
className="col-span-8 py-3"
|
className="col-span-8 py-3"
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ function NameInput() {
|
|||||||
error={Boolean(errors.name)}
|
error={Boolean(errors.name)}
|
||||||
variant="inline"
|
variant="inline"
|
||||||
className="col-span-8 py-3"
|
className="col-span-8 py-3"
|
||||||
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ function NameInput({ index }: FieldArrayInputProps) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
|
autoComplete="off"
|
||||||
aria-label="Name"
|
aria-label="Name"
|
||||||
placeholder="Enter name"
|
placeholder="Enter name"
|
||||||
hideEmptyHelperText
|
hideEmptyHelperText
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import Option from '@/ui/v2/Option';
|
|||||||
import Text from '@/ui/v2/Text';
|
import Text from '@/ui/v2/Text';
|
||||||
import getPermissionVariablesArray from '@/utils/settings/getPermissionVariablesArray';
|
import getPermissionVariablesArray from '@/utils/settings/getPermissionVariablesArray';
|
||||||
import { useGetAppCustomClaimsQuery } from '@/utils/__generated__/graphql';
|
import { useGetAppCustomClaimsQuery } from '@/utils/__generated__/graphql';
|
||||||
|
import { useTheme } from '@mui/material';
|
||||||
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
|
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
|
||||||
import PermissionSettingsSection from './PermissionSettingsSection';
|
import PermissionSettingsSection from './PermissionSettingsSection';
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ export default function ColumnPresetsSection({
|
|||||||
table,
|
table,
|
||||||
disabled,
|
disabled,
|
||||||
}: ColumnPresetSectionProps) {
|
}: ColumnPresetSectionProps) {
|
||||||
|
const theme = useTheme();
|
||||||
const {
|
const {
|
||||||
data: tableData,
|
data: tableData,
|
||||||
status: tableStatus,
|
status: tableStatus,
|
||||||
@@ -131,7 +133,12 @@ export default function ColumnPresetsSection({
|
|||||||
freeSolo
|
freeSolo
|
||||||
fullWidth
|
fullWidth
|
||||||
disableClearable={false}
|
disableClearable={false}
|
||||||
clearIcon={<XIcon />}
|
clearIcon={
|
||||||
|
<XIcon
|
||||||
|
className="w-4 h-4 mt-px"
|
||||||
|
sx={{ color: theme.palette.text.primary }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
autoSelect
|
autoSelect
|
||||||
autoHighlight={false}
|
autoHighlight={false}
|
||||||
error={Boolean(
|
error={Boolean(
|
||||||
|
|||||||
@@ -0,0 +1,239 @@
|
|||||||
|
import Form from '@/components/common/Form';
|
||||||
|
import Button from '@/ui/v2/Button';
|
||||||
|
import Input from '@/ui/v2/Input';
|
||||||
|
import {
|
||||||
|
refetchGetOneUserQuery,
|
||||||
|
useInsertWorkspaceMutation,
|
||||||
|
useUpdateWorkspaceMutation,
|
||||||
|
} from '@/utils/__generated__/graphql';
|
||||||
|
import { slugifyString } from '@/utils/helpers';
|
||||||
|
import { toastStyleProps } from '@/utils/settings/settingsConstants';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useUserData } from '@nhost/nextjs';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
import { toast } from 'react-hot-toast';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
|
export interface EditWorkspaceNameFormProps {
|
||||||
|
/**
|
||||||
|
* The current workspace name if this is an edit operation.
|
||||||
|
*/
|
||||||
|
currentWorkspaceName?: string;
|
||||||
|
/**
|
||||||
|
* The current workspace name id if this is an edit operation.
|
||||||
|
*/
|
||||||
|
currentWorkspaceId?: string;
|
||||||
|
/**
|
||||||
|
* Determines whether the form is disabled.
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
/**
|
||||||
|
* Submit button text.
|
||||||
|
*
|
||||||
|
* @default 'Create'
|
||||||
|
*/
|
||||||
|
submitButtonText?: string;
|
||||||
|
/**
|
||||||
|
* Function to be called when the form is submitted.
|
||||||
|
*/
|
||||||
|
onSubmit?: () => void;
|
||||||
|
/**
|
||||||
|
* Function to be called when the operation is cancelled.
|
||||||
|
*/
|
||||||
|
onCancel?: VoidFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditWorkspaceNameFormValues {
|
||||||
|
/**
|
||||||
|
* New workspace name.
|
||||||
|
*/
|
||||||
|
newWorkspaceName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
newWorkspaceName: Yup.string()
|
||||||
|
.required('Workspace name is required.')
|
||||||
|
.min(4, 'The new Workspace name must be at least 4 characters.')
|
||||||
|
.max(32, "The new Workspace name can't be longer than 32 characters.")
|
||||||
|
.test(
|
||||||
|
'canBeSlugified',
|
||||||
|
`This field should be at least 4 characters and can't be longer than 32 characters.`,
|
||||||
|
(value) => {
|
||||||
|
const slug = slugifyString(value);
|
||||||
|
|
||||||
|
if (slug.length < 4 || slug.length > 32) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function EditWorkspaceName({
|
||||||
|
disabled,
|
||||||
|
onSubmit,
|
||||||
|
onCancel,
|
||||||
|
currentWorkspaceName,
|
||||||
|
currentWorkspaceId,
|
||||||
|
submitButtonText = 'Create',
|
||||||
|
}: EditWorkspaceNameFormProps) {
|
||||||
|
const currentUser = useUserData();
|
||||||
|
const [insertWorkspace, { client }] = useInsertWorkspaceMutation();
|
||||||
|
const [updateWorkspaceName] = useUpdateWorkspaceMutation({
|
||||||
|
refetchQueries: [
|
||||||
|
refetchGetOneUserQuery({
|
||||||
|
userId: currentUser.id,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
awaitRefetchQueries: true,
|
||||||
|
ignoreResults: true,
|
||||||
|
});
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const form = useForm<EditWorkspaceNameFormValues>({
|
||||||
|
defaultValues: {
|
||||||
|
newWorkspaceName: currentWorkspaceName || '',
|
||||||
|
},
|
||||||
|
resolver: yupResolver(validationSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
formState: { dirtyFields, isSubmitting, errors },
|
||||||
|
} = form;
|
||||||
|
const isDirty = Object.keys(dirtyFields).length > 0;
|
||||||
|
|
||||||
|
async function handleSubmit({
|
||||||
|
newWorkspaceName,
|
||||||
|
}: EditWorkspaceNameFormValues) {
|
||||||
|
const slug = slugifyString(newWorkspaceName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (currentWorkspaceId) {
|
||||||
|
// In this bit of code we spread the props of the current path (e.g. /workspace/...) and add one key-value pair: `mutating: true`.
|
||||||
|
// We want to indicate that the currently we're in the process of running a mutation state that will affect the routing behaviour of the website
|
||||||
|
// i.e. redirecting to 404 if there's no workspace/project with that slug.
|
||||||
|
await router.replace({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { ...router.query, updating: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
await toast.promise(
|
||||||
|
updateWorkspaceName({
|
||||||
|
variables: {
|
||||||
|
id: currentWorkspaceId,
|
||||||
|
workspace: {
|
||||||
|
name: newWorkspaceName,
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
loading: 'Updating workspace name...',
|
||||||
|
success: 'Workspace name has been updated successfully.',
|
||||||
|
error: 'An error occurred while updating the workspace name.',
|
||||||
|
},
|
||||||
|
toastStyleProps,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await toast.promise(
|
||||||
|
insertWorkspace({
|
||||||
|
variables: {
|
||||||
|
workspace: {
|
||||||
|
name: newWorkspaceName,
|
||||||
|
companyName: newWorkspaceName,
|
||||||
|
email: currentUser.email,
|
||||||
|
slug,
|
||||||
|
workspaceMembers: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
userId: currentUser.id,
|
||||||
|
type: 'owner',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
loading: 'Creating new workspace...',
|
||||||
|
success: 'The new workspace has been created successfully.',
|
||||||
|
error: 'An error occurred while creating the new workspace.',
|
||||||
|
},
|
||||||
|
toastStyleProps,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message?.includes('duplicate key value')) {
|
||||||
|
form.setError(
|
||||||
|
'newWorkspaceName',
|
||||||
|
{
|
||||||
|
type: 'manual',
|
||||||
|
message: 'This workspace name is already taken.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shouldFocus: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.refetchQueries({
|
||||||
|
include: ['getOneUser'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await router.push(slug);
|
||||||
|
onSubmit?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<Form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className="flex flex-col content-between flex-auto pt-2 pb-6 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex-auto px-6 overflow-y-auto">
|
||||||
|
<Input
|
||||||
|
{...register('newWorkspaceName')}
|
||||||
|
error={Boolean(errors.newWorkspaceName?.message)}
|
||||||
|
label="Name"
|
||||||
|
helperText={errors.newWorkspaceName?.message}
|
||||||
|
autoFocus={!disabled}
|
||||||
|
disabled={disabled}
|
||||||
|
fullWidth
|
||||||
|
hideEmptyHelperText
|
||||||
|
placeholder='e.g. "My Workspace"'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid flex-shrink-0 grid-flow-row gap-2 px-6 pt-4">
|
||||||
|
{!disabled && (
|
||||||
|
<Button
|
||||||
|
loading={isSubmitting}
|
||||||
|
disabled={
|
||||||
|
isSubmitting || Boolean(errors.newWorkspaceName?.message)
|
||||||
|
}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{currentWorkspaceName ? 'Save' : submitButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
onClick={onCancel}
|
||||||
|
tabIndex={isDirty ? -1 : 0}
|
||||||
|
autoFocus={disabled}
|
||||||
|
>
|
||||||
|
{disabled ? 'Close' : 'Cancel'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './EditWorkspaceNameForm';
|
||||||
|
export { default } from './EditWorkspaceNameForm';
|
||||||
|
|
||||||
@@ -4,11 +4,8 @@ import { InviteAnnounce } from '@/components/home/InviteAnnounce';
|
|||||||
import type { BaseLayoutProps } from '@/components/layout/BaseLayout';
|
import type { BaseLayoutProps } from '@/components/layout/BaseLayout';
|
||||||
import BaseLayout from '@/components/layout/BaseLayout';
|
import BaseLayout from '@/components/layout/BaseLayout';
|
||||||
import Container from '@/components/layout/Container';
|
import Container from '@/components/layout/Container';
|
||||||
import AddWorkspace from '@/components/workspace/AddWorkspace';
|
|
||||||
import { useUI } from '@/context/UIContext';
|
|
||||||
import useIsHealthy from '@/hooks/common/useIsHealthy';
|
import useIsHealthy from '@/hooks/common/useIsHealthy';
|
||||||
import useIsPlatform from '@/hooks/common/useIsPlatform';
|
import useIsPlatform from '@/hooks/common/useIsPlatform';
|
||||||
import { Modal } from '@/ui';
|
|
||||||
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
|
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
|
||||||
import Link from '@/ui/v2/Link';
|
import Link from '@/ui/v2/Link';
|
||||||
import Text from '@/ui/v2/Text';
|
import Text from '@/ui/v2/Text';
|
||||||
@@ -39,7 +36,6 @@ export default function AuthenticatedLayout({
|
|||||||
}: AuthenticatedLayoutProps) {
|
}: AuthenticatedLayoutProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isPlatform = useIsPlatform();
|
const isPlatform = useIsPlatform();
|
||||||
const { newWorkspace, closeSection } = useUI();
|
|
||||||
const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
||||||
const isHealthy = useIsHealthy();
|
const isHealthy = useIsHealthy();
|
||||||
|
|
||||||
@@ -85,7 +81,7 @@ export default function AuthenticatedLayout({
|
|||||||
<BaseLayout {...props}>
|
<BaseLayout {...props}>
|
||||||
<Header className="flex max-h-[59px] flex-auto" />
|
<Header className="flex max-h-[59px] flex-auto" />
|
||||||
|
|
||||||
<Container className="my-12 grid max-w-md grid-flow-row justify-center gap-2 text-center">
|
<Container className="grid justify-center max-w-md grid-flow-row gap-2 my-12 text-center">
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<Image
|
<Image
|
||||||
src="/terminal-text.svg"
|
src="/terminal-text.svg"
|
||||||
@@ -123,13 +119,7 @@ export default function AuthenticatedLayout({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseLayout className="flex h-full flex-col" {...props}>
|
<BaseLayout className="flex flex-col h-full" {...props}>
|
||||||
<Modal
|
|
||||||
showModal={newWorkspace}
|
|
||||||
close={closeSection}
|
|
||||||
Component={AddWorkspace}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Header className="flex max-h-[59px] flex-auto" />
|
<Header className="flex max-h-[59px] flex-auto" />
|
||||||
|
|
||||||
<InviteAnnounce />
|
<InviteAnnounce />
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
import { useUI } from '@/context/UIContext';
|
|
||||||
import { useInsertWorkspaceMutation } from '@/generated/graphql';
|
|
||||||
import { Alert } from '@/ui/Alert';
|
|
||||||
import Button from '@/ui/v2/Button';
|
|
||||||
import Input from '@/ui/v2/Input';
|
|
||||||
import Text from '@/ui/v2/Text';
|
|
||||||
import { getErrorMessage, inputErrorMessages } from '@/utils/getErrorMessage';
|
|
||||||
import { slugifyString } from '@/utils/helpers';
|
|
||||||
import { nhost } from '@/utils/nhost';
|
|
||||||
import { triggerToast } from '@/utils/toast';
|
|
||||||
import router from 'next/router';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import slugify from 'slugify';
|
|
||||||
|
|
||||||
function AddNewWorkspaceForm({
|
|
||||||
closeSection: externalCloseSection,
|
|
||||||
}: {
|
|
||||||
closeSection: VoidFunction;
|
|
||||||
}) {
|
|
||||||
const [workspace, setWorkspace] = useState('');
|
|
||||||
const { closeSection } = useUI();
|
|
||||||
const [workspaceError, setWorkspaceError] = useState<string>('');
|
|
||||||
const [loadingAddWorkspace, setLoadingAddWorkspace] = useState(false);
|
|
||||||
|
|
||||||
const [insertWorkspace, { client }] = useInsertWorkspaceMutation();
|
|
||||||
|
|
||||||
const slug = slugify(workspace, { lower: true, strict: true });
|
|
||||||
const user = nhost.auth.getUser();
|
|
||||||
if (!user) {
|
|
||||||
return <div>No user..</div>;
|
|
||||||
}
|
|
||||||
const userId = user.id;
|
|
||||||
|
|
||||||
async function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
|
|
||||||
e.preventDefault();
|
|
||||||
setWorkspaceError('');
|
|
||||||
setLoadingAddWorkspace(true);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!inputErrorMessages(
|
|
||||||
workspace,
|
|
||||||
setWorkspace,
|
|
||||||
setWorkspaceError,
|
|
||||||
'Workspace',
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slug.length < 4 || slug.length > 32) {
|
|
||||||
setWorkspaceError('Slug should be within 4 and 32 characters.');
|
|
||||||
setLoadingAddWorkspace(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentUser = nhost.auth.getUser();
|
|
||||||
|
|
||||||
if (!currentUser) {
|
|
||||||
triggerToast('User is not signed in');
|
|
||||||
setLoadingAddWorkspace(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await insertWorkspace({
|
|
||||||
variables: {
|
|
||||||
workspace: {
|
|
||||||
name: workspace,
|
|
||||||
companyName: workspace,
|
|
||||||
email: user.email,
|
|
||||||
slug,
|
|
||||||
workspaceMembers: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
userId,
|
|
||||||
type: 'owner',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await client.refetchQueries({ include: ['getOneUser'] });
|
|
||||||
router.push(`/${slug}`);
|
|
||||||
setLoadingAddWorkspace(false);
|
|
||||||
closeSection();
|
|
||||||
} catch (error: any) {
|
|
||||||
setWorkspaceError(getErrorMessage(error, 'workspace'));
|
|
||||||
setLoadingAddWorkspace(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<form onSubmit={handleSubmit} className="grid grid-flow-row gap-4">
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder="Your new workspace"
|
|
||||||
name="workspace"
|
|
||||||
id="workspace"
|
|
||||||
label="Workspace"
|
|
||||||
fullWidth
|
|
||||||
autoFocus
|
|
||||||
helperText={`https://app.nhost.io/${slugifyString(workspace)}`}
|
|
||||||
onChange={(event) => {
|
|
||||||
setWorkspace(event.target.value);
|
|
||||||
setWorkspaceError('');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{workspaceError && <Alert severity="error">{workspaceError}</Alert>}
|
|
||||||
|
|
||||||
<div className="grid grid-flow-col justify-between gap-2">
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
color="secondary"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
externalCloseSection();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
disabled={!!workspaceError}
|
|
||||||
loading={loadingAddWorkspace}
|
|
||||||
>
|
|
||||||
Create Workspace
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AddWorkspace() {
|
|
||||||
const { closeSection } = useUI();
|
|
||||||
|
|
||||||
const user = nhost.auth.getUser();
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return <div>No user..</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="grid w-modal grid-flow-row gap-2 px-6 py-6 text-left">
|
|
||||||
<div className="grid w-full grid-flow-row gap-1">
|
|
||||||
<Text variant="h3" component="h2">
|
|
||||||
New Workspace
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text variant="subtitle2">
|
|
||||||
Invite team members to workspaces to work collaboratively.
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<AddNewWorkspaceForm closeSection={closeSection} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
import { Avatar } from '@/ui/Avatar';
|
import { Avatar } from '@/ui/Avatar';
|
||||||
import Text from '@/ui/v2/Text';
|
import Text from '@/ui/v2/Text';
|
||||||
import { nhost } from '@/utils/nhost';
|
|
||||||
import { useGetWorkspacesQuery } from '@/utils/__generated__/graphql';
|
import { useGetWorkspacesQuery } from '@/utils/__generated__/graphql';
|
||||||
|
import { nhost } from '@/utils/nhost';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export default function SidebarWorkspaces() {
|
export default function SidebarWorkspaces() {
|
||||||
const user = nhost.auth.getUser();
|
const user = nhost.auth.getUser();
|
||||||
const { data, loading, startPolling, stopPolling } = useGetWorkspacesQuery();
|
const { data, loading, startPolling, stopPolling } = useGetWorkspacesQuery({
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
startPolling(1000);
|
startPolling(1000);
|
||||||
@@ -28,7 +30,7 @@ export default function SidebarWorkspaces() {
|
|||||||
<div className="mt-3 mb-4 space-y-2">
|
<div className="mt-3 mb-4 space-y-2">
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<svg
|
<svg
|
||||||
className="ml-1 h-4 w-4 animate-spin self-center text-dark"
|
className="self-center w-4 h-4 ml-1 animate-spin text-dark"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -47,7 +49,7 @@ export default function SidebarWorkspaces() {
|
|||||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<Text size="tiny" className="ml-2 self-center" color="greyscaleGrey">
|
<Text size="tiny" className="self-center ml-2" color="greyscaleGrey">
|
||||||
Creating first workspace...
|
Creating first workspace...
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,12 +68,12 @@ export default function SidebarWorkspaces() {
|
|||||||
>
|
>
|
||||||
{name === 'Default Workspace' && creatorUserId === user.id ? (
|
{name === 'Default Workspace' && creatorUserId === user.id ? (
|
||||||
<Avatar
|
<Avatar
|
||||||
className="h-8 w-8 self-center rounded-full"
|
className="self-center w-8 h-8 rounded-full"
|
||||||
name={user?.displayName}
|
name={user?.displayName}
|
||||||
avatarUrl={user?.avatarUrl}
|
avatarUrl={user?.avatarUrl}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="inline-block h-8 w-8 overflow-hidden rounded-lg">
|
<div className="inline-block w-8 h-8 overflow-hidden rounded-lg">
|
||||||
<Image
|
<Image
|
||||||
src="/logos/new.svg"
|
src="/logos/new.svg"
|
||||||
alt="Nhost Logo"
|
alt="Nhost Logo"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import ChangeWorkspaceName from '@/components/applications/ChangeWorkspaceName';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import RemoveWorkspaceModal from '@/components/workspace/RemoveWorkspaceModal';
|
import RemoveWorkspaceModal from '@/components/workspace/RemoveWorkspaceModal';
|
||||||
import { useUI } from '@/context/UIContext';
|
import { useUI } from '@/context/UIContext';
|
||||||
import { useGetWorkspace } from '@/hooks/use-GetWorkspace';
|
import { useGetWorkspace } from '@/hooks/use-GetWorkspace';
|
||||||
@@ -13,7 +13,6 @@ import { copy } from '@/utils/copy';
|
|||||||
import { nhost } from '@/utils/nhost';
|
import { nhost } from '@/utils/nhost';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
export default function WorkspaceHeader() {
|
export default function WorkspaceHeader() {
|
||||||
const { currentWorkspace } = useCurrentWorkspaceAndApplication();
|
const { currentWorkspace } = useCurrentWorkspaceAndApplication();
|
||||||
@@ -21,14 +20,14 @@ export default function WorkspaceHeader() {
|
|||||||
query: { workspaceSlug },
|
query: { workspaceSlug },
|
||||||
} = useRouter();
|
} = useRouter();
|
||||||
|
|
||||||
const [changeWorkspaceNameModal, setChangeWorkspaceNameModal] =
|
|
||||||
useState(false);
|
|
||||||
const {
|
const {
|
||||||
openDeleteWorkspaceModal,
|
openDeleteWorkspaceModal,
|
||||||
closeDeleteWorkspaceModal,
|
closeDeleteWorkspaceModal,
|
||||||
deleteWorkspaceModal,
|
deleteWorkspaceModal,
|
||||||
} = useUI();
|
} = useUI();
|
||||||
|
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
|
||||||
const { data } = useGetWorkspace(workspaceSlug);
|
const { data } = useGetWorkspace(workspaceSlug);
|
||||||
|
|
||||||
const workspace = data?.workspaces[0];
|
const workspace = data?.workspaces[0];
|
||||||
@@ -45,11 +44,6 @@ export default function WorkspaceHeader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto flex max-w-3xl flex-col">
|
<div className="mx-auto flex max-w-3xl flex-col">
|
||||||
<Modal
|
|
||||||
showModal={changeWorkspaceNameModal}
|
|
||||||
close={() => setChangeWorkspaceNameModal(!changeWorkspaceNameModal)}
|
|
||||||
Component={ChangeWorkspaceName}
|
|
||||||
/>
|
|
||||||
<Modal
|
<Modal
|
||||||
showModal={deleteWorkspaceModal}
|
showModal={deleteWorkspaceModal}
|
||||||
close={closeDeleteWorkspaceModal}
|
close={closeDeleteWorkspaceModal}
|
||||||
@@ -112,9 +106,23 @@ export default function WorkspaceHeader() {
|
|||||||
>
|
>
|
||||||
<Dropdown.Item
|
<Dropdown.Item
|
||||||
className="py-2"
|
className="py-2"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
setChangeWorkspaceNameModal(!changeWorkspaceNameModal)
|
openDialog('EDIT_WORKSPACE_NAME', {
|
||||||
}
|
title: (
|
||||||
|
<span className="grid grid-flow-row">
|
||||||
|
<span>Change Workspace Name</span>
|
||||||
|
<Text variant="subtitle1" component="span">
|
||||||
|
Changing the workspace name will also affect the URL
|
||||||
|
of the workspace.
|
||||||
|
</Text>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
payload: {
|
||||||
|
currentWorkspaceName: currentWorkspace.name,
|
||||||
|
currentWorkspaceId: currentWorkspace.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Change workspace name
|
Change workspace name
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { SidebarTitle } from '@/components/home/SidebarTitle';
|
import { SidebarTitle } from '@/components/home/SidebarTitle';
|
||||||
import { useUI } from '@/context/UIContext';
|
|
||||||
import Button from '@/ui/v2/Button';
|
import Button from '@/ui/v2/Button';
|
||||||
|
import Text from '@/ui/v2/Text';
|
||||||
import PlusCircleIcon from '@/ui/v2/icons/PlusCircleIcon';
|
import PlusCircleIcon from '@/ui/v2/icons/PlusCircleIcon';
|
||||||
import SidebarWorkspaces from './SidebarWorkspaces';
|
import SidebarWorkspaces from './SidebarWorkspaces';
|
||||||
|
|
||||||
export function WorkspaceSection() {
|
export function WorkspaceSection() {
|
||||||
const { openSection } = useUI();
|
const { openDialog } = useDialog();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -15,7 +16,19 @@ export function WorkspaceSection() {
|
|||||||
<Button
|
<Button
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={openSection}
|
onClick={() => {
|
||||||
|
openDialog('EDIT_WORKSPACE_NAME', {
|
||||||
|
title: (
|
||||||
|
<span className="grid grid-flow-row">
|
||||||
|
<span>New Workspace</span>
|
||||||
|
|
||||||
|
<Text variant="subtitle1" component="span">
|
||||||
|
Invite team members to workspaces to work collaboratively.
|
||||||
|
</Text>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}}
|
||||||
startIcon={<PlusCircleIcon />}
|
startIcon={<PlusCircleIcon />}
|
||||||
>
|
>
|
||||||
New Workspace
|
New Workspace
|
||||||
|
|||||||
@@ -237,7 +237,10 @@ test('should drop existing relationships and prepare a new one-to-many relations
|
|||||||
"cascade": false,
|
"cascade": false,
|
||||||
"relationship": "books",
|
"relationship": "books",
|
||||||
"source": "default",
|
"source": "default",
|
||||||
"table": "authors",
|
"table": {
|
||||||
|
"name": "authors",
|
||||||
|
"schema": "public",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"type": "pg_drop_relationship",
|
"type": "pg_drop_relationship",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,12 @@ export default async function prepareTrackForeignKeyRelationsMetadata({
|
|||||||
type: 'pg_drop_relationship',
|
type: 'pg_drop_relationship',
|
||||||
args: {
|
args: {
|
||||||
source: dataSource,
|
source: dataSource,
|
||||||
table: foreignKeyRelation.referencedTable,
|
table: foreignKeyRelation.referencedSchema
|
||||||
|
? {
|
||||||
|
name: foreignKeyRelation.referencedTable,
|
||||||
|
schema: foreignKeyRelation.referencedSchema,
|
||||||
|
}
|
||||||
|
: foreignKeyRelation.referencedTable,
|
||||||
relationship: oneToManyRelationshipName,
|
relationship: oneToManyRelationshipName,
|
||||||
cascade: false,
|
cascade: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export default function prepareUpdateTableQuery({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...args,
|
...updatedArgs,
|
||||||
...prepareUpdateForeignKeyConstraintQuery({
|
...prepareUpdateForeignKeyConstraintQuery({
|
||||||
...baseVariables,
|
...baseVariables,
|
||||||
originalForeignKeyRelation,
|
originalForeignKeyRelation,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function useNotFoundRedirect() {
|
|||||||
useCurrentWorkspaceAndApplication();
|
useCurrentWorkspaceAndApplication();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {
|
const {
|
||||||
query: { workspaceSlug, appSlug },
|
query: { workspaceSlug, appSlug, updating },
|
||||||
} = useRouter();
|
} = useRouter();
|
||||||
|
|
||||||
const notIn404Already = router.pathname !== '/404';
|
const notIn404Already = router.pathname !== '/404';
|
||||||
@@ -25,6 +25,15 @@ export default function useNotFoundRedirect() {
|
|||||||
const inSettingsDatabasePage = router.pathname.includes('/settings/database');
|
const inSettingsDatabasePage = router.pathname.includes('/settings/database');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// This code is checking if the URL has a query of the form `?updating=true`
|
||||||
|
// If it does (`updating` is true) this useEffect will immediately exit without executing
|
||||||
|
// any further statements (e.g. the page will show a loader until `updating` is false).
|
||||||
|
// This is to prevent the user from being redirected to the 404 page while we are updating
|
||||||
|
// either the workspace slug or application slug.
|
||||||
|
if (updating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (noResolvedWorkspace && notIn404Already) {
|
if (noResolvedWorkspace && notIn404Already) {
|
||||||
router.push('/404');
|
router.push('/404');
|
||||||
}
|
}
|
||||||
@@ -37,6 +46,7 @@ export default function useNotFoundRedirect() {
|
|||||||
router.push('/404');
|
router.push('/404');
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
updating,
|
||||||
currentApplication,
|
currentApplication,
|
||||||
currentWorkspace,
|
currentWorkspace,
|
||||||
noResolvedApplication,
|
noResolvedApplication,
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import {
|
|||||||
useUpdateAppMutation,
|
useUpdateAppMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
|
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
|
||||||
import CheckIcon from '@/ui/v2/icons/CheckIcon';
|
|
||||||
import Input from '@/ui/v2/Input';
|
import Input from '@/ui/v2/Input';
|
||||||
|
import CheckIcon from '@/ui/v2/icons/CheckIcon';
|
||||||
import { discordAnnounce } from '@/utils/discordAnnounce';
|
import { discordAnnounce } from '@/utils/discordAnnounce';
|
||||||
import { slugifyString } from '@/utils/helpers';
|
import { slugifyString } from '@/utils/helpers';
|
||||||
import { updateOwnCache } from '@/utils/updateOwnCache';
|
import { updateOwnCache } from '@/utils/updateOwnCache';
|
||||||
@@ -53,6 +53,7 @@ export default function SettingsGeneralPage() {
|
|||||||
const [deleteApplication] = useDeleteApplicationMutation({
|
const [deleteApplication] = useDeleteApplicationMutation({
|
||||||
variables: { appId: currentApplication?.id },
|
variables: { appId: currentApplication?.id },
|
||||||
});
|
});
|
||||||
|
const { currentWorkspace } = useCurrentWorkspaceAndApplication();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const form = useForm<ProjectNameValidationSchema>({
|
const form = useForm<ProjectNameValidationSchema>({
|
||||||
@@ -69,6 +70,14 @@ export default function SettingsGeneralPage() {
|
|||||||
const { register, formState } = form;
|
const { register, formState } = form;
|
||||||
|
|
||||||
const handleProjectNameChange = async (data: ProjectNameValidationSchema) => {
|
const handleProjectNameChange = async (data: ProjectNameValidationSchema) => {
|
||||||
|
// In this bit of code we spread the props of the current path (e.g. /workspace/...) and add one key-value pair: `updating: true`.
|
||||||
|
// We want to indicate that the currently we're in the process of running a mutation state that will affect the routing behaviour of the website
|
||||||
|
// i.e. redirecting to 404 if there's no workspace/project with that slug.
|
||||||
|
await router.replace({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { ...router.query, updating: true },
|
||||||
|
});
|
||||||
|
|
||||||
const newProjectSlug = slugifyString(data.name);
|
const newProjectSlug = slugifyString(data.name);
|
||||||
|
|
||||||
if (newProjectSlug.length < 1 || newProjectSlug.length > 32) {
|
if (newProjectSlug.length < 1 || newProjectSlug.length > 32) {
|
||||||
@@ -100,8 +109,13 @@ export default function SettingsGeneralPage() {
|
|||||||
toastStyleProps,
|
toastStyleProps,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await client.refetchQueries({ include: ['getOneUser'] });
|
await client.refetchQueries({
|
||||||
|
include: ['getOneUser'],
|
||||||
|
});
|
||||||
form.reset(undefined, { keepValues: true, keepDirty: false });
|
form.reset(undefined, { keepValues: true, keepDirty: false });
|
||||||
|
await router.push(
|
||||||
|
`/${currentWorkspace.slug}/${newProjectSlug}/settings/general`,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await discordAnnounce(
|
await discordAnnounce(
|
||||||
error.message || 'Error while trying to update application cache',
|
error.message || 'Error while trying to update application cache',
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/docs
|
# @nhost/docs
|
||||||
|
|
||||||
|
## 0.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 0.0.9
|
## 0.0.9
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/docs",
|
"name": "@nhost/docs",
|
||||||
"version": "0.0.9",
|
"version": "0.0.10",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# @nhost-examples/codegen-react-apollo
|
# @nhost-examples/codegen-react-apollo
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
- @nhost/react-apollo@4.13.2
|
||||||
|
|
||||||
## 0.1.4
|
## 0.1.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/codegen-react-apollo",
|
"name": "@nhost-examples/codegen-react-apollo",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.6.9",
|
"@apollo/client": "^3.6.9",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# @nhost-examples/codegen-react-query
|
# @nhost-examples/codegen-react-query
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
|
||||||
## 0.1.4
|
## 0.1.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/codegen-react-query",
|
"name": "@nhost-examples/codegen-react-query",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nhost/react": "*",
|
"@nhost/react": "*",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost-examples/docker-compose
|
# @nhost-examples/docker-compose
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/docker-compose",
|
"name": "@nhost-examples/docker-compose",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"e2e": "vitest run"
|
"e2e": "vitest run"
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
# @nhost-examples/nextjs
|
# @nhost-examples/nextjs
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/nextjs@1.13.2
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
- @nhost/react-apollo@4.13.2
|
||||||
|
|
||||||
## 0.1.4
|
## 0.1.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/nextjs",
|
"name": "@nhost-examples/nextjs",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
@@ -1,5 +1,27 @@
|
|||||||
# @nhost-examples/react-apollo
|
# @nhost-examples/react-apollo
|
||||||
|
|
||||||
|
## 0.1.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
- @nhost/react-apollo@4.13.2
|
||||||
|
|
||||||
|
## 0.1.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- c2706c7d: Export commonly used types
|
||||||
|
|
||||||
|
`BackendUrl`, `ErrorPayload`, `NhostSession`, `Subdomain`, and `User` are now exported in all our SDKs
|
||||||
|
|
||||||
|
- Updated dependencies [c2706c7d]
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- @nhost/react@1.13.1
|
||||||
|
- @nhost/react-apollo@4.13.1
|
||||||
|
|
||||||
## 0.1.5
|
## 0.1.5
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { faker } from '@faker-js/faker'
|
||||||
|
|
||||||
|
context('Forgot password', () => {
|
||||||
|
it('should reset password', () => {
|
||||||
|
const email = faker.internet.email()
|
||||||
|
const password = faker.internet.password(8)
|
||||||
|
|
||||||
|
cy.signUpEmailPassword(email, password)
|
||||||
|
cy.contains('Verification email sent').should('be.visible')
|
||||||
|
|
||||||
|
cy.visit('/sign-in')
|
||||||
|
cy.findByRole('button', { name: /Continue with email \+ password/i }).click()
|
||||||
|
cy.findByRole('button', { name: /Forgot Password?/i }).click()
|
||||||
|
|
||||||
|
cy.findByPlaceholderText('Email Address').type(email)
|
||||||
|
cy.findByRole('button', { name: /Reset your password/i }).click()
|
||||||
|
|
||||||
|
cy.confirmEmail(email)
|
||||||
|
cy.contains('Profile page')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { faker } from '@faker-js/faker'
|
import { faker } from '@faker-js/faker'
|
||||||
import { User } from '@nhost/hasura-auth-js'
|
import { User } from '@nhost/react'
|
||||||
|
|
||||||
import '@testing-library/cypress/add-commands'
|
import '@testing-library/cypress/add-commands'
|
||||||
import 'cypress-mailhog'
|
import 'cypress-mailhog'
|
||||||
@@ -83,7 +83,7 @@ Cypress.Commands.add('signOut', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add('confirmEmail', (email) => {
|
Cypress.Commands.add('confirmEmail', (email) => {
|
||||||
cy.mhGetMailsByRecipient(email)
|
cy.mhGetMailsByRecipient(email, 1)
|
||||||
.should('have.length', 1)
|
.should('have.length', 1)
|
||||||
.then(([message]) => {
|
.then(([message]) => {
|
||||||
cy.visit(message.Content.Headers['X-Link'][0])
|
cy.visit(message.Content.Headers['X-Link'][0])
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/react-apollo",
|
"name": "@nhost-examples/react-apollo",
|
||||||
"version": "0.1.5",
|
"version": "0.1.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.6.9",
|
"@apollo/client": "^3.6.9",
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"@xstate/inspect": "^0.6.2",
|
"@xstate/inspect": "^0.6.2",
|
||||||
"cypress": "^10.7.0",
|
"cypress": "^10.7.0",
|
||||||
"cypress-mailhog": "^1.6.0",
|
"cypress-mailhog": "^1.6.0",
|
||||||
"start-server-and-test": "^1.14.0",
|
"start-server-and-test": "^1.15.2",
|
||||||
"totp-generator": "^0.0.13",
|
"totp-generator": "^0.0.13",
|
||||||
"typescript": "^4.8.2",
|
"typescript": "^4.8.2",
|
||||||
"vite": "^4.0.2",
|
"vite": "^4.0.2",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# @nhost-examples/react-gqty
|
# @nhost-examples/react-gqty
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/react-gqty",
|
"name": "@nhost-examples/react-gqty",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# @nhost-examples/react-urql
|
# @nhost-examples/react-urql
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
- @nhost/react-urql@1.0.2
|
||||||
|
|
||||||
## 0.0.1
|
## 0.0.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/react-urql",
|
"name": "@nhost-examples/react-urql",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# @nhost-examples/serverless-functions
|
# @nhost-examples/serverless-functions
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/stripe-graphql-js@0.0.8
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/serverless-functions",
|
"name": "@nhost-examples/serverless-functions",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.13"
|
"@types/express": "^4.17.13"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@graphql-yoga/node": "^2.13.13",
|
"@graphql-yoga/node": "^2.13.13",
|
||||||
"@nhost/stripe-graphql-js": "^0.0.7",
|
"@nhost/stripe-graphql-js": "^0.0.8",
|
||||||
"@pothos/core": "^3.21.0",
|
"@pothos/core": "^3.21.0",
|
||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"graphql": "15.7.2",
|
"graphql": "15.7.2",
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
# @nhost-examples/vue-apollo
|
# @nhost-examples/vue-apollo
|
||||||
|
|
||||||
|
## 0.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/apollo@4.13.1
|
||||||
|
- @nhost/vue@1.13.2
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- c2706c7d: Export commonly used types
|
||||||
|
|
||||||
|
`BackendUrl`, `ErrorPayload`, `NhostSession`, `Subdomain`, and `User` are now exported in all our SDKs
|
||||||
|
|
||||||
|
- Updated dependencies [c2706c7d]
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- @nhost/vue@1.13.1
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/vue-apollo",
|
"name": "@nhost-examples/vue-apollo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.3",
|
"version": "0.0.5",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PropType, ref, watchEffect } from 'vue'
|
import { PropType, ref, watchEffect } from 'vue'
|
||||||
|
|
||||||
import { ErrorPayload } from '@nhost/hasura-auth-js'
|
import { ErrorPayload } from '@nhost/vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
error: Object as PropType<ErrorPayload | null>
|
error: Object as PropType<ErrorPayload | null>
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# @nhost-examples/vue-quickstart
|
# @nhost-examples/vue-quickstart
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/apollo@4.13.1
|
||||||
|
- @nhost/vue@1.13.2
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost-examples/vue-quickstart",
|
"name": "@nhost-examples/vue-quickstart",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# @nhost/apollo
|
# @nhost/apollo
|
||||||
|
|
||||||
|
## 4.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/nhost-js@1.13.1
|
||||||
|
|
||||||
## 4.13.0
|
## 4.13.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/apollo",
|
"name": "@nhost/apollo",
|
||||||
"version": "4.13.0",
|
"version": "4.13.1",
|
||||||
"description": "Nhost Apollo Client library",
|
"description": "Nhost Apollo Client library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
7
integrations/google-translation/CHANGELOG.md
Normal file
7
integrations/google-translation/CHANGELOG.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# @nhost/google-translation
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/google-translation",
|
"name": "@nhost/google-translation",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "Google Translation GraphQL API",
|
"description": "Google Translation GraphQL API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
# @nhost/react-apollo
|
# @nhost/react-apollo
|
||||||
|
|
||||||
|
## 4.13.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/apollo@4.13.1
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
|
||||||
|
## 4.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [c2706c7d]
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- @nhost/react@1.13.1
|
||||||
|
|
||||||
## 4.13.0
|
## 4.13.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/react-apollo",
|
"name": "@nhost/react-apollo",
|
||||||
"version": "4.13.0",
|
"version": "4.13.2",
|
||||||
"description": "Nhost React Apollo client",
|
"description": "Nhost React Apollo client",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
# @nhost/react-urql
|
# @nhost/react-urql
|
||||||
|
|
||||||
|
## 1.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [c2706c7d]
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- @nhost/react@1.13.1
|
||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/react-urql",
|
"name": "@nhost/react-urql",
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"description": "Nhost React URQL client",
|
"description": "Nhost React URQL client",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/stripe-graphql-js
|
# @nhost/stripe-graphql-js
|
||||||
|
|
||||||
|
## 0.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 0.0.7
|
## 0.0.7
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/stripe-graphql-js",
|
"name": "@nhost/stripe-graphql-js",
|
||||||
"version": "0.0.7",
|
"version": "0.0.8",
|
||||||
"description": "Stripe GraphQL API",
|
"description": "Stripe GraphQL API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
||||||
"@typescript-eslint/parser": "^5.42.1",
|
"@typescript-eslint/parser": "^5.42.1",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
"@vitest/coverage-c8": "^0.26.0",
|
"@vitest/coverage-c8": "^0.27.0",
|
||||||
"eslint": "^8.26.0",
|
"eslint": "^8.26.0",
|
||||||
"eslint-config-react-app": "^7.0.1",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"eslint-plugin-cypress": "^2.12.1",
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
"vite": "^4.0.2",
|
"vite": "^4.0.2",
|
||||||
"vite-plugin-dts": "^1.7.1",
|
"vite-plugin-dts": "^1.7.1",
|
||||||
"vite-tsconfig-paths": "^4.0.3",
|
"vite-tsconfig-paths": "^4.0.3",
|
||||||
"vitest": "^0.26.2"
|
"vitest": "^0.27.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"graphql": "16.6.0"
|
"graphql": "16.6.0"
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/docgen
|
# @nhost/docgen
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 0.1.4
|
## 0.1.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@nhost/docgen",
|
"name": "@nhost/docgen",
|
||||||
"description": "Documentation generator for classes and functions",
|
"description": "Documentation generator for classes and functions",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.cjs.js",
|
"main": "dist/index.cjs.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/hasura-auth-js
|
# @nhost/hasura-auth-js
|
||||||
|
|
||||||
|
## 1.12.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 1.12.0
|
## 1.12.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/hasura-auth-js",
|
"name": "@nhost/hasura-auth-js",
|
||||||
"version": "1.12.0",
|
"version": "1.12.1",
|
||||||
"description": "Hasura-auth client",
|
"description": "Hasura-auth client",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -75,6 +75,6 @@
|
|||||||
"cheerio": "1.0.0-rc.12",
|
"cheerio": "1.0.0-rc.12",
|
||||||
"mailhog": "^4.16.0",
|
"mailhog": "^4.16.0",
|
||||||
"msw": "^0.47.4",
|
"msw": "^0.47.4",
|
||||||
"start-server-and-test": "^1.14.0"
|
"start-server-and-test": "^1.15.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/hasura-storage-js
|
# @nhost/hasura-storage-js
|
||||||
|
|
||||||
|
## 1.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 1.13.0
|
## 1.13.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/hasura-storage-js",
|
"name": "@nhost/hasura-storage-js",
|
||||||
"version": "1.13.0",
|
"version": "1.13.1",
|
||||||
"description": "Hasura-storage client",
|
"description": "Hasura-storage client",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"jpeg-js": "^0.4.4",
|
"jpeg-js": "^0.4.4",
|
||||||
"pixelmatch": "^5.3.0",
|
"pixelmatch": "^5.3.0",
|
||||||
"start-server-and-test": "^1.14.0",
|
"start-server-and-test": "^1.15.2",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
# @nhost/nextjs
|
# @nhost/nextjs
|
||||||
|
|
||||||
|
## 1.13.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/react@1.13.2
|
||||||
|
|
||||||
|
## 1.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- d42c27ae: Add explicit return types to React hooks
|
||||||
|
- 927be4a2: Store the session in a cookie so there is no need for an SSR page to ask for a new access token
|
||||||
|
- Updated dependencies [c2706c7d]
|
||||||
|
- Updated dependencies [d42c27ae]
|
||||||
|
- @nhost/react@1.13.1
|
||||||
|
|
||||||
## 1.13.0
|
## 1.13.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/nextjs",
|
"name": "@nhost/nextjs",
|
||||||
"version": "1.13.0",
|
"version": "1.13.2",
|
||||||
"description": "Nhost NextJS library",
|
"description": "Nhost NextJS library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { AuthMachine, NHOST_REFRESH_TOKEN_KEY, VanillaNhostClient } from '@nhost/react'
|
import {
|
||||||
|
AuthMachine,
|
||||||
|
NhostSession,
|
||||||
|
NHOST_REFRESH_TOKEN_KEY,
|
||||||
|
VanillaNhostClient
|
||||||
|
} from '@nhost/react'
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
import { GetServerSidePropsContext } from 'next'
|
import { GetServerSidePropsContext } from 'next'
|
||||||
import { StateFrom } from 'xstate'
|
import { StateFrom } from 'xstate'
|
||||||
import { waitFor } from 'xstate/lib/waitFor'
|
import { waitFor } from 'xstate/lib/waitFor'
|
||||||
|
import { NHOST_SESSION_KEY } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an Nhost client that runs on the server side.
|
* Creates an Nhost client that runs on the server side.
|
||||||
@@ -42,11 +48,17 @@ export const createServerSideClient = async (
|
|||||||
Cookies.remove(key)
|
Cookies.remove(key)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
start: true,
|
start: false,
|
||||||
autoRefreshToken: false,
|
autoRefreshToken: false,
|
||||||
autoSignIn: true
|
autoSignIn: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const strSession = context.req.cookies[NHOST_SESSION_KEY]
|
||||||
|
const refreshToken = context.req.cookies[NHOST_REFRESH_TOKEN_KEY]
|
||||||
|
const initialSession: NhostSession = strSession &&
|
||||||
|
refreshToken && { ...JSON.parse(strSession), refreshToken }
|
||||||
|
|
||||||
|
nhost.auth.client.start({ initialSession })
|
||||||
await waitFor(
|
await waitFor(
|
||||||
nhost.auth.client.interpreter!,
|
nhost.auth.client.interpreter!,
|
||||||
(state: StateFrom<AuthMachine>) => !state.hasTag('loading')
|
(state: StateFrom<AuthMachine>) => !state.hasTag('loading')
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
NhostProvider,
|
NhostProvider,
|
||||||
Subdomain
|
Subdomain
|
||||||
} from '@nhost/react'
|
} from '@nhost/react'
|
||||||
|
import { setNhostSessionInCookie } from './utils'
|
||||||
|
|
||||||
export * from '@nhost/react'
|
export * from '@nhost/react'
|
||||||
export * from './create-server-side-client'
|
export * from './create-server-side-client'
|
||||||
@@ -38,5 +39,10 @@ export class NhostClient extends ReactNhostClient {
|
|||||||
autoRefreshToken: isBrowser && params.autoRefreshToken,
|
autoRefreshToken: isBrowser && params.autoRefreshToken,
|
||||||
clientStorageType: 'cookie'
|
clientStorageType: 'cookie'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.auth.onAuthStateChanged(() => {
|
||||||
|
setNhostSessionInCookie(this)
|
||||||
|
})
|
||||||
|
this.auth.onTokenChanged(setNhostSessionInCookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { NhostSession } from '@nhost/react'
|
import { NhostClient, NhostSession } from '@nhost/react'
|
||||||
import fetch from 'cross-fetch'
|
import fetch from 'cross-fetch'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
export const refresh = async (nhostUrl: string, refreshToken: string): Promise<NhostSession> => {
|
export const refresh = async (nhostUrl: string, refreshToken: string): Promise<NhostSession> => {
|
||||||
const result = await fetch(`${nhostUrl}/v1/auth/token`, {
|
const result = await fetch(`${nhostUrl}/v1/auth/token`, {
|
||||||
@@ -9,6 +10,26 @@ export const refresh = async (nhostUrl: string, refreshToken: string): Promise<N
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({ refreshToken })
|
body: JSON.stringify({ refreshToken })
|
||||||
})
|
})
|
||||||
if (result.ok) return result.json()
|
if (result.ok) {
|
||||||
else return Promise.reject(result.statusText)
|
return result.json()
|
||||||
|
}
|
||||||
|
return Promise.reject(result.statusText)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NHOST_SESSION_KEY = 'nhostSession'
|
||||||
|
|
||||||
|
export const setNhostSessionInCookie = (param: NhostClient | NhostSession | null) => {
|
||||||
|
const session = param && 'auth' in param ? param.auth.getSession() : param
|
||||||
|
if (!session) {
|
||||||
|
Cookies.remove(NHOST_SESSION_KEY)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { refreshToken, ...rest } = session
|
||||||
|
const expires = new Date()
|
||||||
|
// * Expire the cookie 60 seconds before the token expires
|
||||||
|
expires.setSeconds(expires.getSeconds() + session.accessTokenExpiresIn - 60)
|
||||||
|
Cookies.set(NHOST_SESSION_KEY, JSON.stringify(rest), {
|
||||||
|
sameSite: 'strict',
|
||||||
|
expires
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# @nhost/nhost-js
|
# @nhost/nhost-js
|
||||||
|
|
||||||
|
## 1.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/hasura-auth-js@1.12.1
|
||||||
|
- @nhost/hasura-storage-js@1.13.1
|
||||||
|
|
||||||
## 1.13.0
|
## 1.13.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/nhost-js",
|
"name": "@nhost/nhost-js",
|
||||||
"version": "1.13.0",
|
"version": "1.13.1",
|
||||||
"description": "Nhost JavaScript SDK",
|
"description": "Nhost JavaScript SDK",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"@faker-js/faker": "^7.6.0",
|
"@faker-js/faker": "^7.6.0",
|
||||||
"@nhost/docgen": "workspace:*",
|
"@nhost/docgen": "workspace:*",
|
||||||
"graphql": "16.6.0",
|
"graphql": "16.6.0",
|
||||||
"start-server-and-test": "^1.14.0"
|
"start-server-and-test": "^1.15.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# @nhost/react
|
# @nhost/react
|
||||||
|
|
||||||
|
## 1.13.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
- Updated dependencies [200e9f77]
|
||||||
|
- @nhost/nhost-js@1.13.1
|
||||||
|
|
||||||
|
## 1.13.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- c2706c7d: Export commonly used types
|
||||||
|
|
||||||
|
`BackendUrl`, `ErrorPayload`, `NhostSession`, `Subdomain`, and `User` are now exported in all our SDKs
|
||||||
|
|
||||||
|
- d42c27ae: Add explicit return types to React hooks
|
||||||
|
|
||||||
## 1.13.0
|
## 1.13.0
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/react",
|
"name": "@nhost/react",
|
||||||
"version": "1.13.0",
|
"version": "1.13.2",
|
||||||
"description": "Nhost React library",
|
"description": "Nhost React library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import {
|
|||||||
BackendUrl,
|
BackendUrl,
|
||||||
NhostAuthConstructorParams,
|
NhostAuthConstructorParams,
|
||||||
NhostClient as _VanillaNhostClient,
|
NhostClient as _VanillaNhostClient,
|
||||||
NhostSession,
|
|
||||||
NHOST_REFRESH_TOKEN_KEY,
|
NHOST_REFRESH_TOKEN_KEY,
|
||||||
Subdomain
|
Subdomain
|
||||||
} from '@nhost/nhost-js'
|
} from '@nhost/nhost-js'
|
||||||
|
|
||||||
export type { NhostSession, NhostAuthConstructorParams, AuthMachine, Subdomain, BackendUrl }
|
// * Required for @nhost/nextjs
|
||||||
|
export type { NhostAuthConstructorParams, AuthMachine }
|
||||||
export { NHOST_REFRESH_TOKEN_KEY }
|
export { NHOST_REFRESH_TOKEN_KEY }
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export type { BackendUrl, ErrorPayload, NhostSession, Subdomain, User } from '@nhost/nhost-js'
|
||||||
export * from './client'
|
export * from './client'
|
||||||
export * from './components'
|
export * from './components'
|
||||||
export * from './provider'
|
export * from './provider'
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-access-token
|
* @docs https://docs.nhost.io/reference/react/use-access-token
|
||||||
*/
|
*/
|
||||||
export const useAccessToken = () => {
|
export const useAccessToken = (): string | null => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(service, (state) => state.context.accessToken.value)
|
return useSelector(service, (state) => state.context.accessToken.value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* Use {@link useAuthenticationStatus} instead.
|
* Use {@link useAuthenticationStatus} instead.
|
||||||
*/
|
*/
|
||||||
export const useAuthLoading = () => {
|
export const useAuthLoading = (): boolean => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(service, (state) => state.hasTag('loading'))
|
return useSelector(service, (state) => state.hasTag('loading'))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-access-token
|
* @docs https://docs.nhost.io/reference/react/use-access-token
|
||||||
*/
|
*/
|
||||||
export const useAuthenticated = () => {
|
export const useAuthenticated = (): boolean => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(
|
const [isAuthenticated, setIsAuthenticated] = useState(
|
||||||
!!service.status && service.getSnapshot().matches({ authentication: 'signedIn' })
|
!!service.status && service.getSnapshot().matches({ authentication: 'signedIn' })
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ErrorPayload } from '@nhost/nhost-js'
|
||||||
import { useSelector } from '@xstate/react'
|
import { useSelector } from '@xstate/react'
|
||||||
|
|
||||||
import { useAuthInterpreter } from './useAuthInterpreter'
|
import { useAuthInterpreter } from './useAuthInterpreter'
|
||||||
@@ -10,7 +11,13 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
* const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
* const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export const useAuthenticationStatus = () => {
|
export const useAuthenticationStatus = (): {
|
||||||
|
isAuthenticated: boolean
|
||||||
|
isLoading: boolean
|
||||||
|
error: ErrorPayload | null
|
||||||
|
isError: boolean
|
||||||
|
connectionAttempts: number
|
||||||
|
} => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAccessToken } from './useAccessToken'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-decoded-access-token
|
* @docs https://docs.nhost.io/reference/react/use-decoded-access-token
|
||||||
*/
|
*/
|
||||||
export const useDecodedAccessToken = () => {
|
export const useDecodedAccessToken = (): JWTClaims | null => {
|
||||||
const jwt = useAccessToken()
|
const jwt = useAccessToken()
|
||||||
return jwt ? jwt_decode<JWTClaims>(jwt) : null
|
return jwt ? jwt_decode<JWTClaims>(jwt) : null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useHasuraClaims } from './useHasuraClaims'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-hasura-claim
|
* @docs https://docs.nhost.io/reference/react/use-hasura-claim
|
||||||
*/
|
*/
|
||||||
export const useHasuraClaim = (name: string) => {
|
export const useHasuraClaim = (name: string): string | string[] | null => {
|
||||||
const hasuraClaims = useHasuraClaims()
|
const hasuraClaims = useHasuraClaims()
|
||||||
return hasuraClaims?.[name.startsWith('x-hasura-') ? name : `x-hasura-${name}`] || null
|
return hasuraClaims?.[name.startsWith('x-hasura-') ? name : `x-hasura-${name}`] || null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
import { JWTHasuraClaims } from '@nhost/nhost-js'
|
||||||
import { useDecodedAccessToken } from './useDecodedAccessToken'
|
import { useDecodedAccessToken } from './useDecodedAccessToken'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,7 +11,7 @@ import { useDecodedAccessToken } from './useDecodedAccessToken'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-hasura-claims
|
* @docs https://docs.nhost.io/reference/react/use-hasura-claims
|
||||||
*/
|
*/
|
||||||
export const useHasuraClaims = () => {
|
export const useHasuraClaims = (): JWTHasuraClaims | null => {
|
||||||
const claims = useDecodedAccessToken()
|
const claims = useDecodedAccessToken()
|
||||||
return claims?.['https://hasura.io/jwt/claims'] || null
|
return claims?.['https://hasura.io/jwt/claims'] || null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { User } from '@nhost/nhost-js'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { useAuthenticationStatus } from './useAuthenticationStatus'
|
import { useAuthenticationStatus } from './useAuthenticationStatus'
|
||||||
@@ -7,7 +8,11 @@ import { useUserData } from './useUserData'
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
* This hook ensures backward compatibility with `@nhost/react-auth`, which is deprecated.
|
* This hook ensures backward compatibility with `@nhost/react-auth`, which is deprecated.
|
||||||
*/
|
*/
|
||||||
export const useNhostAuth = () => {
|
export const useNhostAuth = (): {
|
||||||
|
isLoading: boolean
|
||||||
|
isAuthenticated: boolean
|
||||||
|
user: User | null
|
||||||
|
} => {
|
||||||
const { isLoading, isAuthenticated } = useAuthenticationStatus()
|
const { isLoading, isAuthenticated } = useAuthenticationStatus()
|
||||||
const user = useUserData()
|
const user = useUserData()
|
||||||
return useMemo(() => ({ isLoading, isAuthenticated, user }), [isLoading, isAuthenticated, user])
|
return useMemo(() => ({ isLoading, isAuthenticated, user }), [isLoading, isAuthenticated, user])
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { NhostReactContext } from './provider'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-nhost-backend-url
|
* @docs https://docs.nhost.io/reference/react/use-nhost-backend-url
|
||||||
*/
|
*/
|
||||||
export const useNhostBackendUrl = () => {
|
export const useNhostBackendUrl = (): string => {
|
||||||
const nhost = useContext(NhostReactContext)
|
const nhost = useContext(NhostReactContext)
|
||||||
return nhost.auth.client.backendUrl.replace('/v1/auth', '')
|
return nhost.auth.client.backendUrl.replace('/v1/auth', '')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import { NhostReactContext } from './provider'
|
|||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export const useProviderLink = (options?: ProviderOptions) => {
|
export const useProviderLink = (options?: ProviderOptions): Record<Provider, string> => {
|
||||||
/**
|
/**
|
||||||
* @internal When using Nextjs or any SSR framework, nhost.auth.client.clientUrl will be set to `undefined`
|
* @internal When using Nextjs or any SSR framework, nhost.auth.client.clientUrl will be set to `undefined`
|
||||||
* as its value is set to window.location.origin.
|
* as its value is set to window.location.origin.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-avatar-url
|
* @docs https://docs.nhost.io/reference/react/use-user-avatar-url
|
||||||
*/
|
*/
|
||||||
export const useUserAvatarUrl = () => {
|
export const useUserAvatarUrl = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { User } from '@nhost/nhost-js'
|
||||||
import { useSelector } from '@xstate/react'
|
import { useSelector } from '@xstate/react'
|
||||||
|
|
||||||
import { useAuthInterpreter } from './useAuthInterpreter'
|
import { useAuthInterpreter } from './useAuthInterpreter'
|
||||||
@@ -31,7 +32,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-data
|
* @docs https://docs.nhost.io/reference/react/use-user-data
|
||||||
*/
|
*/
|
||||||
export const useUserData = () => {
|
export const useUserData = (): User | null => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-default-role
|
* @docs https://docs.nhost.io/reference/react/use-user-default-role
|
||||||
*/
|
*/
|
||||||
export const useUserDefaultRole = () => {
|
export const useUserDefaultRole = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-display-name
|
* @docs https://docs.nhost.io/reference/react/use-user-display-name
|
||||||
*/
|
*/
|
||||||
export const useUserDisplayName = () => {
|
export const useUserDisplayName = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-email
|
* @docs https://docs.nhost.io/reference/react/use-user-email
|
||||||
*/
|
*/
|
||||||
export const useUserEmail = () => {
|
export const useUserEmail = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-id
|
* @docs https://docs.nhost.io/reference/react/use-user-id
|
||||||
*/
|
*/
|
||||||
export const useUserId = () => {
|
export const useUserId = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-is-anonymous
|
* @docs https://docs.nhost.io/reference/react/use-user-is-anonymous
|
||||||
*/
|
*/
|
||||||
export const useUserIsAnonymous = () => {
|
export const useUserIsAnonymous = (): boolean | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-locale
|
* @docs https://docs.nhost.io/reference/react/use-user-locale
|
||||||
*/
|
*/
|
||||||
export const useUserLocale = () => {
|
export const useUserLocale = (): string | undefined => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(
|
return useSelector(
|
||||||
service,
|
service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useAuthInterpreter } from './useAuthInterpreter'
|
|||||||
*
|
*
|
||||||
* @docs https://docs.nhost.io/reference/react/use-user-roles
|
* @docs https://docs.nhost.io/reference/react/use-user-roles
|
||||||
*/
|
*/
|
||||||
export const useUserRoles = () => {
|
export const useUserRoles = (): string[] => {
|
||||||
const service = useAuthInterpreter()
|
const service = useAuthInterpreter()
|
||||||
return useSelector(service, (state) => {
|
return useSelector(service, (state) => {
|
||||||
if (!state.matches('authentication.signedIn')) {
|
if (!state.matches('authentication.signedIn')) {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @nhost/sync-versions
|
# @nhost/sync-versions
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
|
||||||
|
|
||||||
## 0.0.3
|
## 0.0.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@nhost/sync-versions",
|
"name": "@nhost/sync-versions",
|
||||||
"description": "Sync the versions of Nhost services in each of the packages of a pnpm workspace",
|
"description": "Sync the versions of Nhost services in each of the packages of a pnpm workspace",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.cjs.js",
|
"main": "dist/index.cjs.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user