Compare commits
17 Commits
@nhost/das
...
@nhost/nex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4854df4559 | ||
|
|
865dd93fbe | ||
|
|
0c50816717 | ||
|
|
d3b4fc358e | ||
|
|
b3bcacb300 | ||
|
|
aa7ecdb38f | ||
|
|
20672c7a9b | ||
|
|
29d27e19b4 | ||
|
|
46fc520707 | ||
|
|
21e90da476 | ||
|
|
b944d053d0 | ||
|
|
6902a36512 | ||
|
|
aea6d186c2 | ||
|
|
a535aa3834 | ||
|
|
c9dca09478 | ||
|
|
414896491f | ||
|
|
cdf6776523 |
@@ -20,7 +20,7 @@ runs:
|
||||
id: pnpm-cache-dir
|
||||
shell: bash
|
||||
run: echo "dir=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
id: pnpm-cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache-dir.outputs.dir }}
|
||||
|
||||
2
.github/workflows/gen_ai_review.yaml
vendored
2
.github/workflows/gen_ai_review.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
steps:
|
||||
- name: PR Agent action step
|
||||
id: pragent
|
||||
uses: Codium-ai/pr-agent@v0.24
|
||||
uses: Codium-ai/pr-agent@v0.26
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
OPENAI_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @nhost/dashboard
|
||||
|
||||
## 2.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 21e90da: chore: remove restrictions on SMTP sender so My Name <name@acme.com> can be added
|
||||
- 865dd93: fix: duplicate Run placeholders when there is an error in the backend
|
||||
- 6902a36: fix: can remove resources if postgres capacity is higher than 10
|
||||
- a535aa3: fix: fetch user roles locally in auth section
|
||||
- 0c50816: fix: allow decimal numbers in database row insert
|
||||
- aea6d18: chore: add warning when pausing a project about losing Run services persistent volume data
|
||||
- d3b4fc3: feat: allow to change postgres settings if project is paused
|
||||
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
|
||||
- c9dca09: feat: add reset password form
|
||||
- b3bcacb: fix: paused project banner cannot read null project name
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [46fc520]
|
||||
- Updated dependencies [29d27e1]
|
||||
- @nhost/nextjs@2.2.0
|
||||
- @nhost/react-apollo@15.0.1
|
||||
|
||||
## 2.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/dashboard",
|
||||
"version": "2.12.0",
|
||||
"version": "2.13.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
@@ -84,7 +84,7 @@
|
||||
"just-kebab-case": "^4.2.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lucide-react": "^0.416.0",
|
||||
"next": "^14.2.10",
|
||||
"next": "^14.2.22",
|
||||
"next-nprogress-bar": "^2.3.13",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-themes": "^0.3.0",
|
||||
|
||||
@@ -21,23 +21,22 @@ export default function UnauthenticatedLayout({
|
||||
const router = useRouter();
|
||||
const isPlatform = useIsPlatform();
|
||||
const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
||||
const isOnResetPassword = router.route === '/password/reset';
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlatform || (!isLoading && isAuthenticated)) {
|
||||
router.push('/');
|
||||
// we do not want to redirect if the user tries to reset their password
|
||||
if (!isOnResetPassword) {
|
||||
router.push('/');
|
||||
}
|
||||
}
|
||||
}, [isLoading, isAuthenticated, router, isPlatform]);
|
||||
}, [isLoading, isAuthenticated, router, isPlatform, isOnResetPassword]);
|
||||
|
||||
if (!isPlatform || isLoading || isAuthenticated) {
|
||||
if ((!isPlatform || isLoading || isAuthenticated) && !isOnResetPassword) {
|
||||
return (
|
||||
<BaseLayout {...props}>
|
||||
<LoadingScreen
|
||||
sx={{ backgroundColor: (theme) => theme.palette.background.default }}
|
||||
slotProps={{
|
||||
activityIndicator: {
|
||||
className: 'text-white',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</BaseLayout>
|
||||
);
|
||||
@@ -59,19 +58,19 @@ export default function UnauthenticatedLayout({
|
||||
|
||||
<RetryableErrorBoundary>
|
||||
<Box
|
||||
className="flex items-center min-h-screen"
|
||||
className="flex min-h-screen items-center"
|
||||
sx={{ backgroundColor: (theme) => theme.palette.common.black }}
|
||||
>
|
||||
<Container
|
||||
rootClassName="bg-transparent h-full"
|
||||
className="grid items-center w-full h-full gap-12 pt-8 pb-12 bg-transparent justify-items-center lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-0"
|
||||
className="grid h-full w-full items-center justify-items-center gap-12 bg-transparent pb-12 pt-8 lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-0"
|
||||
>
|
||||
<div className="relative z-10 order-2 grid w-full max-w-[544px] grid-flow-row gap-12 lg:order-1">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className="relative z-0 order-1 flex h-full w-full items-center justify-center md:min-h-[150px] lg:order-2 lg:min-h-[none]">
|
||||
<div className="absolute top-0 bottom-0 left-0 right-0 flex items-center justify-center w-full h-full max-w-xl mx-auto overflow-hidden opacity-70">
|
||||
<div className="absolute bottom-0 left-0 right-0 top-0 mx-auto flex h-full w-full max-w-xl items-center justify-center overflow-hidden opacity-70">
|
||||
<Image
|
||||
priority
|
||||
src="/assets/line-grid.svg"
|
||||
|
||||
@@ -19,7 +19,7 @@ import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWith
|
||||
|
||||
const validationSchema = yup
|
||||
.object({
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
sender: yup.string().label('SMTP Sender').required(),
|
||||
password: yup.string().label('Password').required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
@@ -30,7 +30,7 @@ const smtpValidationSchema = yup
|
||||
user: yup.string().label('Username').required(),
|
||||
password: yup.string().label('Password'),
|
||||
method: yup.string().required(),
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
sender: yup.string().label('SMTP Sender').required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
|
||||
@@ -16,18 +16,20 @@ import { Text } from '@/components/ui/v2/Text';
|
||||
import { useRemoteApplicationGQLClient } from '@/features/orgs/hooks/useRemoteApplicationGQLClient';
|
||||
import { EditUserPasswordForm } from '@/features/orgs/projects/authentication/users/components/EditUserPasswordForm';
|
||||
import { getReadableProviderName } from '@/features/orgs/projects/authentication/users/utils/getReadableProviderName';
|
||||
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
||||
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
||||
import { type RemoteAppUser } from '@/pages/orgs/[orgSlug]/projects/[appSubdomain]/users';
|
||||
import type { DialogFormProps } from '@/types/common';
|
||||
import { copy } from '@/utils/copy';
|
||||
import {
|
||||
RemoteAppGetUsersDocument,
|
||||
useGetProjectLocalesQuery,
|
||||
useGetRolesPermissionsQuery,
|
||||
useUpdateRemoteAppUserMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { copy } from '@/utils/copy';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useTheme } from '@mui/material';
|
||||
import { format } from 'date-fns';
|
||||
@@ -106,6 +108,8 @@ export default function EditUserForm({
|
||||
onDeleteUser,
|
||||
roles,
|
||||
}: EditUserFormProps) {
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const theme = useTheme();
|
||||
const { onDirtyStateChange, openDialog } = useDialog();
|
||||
const { project } = useProject();
|
||||
@@ -196,6 +200,7 @@ export default function EditUserForm({
|
||||
|
||||
const { data: dataRoles } = useGetRolesPermissionsQuery({
|
||||
variables: { appId: project?.id },
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const allAvailableProjectRoles = getUserRoles(
|
||||
@@ -206,6 +211,7 @@ export default function EditUserForm({
|
||||
variables: {
|
||||
appId: project?.id,
|
||||
},
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const allowedLocales = data?.config?.auth?.user?.locale?.allowed || [];
|
||||
|
||||
@@ -15,6 +15,8 @@ import { Text } from '@/components/ui/v2/Text';
|
||||
import { useRemoteApplicationGQLClient } from '@/features/orgs/hooks/useRemoteApplicationGQLClient';
|
||||
import type { EditUserFormValues } from '@/features/orgs/projects/authentication/users/components/EditUserForm';
|
||||
import { getReadableProviderName } from '@/features/orgs/projects/authentication/users/utils/getReadableProviderName';
|
||||
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
|
||||
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
||||
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
||||
@@ -61,6 +63,8 @@ export interface UsersBodyProps {
|
||||
|
||||
export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
|
||||
const theme = useTheme();
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { openAlertDialog, openDrawer, closeDrawer } = useDialog();
|
||||
const { project } = useProject();
|
||||
const remoteProjectGQLClient = useRemoteApplicationGQLClient();
|
||||
@@ -88,6 +92,7 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
|
||||
*/
|
||||
const { data: dataRoles } = useGetRolesPermissionsQuery({
|
||||
variables: { appId: project?.id },
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
|
||||
const { allowed: allowedRoles } = dataRoles?.config?.auth?.user?.roles || {};
|
||||
|
||||
@@ -36,8 +36,8 @@ export default function ApplicationPaused() {
|
||||
>
|
||||
<RemoveApplicationModal
|
||||
close={() => setShowDeletingModal(false)}
|
||||
title={`Remove project ${project.name}?`}
|
||||
description={`The project ${project.name} will be removed. All data will be lost and there will be no way to
|
||||
title={`Remove project ${project?.name}?`}
|
||||
description={`The project ${project?.name} will be removed. All data will be lost and there will be no way to
|
||||
recover the app once it has been deleted.`}
|
||||
className="z-50"
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function useProjectRedirectWhenReady(
|
||||
const { data, client, startPolling, ...rest } = useGetApplicationStateQuery({
|
||||
...options,
|
||||
variables: { ...options.variables, appId: project?.id },
|
||||
skip: !project.id,
|
||||
skip: !project?.id,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
|
||||
import { DataGrid } from '@/components/dataGrid/DataGrid';
|
||||
import { DataGridBooleanCell } from '@/components/dataGrid/DataGridBooleanCell';
|
||||
import { DataGridDateCell } from '@/components/dataGrid/DataGridDateCell';
|
||||
import { DataGridNumericCell } from '@/components/dataGrid/DataGridNumericCell';
|
||||
import { DataGridTextCell } from '@/components/dataGrid/DataGridTextCell';
|
||||
import { FormActivityIndicator } from '@/components/form/FormActivityIndicator';
|
||||
import { InlineCode } from '@/components/presentational/InlineCode';
|
||||
import { KeyIcon } from '@/components/ui/v2/icons/KeyIcon';
|
||||
@@ -23,11 +17,19 @@ import { normalizeDefaultValue } from '@/features/orgs/projects/database/dataGri
|
||||
import {
|
||||
POSTGRESQL_CHARACTER_TYPES,
|
||||
POSTGRESQL_DATE_TIME_TYPES,
|
||||
POSTGRESQL_DECIMAL_TYPES,
|
||||
POSTGRESQL_INTEGER_TYPES,
|
||||
POSTGRESQL_JSON_TYPES,
|
||||
POSTGRESQL_NUMERIC_TYPES,
|
||||
} from '@/features/orgs/projects/database/dataGrid/utils/postgresqlConstants';
|
||||
import { isSchemaLocked } from '@/features/orgs/projects/database/dataGrid/utils/schemaHelpers';
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
import type { DataGridProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
|
||||
import { DataGrid } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
|
||||
import { DataGridBooleanCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridBooleanCell';
|
||||
import { DataGridDateCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridDateCell';
|
||||
import { DataGridDecimalCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridDecimalCell';
|
||||
import { DataGridIntegerCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridIntegerCell';
|
||||
import { DataGridTextCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridTextCell';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -68,10 +70,10 @@ export function createDataGridColumn(
|
||||
|
||||
const defaultColumnConfiguration = {
|
||||
Header: () => (
|
||||
<div className="grid items-center justify-start grid-flow-col gap-1 font-normal">
|
||||
<div className="grid grid-flow-col items-center justify-start gap-1 font-normal">
|
||||
{column.is_primary && <KeyIcon className="text-sm" />}
|
||||
|
||||
<span className="font-bold truncate" title={column.column_name}>
|
||||
<span className="truncate font-bold" title={column.column_name}>
|
||||
{column.column_name}
|
||||
</span>
|
||||
|
||||
@@ -104,12 +106,21 @@ export function createDataGridColumn(
|
||||
foreignKeyRelation: column.foreign_key_relation,
|
||||
};
|
||||
|
||||
if (POSTGRESQL_NUMERIC_TYPES.includes(column.data_type)) {
|
||||
if (POSTGRESQL_INTEGER_TYPES.includes(column.data_type)) {
|
||||
return {
|
||||
...defaultColumnConfiguration,
|
||||
type: 'number',
|
||||
width: 200,
|
||||
Cell: DataGridNumericCell,
|
||||
Cell: DataGridIntegerCell,
|
||||
};
|
||||
}
|
||||
|
||||
if (POSTGRESQL_DECIMAL_TYPES.includes(column.data_type)) {
|
||||
return {
|
||||
...defaultColumnConfiguration,
|
||||
type: 'text',
|
||||
width: 200,
|
||||
Cell: DataGridDecimalCell,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,6 @@ export default function DatabaseRecordInputGroup({
|
||||
autoFocus={index === 0 && autoFocusFirstInput}
|
||||
slotProps={{
|
||||
label: commonLabelProps,
|
||||
inputRoot: { step: 1 },
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -19,20 +19,23 @@ export const POSTGRESQL_ERROR_CODES = {
|
||||
*
|
||||
* @docs https://www.postgresql.org/docs/current/datatype-numeric.html
|
||||
*/
|
||||
export const POSTGRESQL_NUMERIC_TYPES = [
|
||||
export const POSTGRESQL_INTEGER_TYPES = [
|
||||
'smallint',
|
||||
'integer',
|
||||
'bigint',
|
||||
'decimal',
|
||||
'numeric',
|
||||
'real',
|
||||
'double precision',
|
||||
'smallserial',
|
||||
'serial',
|
||||
'bigserial',
|
||||
'oid',
|
||||
];
|
||||
|
||||
export const POSTGRESQL_DECIMAL_TYPES = [
|
||||
'decimal',
|
||||
'numeric',
|
||||
'real',
|
||||
'double precision',
|
||||
];
|
||||
|
||||
/**
|
||||
* Character data types in PostgreSQL.
|
||||
*
|
||||
|
||||
@@ -118,8 +118,8 @@ export default function DatabaseConnectionInfo() {
|
||||
}
|
||||
|
||||
const postgresHost = generateAppServiceUrl(
|
||||
project.subdomain,
|
||||
project.region,
|
||||
project?.subdomain,
|
||||
project?.region,
|
||||
'db',
|
||||
).replace('https://', '');
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ const validationSchema = Yup.object({
|
||||
value: Yup.string().required('Major version is a required field'),
|
||||
})
|
||||
.label('Postgres major version')
|
||||
.required(),
|
||||
.required()
|
||||
.test('not-zero', 'Invalid major version', (value) => value?.value !== '0'),
|
||||
minorVersion: Yup.object({
|
||||
label: Yup.string().required(),
|
||||
value: Yup.string().required('Minor version is a required field'),
|
||||
@@ -186,18 +187,29 @@ export default function DatabaseServiceVersionSettings() {
|
||||
shouldPoll: true,
|
||||
});
|
||||
|
||||
const showMigrateWarning =
|
||||
Number(selectedMajor) > Number(currentPostgresMajor);
|
||||
|
||||
const { state } = useAppState();
|
||||
const applicationUpdating =
|
||||
state === ApplicationStatus.Updating ||
|
||||
state === ApplicationStatus.Migrating;
|
||||
|
||||
const applicationLive = state === ApplicationStatus.Live;
|
||||
const applicationPaused = state === ApplicationStatus.Paused;
|
||||
const applicationPausing = state === ApplicationStatus.Pausing;
|
||||
|
||||
const showMigrateWarning =
|
||||
!applicationPaused &&
|
||||
!applicationPausing &&
|
||||
Number(selectedMajor) > Number(currentPostgresMajor);
|
||||
|
||||
const applicationUnhealthy =
|
||||
state !== ApplicationStatus.Live && !applicationUpdating;
|
||||
!applicationLive &&
|
||||
!applicationPaused &&
|
||||
!applicationPausing &&
|
||||
!applicationUpdating;
|
||||
const isMajorVersionDirty = formState?.dirtyFields?.majorVersion;
|
||||
const isMinorVersionDirty = formState?.dirtyFields?.minorVersion;
|
||||
const isDirty = isMajorVersionDirty || isMinorVersionDirty;
|
||||
|
||||
const versionFieldsDisabled =
|
||||
applicationUpdating || applicationUnhealthy || maintenanceActive;
|
||||
const saveDisabled = versionFieldsDisabled || !isDirty;
|
||||
@@ -208,7 +220,7 @@ export default function DatabaseServiceVersionSettings() {
|
||||
const newVersion = `${formValues.majorVersion.value}.${formValues.minorVersion.value}`;
|
||||
|
||||
// Major version change
|
||||
if (isMajorVersionDirty) {
|
||||
if (isMajorVersionDirty && applicationLive) {
|
||||
openDialog({
|
||||
title: 'Update Postgres MAJOR version',
|
||||
component: (
|
||||
@@ -228,7 +240,7 @@ export default function DatabaseServiceVersionSettings() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Minor version change
|
||||
// Only minor version change or project is paused/pausing
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: project.id,
|
||||
@@ -338,7 +350,6 @@ export default function DatabaseServiceVersionSettings() {
|
||||
return option.value;
|
||||
}}
|
||||
showCustomOption="auto"
|
||||
isOptionEqualToValue={() => false}
|
||||
filterOptions={(options, { inputValue }) => {
|
||||
const inputValueLower = inputValue.toLowerCase();
|
||||
const matched = [];
|
||||
@@ -383,12 +394,13 @@ export default function DatabaseServiceVersionSettings() {
|
||||
form.setValue('majorVersion', value);
|
||||
}
|
||||
}}
|
||||
clearOnBlur
|
||||
fullWidth
|
||||
className="lg:col-span-1"
|
||||
label="MAJOR"
|
||||
options={availableMajorVersions}
|
||||
error={!!formState.errors?.majorVersion?.value?.message}
|
||||
helperText={formState.errors?.majorVersion?.value?.message}
|
||||
error={!!formState.errors?.majorVersion?.message}
|
||||
helperText={formState.errors?.majorVersion?.message}
|
||||
customOptionLabel={(value) => `Use custom value: "${value}"`}
|
||||
/>
|
||||
<ControlledAutocomplete
|
||||
@@ -424,12 +436,13 @@ export default function DatabaseServiceVersionSettings() {
|
||||
|
||||
return result;
|
||||
}}
|
||||
clearOnBlur
|
||||
fullWidth
|
||||
className="lg:col-span-2"
|
||||
label="MINOR"
|
||||
options={availableMinorVersions}
|
||||
error={!!formState.errors?.minorVersion?.value?.message}
|
||||
helperText={formState.errors?.minorVersion?.value?.message}
|
||||
error={!!formState.errors?.minorVersion?.message}
|
||||
helperText={formState.errors?.minorVersion?.message}
|
||||
showCustomOption="auto"
|
||||
customOptionLabel={(value) => `Use custom value: "${value}"`}
|
||||
/>
|
||||
|
||||
@@ -2,11 +2,13 @@ import { useUI } from '@/components/common/UIProvider';
|
||||
import { Form } from '@/components/form/Form';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||
import { Alert } from '@/components/ui/v2/Alert';
|
||||
import { Box } from '@/components/ui/v2/Box';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
||||
import { UpgradeNotification } from '@/features/orgs/projects/common/components/UpgradeNotification';
|
||||
import { useAppState } from '@/features/orgs/projects/common/hooks/useAppState';
|
||||
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
|
||||
import { DatabaseStorageCapacityWarning } from '@/features/orgs/projects/database/settings/components/DatabaseStorageCapacityWarning';
|
||||
import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
|
||||
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
@@ -15,18 +17,25 @@ import {
|
||||
useGetPostgresSettingsQuery,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/generated/graphql';
|
||||
import { ApplicationStatus } from '@/types/application';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
capacity: Yup.number().required().min(10),
|
||||
capacity: Yup.number()
|
||||
.integer('Capacity must be an integer')
|
||||
.typeError('You must specify a number')
|
||||
.min(1, 'Capacity must be greater than 0')
|
||||
.required('Capacity is required'),
|
||||
});
|
||||
|
||||
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
|
||||
export type DatabaseStorageCapacityFormValues = Yup.InferType<
|
||||
typeof validationSchema
|
||||
>;
|
||||
|
||||
export default function AuthDomain() {
|
||||
export default function DatabaseStorageCapacity() {
|
||||
const isPlatform = useIsPlatform();
|
||||
const { org } = useCurrentOrg();
|
||||
const { maintenanceActive } = useUI();
|
||||
@@ -58,8 +67,32 @@ export default function AuthDomain() {
|
||||
resolver: yupResolver(validationSchema),
|
||||
});
|
||||
|
||||
const { formState, register, reset } = form;
|
||||
const { state } = useAppState();
|
||||
|
||||
const applicationPause =
|
||||
state === ApplicationStatus.Paused || state === ApplicationStatus.Pausing;
|
||||
|
||||
const { formState, register, reset, watch } = form;
|
||||
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
||||
const newCapacity = watch('capacity');
|
||||
|
||||
const decreasingSize = newCapacity < capacity;
|
||||
|
||||
const submitDisabled = useMemo(() => {
|
||||
if (!isDirty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (maintenanceActive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (decreasingSize && !applicationPause) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [isDirty, maintenanceActive, decreasingSize, applicationPause]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data && !loading) {
|
||||
@@ -81,7 +114,7 @@ export default function AuthDomain() {
|
||||
throw error;
|
||||
}
|
||||
|
||||
async function handleSubmit(formValues: AuthDomainFormValues) {
|
||||
async function handleSubmit(formValues: DatabaseStorageCapacityFormValues) {
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await updateConfig({
|
||||
@@ -120,7 +153,7 @@ export default function AuthDomain() {
|
||||
description="Specify the storage capacity for your PostgreSQL database."
|
||||
slotProps={{
|
||||
submitButton: {
|
||||
disabled: !isDirty || maintenanceActive,
|
||||
disabled: submitDisabled,
|
||||
loading: formState.isSubmitting,
|
||||
},
|
||||
}}
|
||||
@@ -134,25 +167,25 @@ export default function AuthDomain() {
|
||||
{...register('capacity')}
|
||||
id="capacity"
|
||||
name="capacity"
|
||||
type="number"
|
||||
type="text"
|
||||
endAdornment={
|
||||
<InputAdornment className="absolute right-2" position="end">
|
||||
GB
|
||||
</InputAdornment>
|
||||
}
|
||||
fullWidth
|
||||
disabled={project.legacyPlan?.isFree}
|
||||
className="lg:col-span-2"
|
||||
error={Boolean(formState.errors.capacity?.message)}
|
||||
helperText={formState.errors.capacity?.message}
|
||||
slotProps={{
|
||||
inputRoot: {
|
||||
min: capacity,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{!project.legacyPlan?.isFree && (
|
||||
<Alert severity="info" className="col-span-6 text-left">
|
||||
Note that volumes can only be increased (not decreased). Also, due
|
||||
to an AWS limitation, the same volume can only be increased once
|
||||
every 6 hours.
|
||||
</Alert>
|
||||
<DatabaseStorageCapacityWarning
|
||||
state={state}
|
||||
decreasingSize={decreasingSize}
|
||||
isDirty={isDirty}
|
||||
/>
|
||||
)}
|
||||
</SettingsContainer>
|
||||
</Form>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Alert } from '@/components/ui/v2/Alert';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import { ApplicationStatus } from '@/types/application';
|
||||
|
||||
interface DatabaseStorageCapacityWarningProps {
|
||||
state: ApplicationStatus;
|
||||
decreasingSize: boolean;
|
||||
isDirty: boolean;
|
||||
}
|
||||
|
||||
export default function DatabaseStorageCapacityWarning({
|
||||
state,
|
||||
decreasingSize,
|
||||
isDirty,
|
||||
}: DatabaseStorageCapacityWarningProps) {
|
||||
const applicationPause =
|
||||
state === ApplicationStatus.Paused || state === ApplicationStatus.Pausing;
|
||||
|
||||
if (!isDirty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (state === ApplicationStatus.Live && !decreasingSize) {
|
||||
return (
|
||||
<Alert severity="warning" className="flex flex-col gap-3 text-left">
|
||||
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
|
||||
<Text className="flex items-start gap-1 font-semibold">
|
||||
<span>⚠</span> Warning: Increasing disk size
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text>
|
||||
Due to AWS limitations, disk size can only be modified once every 6
|
||||
hours. Please ensure you increase capacity sufficiently to cover
|
||||
your needs during this period.
|
||||
</Text>
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
if (state === ApplicationStatus.Live && decreasingSize) {
|
||||
return (
|
||||
<Alert severity="warning" className="flex flex-col gap-3 text-left">
|
||||
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
|
||||
<Text className="flex items-start gap-1 font-semibold">
|
||||
<span>⚠</span> Warning: Decreasing disk size requires project to be
|
||||
paused first.
|
||||
</Text>
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
if (applicationPause && decreasingSize) {
|
||||
return (
|
||||
<Alert severity="warning" className="flex flex-col gap-3 text-left">
|
||||
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
|
||||
<Text className="flex items-start gap-1 font-semibold">
|
||||
<span>⚠</span> Warning: Ensure enough space before downsizing.
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text>
|
||||
Before downsizing, ensure enough space for your database, WAL files,
|
||||
and other supporting data to prevent issues when unpausing your
|
||||
project.
|
||||
</Text>
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as DatabaseStorageCapacityWarning } from './DatabaseStorageCapacityWarning';
|
||||
@@ -28,7 +28,7 @@ const smtpValidationSchema = yup
|
||||
.required(),
|
||||
user: yup.string().label('Username').required(),
|
||||
password: yup.string().label('Password'),
|
||||
sender: yup.string().label('SMTP Sender').email().required(),
|
||||
sender: yup.string().label('SMTP Sender').required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
|
||||
@@ -18,15 +18,19 @@ import { calculateBillableResources } from '@/features/orgs/projects/resources/s
|
||||
import type { ResourceSettingsFormValues } from '@/features/orgs/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||
import { resourceSettingsValidationSchema } from '@/features/orgs/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
||||
import {
|
||||
RESOURCE_VCPU_MULTIPLIER,
|
||||
RESOURCE_VCPU_PRICE,
|
||||
} from '@/utils/constants/common';
|
||||
import type { GetResourcesQuery } from '@/utils/__generated__/graphql';
|
||||
import type {
|
||||
ConfigConfigUpdateInput,
|
||||
GetResourcesQuery,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import {
|
||||
useGetResourcesQuery,
|
||||
useUpdateConfigMutation,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import {
|
||||
RESOURCE_VCPU_MULTIPLIER,
|
||||
RESOURCE_VCPU_PRICE,
|
||||
} from '@/utils/constants/common';
|
||||
import { removeTypename } from '@/utils/helpers';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
@@ -36,7 +40,7 @@ function getInitialServiceResources(
|
||||
data: GetResourcesQuery,
|
||||
service: Exclude<keyof GetResourcesQuery['config'], '__typename'>,
|
||||
) {
|
||||
const { compute, replicas, autoscaler } =
|
||||
const { compute, replicas, autoscaler, ...rest } =
|
||||
data?.config?.[service]?.resources || {};
|
||||
|
||||
return {
|
||||
@@ -44,6 +48,7 @@ function getInitialServiceResources(
|
||||
vcpu: compute?.cpu || 0,
|
||||
memory: compute?.memory || 0,
|
||||
autoscale: autoscaler || null,
|
||||
rest,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,76 +181,130 @@ export default function ResourcesForm() {
|
||||
? (billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) * RESOURCE_VCPU_PRICE
|
||||
: 0;
|
||||
|
||||
const getFormattedConfig = (
|
||||
values: ResourceSettingsFormValues,
|
||||
): ConfigConfigUpdateInput => {
|
||||
const sanitizedValues = removeTypename(
|
||||
values,
|
||||
) as ResourceSettingsFormValues;
|
||||
|
||||
const sanitizedInitialDatabaseResources = removeTypename(
|
||||
initialDatabaseResources,
|
||||
);
|
||||
const sanitizedInitialHasuraResources = removeTypename(
|
||||
initialHasuraResources,
|
||||
);
|
||||
const sanitizedInitialAuthResources = removeTypename(initialAuthResources);
|
||||
const sanitizedInitialStorageResources = removeTypename(
|
||||
initialStorageResources,
|
||||
);
|
||||
|
||||
if (sanitizedValues.enabled) {
|
||||
return {
|
||||
postgres: {
|
||||
resources: {
|
||||
compute: {
|
||||
cpu: sanitizedValues.database.vcpu,
|
||||
memory: sanitizedValues.database.memory,
|
||||
},
|
||||
replicas: sanitizedValues.database.replicas,
|
||||
autoscaler: sanitizedValues.database.autoscale
|
||||
? {
|
||||
maxReplicas: sanitizedValues.database.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
...sanitizedInitialDatabaseResources.rest,
|
||||
},
|
||||
},
|
||||
hasura: {
|
||||
resources: {
|
||||
compute: {
|
||||
cpu: sanitizedValues.hasura.vcpu,
|
||||
memory: sanitizedValues.hasura.memory,
|
||||
},
|
||||
replicas: sanitizedValues.hasura.replicas,
|
||||
autoscaler: sanitizedValues.hasura.autoscale
|
||||
? {
|
||||
maxReplicas: sanitizedValues.hasura.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
...sanitizedInitialHasuraResources.rest,
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
resources: {
|
||||
compute: {
|
||||
cpu: sanitizedValues.auth.vcpu,
|
||||
memory: sanitizedValues.auth.memory,
|
||||
},
|
||||
replicas: sanitizedValues.auth.replicas,
|
||||
autoscaler: sanitizedValues.auth.autoscale
|
||||
? {
|
||||
maxReplicas: sanitizedValues.auth.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
...sanitizedInitialAuthResources.rest,
|
||||
},
|
||||
},
|
||||
storage: {
|
||||
resources: {
|
||||
compute: {
|
||||
cpu: sanitizedValues.storage.vcpu,
|
||||
memory: sanitizedValues.storage.memory,
|
||||
},
|
||||
replicas: sanitizedValues.storage.replicas,
|
||||
autoscaler: sanitizedValues.storage.autoscale
|
||||
? {
|
||||
maxReplicas: sanitizedValues.storage.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
...sanitizedInitialStorageResources.rest,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
postgres: {
|
||||
resources: {
|
||||
compute: null,
|
||||
replicas: null,
|
||||
autoscaler: null,
|
||||
...sanitizedInitialDatabaseResources.rest,
|
||||
},
|
||||
},
|
||||
hasura: {
|
||||
resources: {
|
||||
compute: null,
|
||||
replicas: null,
|
||||
autoscaler: null,
|
||||
...sanitizedInitialHasuraResources.rest,
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
resources: {
|
||||
compute: null,
|
||||
replicas: null,
|
||||
autoscaler: null,
|
||||
...sanitizedInitialAuthResources.rest,
|
||||
},
|
||||
},
|
||||
storage: {
|
||||
resources: {
|
||||
compute: null,
|
||||
replicas: null,
|
||||
autoscaler: null,
|
||||
...sanitizedInitialStorageResources.rest,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
async function handleSubmit(formValues: ResourceSettingsFormValues) {
|
||||
const updateConfigPromise = updateConfig({
|
||||
variables: {
|
||||
appId: project?.id,
|
||||
config: {
|
||||
postgres: {
|
||||
resources: formValues.enabled
|
||||
? {
|
||||
compute: {
|
||||
cpu: formValues.database.vcpu,
|
||||
memory: formValues.database.memory,
|
||||
},
|
||||
replicas: formValues.database.replicas,
|
||||
autoscaler: formValues.database.autoscale
|
||||
? {
|
||||
maxReplicas: formValues.database.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
hasura: {
|
||||
resources: formValues.enabled
|
||||
? {
|
||||
compute: {
|
||||
cpu: formValues.hasura.vcpu,
|
||||
memory: formValues.hasura.memory,
|
||||
},
|
||||
replicas: formValues.hasura.replicas,
|
||||
autoscaler: formValues.hasura.autoscale
|
||||
? {
|
||||
maxReplicas: formValues.hasura.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
auth: {
|
||||
resources: formValues.enabled
|
||||
? {
|
||||
compute: {
|
||||
cpu: formValues.auth.vcpu,
|
||||
memory: formValues.auth.memory,
|
||||
},
|
||||
replicas: formValues.auth.replicas,
|
||||
autoscaler: formValues.auth.autoscale
|
||||
? {
|
||||
maxReplicas: formValues.auth.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
storage: {
|
||||
resources: formValues.enabled
|
||||
? {
|
||||
compute: {
|
||||
cpu: formValues.storage.vcpu,
|
||||
memory: formValues.storage.memory,
|
||||
},
|
||||
replicas: formValues.storage.replicas,
|
||||
autoscaler: formValues.storage.autoscale
|
||||
? {
|
||||
maxReplicas: formValues.storage.maxReplicas,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
},
|
||||
config: getFormattedConfig(formValues),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ export default function ServiceResourcesFormFragment({
|
||||
</Box>
|
||||
|
||||
<Box className="grid grid-flow-row gap-2">
|
||||
<Box className="grid items-center justify-between grid-flow-col gap-2">
|
||||
<Box className="grid grid-flow-col items-center justify-between gap-2">
|
||||
<Text>
|
||||
Allocated vCPUs:{' '}
|
||||
<span className="font-medium">
|
||||
@@ -201,7 +201,7 @@ export default function ServiceResourcesFormFragment({
|
||||
</Box>
|
||||
|
||||
<Box className="grid grid-flow-row gap-2">
|
||||
<Box className="grid items-center justify-between grid-flow-col gap-2">
|
||||
<Box className="grid grid-flow-col items-center justify-between gap-2">
|
||||
<Text>
|
||||
Allocated Memory:{' '}
|
||||
<span className="font-medium">
|
||||
@@ -246,7 +246,7 @@ export default function ServiceResourcesFormFragment({
|
||||
>
|
||||
<ExclamationIcon
|
||||
color="error"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
aria-hidden="false"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -274,7 +274,7 @@ export default function ServiceResourcesFormFragment({
|
||||
>
|
||||
<ExclamationIcon
|
||||
color="error"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
aria-hidden="false"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -306,7 +306,7 @@ export default function ServiceResourcesFormFragment({
|
||||
<Tooltip
|
||||
title={`Enable autoscaler to automatically provision extra ${title} replicas when needed.`}
|
||||
>
|
||||
<InfoOutlinedIcon className="w-4 h-4 text-black" />
|
||||
<InfoOutlinedIcon className="h-4 w-4" />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -323,7 +323,7 @@ export default function ServiceResourcesFormFragment({
|
||||
className="font-medium"
|
||||
>
|
||||
Service Replicas
|
||||
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
|
||||
<ArrowSquareOutIcon className="ml-1 h-4 w-4" />
|
||||
</Link>
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -9,6 +9,11 @@ fragment ServiceResources on ConfigConfig {
|
||||
autoscaler {
|
||||
maxReplicas
|
||||
}
|
||||
networking {
|
||||
ingresses {
|
||||
fqdn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hasura {
|
||||
@@ -21,10 +26,19 @@ fragment ServiceResources on ConfigConfig {
|
||||
autoscaler {
|
||||
maxReplicas
|
||||
}
|
||||
networking {
|
||||
ingresses {
|
||||
fqdn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
postgres {
|
||||
resources {
|
||||
storage {
|
||||
capacity
|
||||
}
|
||||
enablePublicAccess
|
||||
compute {
|
||||
cpu
|
||||
memory
|
||||
|
||||
@@ -19,7 +19,6 @@ import { StorageFormSection } from '@/features/orgs/projects/services/components
|
||||
import { useHostName } from '@/features/projects/common/hooks/useHostName';
|
||||
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import {
|
||||
validationSchema,
|
||||
@@ -29,16 +28,15 @@ import {
|
||||
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import {
|
||||
useInsertRunServiceConfigMutation,
|
||||
useReplaceRunServiceConfigMutation,
|
||||
type ConfigRunServiceConfigInsertInput,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
||||
import { copy } from '@/utils/copy';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import { removeTypename } from '@/utils/helpers';
|
||||
import {
|
||||
useInsertRunServiceConfigMutation,
|
||||
useInsertRunServiceMutation,
|
||||
useReplaceRunServiceConfigMutation,
|
||||
type ConfigRunServiceConfigInsertInput,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
@@ -58,9 +56,10 @@ export default function ServiceForm({
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
|
||||
const [insertRunService] = useInsertRunServiceMutation();
|
||||
const { project } = useProject();
|
||||
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
|
||||
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation({
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation({
|
||||
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||
});
|
||||
@@ -96,14 +95,14 @@ export default function ServiceForm({
|
||||
if (serviceID) {
|
||||
return serviceID;
|
||||
}
|
||||
return uuidv4();
|
||||
return '<uuid-to-be-generated-on-creation>';
|
||||
}, [serviceID]);
|
||||
|
||||
const privateRegistryImage = `registry.${project?.region.name}.${project?.region.domain}/${newServiceID}`;
|
||||
|
||||
let initialImageType: 'public' | 'private' | 'nhost' = 'public';
|
||||
|
||||
if (initialData?.image?.startsWith(privateRegistryImage)) {
|
||||
if (initialData?.image?.startsWith(privateRegistryImage.split('/')[0])) {
|
||||
initialImageType = 'nhost';
|
||||
}
|
||||
|
||||
@@ -225,33 +224,14 @@ export default function ServiceForm({
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Insert service config
|
||||
const {
|
||||
data: {
|
||||
insertRunService: { id },
|
||||
},
|
||||
} = await insertRunService({
|
||||
variables: {
|
||||
object: {
|
||||
appID: project.id,
|
||||
id: newServiceID,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Create service
|
||||
await insertRunServiceConfig({
|
||||
variables: {
|
||||
appID: project.id,
|
||||
serviceID: id,
|
||||
config: {
|
||||
...config,
|
||||
image: {
|
||||
// If the image field left empty then we auto-populate following this format
|
||||
// registry.<region>.<nhost_domain>/<service_id>
|
||||
image:
|
||||
values.image.length > 0
|
||||
? values.image
|
||||
: `registry.${project.region.name}.${project.region.domain}/${newServiceID}`,
|
||||
image: values.image,
|
||||
pullCredentials:
|
||||
values.pullCredentials?.length > 0
|
||||
? values.pullCredentials
|
||||
@@ -335,7 +315,7 @@ export default function ServiceForm({
|
||||
<Tooltip title="Name of the service, must be unique per project.">
|
||||
<InfoIcon
|
||||
aria-label="Info"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
color="primary"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -359,7 +339,7 @@ export default function ServiceForm({
|
||||
<Tooltip title="Command to run when to start the service. This is optional as the image may already have a baked-in command.">
|
||||
<InfoIcon
|
||||
aria-label="Info"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
color="primary"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -414,7 +394,7 @@ export default function ServiceForm({
|
||||
{createServiceFormError && (
|
||||
<Alert
|
||||
severity="error"
|
||||
className="grid items-center justify-between grid-flow-col px-4 py-3"
|
||||
className="grid grid-flow-col items-center justify-between px-4 py-3"
|
||||
>
|
||||
<span className="text-left">
|
||||
<strong>Error:</strong> {createServiceFormError.message}
|
||||
|
||||
@@ -12,7 +12,11 @@ import {
|
||||
|
||||
export const validationSchema = Yup.object({
|
||||
name: Yup.string().required('The name is required.'),
|
||||
image: Yup.string().label('Image to run').required('The image is required.'),
|
||||
image: Yup.string()
|
||||
.trim()
|
||||
.label('Image to run')
|
||||
.required('The image is required.')
|
||||
.min(1, 'Image must be at least 1 character long'),
|
||||
pullCredentials: Yup.string().label('Pull credentials').nullable(),
|
||||
command: Yup.string(),
|
||||
environment: Yup.array().of(
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function ReplicasFormSection() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className="p-4 space-y-4 rounded border-1">
|
||||
<Box className="space-y-4 rounded border-1 p-4">
|
||||
<Box className="flex flex-row items-center space-x-2">
|
||||
<Text variant="h4" className="font-semibold">
|
||||
Replicas ({replicas})
|
||||
@@ -65,7 +65,7 @@ export default function ReplicasFormSection() {
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
<InfoIcon aria-label="Info" className="w-4 h-4" color="primary" />
|
||||
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function ReplicasFormSection() {
|
||||
/>
|
||||
<Text>Autoscaler</Text>
|
||||
<Tooltip title="Enable autoscaler to automatically provision extra run service replicas when needed.">
|
||||
<InfoOutlinedIcon className="w-4 h-4 text-black" />
|
||||
<InfoOutlinedIcon className="h-4 w-4" />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
|
||||
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
|
||||
import { Input, inputClasses } from '@/components/ui/v2/Input';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
|
||||
export type DataGridDecimalCellProps<TData extends object> =
|
||||
CommonDataGridCellProps<TData, number | string>;
|
||||
|
||||
export default function DataGridDecimalCell<TData extends object>({
|
||||
onSave,
|
||||
optimisticValue,
|
||||
temporaryValue,
|
||||
onTemporaryValueChange,
|
||||
}: DataGridDecimalCellProps<TData>) {
|
||||
const { inputRef, focusCell, isEditing, cancelEditCell } =
|
||||
useDataGridCell<HTMLInputElement>();
|
||||
|
||||
async function handleSave() {
|
||||
if (onSave) {
|
||||
if (typeof temporaryValue === 'string') {
|
||||
await onSave(parseFloat(temporaryValue));
|
||||
} else if (typeof temporaryValue === 'number') {
|
||||
await onSave(temporaryValue);
|
||||
} else {
|
||||
await onSave(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {
|
||||
if (
|
||||
event.key === 'ArrowLeft' ||
|
||||
event.key === 'ArrowRight' ||
|
||||
event.key === 'ArrowUp' ||
|
||||
event.key === 'ArrowDown' ||
|
||||
event.key === 'Backspace'
|
||||
) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (event.key === 'Tab') {
|
||||
await handleSave();
|
||||
}
|
||||
|
||||
if (event.key === 'Enter') {
|
||||
await handleSave();
|
||||
await focusCell();
|
||||
cancelEditCell();
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
if (onTemporaryValueChange) {
|
||||
onTemporaryValueChange(event.target.value ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
return (
|
||||
<Input
|
||||
type="text"
|
||||
ref={inputRef}
|
||||
value={
|
||||
temporaryValue !== null && typeof temporaryValue !== 'undefined'
|
||||
? temporaryValue
|
||||
: ''
|
||||
}
|
||||
onKeyDown={handleKeyDown}
|
||||
onChange={handleChange}
|
||||
fullWidth
|
||||
className="absolute top-0 z-10 -mx-0.5 h-full place-content-stretch"
|
||||
sx={{
|
||||
[`&.${inputClasses.focused}`]: {
|
||||
boxShadow: `inset 0 0 0 1.5px rgba(0, 82, 205, 1)`,
|
||||
borderColor: 'transparent !important',
|
||||
borderRadius: 0,
|
||||
backgroundColor: (theme) =>
|
||||
theme.palette.mode === 'dark'
|
||||
? `${theme.palette.secondary[100]} !important`
|
||||
: `${theme.palette.common.white} !important`,
|
||||
},
|
||||
[`& .${inputClasses.input}`]: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
}}
|
||||
slotProps={{
|
||||
inputWrapper: { className: 'h-full' },
|
||||
input: { className: 'h-full' },
|
||||
inputRoot: {
|
||||
className:
|
||||
'resize-none outline-none focus:outline-none !text-xs focus:ring-0',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (optimisticValue === null || typeof optimisticValue === 'undefined') {
|
||||
return (
|
||||
<Text className="truncate !text-xs" color="disabled">
|
||||
null
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return <Text className="truncate !text-xs">{optimisticValue}</Text>;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './DataGridDecimalCell';
|
||||
export { default as DataGridDecimalCell } from './DataGridDecimalCell';
|
||||
@@ -4,15 +4,15 @@ import { Input, inputClasses } from '@/components/ui/v2/Input';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
|
||||
export type DataGridNumericCellProps<TData extends object> =
|
||||
export type DataGridIntegerCellProps<TData extends object> =
|
||||
CommonDataGridCellProps<TData, number>;
|
||||
|
||||
export default function DataGridNumericCell<TData extends object>({
|
||||
export default function DataGridIntegerCell<TData extends object>({
|
||||
onSave,
|
||||
optimisticValue,
|
||||
temporaryValue,
|
||||
onTemporaryValueChange,
|
||||
}: DataGridNumericCellProps<TData>) {
|
||||
}: DataGridIntegerCellProps<TData>) {
|
||||
const { inputRef, focusCell, isEditing, cancelEditCell } =
|
||||
useDataGridCell<HTMLInputElement>();
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './DataGridIntegerCell';
|
||||
export { default as DataGridIntegerCell } from './DataGridIntegerCell';
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './DataGridNumericCell';
|
||||
export { default as DataGridNumericCell } from './DataGridNumericCell';
|
||||
@@ -28,16 +28,15 @@ import {
|
||||
type ServiceFormValues,
|
||||
} from '@/features/services/components/ServiceForm/ServiceFormTypes';
|
||||
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||
import {
|
||||
useInsertRunServiceConfigMutation,
|
||||
useReplaceRunServiceConfigMutation,
|
||||
type ConfigRunServiceConfigInsertInput,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
||||
import { copy } from '@/utils/copy';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import { removeTypename } from '@/utils/helpers';
|
||||
import {
|
||||
useInsertRunServiceConfigMutation,
|
||||
useInsertRunServiceMutation,
|
||||
useReplaceRunServiceConfigMutation,
|
||||
type ConfigRunServiceConfigInsertInput,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
@@ -57,7 +56,6 @@ export default function ServiceForm({
|
||||
const isPlatform = useIsPlatform();
|
||||
const localMimirClient = useLocalMimirClient();
|
||||
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
|
||||
const [insertRunService] = useInsertRunServiceMutation();
|
||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
|
||||
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation({
|
||||
@@ -187,20 +185,11 @@ export default function ServiceForm({
|
||||
// Insert service config
|
||||
const {
|
||||
data: {
|
||||
insertRunService: { id: newServiceID, subdomain },
|
||||
insertRunServiceConfig: { serviceID: newServiceID },
|
||||
},
|
||||
} = await insertRunService({
|
||||
variables: {
|
||||
object: {
|
||||
appID: currentProject.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await insertRunServiceConfig({
|
||||
} = await insertRunServiceConfig({
|
||||
variables: {
|
||||
appID: currentProject.id,
|
||||
serviceID: newServiceID,
|
||||
config: {
|
||||
...config,
|
||||
image: {
|
||||
@@ -209,14 +198,14 @@ export default function ServiceForm({
|
||||
image:
|
||||
values.image.length > 0
|
||||
? values.image
|
||||
: `registry.${currentProject.region.name}.${currentProject.region.domain}/${newServiceID}`,
|
||||
: `registry.${currentProject.region.name}.${currentProject.region.domain}/<uuid-to-be-generated-on-creation>`,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setDetailsServiceId(newServiceID);
|
||||
setDetailsServiceSubdomain(subdomain);
|
||||
setDetailsServiceSubdomain('');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -322,7 +311,7 @@ export default function ServiceForm({
|
||||
<Tooltip title="Name of the service, must be unique per project.">
|
||||
<InfoIcon
|
||||
aria-label="Info"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
color="primary"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -362,7 +351,7 @@ export default function ServiceForm({
|
||||
>
|
||||
<InfoIcon
|
||||
aria-label="Info"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
color="primary"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -393,7 +382,7 @@ export default function ServiceForm({
|
||||
<Tooltip title="Command to run when to start the service. This is optional as the image may already have a baked-in command.">
|
||||
<InfoIcon
|
||||
aria-label="Info"
|
||||
className="w-4 h-4"
|
||||
className="h-4 w-4"
|
||||
color="primary"
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -441,7 +430,7 @@ export default function ServiceForm({
|
||||
{createServiceFormError && (
|
||||
<Alert
|
||||
severity="error"
|
||||
className="grid items-center justify-between grid-flow-col px-4 py-3"
|
||||
className="grid grid-flow-col items-center justify-between px-4 py-3"
|
||||
>
|
||||
<span className="text-left">
|
||||
<strong>Error:</strong> {createServiceFormError.message}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
mutation insertRunService($object: run_service_insert_input!) {
|
||||
insertRunService(object: $object) {
|
||||
id
|
||||
subdomain
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
mutation insertRunServiceConfig(
|
||||
mutation InsertRunServiceConfig(
|
||||
$appID: uuid!
|
||||
$serviceID: uuid!
|
||||
$config: ConfigRunServiceConfigInsertInput!
|
||||
) {
|
||||
insertRunServiceConfig(
|
||||
appID: $appID
|
||||
serviceID: $serviceID
|
||||
config: $config
|
||||
) {
|
||||
name
|
||||
insertRunServiceConfig(appID: $appID, config: $config) {
|
||||
serviceID
|
||||
config {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import { Form } from '@/components/form/Form';
|
||||
import { Container } from '@/components/layout/Container';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||
import { Alert } from '@/components/ui/v2/Alert';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { Link } from '@/components/ui/v2/Link';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import { TransferProject } from '@/features/orgs/components/TransferProject';
|
||||
import { ProjectLayout } from '@/features/orgs/layout/ProjectLayout';
|
||||
import { SettingsLayout } from '@/features/orgs/layout/SettingsLayout';
|
||||
@@ -12,6 +15,7 @@ import { RemoveApplicationModal } from '@/features/orgs/projects/common/componen
|
||||
import { useAppState } from '@/features/orgs/projects/common/hooks/useAppState';
|
||||
import { useIsCurrentUserOwner } from '@/features/orgs/projects/common/hooks/useIsCurrentUserOwner';
|
||||
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
|
||||
import { useRunServices } from '@/features/orgs/projects/common/hooks/useRunServices';
|
||||
import { useOrgs } from '@/features/orgs/projects/hooks/useOrgs';
|
||||
import { useProject } from '@/features/orgs/projects/hooks/useProject';
|
||||
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
||||
@@ -25,7 +29,7 @@ import { ApplicationStatus } from '@/types/application';
|
||||
import { slugifyString } from '@/utils/helpers';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useMemo, type ReactElement } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
@@ -51,6 +55,20 @@ export default function SettingsGeneralPage() {
|
||||
const { project, loading, refetch: refetchProject } = useProject();
|
||||
const { state } = useAppState();
|
||||
|
||||
const { services } = useRunServices();
|
||||
|
||||
const showWarning = useMemo(() => {
|
||||
const isPlanFree = org?.plan?.isFree;
|
||||
|
||||
if (isPlanFree) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return services?.some(
|
||||
(service) => service?.config?.resources?.storage?.length > 0,
|
||||
);
|
||||
}, [org?.plan?.isFree, services]);
|
||||
|
||||
const [updateApp] = useUpdateApplicationMutation();
|
||||
const [deleteApplication] = useBillingDeleteAppMutation();
|
||||
const [pauseApplication, { loading: pauseApplicationLoading }] =
|
||||
@@ -242,9 +260,49 @@ export default function SettingsGeneralPage() {
|
||||
onClick: () => {
|
||||
openAlertDialog({
|
||||
title: 'Pause Project?',
|
||||
payload:
|
||||
'Are you sure you want to pause this project? It will not be accessible until you unpause it.',
|
||||
payload: (
|
||||
<div className="flex flex-col gap-2">
|
||||
{showWarning ? (
|
||||
<Alert
|
||||
severity="warning"
|
||||
className="flex flex-col gap-3 text-left"
|
||||
>
|
||||
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
|
||||
<Text className="flex items-start gap-1 font-semibold">
|
||||
<span>⚠</span> Warning: This action will delete
|
||||
all volume data for your Run services.
|
||||
</Text>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Text>
|
||||
Pausing this project will delete all persistent
|
||||
volume data for your Run services. No automatic
|
||||
backups are made. Please backup your data
|
||||
manually to prevent loss. Contact{' '}
|
||||
<Link
|
||||
href="/support"
|
||||
target="_blank"
|
||||
className="underline"
|
||||
sx={{
|
||||
color: 'text.primary',
|
||||
}}
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
support
|
||||
</Link>{' '}
|
||||
with any questions.
|
||||
</Text>
|
||||
</div>
|
||||
</Alert>
|
||||
) : null}
|
||||
<p className="text-pretty">
|
||||
Are you sure you want to pause this project? It will
|
||||
not be accessible until you unpause it.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
props: {
|
||||
maxWidth: 'sm',
|
||||
onPrimaryAction: handlePauseApplication,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ const validationSchema = Yup.object({
|
||||
email: Yup.string().label('Email').email().required(),
|
||||
});
|
||||
|
||||
export type ResetPasswordFormValues = Yup.InferType<typeof validationSchema>;
|
||||
export type NewPasswordFormValues = Yup.InferType<typeof validationSchema>;
|
||||
|
||||
const StyledInput = styled(Input)({
|
||||
backgroundColor: 'transparent',
|
||||
@@ -28,10 +28,10 @@ const StyledInput = styled(Input)({
|
||||
},
|
||||
});
|
||||
|
||||
export default function ResetPasswordPage() {
|
||||
export default function NewPasswordPage() {
|
||||
const { resetPassword, error, isSent } = useResetPassword();
|
||||
|
||||
const form = useForm<ResetPasswordFormValues>({
|
||||
const form = useForm<NewPasswordFormValues>({
|
||||
reValidateMode: 'onSubmit',
|
||||
defaultValues: {
|
||||
email: '',
|
||||
@@ -52,9 +52,11 @@ export default function ResetPasswordPage() {
|
||||
);
|
||||
}, [error]);
|
||||
|
||||
async function handleSubmit({ email }: ResetPasswordFormValues) {
|
||||
async function handleSubmit({ email }: NewPasswordFormValues) {
|
||||
try {
|
||||
await resetPassword(email);
|
||||
await resetPassword(email, {
|
||||
redirectTo: '/password/reset',
|
||||
});
|
||||
} catch {
|
||||
toast.error(
|
||||
'An error occurred while signing up. Please try again.',
|
||||
@@ -124,8 +126,10 @@ export default function ResetPasswordPage() {
|
||||
);
|
||||
}
|
||||
|
||||
ResetPasswordPage.getLayout = function getLayout(page: ReactElement) {
|
||||
NewPasswordPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<UnauthenticatedLayout title="Reset Password">{page}</UnauthenticatedLayout>
|
||||
<UnauthenticatedLayout title="Request Password Reset">
|
||||
{page}
|
||||
</UnauthenticatedLayout>
|
||||
);
|
||||
};
|
||||
144
dashboard/src/pages/password/reset.tsx
Normal file
144
dashboard/src/pages/password/reset.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import { NavLink } from '@/components/common/NavLink';
|
||||
import { Form } from '@/components/form/Form';
|
||||
import { UnauthenticatedLayout } from '@/components/layout/UnauthenticatedLayout';
|
||||
import { Box } from '@/components/ui/v2/Box';
|
||||
import { Button } from '@/components/ui/v2/Button';
|
||||
import { Input, inputClasses } from '@/components/ui/v2/Input';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import { getToastStyleProps } from '@/utils/constants/settings';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { styled } from '@mui/material';
|
||||
import { useChangePassword } from '@nhost/nextjs';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { ReactElement } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
newPassword: Yup.string()
|
||||
.label('New Password')
|
||||
.required('New Password is required'),
|
||||
confirmNewPassword: Yup.string()
|
||||
.label('Confirm New Password')
|
||||
.required('Confirm New Password is required')
|
||||
.oneOf([Yup.ref('newPassword')], 'Passwords must match'),
|
||||
});
|
||||
|
||||
export type ResetPasswordFormValues = Yup.InferType<typeof validationSchema>;
|
||||
|
||||
const StyledInput = styled(Input)({
|
||||
backgroundColor: 'transparent',
|
||||
[`& .${inputClasses.input}`]: {
|
||||
backgroundColor: 'transparent !important',
|
||||
},
|
||||
});
|
||||
|
||||
export default function ResetPasswordPage() {
|
||||
const router = useRouter();
|
||||
const { changePassword } = useChangePassword();
|
||||
|
||||
const form = useForm<ResetPasswordFormValues>({
|
||||
reValidateMode: 'onSubmit',
|
||||
defaultValues: {
|
||||
newPassword: '',
|
||||
confirmNewPassword: '',
|
||||
},
|
||||
resolver: yupResolver(validationSchema),
|
||||
});
|
||||
|
||||
const { register, formState } = form;
|
||||
|
||||
async function handleSubmit({ newPassword }: ResetPasswordFormValues) {
|
||||
try {
|
||||
const password = newPassword;
|
||||
|
||||
const { isError, error } = await changePassword(password);
|
||||
|
||||
if (isError) {
|
||||
toast.error(
|
||||
`An error occurred while changing your password: ${error.message}`,
|
||||
getToastStyleProps(),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success('Password was updated successfully.');
|
||||
router.push('/');
|
||||
} catch {
|
||||
toast.error(
|
||||
'An error occurred while updating your password. Please try again.',
|
||||
getToastStyleProps(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text
|
||||
variant="h2"
|
||||
component="h1"
|
||||
className="text-center text-3.5xl font-semibold lg:text-4.5xl"
|
||||
>
|
||||
Change password
|
||||
</Text>
|
||||
|
||||
<Box className="grid grid-flow-row gap-4 rounded-md border bg-transparent p-6 lg:p-12">
|
||||
<FormProvider {...form}>
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
className="grid grid-flow-row gap-4 bg-transparent"
|
||||
>
|
||||
<StyledInput
|
||||
{...register('newPassword')}
|
||||
type="password"
|
||||
id="newPassword"
|
||||
label="New Password"
|
||||
fullWidth
|
||||
inputProps={{ min: 2, max: 128 }}
|
||||
error={!!formState.errors.newPassword}
|
||||
helperText={formState.errors.newPassword?.message}
|
||||
/>
|
||||
|
||||
<StyledInput
|
||||
{...register('confirmNewPassword')}
|
||||
type="password"
|
||||
id="confirmNewPassword"
|
||||
label="Confirm New Password"
|
||||
fullWidth
|
||||
inputProps={{ min: 2, max: 128 }}
|
||||
error={!!formState.errors.confirmNewPassword}
|
||||
helperText={formState.errors.confirmNewPassword?.message}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="!bg-white !text-black disabled:!text-black disabled:!text-opacity-60"
|
||||
size="large"
|
||||
type="submit"
|
||||
disabled={formState.isSubmitting}
|
||||
loading={formState.isSubmitting}
|
||||
>
|
||||
Change password
|
||||
</Button>
|
||||
</Form>
|
||||
</FormProvider>
|
||||
</Box>
|
||||
|
||||
<Text color="secondary" className="text-center text-base lg:text-lg">
|
||||
Go back to{' '}
|
||||
<NavLink href="/signin/email" color="white" className="font-medium">
|
||||
Sign In
|
||||
</NavLink>
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ResetPasswordPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<UnauthenticatedLayout title="Request Password Reset">
|
||||
{page}
|
||||
</UnauthenticatedLayout>
|
||||
);
|
||||
};
|
||||
@@ -85,7 +85,7 @@ export default function EmailSignUpPage() {
|
||||
Sign In
|
||||
</Text>
|
||||
|
||||
<Box className="grid grid-flow-row gap-4 p-6 bg-transparent border rounded-md lg:p-12">
|
||||
<Box className="grid grid-flow-row gap-4 rounded-md border bg-transparent p-6 lg:p-12">
|
||||
<FormProvider {...form}>
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
@@ -123,9 +123,9 @@ export default function EmailSignUpPage() {
|
||||
/>
|
||||
|
||||
<NavLink
|
||||
href="/reset-password"
|
||||
href="/password/new"
|
||||
color="white"
|
||||
className="font-semibold justify-self-start"
|
||||
className="justify-self-start font-semibold"
|
||||
>
|
||||
Forgot password?
|
||||
</NavLink>
|
||||
@@ -150,7 +150,7 @@ export default function EmailSignUpPage() {
|
||||
</FormProvider>
|
||||
</Box>
|
||||
|
||||
<Text color="secondary" className="text-base text-center lg:text-lg">
|
||||
<Text color="secondary" className="text-center text-base lg:text-lg">
|
||||
Don't have an account?{' '}
|
||||
<NavLink href="/signup" color="white">
|
||||
Sign Up
|
||||
|
||||
130
dashboard/src/utils/__generated__/graphql.ts
generated
130
dashboard/src/utils/__generated__/graphql.ts
generated
@@ -3191,6 +3191,12 @@ export type ContainerError = {
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
export type InsertRunServiceConfigResponse = {
|
||||
__typename?: 'InsertRunServiceConfigResponse';
|
||||
config: ConfigRunServiceConfig;
|
||||
serviceID: Scalars['uuid'];
|
||||
};
|
||||
|
||||
/** Boolean expression to compare columns of type "Int". All fields are combined with logical 'AND'. */
|
||||
export type Int_Comparison_Exp = {
|
||||
_eq?: InputMaybe<Scalars['Int']>;
|
||||
@@ -13530,7 +13536,7 @@ export type Mutation_Root = {
|
||||
insertRegionsAllowedWorkspaces?: Maybe<Regions_Allowed_Workspace_Mutation_Response>;
|
||||
/** insert a single row into the table: "run_service" */
|
||||
insertRunService?: Maybe<Run_Service>;
|
||||
insertRunServiceConfig: ConfigRunServiceConfig;
|
||||
insertRunServiceConfig: InsertRunServiceConfigResponse;
|
||||
/** insert data into the table: "run_service" */
|
||||
insertRunServices?: Maybe<Run_Service_Mutation_Response>;
|
||||
insertSecret: ConfigEnvironmentVariable;
|
||||
@@ -15213,7 +15219,6 @@ export type Mutation_RootInsertRunServiceArgs = {
|
||||
export type Mutation_RootInsertRunServiceConfigArgs = {
|
||||
appID: Scalars['uuid'];
|
||||
config: ConfigRunServiceConfigInsertInput;
|
||||
serviceID: Scalars['uuid'];
|
||||
};
|
||||
|
||||
|
||||
@@ -16986,7 +16991,7 @@ export type Organization_Member_Invites = {
|
||||
role: Organization_Members_Role_Enum;
|
||||
updateAt: Scalars['timestamptz'];
|
||||
/** An object relationship */
|
||||
user: Users;
|
||||
user?: Maybe<Users>;
|
||||
};
|
||||
|
||||
/** aggregated selection of "organization_member_invites" */
|
||||
@@ -22517,9 +22522,6 @@ export type Run_Service = {
|
||||
appID: Scalars['uuid'];
|
||||
config?: Maybe<ConfigRunServiceConfig>;
|
||||
createdAt: Scalars['timestamptz'];
|
||||
/** An object relationship */
|
||||
creator: Users;
|
||||
creatorUserId: Scalars['uuid'];
|
||||
id: Scalars['uuid'];
|
||||
mimirConfigEnc?: Maybe<Scalars['String']>;
|
||||
subdomain: Scalars['String'];
|
||||
@@ -22587,8 +22589,6 @@ export type Run_Service_Bool_Exp = {
|
||||
app?: InputMaybe<Apps_Bool_Exp>;
|
||||
appID?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
createdAt?: InputMaybe<Timestamptz_Comparison_Exp>;
|
||||
creator?: InputMaybe<Users_Bool_Exp>;
|
||||
creatorUserId?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
id?: InputMaybe<Uuid_Comparison_Exp>;
|
||||
mimirConfigEnc?: InputMaybe<String_Comparison_Exp>;
|
||||
subdomain?: InputMaybe<String_Comparison_Exp>;
|
||||
@@ -22608,8 +22608,6 @@ export type Run_Service_Insert_Input = {
|
||||
app?: InputMaybe<Apps_Obj_Rel_Insert_Input>;
|
||||
appID?: InputMaybe<Scalars['uuid']>;
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
creator?: InputMaybe<Users_Obj_Rel_Insert_Input>;
|
||||
creatorUserId?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
mimirConfigEnc?: InputMaybe<Scalars['String']>;
|
||||
subdomain?: InputMaybe<Scalars['String']>;
|
||||
@@ -22621,7 +22619,6 @@ export type Run_Service_Max_Fields = {
|
||||
__typename?: 'run_service_max_fields';
|
||||
appID?: Maybe<Scalars['uuid']>;
|
||||
createdAt?: Maybe<Scalars['timestamptz']>;
|
||||
creatorUserId?: Maybe<Scalars['uuid']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
mimirConfigEnc?: Maybe<Scalars['String']>;
|
||||
subdomain?: Maybe<Scalars['String']>;
|
||||
@@ -22632,7 +22629,6 @@ export type Run_Service_Max_Fields = {
|
||||
export type Run_Service_Max_Order_By = {
|
||||
appID?: InputMaybe<Order_By>;
|
||||
createdAt?: InputMaybe<Order_By>;
|
||||
creatorUserId?: InputMaybe<Order_By>;
|
||||
id?: InputMaybe<Order_By>;
|
||||
mimirConfigEnc?: InputMaybe<Order_By>;
|
||||
subdomain?: InputMaybe<Order_By>;
|
||||
@@ -22644,7 +22640,6 @@ export type Run_Service_Min_Fields = {
|
||||
__typename?: 'run_service_min_fields';
|
||||
appID?: Maybe<Scalars['uuid']>;
|
||||
createdAt?: Maybe<Scalars['timestamptz']>;
|
||||
creatorUserId?: Maybe<Scalars['uuid']>;
|
||||
id?: Maybe<Scalars['uuid']>;
|
||||
mimirConfigEnc?: Maybe<Scalars['String']>;
|
||||
subdomain?: Maybe<Scalars['String']>;
|
||||
@@ -22655,7 +22650,6 @@ export type Run_Service_Min_Fields = {
|
||||
export type Run_Service_Min_Order_By = {
|
||||
appID?: InputMaybe<Order_By>;
|
||||
createdAt?: InputMaybe<Order_By>;
|
||||
creatorUserId?: InputMaybe<Order_By>;
|
||||
id?: InputMaybe<Order_By>;
|
||||
mimirConfigEnc?: InputMaybe<Order_By>;
|
||||
subdomain?: InputMaybe<Order_By>;
|
||||
@@ -22683,8 +22677,6 @@ export type Run_Service_Order_By = {
|
||||
app?: InputMaybe<Apps_Order_By>;
|
||||
appID?: InputMaybe<Order_By>;
|
||||
createdAt?: InputMaybe<Order_By>;
|
||||
creator?: InputMaybe<Users_Order_By>;
|
||||
creatorUserId?: InputMaybe<Order_By>;
|
||||
id?: InputMaybe<Order_By>;
|
||||
mimirConfigEnc?: InputMaybe<Order_By>;
|
||||
subdomain?: InputMaybe<Order_By>;
|
||||
@@ -22703,8 +22695,6 @@ export enum Run_Service_Select_Column {
|
||||
/** column name */
|
||||
CreatedAt = 'createdAt',
|
||||
/** column name */
|
||||
CreatorUserId = 'creatorUserId',
|
||||
/** column name */
|
||||
Id = 'id',
|
||||
/** column name */
|
||||
MimirConfigEnc = 'mimirConfigEnc',
|
||||
@@ -22718,7 +22708,6 @@ export enum Run_Service_Select_Column {
|
||||
export type Run_Service_Set_Input = {
|
||||
appID?: InputMaybe<Scalars['uuid']>;
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
creatorUserId?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
mimirConfigEnc?: InputMaybe<Scalars['String']>;
|
||||
subdomain?: InputMaybe<Scalars['String']>;
|
||||
@@ -22737,7 +22726,6 @@ export type Run_Service_Stream_Cursor_Input = {
|
||||
export type Run_Service_Stream_Cursor_Value_Input = {
|
||||
appID?: InputMaybe<Scalars['uuid']>;
|
||||
createdAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
creatorUserId?: InputMaybe<Scalars['uuid']>;
|
||||
id?: InputMaybe<Scalars['uuid']>;
|
||||
mimirConfigEnc?: InputMaybe<Scalars['String']>;
|
||||
subdomain?: InputMaybe<Scalars['String']>;
|
||||
@@ -22751,8 +22739,6 @@ export enum Run_Service_Update_Column {
|
||||
/** column name */
|
||||
CreatedAt = 'createdAt',
|
||||
/** column name */
|
||||
CreatorUserId = 'creatorUserId',
|
||||
/** column name */
|
||||
Id = 'id',
|
||||
/** column name */
|
||||
MimirConfigEnc = 'mimirConfigEnc',
|
||||
@@ -25315,10 +25301,6 @@ export type Users = {
|
||||
/** An aggregate relationship */
|
||||
roles_aggregate: AuthUserRoles_Aggregate;
|
||||
/** An array relationship */
|
||||
runServices: Array<Run_Service>;
|
||||
/** An aggregate relationship */
|
||||
runServices_aggregate: Run_Service_Aggregate;
|
||||
/** An array relationship */
|
||||
securityKeys: Array<AuthUserSecurityKeys>;
|
||||
/** An aggregate relationship */
|
||||
securityKeys_aggregate: AuthUserSecurityKeys_Aggregate;
|
||||
@@ -25511,26 +25493,6 @@ export type UsersRoles_AggregateArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
|
||||
export type UsersRunServicesArgs = {
|
||||
distinct_on?: InputMaybe<Array<Run_Service_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Run_Service_Order_By>>;
|
||||
where?: InputMaybe<Run_Service_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
|
||||
export type UsersRunServices_AggregateArgs = {
|
||||
distinct_on?: InputMaybe<Array<Run_Service_Select_Column>>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
offset?: InputMaybe<Scalars['Int']>;
|
||||
order_by?: InputMaybe<Array<Run_Service_Order_By>>;
|
||||
where?: InputMaybe<Run_Service_Bool_Exp>;
|
||||
};
|
||||
|
||||
|
||||
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
|
||||
export type UsersSecurityKeysArgs = {
|
||||
distinct_on?: InputMaybe<Array<AuthUserSecurityKeys_Select_Column>>;
|
||||
@@ -25742,8 +25704,6 @@ export type Users_Bool_Exp = {
|
||||
role?: InputMaybe<AuthRoles_Bool_Exp>;
|
||||
roles?: InputMaybe<AuthUserRoles_Bool_Exp>;
|
||||
roles_aggregate?: InputMaybe<AuthUserRoles_Aggregate_Bool_Exp>;
|
||||
runServices?: InputMaybe<Run_Service_Bool_Exp>;
|
||||
runServices_aggregate?: InputMaybe<Run_Service_Aggregate_Bool_Exp>;
|
||||
securityKeys?: InputMaybe<AuthUserSecurityKeys_Bool_Exp>;
|
||||
securityKeys_aggregate?: InputMaybe<AuthUserSecurityKeys_Aggregate_Bool_Exp>;
|
||||
ticket?: InputMaybe<String_Comparison_Exp>;
|
||||
@@ -25818,7 +25778,6 @@ export type Users_Insert_Input = {
|
||||
refreshTokens?: InputMaybe<AuthRefreshTokens_Arr_Rel_Insert_Input>;
|
||||
role?: InputMaybe<AuthRoles_Obj_Rel_Insert_Input>;
|
||||
roles?: InputMaybe<AuthUserRoles_Arr_Rel_Insert_Input>;
|
||||
runServices?: InputMaybe<Run_Service_Arr_Rel_Insert_Input>;
|
||||
securityKeys?: InputMaybe<AuthUserSecurityKeys_Arr_Rel_Insert_Input>;
|
||||
ticket?: InputMaybe<Scalars['String']>;
|
||||
ticketExpiresAt?: InputMaybe<Scalars['timestamptz']>;
|
||||
@@ -25984,7 +25943,6 @@ export type Users_Order_By = {
|
||||
refreshTokens_aggregate?: InputMaybe<AuthRefreshTokens_Aggregate_Order_By>;
|
||||
role?: InputMaybe<AuthRoles_Order_By>;
|
||||
roles_aggregate?: InputMaybe<AuthUserRoles_Aggregate_Order_By>;
|
||||
runServices_aggregate?: InputMaybe<Run_Service_Aggregate_Order_By>;
|
||||
securityKeys_aggregate?: InputMaybe<AuthUserSecurityKeys_Aggregate_Order_By>;
|
||||
ticket?: InputMaybe<Order_By>;
|
||||
ticketExpiresAt?: InputMaybe<Order_By>;
|
||||
@@ -27738,14 +27696,14 @@ export type GetObservabilitySettingsQueryVariables = Exact<{
|
||||
|
||||
export type GetObservabilitySettingsQuery = { __typename?: 'query_root', config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', observability: { __typename?: 'ConfigObservability', grafana: { __typename?: 'ConfigGrafana', alerting?: { __typename?: 'ConfigGrafanaAlerting', enabled?: boolean | null } | null, smtp?: { __typename?: 'ConfigGrafanaSmtp', host: string, password: string, port: any, sender: string, user: string } | null, contacts?: { __typename?: 'ConfigGrafanaContacts', emails?: Array<string> | null, discord?: Array<{ __typename?: 'ConfigGrafanacontactsDiscord', avatarUrl: string, url: string }> | null, pagerduty?: Array<{ __typename?: 'ConfigGrafanacontactsPagerduty', integrationKey: string, severity: string, class: string, component: string, group: string }> | null, slack?: Array<{ __typename?: 'ConfigGrafanacontactsSlack', recipient: string, token: string, username: string, iconEmoji: string, iconURL: string, mentionUsers: Array<string>, mentionGroups: Array<string>, mentionChannel: string, url: string, endpointURL: string }> | null, webhook?: Array<{ __typename?: 'ConfigGrafanacontactsWebhook', url: string, httpMethod: string, username: string, password: string, authorizationScheme: string, authorizationCredentials: string, maxAlerts: number }> | null } | null } } } | null };
|
||||
|
||||
export type ServiceResourcesFragment = { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null };
|
||||
export type ServiceResourcesFragment = { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, replicas?: any | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null };
|
||||
|
||||
export type GetResourcesQueryVariables = Exact<{
|
||||
appId: Scalars['uuid'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetResourcesQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null } | null };
|
||||
export type GetResourcesQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, replicas?: any | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null } | null };
|
||||
|
||||
export type GetStorageSettingsQueryVariables = Exact<{
|
||||
appId: Scalars['uuid'];
|
||||
@@ -28592,21 +28550,13 @@ export type GetLocalRunServiceRateLimitQueryVariables = Exact<{
|
||||
|
||||
export type GetLocalRunServiceRateLimitQuery = { __typename?: 'query_root', runServiceConfigs: Array<{ __typename?: 'ConfigRunServiceConfigWithID', serviceID: any, config: { __typename?: 'ConfigRunServiceConfig', name: any, ports?: Array<{ __typename?: 'ConfigRunServicePort', port: any, type: string, publish?: boolean | null, rateLimit?: { __typename?: 'ConfigRateLimit', limit: any, interval: string } | null, ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null }> | null } }> };
|
||||
|
||||
export type InsertRunServiceMutationVariables = Exact<{
|
||||
object: Run_Service_Insert_Input;
|
||||
}>;
|
||||
|
||||
|
||||
export type InsertRunServiceMutation = { __typename?: 'mutation_root', insertRunService?: { __typename?: 'run_service', id: any, subdomain: string } | null };
|
||||
|
||||
export type InsertRunServiceConfigMutationVariables = Exact<{
|
||||
appID: Scalars['uuid'];
|
||||
serviceID: Scalars['uuid'];
|
||||
config: ConfigRunServiceConfigInsertInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type InsertRunServiceConfigMutation = { __typename?: 'mutation_root', insertRunServiceConfig: { __typename?: 'ConfigRunServiceConfig', name: any } };
|
||||
export type InsertRunServiceConfigMutation = { __typename?: 'mutation_root', insertRunServiceConfig: { __typename?: 'InsertRunServiceConfigResponse', serviceID: any, config: { __typename?: 'ConfigRunServiceConfig', name: any } } };
|
||||
|
||||
export type ReplaceRunServiceConfigMutationVariables = Exact<{
|
||||
appID: Scalars['uuid'];
|
||||
@@ -28730,6 +28680,11 @@ export const ServiceResourcesFragmentDoc = gql`
|
||||
autoscaler {
|
||||
maxReplicas
|
||||
}
|
||||
networking {
|
||||
ingresses {
|
||||
fqdn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hasura {
|
||||
@@ -28742,10 +28697,19 @@ export const ServiceResourcesFragmentDoc = gql`
|
||||
autoscaler {
|
||||
maxReplicas
|
||||
}
|
||||
networking {
|
||||
ingresses {
|
||||
fqdn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
postgres {
|
||||
resources {
|
||||
storage {
|
||||
capacity
|
||||
}
|
||||
enablePublicAccess
|
||||
compute {
|
||||
cpu
|
||||
memory
|
||||
@@ -34696,44 +34660,13 @@ export type GetLocalRunServiceRateLimitQueryResult = Apollo.QueryResult<GetLocal
|
||||
export function refetchGetLocalRunServiceRateLimitQuery(variables: GetLocalRunServiceRateLimitQueryVariables) {
|
||||
return { query: GetLocalRunServiceRateLimitDocument, variables: variables }
|
||||
}
|
||||
export const InsertRunServiceDocument = gql`
|
||||
mutation insertRunService($object: run_service_insert_input!) {
|
||||
insertRunService(object: $object) {
|
||||
id
|
||||
subdomain
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type InsertRunServiceMutationFn = Apollo.MutationFunction<InsertRunServiceMutation, InsertRunServiceMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useInsertRunServiceMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useInsertRunServiceMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useInsertRunServiceMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [insertRunServiceMutation, { data, loading, error }] = useInsertRunServiceMutation({
|
||||
* variables: {
|
||||
* object: // value for 'object'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useInsertRunServiceMutation(baseOptions?: Apollo.MutationHookOptions<InsertRunServiceMutation, InsertRunServiceMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<InsertRunServiceMutation, InsertRunServiceMutationVariables>(InsertRunServiceDocument, options);
|
||||
}
|
||||
export type InsertRunServiceMutationHookResult = ReturnType<typeof useInsertRunServiceMutation>;
|
||||
export type InsertRunServiceMutationResult = Apollo.MutationResult<InsertRunServiceMutation>;
|
||||
export type InsertRunServiceMutationOptions = Apollo.BaseMutationOptions<InsertRunServiceMutation, InsertRunServiceMutationVariables>;
|
||||
export const InsertRunServiceConfigDocument = gql`
|
||||
mutation insertRunServiceConfig($appID: uuid!, $serviceID: uuid!, $config: ConfigRunServiceConfigInsertInput!) {
|
||||
insertRunServiceConfig(appID: $appID, serviceID: $serviceID, config: $config) {
|
||||
name
|
||||
mutation InsertRunServiceConfig($appID: uuid!, $config: ConfigRunServiceConfigInsertInput!) {
|
||||
insertRunServiceConfig(appID: $appID, config: $config) {
|
||||
serviceID
|
||||
config {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -34753,7 +34686,6 @@ export type InsertRunServiceConfigMutationFn = Apollo.MutationFunction<InsertRun
|
||||
* const [insertRunServiceConfigMutation, { data, loading, error }] = useInsertRunServiceConfigMutation({
|
||||
* variables: {
|
||||
* appID: // value for 'appID'
|
||||
* serviceID: // value for 'serviceID'
|
||||
* config: // value for 'config'
|
||||
* },
|
||||
* });
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 2.25.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 46fc520: chore: add support to next.js 15, update quickstart template commands in docs
|
||||
- cdf6776: fix: update links to create new project in dashboard
|
||||
|
||||
## 2.24.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -7,7 +7,7 @@ icon: react
|
||||
|
||||
<Steps>
|
||||
<Step title="Create Project">
|
||||
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io).
|
||||
</Step>
|
||||
|
||||
<Step title="Setup Database">
|
||||
@@ -47,7 +47,7 @@ icon: react
|
||||
Create a Next.js application.
|
||||
|
||||
```bash Terminal
|
||||
npx create-next-app@latest --no-eslint \
|
||||
npx create-next-app@next-14 --no-eslint \
|
||||
--src-dir \
|
||||
--no-tailwind \
|
||||
--import-alias "@/*" \
|
||||
@@ -59,7 +59,7 @@ icon: react
|
||||
</Step>
|
||||
|
||||
<Step title="Install the Nhost package for Next.js">
|
||||
Navidate to the React application and install `@nhost/nextjs`.
|
||||
Navigate to the React application and install `@nhost/nextjs`.
|
||||
|
||||
```bash Terminal
|
||||
cd nhost-nextjs-quickstart && npm install @nhost/nextjs
|
||||
|
||||
@@ -20,7 +20,7 @@ icon: mobile-notch
|
||||
|
||||
<Steps>
|
||||
<Step title="Create Nhost Project">
|
||||
Create your project through the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
Create your project through the [Nhost Dashboard](https://app.nhost.io).
|
||||
</Step>
|
||||
|
||||
<Step title="Setup Database">
|
||||
|
||||
@@ -7,7 +7,7 @@ icon: react
|
||||
|
||||
<Steps>
|
||||
<Step title="Create Nhost Project">
|
||||
Create your project through the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
Create your project through the [Nhost Dashboard](https://app.nhost.io).
|
||||
</Step>
|
||||
|
||||
<Step title="Setup Database">
|
||||
|
||||
@@ -7,7 +7,7 @@ icon: vuejs
|
||||
|
||||
<Steps>
|
||||
<Step title="Create Project">
|
||||
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io).
|
||||
</Step>
|
||||
|
||||
<Step title="Setup Database">
|
||||
@@ -53,7 +53,7 @@ icon: vuejs
|
||||
</Step>
|
||||
|
||||
<Step title="Install the Nhost package for Vue">
|
||||
Navidate to the React application and install `@nhost/vue`.
|
||||
Navigate to the React application and install `@nhost/vue`.
|
||||
|
||||
```bash Terminal
|
||||
cd nhost-vue-quickstart && npm install @nhost/vue
|
||||
|
||||
@@ -30,7 +30,7 @@ In this section, you will create and setup your first Nhost project.
|
||||
|
||||
### Create project
|
||||
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
|
||||
|
||||
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:
|
||||
|
||||
@@ -156,7 +156,7 @@ Now that we have Nhost configured, let's move on to setup the React application
|
||||
Run the following command in your terminal to create a React application using Vite.
|
||||
|
||||
```bash Terminal
|
||||
npx create-next-app@latest --no-eslint \
|
||||
npx create-next-app@next-14 --no-eslint \
|
||||
--src-dir \
|
||||
--no-tailwind \
|
||||
--import-alias "@/*" \
|
||||
|
||||
@@ -30,7 +30,7 @@ In this section, you will create and setup your first Nhost project.
|
||||
|
||||
### Create project
|
||||
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
|
||||
|
||||
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ In this section, you will create and setup your first Nhost project.
|
||||
|
||||
### Create project
|
||||
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
|
||||
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
|
||||
|
||||
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "2.24.0",
|
||||
"version": "2.25.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "mintlify dev"
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/cli
|
||||
|
||||
## 0.3.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 0.3.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/cli",
|
||||
"version": "0.3.14",
|
||||
"version": "0.3.15",
|
||||
"main": "src/index.mjs",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/codegen-react-apollo
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
- @nhost/react-apollo@15.0.1
|
||||
|
||||
## 0.4.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-apollo",
|
||||
"version": "0.4.15",
|
||||
"version": "0.4.16",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/codegen-react-query
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
|
||||
## 0.4.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-query",
|
||||
"version": "0.4.15",
|
||||
"version": "0.4.16",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/react-urql
|
||||
|
||||
## 0.3.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
- @nhost/react-urql@12.0.1
|
||||
|
||||
## 0.3.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-urql",
|
||||
"private": true,
|
||||
"version": "0.3.15",
|
||||
"version": "0.3.16",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/multi-tenant-one-to-many
|
||||
|
||||
## 2.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 2.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/multi-tenant-one-to-many",
|
||||
"private": true,
|
||||
"version": "2.2.15",
|
||||
"version": "2.2.16",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @nhost-examples/nextjs
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [46fc520]
|
||||
- Updated dependencies [29d27e1]
|
||||
- @nhost/nextjs@2.2.0
|
||||
- @nhost/react@3.8.1
|
||||
- @nhost/react-apollo@15.0.1
|
||||
|
||||
## 0.3.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs",
|
||||
"version": "0.3.15",
|
||||
"version": "0.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -24,7 +24,7 @@
|
||||
"@nhost/react": "workspace:^",
|
||||
"@nhost/react-apollo": "workspace:^",
|
||||
"graphql": "16.8.1",
|
||||
"next": "^14.2.10",
|
||||
"next": "^14.2.22",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-icons": "^4.12.0"
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/node-storage
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/node-storage",
|
||||
"version": "0.2.14",
|
||||
"version": "0.2.15",
|
||||
"private": true,
|
||||
"description": "This is an example of how to use the Storage with Node.js",
|
||||
"main": "src/index.mjs",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @nhost-examples/nextjs-server-components
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- b944d05: chore: simplify Nhost client initialization with session and remove xstate dependency
|
||||
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs-server-components",
|
||||
"version": "0.4.16",
|
||||
"version": "0.5.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -18,14 +18,13 @@
|
||||
"form-data": "^4.0.0",
|
||||
"graphql": "16.8.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "^14.2.10",
|
||||
"next": "^14.2.22",
|
||||
"postcss": "^8.4.38",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss": "3.3.3",
|
||||
"typescript": "5.2.2",
|
||||
"xstate": "^4.38.3"
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { AuthErrorPayload, NhostClient, NhostSession } from '@nhost/nhost-js'
|
||||
import { cookies } from 'next/headers'
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { type StateFrom } from 'xstate/lib/types'
|
||||
import { waitFor } from 'xstate/lib/waitFor'
|
||||
|
||||
export const NHOST_SESSION_KEY = 'nhostSession'
|
||||
|
||||
export const getNhost = async (request?: NextRequest) => {
|
||||
@@ -20,9 +16,7 @@ export const getNhost = async (request?: NextRequest) => {
|
||||
const sessionCookieValue = $cookies.get(NHOST_SESSION_KEY)?.value || ''
|
||||
const initialSession: NhostSession = JSON.parse(atob(sessionCookieValue) || 'null')
|
||||
|
||||
nhost.auth.client.start({ initialSession })
|
||||
await waitFor(nhost.auth.client.interpreter!, (state: StateFrom<any>) => !state.hasTag('loading'))
|
||||
|
||||
await nhost.auth.initWithSession({ session: initialSession })
|
||||
return nhost
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/react-apollo
|
||||
|
||||
## 1.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
- @nhost/react-apollo@15.0.1
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-apollo",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/react-gqty
|
||||
|
||||
## 1.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
|
||||
## 1.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-gqty",
|
||||
"private": true,
|
||||
"version": "1.2.15",
|
||||
"version": "1.2.16",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/react-native
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
- @nhost/react-apollo@15.0.1
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-native",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android": "react-native run-android",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @nhost-examples/vue-apollo
|
||||
|
||||
## 0.7.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
- @nhost/apollo@8.0.2
|
||||
- @nhost/vue@2.8.1
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-apollo",
|
||||
"private": true,
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.2",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/vue-quickstart
|
||||
|
||||
## 0.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@8.0.2
|
||||
- @nhost/vue@2.8.1
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-quickstart",
|
||||
"version": "0.2.15",
|
||||
"version": "0.2.16",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 8.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 8.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "8.0.1",
|
||||
"version": "8.0.2",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/react-apollo
|
||||
|
||||
## 15.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@8.0.2
|
||||
- @nhost/react@3.8.1
|
||||
|
||||
## 15.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-apollo",
|
||||
"version": "15.0.0",
|
||||
"version": "15.0.1",
|
||||
"description": "Nhost React Apollo client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/react-urql
|
||||
|
||||
## 12.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
|
||||
## 12.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-urql",
|
||||
"version": "12.0.0",
|
||||
"version": "12.0.1",
|
||||
"description": "Nhost React URQL client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/hasura-auth-js
|
||||
|
||||
## 2.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- b944d05: feat: introduce `initWithSession` to initialize auth client with an existing session
|
||||
|
||||
## 2.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/hasura-auth-js",
|
||||
"version": "2.8.0",
|
||||
"version": "2.9.0",
|
||||
"description": "Hasura-auth client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
JWTHasuraClaims,
|
||||
LinkIdTokenParams,
|
||||
NhostAuthConstructorParams,
|
||||
NhostSession,
|
||||
NhostSessionResponse,
|
||||
OnTokenChangedFunction,
|
||||
ResetPasswordParams,
|
||||
@@ -857,6 +858,23 @@ export class HasuraAuthClient {
|
||||
return getSession(this._client.interpreter?.getSnapshot()?.context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the auth client with an existing session
|
||||
*
|
||||
* @example
|
||||
* ### Initialize with an existing Nhost session
|
||||
* ```ts
|
||||
* await nhost.auth.initWithSession({ session: initialSession })
|
||||
* ```
|
||||
*
|
||||
* @param session - The Nhost session object to initialize the client with
|
||||
* @docs https://docs.nhost.io/reference/javascript/auth/init-with-session
|
||||
*/
|
||||
async initWithSession({ session }: { session: NhostSession }): Promise<void> {
|
||||
this.client.start({ initialSession: session })
|
||||
await this.waitUntilReady()
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Use `nhost.auth.getUser()` to get the signed-in user.
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/hasura-storage-js
|
||||
|
||||
## 2.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 4148964: fix: stack overflow on storage client getHeaders method call
|
||||
|
||||
## 2.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/hasura-storage-js",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.0",
|
||||
"description": "Hasura-storage client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -242,7 +242,7 @@ export class HasuraStorageClient {
|
||||
* @docs https://docs.nhost.io/reference/javascript/storage/get-headers
|
||||
*/
|
||||
getHeaders(): Record<string, string> {
|
||||
return this.getHeaders()
|
||||
return this.api.getHeaders()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 2.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 46fc520: chore: add support to next.js 15, update quickstart template commands in docs
|
||||
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.8.1
|
||||
|
||||
## 2.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "2.1.24",
|
||||
"version": "2.2.0",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@@ -71,15 +71,15 @@
|
||||
"xstate": "^4.38.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^12.0.10 || ^13.0.0 || ^14.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0"
|
||||
"next": "^12.0.10 || ^13.0.0 || ^14.0.0 || ^15.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nhost/docgen": "workspace:*",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"next": "^14.2.10",
|
||||
"next": "^14.2.22",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @nhost/nhost-js
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b944d05]
|
||||
- Updated dependencies [4148964]
|
||||
- @nhost/hasura-auth-js@2.9.0
|
||||
- @nhost/hasura-storage-js@2.6.0
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nhost-js",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"description": "Nhost JavaScript SDK",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/react
|
||||
|
||||
## 3.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 3.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react",
|
||||
"version": "3.8.0",
|
||||
"version": "3.8.1",
|
||||
"description": "Nhost React library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/vue
|
||||
|
||||
## 2.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.2.2
|
||||
|
||||
## 2.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/vue",
|
||||
"version": "2.8.0",
|
||||
"version": "2.8.1",
|
||||
"description": "Nhost Vue library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
643
pnpm-lock.yaml
generated
643
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@
|
||||
"@craco/craco": "^7.1.0",
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@icons-pack/react-simple-icons": "^9.6.0",
|
||||
"@nhost/react": "^3.5.4",
|
||||
"@nhost/react-apollo": "^12.0.4",
|
||||
"@nhost/react": "^3.8.0",
|
||||
"@nhost/react-apollo": "^12.0.5",
|
||||
"@radix-ui/react-dialog": "^1.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
|
||||
Reference in New Issue
Block a user