Compare commits
15 Commits
@nhost/rea
...
@nhost/das
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a2bc98214 | ||
|
|
dd5d262062 | ||
|
|
09962bef37 | ||
|
|
9cdecb6b23 | ||
|
|
e7eb90318e | ||
|
|
f67f22d321 | ||
|
|
87ae23ba05 | ||
|
|
b2be3642aa | ||
|
|
1230081ce6 | ||
|
|
c195c517de | ||
|
|
6f419be2c1 | ||
|
|
93ebdf844f | ||
|
|
bcd889b53a | ||
|
|
992939cdcd | ||
|
|
3c31657c50 |
@@ -1,5 +1,27 @@
|
|||||||
# @nhost/dashboard
|
# @nhost/dashboard
|
||||||
|
|
||||||
|
## 1.13.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- dd5d262: feat: add model field to the auto-embeddings form
|
||||||
|
- 09962be: feat: enable settings and run services when running the dashboard locally
|
||||||
|
- 9cdecb6: feat: enable users to update their email address from the account settings page
|
||||||
|
|
||||||
|
## 1.12.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- c195c51: fix: send email upon signin for unverified users
|
||||||
|
|
||||||
|
## 1.12.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 93ebdf8: fix: use service urls when initilizaing NhostClient running local dashboard
|
||||||
|
- @nhost/react-apollo@11.0.1
|
||||||
|
- @nhost/nextjs@2.1.10
|
||||||
|
|
||||||
## 1.12.0
|
## 1.12.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nhost/dashboard",
|
"name": "@nhost/dashboard",
|
||||||
"version": "1.12.0",
|
"version": "1.13.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
|
import { Button } from '@/components/ui/v2/Button';
|
||||||
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
|
|
||||||
|
export default function ApplyLocalSettingsDialog() {
|
||||||
|
const { closeDialog } = useDialog();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4 px-6 pb-6">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Text color="secondary">
|
||||||
|
Run{' '}
|
||||||
|
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100">
|
||||||
|
$ nhost up
|
||||||
|
</code>{' '}
|
||||||
|
using the cli to apply your changes
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="w-full"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => closeDialog()}
|
||||||
|
autoFocus
|
||||||
|
>
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as ApplyLocalSettingsDialog } from './ApplyLocalSettingsDialog';
|
||||||
@@ -11,7 +11,6 @@ import { useNotFoundRedirect } from '@/features/projects/common/hooks/useNotFoun
|
|||||||
import { useProjectRoutes } from '@/features/projects/common/hooks/useProjectRoutes';
|
import { useProjectRoutes } from '@/features/projects/common/hooks/useProjectRoutes';
|
||||||
import { NextSeo } from 'next-seo';
|
import { NextSeo } from 'next-seo';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export interface ProjectLayoutProps extends AuthenticatedLayoutProps {
|
export interface ProjectLayoutProps extends AuthenticatedLayoutProps {
|
||||||
@@ -48,15 +47,16 @@ function ProjectLayoutContent({
|
|||||||
|
|
||||||
useNotFoundRedirect();
|
useNotFoundRedirect();
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (isPlatform || !router.isReady) {
|
// if (isPlatform || !router.isReady) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (isRestrictedPath) {
|
// TODO // Double check what restricted path means here
|
||||||
router.push('/local/local');
|
// if (isRestrictedPath) {
|
||||||
}
|
// router.push('/local/local');
|
||||||
}, [isPlatform, isRestrictedPath, router]);
|
// }
|
||||||
|
// }, [isPlatform, isRestrictedPath, router]);
|
||||||
|
|
||||||
if (isRestrictedPath || loading) {
|
if (isRestrictedPath || loading) {
|
||||||
return <LoadingScreen />;
|
return <LoadingScreen />;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { List } from '@/components/ui/v2/List';
|
|||||||
import type { ListItemButtonProps } from '@/components/ui/v2/ListItem';
|
import type { ListItemButtonProps } from '@/components/ui/v2/ListItem';
|
||||||
import { ListItem } from '@/components/ui/v2/ListItem';
|
import { ListItem } from '@/components/ui/v2/ListItem';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -61,6 +62,7 @@ export default function SettingsSidebar({
|
|||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: SettingsSidebarProps) {
|
}: SettingsSidebarProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ export default function SettingsSidebar({
|
|||||||
<>
|
<>
|
||||||
<Backdrop
|
<Backdrop
|
||||||
open={expanded}
|
open={expanded}
|
||||||
className="absolute top-0 left-0 bottom-0 right-0 z-[34] md:hidden"
|
className="absolute bottom-0 left-0 right-0 top-0 z-[34] md:hidden"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
onClick={() => setExpanded(false)}
|
onClick={() => setExpanded(false)}
|
||||||
@@ -112,7 +114,7 @@ export default function SettingsSidebar({
|
|||||||
<Box
|
<Box
|
||||||
component="aside"
|
component="aside"
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'absolute top-0 z-[35] h-full w-full overflow-auto border-r-1 px-2 pt-2 pb-17 motion-safe:transition-transform md:relative md:z-0 md:h-full md:py-2.5 md:transition-none',
|
'absolute top-0 z-[35] h-full w-full overflow-auto border-r-1 px-2 pb-17 pt-2 motion-safe:transition-transform md:relative md:z-0 md:h-full md:py-2.5 md:transition-none',
|
||||||
expanded ? 'translate-x-0' : '-translate-x-full md:translate-x-0',
|
expanded ? 'translate-x-0' : '-translate-x-full md:translate-x-0',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
@@ -181,7 +183,12 @@ export default function SettingsSidebar({
|
|||||||
SMTP
|
SMTP
|
||||||
</SettingsNavLink>
|
</SettingsNavLink>
|
||||||
|
|
||||||
<SettingsNavLink href="/git" exact={false} onClick={handleSelect}>
|
<SettingsNavLink
|
||||||
|
href="/git"
|
||||||
|
exact={false}
|
||||||
|
onClick={handleSelect}
|
||||||
|
disabled={!isPlatform}
|
||||||
|
>
|
||||||
Git
|
Git
|
||||||
</SettingsNavLink>
|
</SettingsNavLink>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { Form } from '@/components/form/Form';
|
||||||
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useNhostClient, useUserData } from '@nhost/nextjs';
|
||||||
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
|
const validationSchema = Yup.object({
|
||||||
|
email: Yup.string().label('Email').email().required(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type EmailSettingFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
|
export default function EmailSetting() {
|
||||||
|
const nhost = useNhostClient();
|
||||||
|
const { email } = useUserData();
|
||||||
|
|
||||||
|
const form = useForm<EmailSettingFormValues>({
|
||||||
|
reValidateMode: 'onSubmit',
|
||||||
|
defaultValues: { email },
|
||||||
|
resolver: yupResolver(validationSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { register, formState } = form;
|
||||||
|
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
||||||
|
|
||||||
|
async function handleSubmit(formValues: EmailSettingFormValues) {
|
||||||
|
await execPromiseWithErrorToast(
|
||||||
|
async () => {
|
||||||
|
await nhost.auth.changeEmail({
|
||||||
|
newEmail: formValues.email,
|
||||||
|
options: {
|
||||||
|
redirectTo: `${window.location.origin}/account`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
form.reset({ email: formValues.email });
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loadingMessage: 'Updating your email...',
|
||||||
|
successMessage:
|
||||||
|
'Please check your inbox. Follow the link to finalize changing your email.',
|
||||||
|
errorMessage:
|
||||||
|
'An error occurred while trying to update your email. Please try again.',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<SettingsContainer
|
||||||
|
title="Update your email"
|
||||||
|
slotProps={{
|
||||||
|
submitButton: {
|
||||||
|
disabled: !isDirty,
|
||||||
|
loading: formState.isSubmitting,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
className="grid grid-flow-row lg:grid-cols-5"
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
{...register('email')}
|
||||||
|
className="col-span-2"
|
||||||
|
id="email"
|
||||||
|
spellCheck="false"
|
||||||
|
autoCapitalize="none"
|
||||||
|
type="email"
|
||||||
|
label="Email"
|
||||||
|
hideEmptyHelperText
|
||||||
|
fullWidth
|
||||||
|
helperText={formState.errors.email?.message}
|
||||||
|
error={Boolean(formState.errors.email)}
|
||||||
|
/>
|
||||||
|
</SettingsContainer>
|
||||||
|
</Form>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './EmailSetting';
|
||||||
|
export { default as EmailSetting } from './EmailSetting';
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
|
import { ControlledSelect } from '@/components/form/ControlledSelect';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { Box } from '@/components/ui/v2/Box';
|
import { Box } from '@/components/ui/v2/Box';
|
||||||
import { Button } from '@/components/ui/v2/Button';
|
import { Button } from '@/components/ui/v2/Button';
|
||||||
@@ -6,6 +7,7 @@ import { ArrowsClockwise } from '@/components/ui/v2/icons/ArrowsClockwise';
|
|||||||
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
|
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
|
||||||
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
|
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
|
import { Option } from '@/components/ui/v2/Option';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
|
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
|
||||||
@@ -20,11 +22,18 @@ import { useEffect } from 'react';
|
|||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
|
const AUTO_EMBEDDINGS_MODELS = [
|
||||||
|
'text-embedding-ada-002',
|
||||||
|
'text-embedding-3-small',
|
||||||
|
'text-embedding-3-large',
|
||||||
|
];
|
||||||
|
|
||||||
export const validationSchema = Yup.object({
|
export const validationSchema = Yup.object({
|
||||||
name: Yup.string().required('The name is required.'),
|
name: Yup.string().required('The name field is required.'),
|
||||||
schemaName: Yup.string().required('The schema is required'),
|
model: Yup.string().oneOf(AUTO_EMBEDDINGS_MODELS),
|
||||||
tableName: Yup.string().required('The table is required'),
|
schemaName: Yup.string().required('The schema field is required'),
|
||||||
columnName: Yup.string().required('The column is required'),
|
tableName: Yup.string().required('The table field is required'),
|
||||||
|
columnName: Yup.string().required('The column field is required'),
|
||||||
query: Yup.string(),
|
query: Yup.string(),
|
||||||
mutation: Yup.string(),
|
mutation: Yup.string(),
|
||||||
});
|
});
|
||||||
@@ -40,7 +49,7 @@ export interface AutoEmbeddingsFormProps extends DialogFormProps {
|
|||||||
/**
|
/**
|
||||||
* if there is initialData then it's an update operation
|
* if there is initialData then it's an update operation
|
||||||
*/
|
*/
|
||||||
initialData?: AutoEmbeddingsFormValues;
|
initialData?: AutoEmbeddingsFormValues & { model: string };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to be called when the operation is cancelled.
|
* Function to be called when the operation is cancelled.
|
||||||
@@ -74,7 +83,10 @@ export default function AutoEmbeddingsForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const form = useForm<AutoEmbeddingsFormValues>({
|
const form = useForm<AutoEmbeddingsFormValues>({
|
||||||
defaultValues: initialData,
|
defaultValues: {
|
||||||
|
...initialData,
|
||||||
|
model: initialData?.model ?? 'text-embedding-ada-002',
|
||||||
|
},
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
@@ -106,7 +118,9 @@ export default function AutoEmbeddingsForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await insertGraphiteAutoEmbeddingsConfiguration({
|
await insertGraphiteAutoEmbeddingsConfiguration({
|
||||||
variables: values,
|
variables: {
|
||||||
|
...values,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,9 +143,9 @@ export default function AutoEmbeddingsForm({
|
|||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form
|
<Form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="flex h-full flex-col gap-4 overflow-hidden"
|
className="flex flex-col h-full gap-4 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="flex flex-1 flex-col space-y-6 overflow-auto px-6">
|
<div className="flex flex-col flex-1 px-6 space-y-6 overflow-auto">
|
||||||
<Input
|
<Input
|
||||||
{...register('name')}
|
{...register('name')}
|
||||||
id="name"
|
id="name"
|
||||||
@@ -141,7 +155,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title="Name of the Auto-Embeddings">
|
<Tooltip title="Name of the Auto-Embeddings">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -155,6 +169,36 @@ export default function AutoEmbeddingsForm({
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ControlledSelect
|
||||||
|
slotProps={{
|
||||||
|
popper: { disablePortal: false, className: 'z-[10000]' },
|
||||||
|
}}
|
||||||
|
id="model"
|
||||||
|
name="model"
|
||||||
|
label={
|
||||||
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
|
<Text>Model</Text>
|
||||||
|
<Tooltip title="Auto-Embeddings Model">
|
||||||
|
<InfoIcon
|
||||||
|
aria-label="Info"
|
||||||
|
className="w-4 h-4"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
fullWidth
|
||||||
|
error={!!errors?.model?.message}
|
||||||
|
helperText={errors?.model?.message}
|
||||||
|
>
|
||||||
|
{AUTO_EMBEDDINGS_MODELS.map((model) => (
|
||||||
|
<Option key={model} value={model}>
|
||||||
|
{model}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</ControlledSelect>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
{...register('schemaName')}
|
{...register('schemaName')}
|
||||||
id="schemaName"
|
id="schemaName"
|
||||||
@@ -164,7 +208,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title={<span>Schema where the table belongs to</span>}>
|
<Tooltip title={<span>Schema where the table belongs to</span>}>
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -186,7 +230,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title="Table Name">
|
<Tooltip title="Table Name">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -208,7 +252,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title="Column name">
|
<Tooltip title="Column name">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -230,7 +274,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title="Query">
|
<Tooltip title="Query">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -254,7 +298,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
<Tooltip title="Mutation">
|
<Tooltip title="Mutation">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -271,7 +315,7 @@ export default function AutoEmbeddingsForm({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Box className="flex w-full flex-row justify-between rounded border-t px-6 py-4">
|
<Box className="flex flex-row justify-between w-full px-6 py-4 border-t rounded">
|
||||||
<Button variant="outlined" color="secondary" onClick={onCancel}>
|
<Button variant="outlined" color="secondary" onClick={onCancel}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
@@ -12,6 +13,7 @@ import { Switch } from '@/components/ui/v2/Switch';
|
|||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||||
import { ComputeFormSection } from '@/features/services/components/ServiceForm/components/ComputeFormSection';
|
import { ComputeFormSection } from '@/features/services/components/ServiceForm/components/ComputeFormSection';
|
||||||
import {
|
import {
|
||||||
@@ -20,6 +22,7 @@ import {
|
|||||||
useGetSoftwareVersionsQuery,
|
useGetSoftwareVersionsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
||||||
import { getToastStyleProps } from '@/utils/constants/settings';
|
import { getToastStyleProps } from '@/utils/constants/settings';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
@@ -50,9 +53,13 @@ const validationSchema = Yup.object({
|
|||||||
export type AISettingsFormValues = Yup.InferType<typeof validationSchema>;
|
export type AISettingsFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function AISettings() {
|
export default function AISettings() {
|
||||||
const { maintenanceActive } = useUI();
|
const isPlatform = useIsPlatform();
|
||||||
const { openDialog } = useDialog();
|
const { openDialog } = useDialog();
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
|
const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
|
||||||
@@ -67,6 +74,7 @@ export default function AISettings() {
|
|||||||
variables: {
|
variables: {
|
||||||
appId: currentProject.id,
|
appId: currentProject.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: graphiteVersionsData, loading: loadingGraphiteVersionsData } =
|
const { data: graphiteVersionsData, loading: loadingGraphiteVersionsData } =
|
||||||
@@ -74,6 +82,7 @@ export default function AISettings() {
|
|||||||
variables: {
|
variables: {
|
||||||
software: Software_Type_Enum.Graphite,
|
software: Software_Type_Enum.Graphite,
|
||||||
},
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
const graphiteVersions = graphiteVersionsData?.softwareVersions || [];
|
const graphiteVersions = graphiteVersionsData?.softwareVersions || [];
|
||||||
@@ -98,8 +107,8 @@ export default function AISettings() {
|
|||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
version: {
|
version: {
|
||||||
label: ai?.version ?? availableVersions?.at(0)?.label,
|
label: ai?.version || availableVersions?.at(0)?.label || '',
|
||||||
value: ai?.version ?? availableVersions?.at(0)?.value,
|
value: ai?.version || availableVersions?.at(0)?.value || '',
|
||||||
},
|
},
|
||||||
webhookSecret: '',
|
webhookSecret: '',
|
||||||
organization: '',
|
organization: '',
|
||||||
@@ -225,6 +234,18 @@ export default function AISettings() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'AI settings are being updated...',
|
loadingMessage: 'AI settings are being updated...',
|
||||||
@@ -247,7 +268,7 @@ export default function AISettings() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="space-y-4" sx={{ backgroundColor: 'background.default' }}>
|
<Box className="space-y-4" sx={{ backgroundColor: 'background.default' }}>
|
||||||
<Box className="flex flex-row items-center justify-between rounded-lg border-1 p-4">
|
<Box className="flex flex-row items-center justify-between p-4 rounded-lg border-1">
|
||||||
<Text className="text-lg font-semibold">Enable AI service</Text>
|
<Text className="text-lg font-semibold">Enable AI service</Text>
|
||||||
<Switch
|
<Switch
|
||||||
checked={aiServiceEnabled}
|
checked={aiServiceEnabled}
|
||||||
@@ -270,54 +291,58 @@ export default function AISettings() {
|
|||||||
className="flex flex-col"
|
className="flex flex-col"
|
||||||
>
|
>
|
||||||
<Box className="space-y-4">
|
<Box className="space-y-4">
|
||||||
{availableVersions.length > 0 && (
|
<Box className="space-y-2">
|
||||||
<Box className="space-y-2">
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
<Box className="flex flex-row items-center space-x-2">
|
<Text className="text-lg font-semibold">Version</Text>
|
||||||
<Text className="text-lg font-semibold">Version</Text>
|
<Tooltip title="Version of the service to use.">
|
||||||
<Tooltip title="Version of the service to use.">
|
<InfoIcon
|
||||||
<InfoIcon
|
aria-label="Info"
|
||||||
aria-label="Info"
|
className="w-4 h-4"
|
||||||
className="h-4 w-4"
|
color="primary"
|
||||||
color="primary"
|
/>
|
||||||
/>
|
</Tooltip>
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
<ControlledAutocomplete
|
|
||||||
id="version"
|
|
||||||
name="version"
|
|
||||||
autoHighlight
|
|
||||||
isOptionEqualToValue={() => false}
|
|
||||||
filterOptions={(options, { inputValue }) => {
|
|
||||||
const inputValueLower = inputValue.toLowerCase();
|
|
||||||
const matched = [];
|
|
||||||
const otherOptions = [];
|
|
||||||
|
|
||||||
options.forEach((option) => {
|
|
||||||
const optionLabelLower = option.label.toLowerCase();
|
|
||||||
|
|
||||||
if (optionLabelLower.startsWith(inputValueLower)) {
|
|
||||||
matched.push(option);
|
|
||||||
} else {
|
|
||||||
otherOptions.push(option);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = [...matched, ...otherOptions];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}}
|
|
||||||
fullWidth
|
|
||||||
className="col-span-4"
|
|
||||||
options={availableVersions}
|
|
||||||
error={!!formState.errors?.version?.message}
|
|
||||||
helperText={formState.errors?.version?.message}
|
|
||||||
showCustomOption="auto"
|
|
||||||
customOptionLabel={(value) =>
|
|
||||||
`Use custom value: "${value}"`
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
<ControlledAutocomplete
|
||||||
|
id="version"
|
||||||
|
name="version"
|
||||||
|
autoHighlight
|
||||||
|
isOptionEqualToValue={() => false}
|
||||||
|
filterOptions={(options, { inputValue }) => {
|
||||||
|
const inputValueLower = inputValue.toLowerCase();
|
||||||
|
const matched = [];
|
||||||
|
const otherOptions = [];
|
||||||
|
|
||||||
|
options.forEach((option) => {
|
||||||
|
const optionLabelLower = option.label.toLowerCase();
|
||||||
|
|
||||||
|
if (optionLabelLower.startsWith(inputValueLower)) {
|
||||||
|
matched.push(option);
|
||||||
|
} else {
|
||||||
|
otherOptions.push(option);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = [...matched, ...otherOptions];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
className="col-span-4"
|
||||||
|
options={availableVersions}
|
||||||
|
error={
|
||||||
|
!!formState.errors?.version?.message ||
|
||||||
|
!!formState.errors?.version?.value?.message
|
||||||
|
}
|
||||||
|
helperText={
|
||||||
|
formState.errors?.version?.message ||
|
||||||
|
formState.errors?.version?.value?.message
|
||||||
|
}
|
||||||
|
showCustomOption="auto"
|
||||||
|
customOptionLabel={(value) =>
|
||||||
|
`Use custom value: "${value}"`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box className="space-y-2">
|
<Box className="space-y-2">
|
||||||
<Box className="flex flex-row items-center space-x-2">
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
@@ -327,7 +352,7 @@ export default function AISettings() {
|
|||||||
<Tooltip title="Used to validate requests between postgres and the AI service. The AI service will also include the header X-Graphite-Webhook-Secret with this value set when calling external webhooks so the source of the request can be validated.">
|
<Tooltip title="Used to validate requests between postgres and the AI service. The AI service will also include the header X-Graphite-Webhook-Secret with this value set when calling external webhooks so the source of the request can be validated.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -351,26 +376,28 @@ export default function AISettings() {
|
|||||||
<Tooltip title="Dedicated resources allocated for the service.">
|
<Tooltip title="Dedicated resources allocated for the service.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Alert
|
{isPlatform ? (
|
||||||
severity="info"
|
<Alert
|
||||||
className="flex items-center justify-between space-x-2"
|
severity="info"
|
||||||
>
|
className="flex items-center justify-between space-x-2"
|
||||||
<span>{getAIResourcesCost()}</span>
|
>
|
||||||
<b>
|
<span>{getAIResourcesCost()}</span>
|
||||||
$
|
<b>
|
||||||
{parseFloat(
|
$
|
||||||
(
|
{parseFloat(
|
||||||
aiSettingsFormValues.compute.cpu * COST_PER_VCPU
|
(
|
||||||
).toFixed(2),
|
aiSettingsFormValues.compute.cpu * COST_PER_VCPU
|
||||||
)}
|
).toFixed(2),
|
||||||
</b>
|
)}
|
||||||
</Alert>
|
</b>
|
||||||
|
</Alert>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<ComputeFormSection />
|
<ComputeFormSection />
|
||||||
</Box>
|
</Box>
|
||||||
@@ -389,7 +416,7 @@ export default function AISettings() {
|
|||||||
<Tooltip title="Key to use for authenticating API requests to OpenAI">
|
<Tooltip title="Key to use for authenticating API requests to OpenAI">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -412,7 +439,7 @@ export default function AISettings() {
|
|||||||
<Tooltip title="Optional. OpenAI organization to use.">
|
<Tooltip title="Optional. OpenAI organization to use.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -440,7 +467,7 @@ export default function AISettings() {
|
|||||||
<Tooltip title="How often to run the job that keeps embeddings up to date.">
|
<Tooltip title="How often to run the job that keeps embeddings up to date.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { Box } from '@/components/ui/v2/Box';
|
import { Box } from '@/components/ui/v2/Box';
|
||||||
import { Button } from '@/components/ui/v2/Button';
|
import { Button } from '@/components/ui/v2/Button';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { useUpdateConfigMutation } from '@/utils/__generated__/graphql';
|
import { useUpdateConfigMutation } from '@/utils/__generated__/graphql';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -23,11 +26,14 @@ export default function DisableAIServiceConfirmationDialog({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onServiceDisabled,
|
onServiceDisabled,
|
||||||
}: DisableAIServiceConfirmationDialogProps) {
|
}: DisableAIServiceConfirmationDialogProps) {
|
||||||
const { closeDialog } = useDialog();
|
const isPlatform = useIsPlatform();
|
||||||
|
const { openDialog, closeDialog } = useDialog();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
async function handleClick() {
|
async function handleClick() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -45,6 +51,18 @@ export default function DisableAIServiceConfirmationDialog({
|
|||||||
|
|
||||||
onServiceDisabled();
|
onServiceDisabled();
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Disabling the AI service...',
|
loadingMessage: 'Disabling the AI service...',
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -26,15 +31,19 @@ export type AllowedEmailSettingsFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function AllowedEmailDomainsSettings() {
|
export default function AllowedEmailDomainsSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { email, emailDomains } = data?.config?.auth?.user || {};
|
const { email, emailDomains } = data?.config?.auth?.user || {};
|
||||||
@@ -54,6 +63,17 @@ export default function AllowedEmailDomainsSettings() {
|
|||||||
|
|
||||||
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && email && emailDomains) {
|
||||||
|
form.reset({
|
||||||
|
enabled:
|
||||||
|
email?.allowed?.length > 0 || emailDomains?.allowed?.length > 0,
|
||||||
|
allowedEmails: email?.allowed?.join(', ') || '',
|
||||||
|
allowedEmailDomains: emailDomains?.allowed?.join(', ') || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, form, email, emailDomains]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -105,6 +125,18 @@ export default function AllowedEmailDomainsSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Allowed email settings are being updated...',
|
loadingMessage: 'Allowed email settings are being updated...',
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -23,15 +28,19 @@ export type AllowedRedirectURLFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function AllowedRedirectURLsSettings() {
|
export default function AllowedRedirectURLsSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { allowedUrls } = data?.config?.auth?.redirections || {};
|
const { allowedUrls } = data?.config?.auth?.redirections || {};
|
||||||
@@ -44,6 +53,14 @@ export default function AllowedRedirectURLsSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && allowedUrls) {
|
||||||
|
form.reset({
|
||||||
|
allowedUrls: allowedUrls?.join(', ') || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, allowedUrls, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -82,6 +99,18 @@ export default function AllowedRedirectURLsSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Allowed redirect URL settings are being updated...',
|
loadingMessage: 'Allowed redirect URL settings are being updated...',
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,15 +25,19 @@ const validationSchema = Yup.object({
|
|||||||
export type AnonymousSignInFormValues = Yup.InferType<typeof validationSchema>;
|
export type AnonymousSignInFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function AnonymousSignInSettings() {
|
export default function AnonymousSignInSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enabled } = data?.config?.auth?.method?.anonymous || {};
|
const { enabled } = data?.config?.auth?.method?.anonymous || {};
|
||||||
@@ -41,6 +50,12 @@ export default function AnonymousSignInSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({ enabled });
|
||||||
|
}
|
||||||
|
}, [loading, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -75,6 +90,18 @@ export default function AnonymousSignInSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Anonymous sign-in settings are being updated...',
|
loadingMessage: 'Anonymous sign-in settings are being updated...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -7,16 +9,19 @@ import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
|
|||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useTheme } from '@mui/material';
|
import { useTheme } from '@mui/material';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -53,15 +58,19 @@ export type AppleProviderFormValues = Yup.InferType<typeof validationSchema>;
|
|||||||
|
|
||||||
export default function AppleProviderSettings() {
|
export default function AppleProviderSettings() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, enabled, keyId, privateKey, teamId } =
|
const { clientId, enabled, keyId, privateKey, teamId } =
|
||||||
@@ -79,6 +88,18 @@ export default function AppleProviderSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
teamId: teamId || '',
|
||||||
|
keyId: keyId || '',
|
||||||
|
clientId: clientId || '',
|
||||||
|
privateKey: privateKey || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, teamId, keyId, clientId, privateKey, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -119,6 +140,18 @@ export default function AppleProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Apple settings are being updated...',
|
loadingMessage: 'Apple settings are being updated...',
|
||||||
@@ -236,7 +269,7 @@ export default function AppleProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
Software_Type_Enum,
|
Software_Type_Enum,
|
||||||
@@ -11,8 +14,10 @@ import {
|
|||||||
useGetSoftwareVersionsQuery,
|
useGetSoftwareVersionsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -28,21 +33,26 @@ export type AuthServiceVersionFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function AuthServiceVersionSettings() {
|
export default function AuthServiceVersionSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: authVersionsData } = useGetSoftwareVersionsQuery({
|
const { data: authVersionsData } = useGetSoftwareVersionsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
software: Software_Type_Enum.Auth,
|
software: Software_Type_Enum.Auth,
|
||||||
},
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { version } = data?.config?.auth || {};
|
const { version } = data?.config?.auth || {};
|
||||||
@@ -59,10 +69,21 @@ export default function AuthServiceVersionSettings() {
|
|||||||
|
|
||||||
const form = useForm<AuthServiceVersionFormValues>({
|
const form = useForm<AuthServiceVersionFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: { version: { label: version, value: version } },
|
defaultValues: { version: { label: '', value: '' } },
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && version) {
|
||||||
|
form.reset({
|
||||||
|
version: {
|
||||||
|
label: version,
|
||||||
|
value: version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, version, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -97,6 +118,18 @@ export default function AuthServiceVersionSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Auth version is being updated...',
|
loadingMessage: 'Auth version is being updated...',
|
||||||
@@ -120,12 +153,20 @@ export default function AuthServiceVersionSettings() {
|
|||||||
}}
|
}}
|
||||||
docsLink="https://github.com/nhost/hasura-auth/releases"
|
docsLink="https://github.com/nhost/hasura-auth/releases"
|
||||||
docsTitle="the latest releases"
|
docsTitle="the latest releases"
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="version"
|
id="version"
|
||||||
name="version"
|
name="version"
|
||||||
autoHighlight
|
autoHighlight
|
||||||
|
freeSolo
|
||||||
|
getOptionLabel={(option) => {
|
||||||
|
if (typeof option === 'string') {
|
||||||
|
return option || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return option.value;
|
||||||
|
}}
|
||||||
isOptionEqualToValue={() => false}
|
isOptionEqualToValue={() => false}
|
||||||
filterOptions={(options, { inputValue }) => {
|
filterOptions={(options, { inputValue }) => {
|
||||||
const inputValueLower = inputValue.toLowerCase();
|
const inputValueLower = inputValue.toLowerCase();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -8,15 +10,18 @@ import { Input } from '@/components/ui/v2/Input';
|
|||||||
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
||||||
import { BaseProviderSettings } from '@/features/authentication/settings/components/BaseProviderSettings';
|
import { BaseProviderSettings } from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -46,15 +51,19 @@ const validationSchema = Yup.object({
|
|||||||
export type AzureADProviderFormValues = Yup.InferType<typeof validationSchema>;
|
export type AzureADProviderFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function AzureADProviderSettings() {
|
export default function AzureADProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, tenant, enabled } =
|
const { clientId, clientSecret, tenant, enabled } =
|
||||||
@@ -71,6 +80,17 @@ export default function AzureADProviderSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
tenant: tenant || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, tenant, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -108,6 +128,18 @@ export default function AzureADProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Azure AD settings are being updated...',
|
loadingMessage: 'Azure AD settings are being updated...',
|
||||||
@@ -182,7 +214,7 @@ export default function AzureADProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -24,15 +29,19 @@ const validationSchema = Yup.object({
|
|||||||
export type BlockedEmailFormValues = Yup.InferType<typeof validationSchema>;
|
export type BlockedEmailFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function BlockedEmailSettings() {
|
export default function BlockedEmailSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { email, emailDomains } = data?.config?.auth?.user || {};
|
const { email, emailDomains } = data?.config?.auth?.user || {};
|
||||||
@@ -51,6 +60,17 @@ export default function BlockedEmailSettings() {
|
|||||||
const enabled = watch('enabled');
|
const enabled = watch('enabled');
|
||||||
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
const isDirty = Object.keys(formState.dirtyFields).length > 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && email && emailDomains) {
|
||||||
|
form.reset({
|
||||||
|
enabled:
|
||||||
|
email?.blocked?.length > 0 || emailDomains?.blocked?.length > 0,
|
||||||
|
blockedEmails: email?.blocked?.join(', ') || '',
|
||||||
|
blockedEmailDomains: emailDomains?.blocked?.join(', ') || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, email, emailDomains, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -112,6 +132,18 @@ export default function BlockedEmailSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage:
|
loadingMessage:
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -21,15 +26,19 @@ const validationSchema = Yup.object({
|
|||||||
export type ClientURLFormValues = Yup.InferType<typeof validationSchema>;
|
export type ClientURLFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function ClientURLSettings() {
|
export default function ClientURLSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientUrl, allowedUrls } = data?.config?.auth?.redirections || {};
|
const { clientUrl, allowedUrls } = data?.config?.auth?.redirections || {};
|
||||||
@@ -42,6 +51,12 @@ export default function ClientURLSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && clientUrl) {
|
||||||
|
form.reset({ clientUrl });
|
||||||
|
}
|
||||||
|
}, [loading, clientUrl, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -77,6 +92,18 @@ export default function ClientURLSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Client URL is being updated...',
|
loadingMessage: 'Client URL is being updated...',
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/utils/__generated__/graphql';
|
} from '@/utils/__generated__/graphql';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -19,15 +24,19 @@ const validationSchema = Yup.object({
|
|||||||
export type DisableNewUsersFormValues = Yup.InferType<typeof validationSchema>;
|
export type DisableNewUsersFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function DisableNewUsersSettings() {
|
export default function DisableNewUsersSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = useForm<DisableNewUsersFormValues>({
|
const form = useForm<DisableNewUsersFormValues>({
|
||||||
@@ -37,6 +46,14 @@ export default function DisableNewUsersSettings() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
disabled: !data?.config?.auth?.signUp?.enabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, data, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -73,6 +90,18 @@ export default function DisableNewUsersSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Disabling new user sign ups...',
|
loadingMessage: 'Disabling new user sign ups...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function DiscordProviderSettings() {
|
export default function DiscordProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function DiscordProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function DiscordProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Discord settings are being updated...',
|
loadingMessage: 'Discord settings are being updated...',
|
||||||
@@ -153,7 +184,7 @@ export default function DiscordProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
@@ -6,13 +8,16 @@ import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
|||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -29,15 +34,19 @@ const validationSchema = Yup.object({
|
|||||||
export type EmailAndPasswordFormValues = Yup.InferType<typeof validationSchema>;
|
export type EmailAndPasswordFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function EmailAndPasswordSettings() {
|
export default function EmailAndPasswordSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, error, loading } = useGetSignInMethodsQuery({
|
const { data, error, loading } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { hibpEnabled, emailVerificationRequired, passwordMinLength } =
|
const { hibpEnabled, emailVerificationRequired, passwordMinLength } =
|
||||||
@@ -53,6 +62,22 @@ export default function EmailAndPasswordSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
hibpEnabled,
|
||||||
|
emailVerificationRequired,
|
||||||
|
passwordMinLength,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
loading,
|
||||||
|
hibpEnabled,
|
||||||
|
emailVerificationRequired,
|
||||||
|
passwordMinLength,
|
||||||
|
form,
|
||||||
|
]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -87,6 +112,18 @@ export default function EmailAndPasswordSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: `Email and password sign-in settings are being updated...`,
|
loadingMessage: `Email and password sign-in settings are being updated...`,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function FacebookProviderSettings() {
|
export default function FacebookProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function FacebookProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function FacebookProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Facebook settings are being updated...',
|
loadingMessage: 'Facebook settings are being updated...',
|
||||||
@@ -153,7 +184,7 @@ export default function FacebookProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,30 +14,37 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useTheme } from '@mui/material';
|
import { useTheme } from '@mui/material';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function GitHubProviderSettings() {
|
export default function GitHubProviderSettings() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -51,6 +60,16 @@ export default function GitHubProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -91,6 +110,18 @@ export default function GitHubProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'GitHub settings are being updated...',
|
loadingMessage: 'GitHub settings are being updated...',
|
||||||
@@ -159,7 +190,7 @@ export default function GitHubProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function GoogleProviderSettings() {
|
export default function GoogleProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function GoogleProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function GoogleProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Google settings are being updated...',
|
loadingMessage: 'Google settings are being updated...',
|
||||||
@@ -153,7 +184,7 @@ export default function GoogleProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledSelect } from '@/components/form/ControlledSelect';
|
import { ControlledSelect } from '@/components/form/ControlledSelect';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
@@ -5,17 +7,20 @@ import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
|||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Option } from '@/components/ui/v2/Option';
|
import { Option } from '@/components/ui/v2/Option';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import {
|
import {
|
||||||
AUTH_GRAVATAR_DEFAULT,
|
AUTH_GRAVATAR_DEFAULT,
|
||||||
AUTH_GRAVATAR_RATING,
|
AUTH_GRAVATAR_RATING,
|
||||||
} from '@/utils/constants/settings';
|
} from '@/utils/constants/settings';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -29,15 +34,19 @@ const validationSchema = Yup.object({
|
|||||||
export type GravatarFormValues = Yup.InferType<typeof validationSchema>;
|
export type GravatarFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function GravatarSettings() {
|
export default function GravatarSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -56,6 +65,16 @@ export default function GravatarSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
default: defaultGravatar || '',
|
||||||
|
rating: rating || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, defaultGravatar, rating, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -91,6 +110,18 @@ export default function GravatarSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Gravatar settings are being updated...',
|
loadingMessage: 'Gravatar settings are being updated...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function LinkedInProviderSettings() {
|
export default function LinkedInProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function LinkedInProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function LinkedInProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'LinkedIn settings are being updated...',
|
loadingMessage: 'LinkedIn settings are being updated...',
|
||||||
@@ -153,7 +184,7 @@ export default function LinkedInProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -23,15 +28,19 @@ const validationSchema = Yup.object({
|
|||||||
export type MFASettingsFormValues = Yup.InferType<typeof validationSchema>;
|
export type MFASettingsFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function MFASettings() {
|
export default function MFASettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enabled, issuer } = data?.config?.auth?.totp || {};
|
const { enabled, issuer } = data?.config?.auth?.totp || {};
|
||||||
@@ -45,6 +54,15 @@ export default function MFASettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && issuer && enabled) {
|
||||||
|
form.reset({
|
||||||
|
issuer,
|
||||||
|
enabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, issuer, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -78,6 +96,18 @@ export default function MFASettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage:
|
loadingMessage:
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,15 +25,19 @@ const validationSchema = Yup.object({
|
|||||||
export type MagicLinkFormValues = Yup.InferType<typeof validationSchema>;
|
export type MagicLinkFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function MagicLinkSettings() {
|
export default function MagicLinkSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enabled } = data?.config?.auth?.method?.emailPasswordless || {};
|
const { enabled } = data?.config?.auth?.method?.emailPasswordless || {};
|
||||||
@@ -41,6 +50,12 @@ export default function MagicLinkSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({ enabled });
|
||||||
|
}
|
||||||
|
}, [loading, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -75,6 +90,18 @@ export default function MagicLinkSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Magic Link settings are being updated...',
|
loadingMessage: 'Magic Link settings are being updated...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -7,14 +9,17 @@ import { Option } from '@/components/ui/v2/Option';
|
|||||||
import { Select } from '@/components/ui/v2/Select';
|
import { Select } from '@/components/ui/v2/Select';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -44,15 +49,19 @@ const validationSchema = Yup.object({
|
|||||||
export type SMSSettingsFormValues = Yup.InferType<typeof validationSchema>;
|
export type SMSSettingsFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function SMSSettings() {
|
export default function SMSSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, error, loading } = useGetSignInMethodsQuery({
|
const { data, error, loading } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { accountSid, authToken, messagingServiceId } =
|
const { accountSid, authToken, messagingServiceId } =
|
||||||
@@ -70,6 +79,17 @@ export default function SMSSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
accountSid: accountSid || '',
|
||||||
|
authToken: authToken || '',
|
||||||
|
messagingServiceId: messagingServiceId || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, accountSid, authToken, messagingServiceId, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -114,6 +134,18 @@ export default function SMSSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'SMS settings are being updated...',
|
loadingMessage: 'SMS settings are being updated...',
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAuthenticationSettingsDocument,
|
GetAuthenticationSettingsDocument,
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -28,15 +33,19 @@ const validationSchema = Yup.object({
|
|||||||
export type SessionFormValues = Yup.InferType<typeof validationSchema>;
|
export type SessionFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function SessionSettings() {
|
export default function SessionSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetAuthenticationSettingsDocument],
|
refetchQueries: [GetAuthenticationSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { accessToken, refreshToken } = data?.config?.auth?.session || {};
|
const { accessToken, refreshToken } = data?.config?.auth?.session || {};
|
||||||
@@ -50,6 +59,15 @@ export default function SessionSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && accessToken && refreshToken) {
|
||||||
|
form.reset({
|
||||||
|
accessTokenExpiresIn: accessToken?.expiresIn || 900,
|
||||||
|
refreshTokenExpiresIn: refreshToken?.expiresIn || 43200,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, accessToken, refreshToken, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -86,6 +104,18 @@ export default function SessionSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Session settings are being updated...',
|
loadingMessage: 'Session settings are being updated...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function SpotifyProviderSettings() {
|
export default function SpotifyProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function SpotifyProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function SpotifyProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Spotify settings are being updated...',
|
loadingMessage: 'Spotify settings are being updated...',
|
||||||
@@ -153,7 +184,7 @@ export default function SpotifyProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,30 +14,37 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useTheme } from '@mui/material';
|
import { useTheme } from '@mui/material';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function TwitchProviderSettings() {
|
export default function TwitchProviderSettings() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -51,6 +60,16 @@ export default function TwitchProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -91,6 +110,18 @@ export default function TwitchProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Twitch settings are being updated...',
|
loadingMessage: 'Twitch settings are being updated...',
|
||||||
@@ -159,7 +190,7 @@ export default function TwitchProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -7,15 +9,18 @@ import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
|
|||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -39,15 +44,19 @@ const validationSchema = Yup.object({
|
|||||||
export type TwitterProviderFormValues = Yup.InferType<typeof validationSchema>;
|
export type TwitterProviderFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function TwitterProviderSettings() {
|
export default function TwitterProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { consumerKey, consumerSecret, enabled } =
|
const { consumerKey, consumerSecret, enabled } =
|
||||||
@@ -63,6 +72,16 @@ export default function TwitterProviderSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
consumerSecret: consumerSecret || '',
|
||||||
|
consumerKey: consumerKey || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, consumerKey, consumerSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -100,6 +119,18 @@ export default function TwitterProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Twitter settings are being updated...',
|
loadingMessage: 'Twitter settings are being updated...',
|
||||||
@@ -185,7 +216,7 @@ export default function TwitterProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,15 +25,19 @@ const validationSchema = Yup.object({
|
|||||||
export type WebAuthnFormValues = Yup.InferType<typeof validationSchema>;
|
export type WebAuthnFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function WebAuthnSettings() {
|
export default function WebAuthnSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enabled } = data?.config?.auth?.method?.webauthn || {};
|
const { enabled } = data?.config?.auth?.method?.webauthn || {};
|
||||||
@@ -41,6 +50,12 @@ export default function WebAuthnSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({ enabled });
|
||||||
|
}
|
||||||
|
}, [loading, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -80,6 +95,18 @@ export default function WebAuthnSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(values);
|
form.reset(values);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'WebAuthn settings are being updated...',
|
loadingMessage: 'WebAuthn settings are being updated...',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -12,28 +14,35 @@ import {
|
|||||||
baseProviderValidationSchema,
|
baseProviderValidationSchema,
|
||||||
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
} from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function WindowsLiveProviderSettings() {
|
export default function WindowsLiveProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, enabled } =
|
const { clientId, clientSecret, enabled } =
|
||||||
@@ -49,6 +58,16 @@ export default function WindowsLiveProviderSettings() {
|
|||||||
resolver: yupResolver(baseProviderValidationSchema),
|
resolver: yupResolver(baseProviderValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, clientId, clientSecret, enabled, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -89,6 +108,18 @@ export default function WindowsLiveProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Windows Live settings are being updated...',
|
loadingMessage: 'Windows Live settings are being updated...',
|
||||||
@@ -151,7 +182,7 @@ export default function WindowsLiveProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -8,15 +10,18 @@ import { Input } from '@/components/ui/v2/Input';
|
|||||||
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
|
||||||
import { BaseProviderSettings } from '@/features/authentication/settings/components/BaseProviderSettings';
|
import { BaseProviderSettings } from '@/features/authentication/settings/components/BaseProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import {
|
import {
|
||||||
GetSignInMethodsDocument,
|
GetSignInMethodsDocument,
|
||||||
useGetSignInMethodsQuery,
|
useGetSignInMethodsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -52,15 +57,19 @@ const validationSchema = Yup.object({
|
|||||||
export type WorkOsProviderFormValues = Yup.InferType<typeof validationSchema>;
|
export type WorkOsProviderFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function WorkOsProviderSettings() {
|
export default function WorkOsProviderSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSignInMethodsDocument],
|
refetchQueries: [GetSignInMethodsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetSignInMethodsQuery({
|
const { data, loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { clientId, clientSecret, organization, connection, enabled } =
|
const { clientId, clientSecret, organization, connection, enabled } =
|
||||||
@@ -78,6 +87,26 @@ export default function WorkOsProviderSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
clientId: clientId || '',
|
||||||
|
clientSecret: clientSecret || '',
|
||||||
|
organization: organization || '',
|
||||||
|
connection: connection || '',
|
||||||
|
enabled: enabled || false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
loading,
|
||||||
|
clientId,
|
||||||
|
clientSecret,
|
||||||
|
organization,
|
||||||
|
connection,
|
||||||
|
enabled,
|
||||||
|
form,
|
||||||
|
]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -115,6 +144,18 @@ export default function WorkOsProviderSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'WorkOS settings are being updated...',
|
loadingMessage: 'WorkOS settings are being updated...',
|
||||||
@@ -203,7 +244,7 @@ export default function WorkOsProviderSettings() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetPostgresSettingsDocument,
|
GetPostgresSettingsDocument,
|
||||||
Software_Type_Enum,
|
Software_Type_Enum,
|
||||||
@@ -11,8 +14,10 @@ import {
|
|||||||
useGetSoftwareVersionsQuery,
|
useGetSoftwareVersionsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -30,24 +35,30 @@ export type DatabaseServiceVersionFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function DatabaseServiceVersionSettings() {
|
export default function DatabaseServiceVersionSettings() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const { openDialog } = useDialog();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetPostgresSettingsDocument],
|
refetchQueries: [GetPostgresSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetPostgresSettingsQuery({
|
const { data, loading, error } = useGetPostgresSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: databaseVersionsData } = useGetSoftwareVersionsQuery({
|
const { data: databaseVersionsData } = useGetSoftwareVersionsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
software: Software_Type_Enum.PostgreSql,
|
software: Software_Type_Enum.PostgreSql,
|
||||||
},
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { version } = data?.config?.postgres || {};
|
const { version } = data?.config?.postgres || {};
|
||||||
|
|
||||||
const databaseVersions = databaseVersionsData?.softwareVersions || [];
|
const databaseVersions = databaseVersionsData?.softwareVersions || [];
|
||||||
const availableVersions = Array.from(
|
const availableVersions = Array.from(
|
||||||
new Set(databaseVersions.map((el) => el.version)).add(version),
|
new Set(databaseVersions.map((el) => el.version)).add(version),
|
||||||
@@ -61,10 +72,21 @@ export default function DatabaseServiceVersionSettings() {
|
|||||||
|
|
||||||
const form = useForm<DatabaseServiceVersionFormValues>({
|
const form = useForm<DatabaseServiceVersionFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: { version: { label: version, value: version } },
|
defaultValues: { version: { label: '', value: '' } },
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && version) {
|
||||||
|
form.reset({
|
||||||
|
version: {
|
||||||
|
label: version,
|
||||||
|
value: version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, version, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -99,6 +121,18 @@ export default function DatabaseServiceVersionSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Postgres version is being updated...',
|
loadingMessage: 'Postgres version is being updated...',
|
||||||
@@ -123,12 +157,20 @@ export default function DatabaseServiceVersionSettings() {
|
|||||||
}}
|
}}
|
||||||
docsLink="https://hub.docker.com/r/nhost/postgres/tags"
|
docsLink="https://hub.docker.com/r/nhost/postgres/tags"
|
||||||
docsTitle="the latest releases"
|
docsTitle="the latest releases"
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="version"
|
id="version"
|
||||||
name="version"
|
name="version"
|
||||||
autoHighlight
|
autoHighlight
|
||||||
|
freeSolo
|
||||||
|
getOptionLabel={(option) => {
|
||||||
|
if (typeof option === 'string') {
|
||||||
|
return option || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return option.value;
|
||||||
|
}}
|
||||||
isOptionEqualToValue={() => false}
|
isOptionEqualToValue={() => false}
|
||||||
filterOptions={(options, { inputValue }) => {
|
filterOptions={(options, { inputValue }) => {
|
||||||
const inputValueLower = inputValue.toLowerCase();
|
const inputValueLower = inputValue.toLowerCase();
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import { Box } from '@/components/ui/v2/Box';
|
|||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
useGetPostgresSettingsQuery,
|
useGetPostgresSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
@@ -18,13 +20,15 @@ import { FormProvider, useForm } from 'react-hook-form';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
const validationSchema = Yup.object({
|
const validationSchema = Yup.object({
|
||||||
capacity: Yup.number().required(),
|
capacity: Yup.number().required().min(10),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
|
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function AuthDomain() {
|
export default function AuthDomain() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -34,14 +38,17 @@ export default function AuthDomain() {
|
|||||||
refetch: refetchPostgresSettings,
|
refetch: refetchPostgresSettings,
|
||||||
} = useGetPostgresSettingsQuery({
|
} = useGetPostgresSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const capacity =
|
const capacity =
|
||||||
data?.config?.postgres?.resources?.storage?.capacity ??
|
(data?.config?.postgres?.resources?.storage?.capacity ??
|
||||||
currentProject.plan.featureMaxDbSize;
|
currentProject?.plan?.featureMaxDbSize) ||
|
||||||
|
0;
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
@@ -117,7 +124,7 @@ export default function AuthDomain() {
|
|||||||
}}
|
}}
|
||||||
className="flex flex-col"
|
className="flex flex-col"
|
||||||
>
|
>
|
||||||
{currentProject.plan.isFree && (
|
{currentProject.plan?.isFree && (
|
||||||
<UpgradeNotification message="Unlock by upgrading your project to the Pro plan." />
|
<UpgradeNotification message="Unlock by upgrading your project to the Pro plan." />
|
||||||
)}
|
)}
|
||||||
<Box className="grid grid-flow-row lg:grid-cols-5">
|
<Box className="grid grid-flow-row lg:grid-cols-5">
|
||||||
@@ -127,7 +134,7 @@ export default function AuthDomain() {
|
|||||||
name="capacity"
|
name="capacity"
|
||||||
type="number"
|
type="number"
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={currentProject.plan.isFree}
|
disabled={currentProject.plan?.isFree}
|
||||||
className="lg:col-span-2"
|
className="lg:col-span-2"
|
||||||
error={Boolean(formState.errors.capacity?.message)}
|
error={Boolean(formState.errors.capacity?.message)}
|
||||||
helperText={formState.errors.capacity?.message}
|
helperText={formState.errors.capacity?.message}
|
||||||
@@ -138,7 +145,7 @@ export default function AuthDomain() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{!currentProject.plan.isFree && (
|
{!currentProject.plan?.isFree && (
|
||||||
<Alert severity="info" className="col-span-6 text-left">
|
<Alert severity="info" className="col-span-6 text-left">
|
||||||
Note that volumes can only be increased (not decreased). Also, due
|
Note that volumes can only be increased (not decreased). Also, due
|
||||||
to an AWS limitation, the same volume can only be increased once
|
to an AWS limitation, the same volume can only be increased once
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,16 +25,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraAllowListFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraAllowListFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraAllowListSettings() {
|
export default function HasuraAllowListSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enableAllowList } = data?.config?.hasura.settings || {};
|
const { enableAllowList } = data?.config?.hasura.settings || {};
|
||||||
@@ -42,6 +51,14 @@ export default function HasuraAllowListSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
enabled: enableAllowList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, enableAllowList, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -75,6 +92,18 @@ export default function HasuraAllowListSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Allow list settings are being updated...',
|
loadingMessage: 'Allow list settings are being updated...',
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,16 +25,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraConsoleFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraConsoleFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraConsoleSettings() {
|
export default function HasuraConsoleSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enableConsole } = data?.config?.hasura.settings || {};
|
const { enableConsole } = data?.config?.hasura.settings || {};
|
||||||
@@ -42,6 +51,14 @@ export default function HasuraConsoleSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
enabled: enableConsole,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, enableConsole, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -75,6 +92,18 @@ export default function HasuraConsoleSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Hasura Console settings are being updated...',
|
loadingMessage: 'Hasura Console settings are being updated...',
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
@@ -28,16 +32,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraCorsDomainFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraCorsDomainFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraCorsDomainSettings() {
|
export default function HasuraCorsDomainSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { corsDomain } = data?.config?.hasura.settings || {};
|
const { corsDomain } = data?.config?.hasura.settings || {};
|
||||||
@@ -98,6 +106,18 @@ export default function HasuraCorsDomainSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'CORS domain settings are being updated...',
|
loadingMessage: 'CORS domain settings are being updated...',
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,16 +25,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraDevModeFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraDevModeFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraDevModeSettings() {
|
export default function HasuraDevModeSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { devMode } = data?.config?.hasura.settings || {};
|
const { devMode } = data?.config?.hasura.settings || {};
|
||||||
@@ -42,6 +51,14 @@ export default function HasuraDevModeSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
enabled: devMode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, devMode, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -63,7 +80,7 @@ export default function HasuraDevModeSettings() {
|
|||||||
config: {
|
config: {
|
||||||
hasura: {
|
hasura: {
|
||||||
settings: {
|
settings: {
|
||||||
enableConsole: formValues.enabled,
|
devMode: formValues.enabled,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -75,6 +92,18 @@ export default function HasuraDevModeSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Dev Mode settings are being updated...',
|
loadingMessage: 'Dev Mode settings are being updated...',
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -30,31 +35,40 @@ export type HasuraEnabledAPIFormValues = Yup.InferType<typeof validationSchema>;
|
|||||||
const AVAILABLE_HASURA_APIS = ['metadata', 'graphql', 'pgdump', 'config'];
|
const AVAILABLE_HASURA_APIS = ['metadata', 'graphql', 'pgdump', 'config'];
|
||||||
|
|
||||||
export default function HasuraEnabledAPISettings() {
|
export default function HasuraEnabledAPISettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enabledAPIs } = data?.config?.hasura.settings || {};
|
const { enabledAPIs = [] } = data?.config?.hasura?.settings || {};
|
||||||
|
|
||||||
const form = useForm<HasuraEnabledAPIFormValues>({
|
const form = useForm<HasuraEnabledAPIFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
enabledAPIs: enabledAPIs.map((api) => ({
|
enabledAPIs: [],
|
||||||
label: api,
|
|
||||||
value: api,
|
|
||||||
})),
|
|
||||||
},
|
},
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (enabledAPIs && !loading) {
|
||||||
|
form.reset({
|
||||||
|
enabledAPIs: enabledAPIs.map((api) => ({ label: api, value: api })),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [form, enabledAPIs, loading]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -96,6 +110,18 @@ export default function HasuraEnabledAPISettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Enabled APIs are being updated...',
|
loadingMessage: 'Enabled APIs are being updated...',
|
||||||
@@ -117,7 +143,7 @@ export default function HasuraEnabledAPISettings() {
|
|||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-6"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-6"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="enabledAPIs"
|
id="enabledAPIs"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
@@ -5,13 +7,16 @@ import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
|||||||
import { HighlightedText } from '@/components/presentational/HighlightedText';
|
import { HighlightedText } from '@/components/presentational/HighlightedText';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -29,16 +34,20 @@ export type HasuraLogLevelFormValues = Yup.InferType<typeof validationSchema>;
|
|||||||
const AVAILABLE_HASURA_LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
|
const AVAILABLE_HASURA_LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
|
||||||
|
|
||||||
export default function HasuraLogLevelSettings() {
|
export default function HasuraLogLevelSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { level } = data?.config?.hasura.logs || {};
|
const { level } = data?.config?.hasura.logs || {};
|
||||||
@@ -56,6 +65,17 @@ export default function HasuraLogLevelSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && level) {
|
||||||
|
form.reset({
|
||||||
|
logLevel: {
|
||||||
|
label: level,
|
||||||
|
value: level,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [form, loading, level]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -97,6 +117,18 @@ export default function HasuraLogLevelSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Log level is being updated...',
|
loadingMessage: 'Log level is being updated...',
|
||||||
@@ -128,7 +160,7 @@ export default function HasuraLogLevelSettings() {
|
|||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="logLevel"
|
id="logLevel"
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
@@ -26,16 +30,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraPoolSizeFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraPoolSizeFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraPoolSizeSettings() {
|
export default function HasuraPoolSizeSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { httpPoolSize } = data?.config?.hasura.events || {};
|
const { httpPoolSize } = data?.config?.hasura.events || {};
|
||||||
@@ -82,6 +90,18 @@ export default function HasuraPoolSizeSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Pool size is being updated...',
|
loadingMessage: 'Pool size is being updated...',
|
||||||
@@ -104,7 +124,7 @@ export default function HasuraPoolSizeSettings() {
|
|||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
{...register('httpPoolSize')}
|
{...register('httpPoolSize')}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -22,16 +27,20 @@ export type HasuraRemoteSchemaPermissionsFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function HasuraRemoteSchemaPermissionsSettings() {
|
export default function HasuraRemoteSchemaPermissionsSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { enableRemoteSchemaPermissions } = data?.config?.hasura.settings || {};
|
const { enableRemoteSchemaPermissions } = data?.config?.hasura.settings || {};
|
||||||
@@ -44,6 +53,14 @@ export default function HasuraRemoteSchemaPermissionsSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
enabled: enableRemoteSchemaPermissions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, enableRemoteSchemaPermissions, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -67,7 +84,7 @@ export default function HasuraRemoteSchemaPermissionsSettings() {
|
|||||||
config: {
|
config: {
|
||||||
hasura: {
|
hasura: {
|
||||||
settings: {
|
settings: {
|
||||||
enableConsole: formValues.enabled,
|
enableRemoteSchemaPermissions: formValues.enabled,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -79,6 +96,18 @@ export default function HasuraRemoteSchemaPermissionsSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage:
|
loadingMessage:
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
Software_Type_Enum,
|
Software_Type_Enum,
|
||||||
@@ -11,8 +14,10 @@ import {
|
|||||||
useGetSoftwareVersionsQuery,
|
useGetSoftwareVersionsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -30,22 +35,27 @@ export type HasuraServiceVersionFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function HasuraServiceVersionSettings() {
|
export default function HasuraServiceVersionSettings() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const { openDialog } = useDialog();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: hasuraVersionsData } = useGetSoftwareVersionsQuery({
|
const { data: hasuraVersionsData } = useGetSoftwareVersionsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
software: Software_Type_Enum.Hasura,
|
software: Software_Type_Enum.Hasura,
|
||||||
},
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { version } = data?.config?.hasura || {};
|
const { version } = data?.config?.hasura || {};
|
||||||
@@ -53,6 +63,7 @@ export default function HasuraServiceVersionSettings() {
|
|||||||
const availableVersions = Array.from(
|
const availableVersions = Array.from(
|
||||||
new Set(versions.map((el) => el.version)).add(version),
|
new Set(versions.map((el) => el.version)).add(version),
|
||||||
)
|
)
|
||||||
|
.filter((v) => !!v)
|
||||||
.sort()
|
.sort()
|
||||||
.reverse()
|
.reverse()
|
||||||
.map((availableVersion) => ({
|
.map((availableVersion) => ({
|
||||||
@@ -60,12 +71,25 @@ export default function HasuraServiceVersionSettings() {
|
|||||||
value: availableVersion,
|
value: availableVersion,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// TODO make sure the network request is made in the parent component
|
||||||
|
// also this request should be made against cache only and the data should be available right away
|
||||||
const form = useForm<HasuraServiceVersionFormValues>({
|
const form = useForm<HasuraServiceVersionFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: { version: { label: version, value: version } },
|
defaultValues: { version: { label: '', value: '' } },
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && version) {
|
||||||
|
form.reset({
|
||||||
|
version: {
|
||||||
|
label: version,
|
||||||
|
value: version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, version, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -99,6 +123,18 @@ export default function HasuraServiceVersionSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Hasura version is being updated...',
|
loadingMessage: 'Hasura version is being updated...',
|
||||||
@@ -123,11 +159,19 @@ export default function HasuraServiceVersionSettings() {
|
|||||||
}}
|
}}
|
||||||
docsLink="https://hub.docker.com/r/nhost/graphql-engine/tags"
|
docsLink="https://hub.docker.com/r/nhost/graphql-engine/tags"
|
||||||
docsTitle="the latest releases"
|
docsTitle="the latest releases"
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="version"
|
id="version"
|
||||||
name="version"
|
name="version"
|
||||||
|
freeSolo
|
||||||
|
getOptionLabel={(option) => {
|
||||||
|
if (typeof option === 'string') {
|
||||||
|
return option || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return option.value;
|
||||||
|
}}
|
||||||
autoHighlight
|
autoHighlight
|
||||||
isOptionEqualToValue={() => false}
|
isOptionEqualToValue={() => false}
|
||||||
filterOptions={(options, { inputValue }) => {
|
filterOptions={(options, { inputValue }) => {
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { Button } from '@/components/ui/v2/Button';
|
|||||||
import { Checkbox } from '@/components/ui/v2/Checkbox';
|
import { Checkbox } from '@/components/ui/v2/Checkbox';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { type RunService } from '@/hooks/useRunServices';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
useDeleteRunServiceConfigMutation,
|
useDeleteRunServiceConfigMutation,
|
||||||
useDeleteRunServiceMutation,
|
useDeleteRunServiceMutation,
|
||||||
} from '@/utils/__generated__/graphql';
|
} from '@/utils/__generated__/graphql';
|
||||||
import { type RunService } from 'pages/[workspaceSlug]/[appSlug]/services';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default function useCurrentWorkspaceAndProject(): UseCurrentWorkspaceAndP
|
|||||||
// Return a default project if working locally
|
// Return a default project if working locally
|
||||||
if (!isPlatform) {
|
if (!isPlatform) {
|
||||||
const localProject: Project = {
|
const localProject: Project = {
|
||||||
id: 'local',
|
id: '00000000-0000-0000-0000-000000000000',
|
||||||
slug: 'local',
|
slug: 'local',
|
||||||
name: 'local',
|
name: 'local',
|
||||||
appStates: [
|
appStates: [
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useGetPlansQuery } from '@/utils/__generated__/graphql';
|
import { useGetPlansQuery } from '@/utils/__generated__/graphql';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Pro plan.
|
* Returns the Pro plan.
|
||||||
*/
|
*/
|
||||||
export default function useProPlan() {
|
export default function useProPlan() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
|
||||||
const { data, ...rest } = useGetPlansQuery({
|
const { data, ...rest } = useGetPlansQuery({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
@@ -13,6 +16,7 @@ export default function useProPlan() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
fetchPolicy: 'cache-first',
|
fetchPolicy: 'cache-first',
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data: data?.plans?.at(0), ...rest };
|
return { data: data?.plans?.at(0), ...rest };
|
||||||
|
|||||||
@@ -90,14 +90,6 @@ export default function useProjectRoutes() {
|
|||||||
icon: <GaugeIcon />,
|
icon: <GaugeIcon />,
|
||||||
disabled: !isPlatform,
|
disabled: !isPlatform,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
relativeMainPath: '/settings',
|
|
||||||
relativePath: '/settings/general',
|
|
||||||
exact: false,
|
|
||||||
label: 'Settings',
|
|
||||||
icon: <CogIcon />,
|
|
||||||
disabled: !isPlatform || maintenanceActive,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const allRoutes: ProjectRoute[] = [
|
const allRoutes: ProjectRoute[] = [
|
||||||
@@ -143,7 +135,6 @@ export default function useProjectRoutes() {
|
|||||||
exact: false,
|
exact: false,
|
||||||
label: 'Run',
|
label: 'Run',
|
||||||
icon: <ServicesIcon />,
|
icon: <ServicesIcon />,
|
||||||
disabled: !isPlatform,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
relativeMainPath: '/ai',
|
relativeMainPath: '/ai',
|
||||||
@@ -153,6 +144,14 @@ export default function useProjectRoutes() {
|
|||||||
icon: <AIIcon />,
|
icon: <AIIcon />,
|
||||||
},
|
},
|
||||||
...nhostRoutes,
|
...nhostRoutes,
|
||||||
|
{
|
||||||
|
relativeMainPath: '/settings',
|
||||||
|
relativePath: '/settings/general',
|
||||||
|
exact: false,
|
||||||
|
label: 'Settings',
|
||||||
|
icon: <CogIcon />,
|
||||||
|
disabled: maintenanceActive,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
||||||
import {
|
import {
|
||||||
useGetAuthenticationSettingsQuery,
|
useGetAuthenticationSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
type ConfigIngressUpdateInput,
|
type ConfigIngressUpdateInput,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -23,12 +27,18 @@ const validationSchema = Yup.object({
|
|||||||
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
|
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function AuthDomain() {
|
export default function AuthDomain() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const [isVerified, setIsVerified] = useState(false);
|
const [isVerified, setIsVerified] = useState(false);
|
||||||
|
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
@@ -40,6 +50,7 @@ export default function AuthDomain() {
|
|||||||
variables: {
|
variables: {
|
||||||
appId: currentProject.id,
|
appId: currentProject.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { networking } = data?.config?.auth?.resources || {};
|
const { networking } = data?.config?.auth?.resources || {};
|
||||||
@@ -94,6 +105,18 @@ export default function AuthDomain() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Auth domain is being updated...',
|
loadingMessage: 'Auth domain is being updated...',
|
||||||
@@ -104,6 +127,14 @@ export default function AuthDomain() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDisabled = () => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
return !isDirty || maintenanceActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isDirty || maintenanceActive || (!isVerified && !initialValue);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
@@ -112,12 +143,11 @@ export default function AuthDomain() {
|
|||||||
description="Enter below your custom domain for the authentication service."
|
description="Enter below your custom domain for the authentication service."
|
||||||
slotProps={{
|
slotProps={{
|
||||||
submitButton: {
|
submitButton: {
|
||||||
disabled:
|
disabled: isDisabled(),
|
||||||
!isDirty || maintenanceActive || (!isVerified && !initialValue),
|
|
||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
{...register('auth_fqdn')}
|
{...register('auth_fqdn')}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
||||||
import {
|
import {
|
||||||
useGetHasuraSettingsQuery,
|
useGetHasuraSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
type ConfigIngressUpdateInput,
|
type ConfigIngressUpdateInput,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -23,12 +27,18 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraDomainFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraDomainFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraDomain() {
|
export default function HasuraDomain() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const [isVerified, setIsVerified] = useState(false);
|
const [isVerified, setIsVerified] = useState(false);
|
||||||
|
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
const form = useForm<Yup.InferType<typeof validationSchema>>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
@@ -40,6 +50,7 @@ export default function HasuraDomain() {
|
|||||||
variables: {
|
variables: {
|
||||||
appId: currentProject.id,
|
appId: currentProject.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { networking } = data?.config?.hasura?.resources || {};
|
const { networking } = data?.config?.hasura?.resources || {};
|
||||||
@@ -96,6 +107,18 @@ export default function HasuraDomain() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Hasura domain is being updated...',
|
loadingMessage: 'Hasura domain is being updated...',
|
||||||
@@ -106,6 +129,14 @@ export default function HasuraDomain() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDisabled = () => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
return !isDirty || maintenanceActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isDirty || maintenanceActive || (!isVerified && !initialValue);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
@@ -114,12 +145,11 @@ export default function HasuraDomain() {
|
|||||||
description="Enter below your custom domain for the Hasura/GraphQL service."
|
description="Enter below your custom domain for the Hasura/GraphQL service."
|
||||||
slotProps={{
|
slotProps={{
|
||||||
submitButton: {
|
submitButton: {
|
||||||
disabled:
|
disabled: isDisabled(),
|
||||||
!isDirty || maintenanceActive || (!isVerified && !initialValue),
|
|
||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
{...register('hasura_fqdn')}
|
{...register('hasura_fqdn')}
|
||||||
|
|||||||
@@ -5,29 +5,12 @@ import { Link } from '@/components/ui/v2/Link';
|
|||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
import { RunServicePortDomain } from '@/features/projects/custom-domains/settings/components/RunServicePortDomain';
|
import { RunServicePortDomain } from '@/features/projects/custom-domains/settings/components/RunServicePortDomain';
|
||||||
import { useGetRunServicesQuery } from '@/utils/__generated__/graphql';
|
import { useRunServices } from '@/hooks/useRunServices';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
export default function RunServiceDomains() {
|
export default function RunServiceDomains() {
|
||||||
const { currentProject, currentWorkspace } = useCurrentWorkspaceAndProject();
|
const { currentProject, currentWorkspace } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const {
|
const { services, loading } = useRunServices();
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
// refetch: refetchServices, // TODO refetch after update
|
|
||||||
} = useGetRunServicesQuery({
|
|
||||||
variables: {
|
|
||||||
appID: currentProject.id,
|
|
||||||
resolve: false,
|
|
||||||
limit: 1000, // TODO consider pagination
|
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const services = useMemo(
|
|
||||||
() => data?.app?.runServices.map((service) => service) ?? [],
|
|
||||||
[data],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@@ -45,7 +28,7 @@ export default function RunServiceDomains() {
|
|||||||
.filter((service) => service.config?.ports?.length > 0)
|
.filter((service) => service.config?.ports?.length > 0)
|
||||||
.map((service) => (
|
.map((service) => (
|
||||||
<SettingsContainer
|
<SettingsContainer
|
||||||
key={service.id}
|
key={service.id ?? service.serviceID}
|
||||||
title={
|
title={
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<Text className="text-lg font-semibold">
|
<Text className="text-lg font-semibold">
|
||||||
@@ -58,7 +41,7 @@ export default function RunServiceDomains() {
|
|||||||
underline="hover"
|
underline="hover"
|
||||||
className="font-medium"
|
className="font-medium"
|
||||||
>
|
>
|
||||||
<ArrowSquareOutIcon className="mb-1 ml-1 h-4 w-4" />
|
<ArrowSquareOutIcon className="w-4 h-4 mb-1 ml-1" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -72,7 +55,7 @@ export default function RunServiceDomains() {
|
|||||||
className: 'hidden',
|
className: 'hidden',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid gap-y-4 gap-x-4 px-4"
|
className="grid px-4 gap-x-4 gap-y-4"
|
||||||
>
|
>
|
||||||
{service.config?.ports?.map((port) => (
|
{service.config?.ports?.map((port) => (
|
||||||
<RunServicePortDomain
|
<RunServicePortDomain
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { Button } from '@/components/ui/v2/Button';
|
import { Button } from '@/components/ui/v2/Button';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
||||||
import { useUpdateRunServiceConfigMutation } from '@/generated/graphql';
|
import { useUpdateRunServiceConfigMutation } from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
|
import { type RunService } from '@/hooks/useRunServices';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { type RunService } from 'pages/[workspaceSlug]/[appSlug]/services';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
@@ -28,12 +32,17 @@ export default function RunServicePortDomain({
|
|||||||
service,
|
service,
|
||||||
port,
|
port,
|
||||||
}: RunServicePortProps) {
|
}: RunServicePortProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [isVerified, setIsVerified] = useState(false);
|
const [isVerified, setIsVerified] = useState(false);
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const [updateRunServiceConfig] = useUpdateRunServiceConfigMutation();
|
const [updateRunServiceConfig] = useUpdateRunServiceConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const runServicePort = service.config.ports.find((p) => p.port === port);
|
const runServicePort = service.config.ports.find((p) => p.port === port);
|
||||||
const initialValue = runServicePort?.ingresses?.[0]?.fqdn?.[0];
|
const initialValue = runServicePort?.ingresses?.[0]?.fqdn?.[0];
|
||||||
@@ -59,7 +68,7 @@ export default function RunServicePortDomain({
|
|||||||
await updateRunServiceConfig({
|
await updateRunServiceConfig({
|
||||||
variables: {
|
variables: {
|
||||||
appID: currentProject.id,
|
appID: currentProject.id,
|
||||||
serviceID: service.id,
|
serviceID: service.id ?? service.serviceID,
|
||||||
config: {
|
config: {
|
||||||
ports: service?.config?.ports?.map((p) => {
|
ports: service?.config?.ports?.map((p) => {
|
||||||
// exclude the `__typename` because the mutation will fail otherwise
|
// exclude the `__typename` because the mutation will fail otherwise
|
||||||
@@ -78,7 +87,7 @@ export default function RunServicePortDomain({
|
|||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
// exclude the `__typename` because the mutation will fail otherwise
|
// exclude the `__typename` because the mutation will fail otherwise
|
||||||
ingresses: rest.ingresses.map((item) => ({
|
ingresses: rest?.ingresses?.map((item) => ({
|
||||||
fqdn: item.fqdn,
|
fqdn: item.fqdn,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
@@ -88,6 +97,18 @@ export default function RunServicePortDomain({
|
|||||||
});
|
});
|
||||||
|
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: `Port ${port} is being updated...`,
|
loadingMessage: `Port ${port} is being updated...`,
|
||||||
@@ -99,6 +120,16 @@ export default function RunServicePortDomain({
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDisabled = () => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
return loading || !isDirty || maintenanceActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
loading || !isDirty || maintenanceActive || (!isVerified && !initialValue)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
@@ -121,16 +152,7 @@ export default function RunServicePortDomain({
|
|||||||
inputRoot: { min: 1, max: 100 },
|
inputRoot: { min: 1, max: 100 },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button variant="outlined" type="submit" disabled={isDisabled()}>
|
||||||
variant="outlined"
|
|
||||||
type="submit"
|
|
||||||
disabled={
|
|
||||||
loading ||
|
|
||||||
!isDirty ||
|
|
||||||
maintenanceActive ||
|
|
||||||
(!isVerified && !initialValue)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
import { VerifyDomain } from '@/features/projects/custom-domains/settings/components/VerifyDomain';
|
||||||
import {
|
import {
|
||||||
useGetServerlessFunctionsSettingsQuery,
|
useGetServerlessFunctionsSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
type ConfigIngressUpdateInput,
|
type ConfigIngressUpdateInput,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -25,12 +29,17 @@ export type ServerlessFunctionsDomainFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function ServerlessFunctionsDomain() {
|
export default function ServerlessFunctionsDomain() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const [isVerified, setIsVerified] = useState(false);
|
const [isVerified, setIsVerified] = useState(false);
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation();
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<ServerlessFunctionsDomainFormValues>({
|
const form = useForm<ServerlessFunctionsDomainFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
@@ -42,6 +51,7 @@ export default function ServerlessFunctionsDomain() {
|
|||||||
variables: {
|
variables: {
|
||||||
appId: currentProject.id,
|
appId: currentProject.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { networking } = data?.config?.functions?.resources || {};
|
const { networking } = data?.config?.functions?.resources || {};
|
||||||
@@ -98,6 +108,18 @@ export default function ServerlessFunctionsDomain() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Serverless Functions domain is being updated...',
|
loadingMessage: 'Serverless Functions domain is being updated...',
|
||||||
@@ -109,6 +131,14 @@ export default function ServerlessFunctionsDomain() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDisabled = () => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
return !isDirty || maintenanceActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isDirty || maintenanceActive || (!isVerified && !initialValue);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
@@ -117,12 +147,11 @@ export default function ServerlessFunctionsDomain() {
|
|||||||
description="Enter below your custom domain for Serverless Functions."
|
description="Enter below your custom domain for Serverless Functions."
|
||||||
slotProps={{
|
slotProps={{
|
||||||
submitButton: {
|
submitButton: {
|
||||||
disabled:
|
disabled: isDisabled(),
|
||||||
!isDirty || maintenanceActive || (!isVerified && !initialValue),
|
|
||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
{...register('functions_fqdn')}
|
{...register('functions_fqdn')}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button } from '@/components/ui/v2/Button';
|
|||||||
import { IconButton } from '@/components/ui/v2/IconButton';
|
import { IconButton } from '@/components/ui/v2/IconButton';
|
||||||
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
|
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { useDnsLookupCnameLazyQuery } from '@/utils/__generated__/graphql';
|
import { useDnsLookupCnameLazyQuery } from '@/utils/__generated__/graphql';
|
||||||
@@ -21,6 +22,7 @@ export default function VerifyDomain({
|
|||||||
value,
|
value,
|
||||||
onHostNameVerified,
|
onHostNameVerified,
|
||||||
}: VerifyDomainProps) {
|
}: VerifyDomainProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const [verificationFailed, setVerificationFailed] = useState(false);
|
const [verificationFailed, setVerificationFailed] = useState(false);
|
||||||
const [verificationSucceeded, setVerificationSucceeded] = useState(false);
|
const [verificationSucceeded, setVerificationSucceeded] = useState(false);
|
||||||
|
|
||||||
@@ -72,8 +74,11 @@ export default function VerifyDomain({
|
|||||||
backgroundColor: 'success.light',
|
backgroundColor: 'success.light',
|
||||||
color: 'success.dark',
|
color: 'success.dark',
|
||||||
},
|
},
|
||||||
|
!isPlatform && {
|
||||||
|
backgroundColor: 'grey.300',
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
className="flex flex-col space-y-4 rounded-md p-4"
|
className="flex flex-col p-4 space-y-4 rounded-md"
|
||||||
>
|
>
|
||||||
<div className="flex flex-row items-center justify-between">
|
<div className="flex flex-row items-center justify-between">
|
||||||
{!verificationFailed && !verificationSucceeded && (
|
{!verificationFailed && !verificationSucceeded && (
|
||||||
@@ -110,23 +115,29 @@ export default function VerifyDomain({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row space-x-2">
|
<div className="flex flex-row space-x-2">
|
||||||
<Text>Value:</Text>
|
<Text>Value:</Text>
|
||||||
<Text className="font-bold">{value}</Text>
|
{isPlatform ? (
|
||||||
<IconButton
|
<>
|
||||||
aria-label="Copy Personal Access Token"
|
<Text className="font-bold">{value}</Text>
|
||||||
variant="borderless"
|
<IconButton
|
||||||
color="secondary"
|
aria-label="Copy Personal Access Token"
|
||||||
onClick={() => copy(value, 'CNAME Value')}
|
variant="borderless"
|
||||||
>
|
color="secondary"
|
||||||
<CopyIcon className="h-4 w-4" />
|
onClick={() => copy(value, 'CNAME Value')}
|
||||||
</IconButton>
|
>
|
||||||
|
<CopyIcon className="w-4 h-4" />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
{isPlatform ? (
|
||||||
disabled={loading || !hostname}
|
<Button
|
||||||
onClick={handleVerifyDomain}
|
disabled={loading || !hostname || isPlatform}
|
||||||
className="mt-4 sm:absolute sm:bottom-0 sm:right-0 sm:mt-0"
|
onClick={handleVerifyDomain}
|
||||||
>
|
className="mt-4 sm:absolute sm:bottom-0 sm:right-0 sm:mt-0"
|
||||||
Verify
|
>
|
||||||
</Button>
|
Verify
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseEnvironmentVariableFormProps,
|
BaseEnvironmentVariableFormProps,
|
||||||
BaseEnvironmentVariableFormValues,
|
BaseEnvironmentVariableFormValues,
|
||||||
@@ -8,6 +11,7 @@ import {
|
|||||||
BaseEnvironmentVariableForm,
|
BaseEnvironmentVariableForm,
|
||||||
baseEnvironmentVariableFormValidationSchema,
|
baseEnvironmentVariableFormValidationSchema,
|
||||||
} from '@/features/projects/environmentVariables/settings/components/BaseEnvironmentVariableForm';
|
} from '@/features/projects/environmentVariables/settings/components/BaseEnvironmentVariableForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetEnvironmentVariablesDocument,
|
GetEnvironmentVariablesDocument,
|
||||||
@@ -22,13 +26,17 @@ export interface CreateEnvironmentVariableFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreateEnvironmentVariableForm({
|
export default function CreateEnvironmentVariableForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: CreateEnvironmentVariableFormProps) {
|
}: CreateEnvironmentVariableFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const form = useForm<BaseEnvironmentVariableFormValues>({
|
const form = useForm<BaseEnvironmentVariableFormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -42,13 +50,14 @@ export default function CreateEnvironmentVariableForm({
|
|||||||
|
|
||||||
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableEnvironmentVariables = data?.config?.global?.environment || [];
|
const availableEnvironmentVariables = data?.config?.global?.environment || [];
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetEnvironmentVariablesDocument],
|
refetchQueries: [GetEnvironmentVariablesDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -103,7 +112,19 @@ export default function CreateEnvironmentVariableForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Creating environment variable...',
|
loadingMessage: 'Creating environment variable...',
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseEnvironmentVariableFormProps,
|
BaseEnvironmentVariableFormProps,
|
||||||
BaseEnvironmentVariableFormValues,
|
BaseEnvironmentVariableFormValues,
|
||||||
@@ -8,6 +11,7 @@ import {
|
|||||||
BaseEnvironmentVariableForm,
|
BaseEnvironmentVariableForm,
|
||||||
baseEnvironmentVariableFormValidationSchema,
|
baseEnvironmentVariableFormValidationSchema,
|
||||||
} from '@/features/projects/environmentVariables/settings/components/BaseEnvironmentVariableForm';
|
} from '@/features/projects/environmentVariables/settings/components/BaseEnvironmentVariableForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { EnvironmentVariable } from '@/types/application';
|
import type { EnvironmentVariable } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -27,7 +31,7 @@ export interface EditEnvironmentVariableFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EditEnvironmentVariableForm({
|
export default function EditEnvironmentVariableForm({
|
||||||
@@ -35,6 +39,10 @@ export default function EditEnvironmentVariableForm({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: EditEnvironmentVariableFormProps) {
|
}: EditEnvironmentVariableFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const form = useForm<BaseEnvironmentVariableFormValues>({
|
const form = useForm<BaseEnvironmentVariableFormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
id: originalEnvironmentVariable.id || '',
|
id: originalEnvironmentVariable.id || '',
|
||||||
@@ -49,13 +57,14 @@ export default function EditEnvironmentVariableForm({
|
|||||||
|
|
||||||
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableEnvironmentVariables = data?.config?.global?.environment || [];
|
const availableEnvironmentVariables = data?.config?.global?.environment || [];
|
||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetEnvironmentVariablesDocument],
|
refetchQueries: [GetEnvironmentVariablesDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -117,7 +126,19 @@ export default function EditEnvironmentVariableForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Updating environment variable...',
|
loadingMessage: 'Updating environment variable...',
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Form } from '@/components/form/Form';
|
|||||||
import { Button } from '@/components/ui/v2/Button';
|
import { Button } from '@/components/ui/v2/Button';
|
||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { DialogFormProps } from '@/types/common';
|
import type { DialogFormProps } from '@/types/common';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -63,9 +65,12 @@ export default function EditJwtSecretForm({
|
|||||||
submitButtonText = 'Save',
|
submitButtonText = 'Save',
|
||||||
location,
|
location,
|
||||||
}: EditJwtSecretFormProps) {
|
}: EditJwtSecretFormProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetEnvironmentVariablesDocument],
|
refetchQueries: [GetEnvironmentVariablesDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { onDirtyStateChange } = useDialog();
|
const { onDirtyStateChange } = useDialog();
|
||||||
@@ -118,9 +123,9 @@ export default function EditJwtSecretForm({
|
|||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form
|
<Form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="flex flex-auto flex-col content-between overflow-hidden pb-4"
|
className="flex flex-col content-between flex-auto pb-4 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="flex-auto overflow-y-auto px-6">
|
<div className="flex-auto px-6 overflow-y-auto">
|
||||||
<Input
|
<Input
|
||||||
{...register('jwtSecret')}
|
{...register('jwtSecret')}
|
||||||
error={Boolean(errors.jwtSecret?.message)}
|
error={Boolean(errors.jwtSecret?.message)}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -13,8 +14,10 @@ import { List } from '@/components/ui/v2/List';
|
|||||||
import { ListItem } from '@/components/ui/v2/ListItem';
|
import { ListItem } from '@/components/ui/v2/ListItem';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { CreateEnvironmentVariableForm } from '@/features/projects/environmentVariables/settings/components/CreateEnvironmentVariableForm';
|
import { CreateEnvironmentVariableForm } from '@/features/projects/environmentVariables/settings/components/CreateEnvironmentVariableForm';
|
||||||
import { EditEnvironmentVariableForm } from '@/features/projects/environmentVariables/settings/components/EditEnvironmentVariableForm';
|
import { EditEnvironmentVariableForm } from '@/features/projects/environmentVariables/settings/components/EditEnvironmentVariableForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { EnvironmentVariable } from '@/types/application';
|
import type { EnvironmentVariable } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -33,12 +36,14 @@ export interface EnvironmentVariableSettingsFormValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function EnvironmentVariableSettings() {
|
export default function EnvironmentVariableSettings() {
|
||||||
const { openDialog, openAlertDialog } = useDialog();
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
const { openDialog, openAlertDialog } = useDialog();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
const { data, loading, error, refetch } = useGetEnvironmentVariablesQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableEnvironmentVariables = [
|
const availableEnvironmentVariables = [
|
||||||
@@ -57,6 +62,7 @@ export default function EnvironmentVariableSettings() {
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetEnvironmentVariablesDocument],
|
refetchQueries: [GetEnvironmentVariablesDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -92,6 +98,18 @@ export default function EnvironmentVariableSettings() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Deleting environment variable...',
|
loadingMessage: 'Deleting environment variable...',
|
||||||
@@ -105,7 +123,7 @@ export default function EnvironmentVariableSettings() {
|
|||||||
function handleOpenCreator() {
|
function handleOpenCreator() {
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Create Environment Variable',
|
title: 'Create Environment Variable',
|
||||||
component: <CreateEnvironmentVariableForm />,
|
component: <CreateEnvironmentVariableForm onSubmit={refetch} />,
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
PaperProps: { className: 'gap-2 max-w-sm' },
|
PaperProps: { className: 'gap-2 max-w-sm' },
|
||||||
@@ -119,6 +137,7 @@ export default function EnvironmentVariableSettings() {
|
|||||||
component: (
|
component: (
|
||||||
<EditEnvironmentVariableForm
|
<EditEnvironmentVariableForm
|
||||||
originalEnvironmentVariable={originalVariable}
|
originalEnvironmentVariable={originalVariable}
|
||||||
|
onSubmit={refetch}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
props: {
|
props: {
|
||||||
@@ -159,7 +178,7 @@ export default function EnvironmentVariableSettings() {
|
|||||||
)}
|
)}
|
||||||
slotProps={{ submitButton: { className: 'hidden' } }}
|
slotProps={{ submitButton: { className: 'hidden' } }}
|
||||||
>
|
>
|
||||||
<Box className="grid grid-cols-2 gap-2 border-b-1 px-4 py-3 lg:grid-cols-3">
|
<Box className="grid grid-cols-2 gap-2 px-4 py-3 border-b-1 lg:grid-cols-3">
|
||||||
<Text className="font-medium">Variable Name</Text>
|
<Text className="font-medium">Variable Name</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -175,7 +194,7 @@ export default function EnvironmentVariableSettings() {
|
|||||||
<Dropdown.Trigger
|
<Dropdown.Trigger
|
||||||
asChild
|
asChild
|
||||||
hideChevron
|
hideChevron
|
||||||
className="absolute right-4 top-1/2 -translate-y-1/2"
|
className="absolute -translate-y-1/2 right-4 top-1/2"
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
|
|||||||
@@ -21,11 +21,15 @@ import {
|
|||||||
} from '@/features/projects/common/utils/generateAppServiceUrl';
|
} from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||||
import { EditJwtSecretForm } from '@/features/projects/environmentVariables/settings/components/EditJwtSecretForm';
|
import { EditJwtSecretForm } from '@/features/projects/environmentVariables/settings/components/EditJwtSecretForm';
|
||||||
import { getJwtSecretsWithoutFalsyValues } from '@/features/projects/environmentVariables/settings/utils/getJwtSecretsWithoutFalsyValues';
|
import { getJwtSecretsWithoutFalsyValues } from '@/features/projects/environmentVariables/settings/utils/getJwtSecretsWithoutFalsyValues';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { getHasuraConsoleServiceUrl } from '@/utils/env';
|
import { getHasuraConsoleServiceUrl } from '@/utils/env';
|
||||||
import { useGetEnvironmentVariablesQuery } from '@/utils/__generated__/graphql';
|
import { useGetEnvironmentVariablesQuery } from '@/utils/__generated__/graphql';
|
||||||
import { Fragment, useState } from 'react';
|
import { Fragment, useState } from 'react';
|
||||||
|
|
||||||
export default function SystemEnvironmentVariableSettings() {
|
export default function SystemEnvironmentVariableSettings() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const [showAdminSecret, setShowAdminSecret] = useState(false);
|
const [showAdminSecret, setShowAdminSecret] = useState(false);
|
||||||
const [showWebhookSecret, setShowWebhookSecret] = useState(false);
|
const [showWebhookSecret, setShowWebhookSecret] = useState(false);
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
const { data, loading, error } = useGetEnvironmentVariablesQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { jwtSecrets, webhookSecret, adminSecret } = data?.config?.hasura || {};
|
const { jwtSecrets, webhookSecret, adminSecret } = data?.config?.hasura || {};
|
||||||
@@ -46,8 +50,6 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
? JSON.stringify(jwtSecretsWithoutFalsyValues[0], null, 2)
|
? JSON.stringify(jwtSecretsWithoutFalsyValues[0], null, 2)
|
||||||
: JSON.stringify(jwtSecretsWithoutFalsyValues, null, 2);
|
: JSON.stringify(jwtSecretsWithoutFalsyValues, null, 2);
|
||||||
|
|
||||||
const isPlatform = useIsPlatform();
|
|
||||||
|
|
||||||
const appClient = useAppClient();
|
const appClient = useAppClient();
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -124,10 +126,10 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
description="System environment variables are automatically generated from the configuration file and your project's subdomain and region."
|
description="System environment variables are automatically generated from the configuration file and your project's subdomain and region."
|
||||||
docsLink="https://docs.nhost.io/platform/environment-variables#system-environment-variables"
|
docsLink="https://docs.nhost.io/platform/environment-variables#system-environment-variables"
|
||||||
rootClassName="gap-0"
|
rootClassName="gap-0"
|
||||||
className="mt-2 mb-2.5 px-0"
|
className="mb-2.5 mt-2 px-0"
|
||||||
slotProps={{ submitButton: { className: 'hidden' } }}
|
slotProps={{ submitButton: { className: 'hidden' } }}
|
||||||
>
|
>
|
||||||
<Box className="grid grid-cols-3 gap-2 border-b-1 px-4 py-3">
|
<Box className="grid grid-cols-3 gap-2 px-4 py-3 border-b-1">
|
||||||
<Text className="font-medium">Variable Name</Text>
|
<Text className="font-medium">Variable Name</Text>
|
||||||
<Text className="font-medium lg:col-span-2">Value</Text>
|
<Text className="font-medium lg:col-span-2">Value</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -136,7 +138,7 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
<ListItem.Root className="grid grid-cols-2 gap-2 px-4 lg:grid-cols-3">
|
<ListItem.Root className="grid grid-cols-2 gap-2 px-4 lg:grid-cols-3">
|
||||||
<ListItem.Text>NHOST_ADMIN_SECRET</ListItem.Text>
|
<ListItem.Text>NHOST_ADMIN_SECRET</ListItem.Text>
|
||||||
|
|
||||||
<div className="grid grid-flow-col items-center justify-start gap-2 lg:col-span-2">
|
<div className="grid items-center justify-start grid-flow-col gap-2 lg:col-span-2">
|
||||||
<Text className="truncate" color="secondary">
|
<Text className="truncate" color="secondary">
|
||||||
{showAdminSecret ? (
|
{showAdminSecret ? (
|
||||||
<InlineCode className="!text-sm font-medium">
|
<InlineCode className="!text-sm font-medium">
|
||||||
@@ -156,9 +158,9 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
onClick={() => setShowAdminSecret((show) => !show)}
|
onClick={() => setShowAdminSecret((show) => !show)}
|
||||||
>
|
>
|
||||||
{showAdminSecret ? (
|
{showAdminSecret ? (
|
||||||
<EyeOffIcon className="h-5 w-5" />
|
<EyeOffIcon className="w-5 h-5" />
|
||||||
) : (
|
) : (
|
||||||
<EyeIcon className="h-5 w-5" />
|
<EyeIcon className="w-5 h-5" />
|
||||||
)}
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,7 +171,7 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
<ListItem.Root className="grid grid-cols-2 gap-2 px-4 lg:grid-cols-3">
|
<ListItem.Root className="grid grid-cols-2 gap-2 px-4 lg:grid-cols-3">
|
||||||
<ListItem.Text>NHOST_WEBHOOK_SECRET</ListItem.Text>
|
<ListItem.Text>NHOST_WEBHOOK_SECRET</ListItem.Text>
|
||||||
|
|
||||||
<div className="grid grid-flow-col items-center justify-start gap-2 lg:col-span-2">
|
<div className="grid items-center justify-start grid-flow-col gap-2 lg:col-span-2">
|
||||||
<Text className="truncate" color="secondary">
|
<Text className="truncate" color="secondary">
|
||||||
{showWebhookSecret ? (
|
{showWebhookSecret ? (
|
||||||
<InlineCode className="!text-sm font-medium">
|
<InlineCode className="!text-sm font-medium">
|
||||||
@@ -191,9 +193,9 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
onClick={() => setShowWebhookSecret((show) => !show)}
|
onClick={() => setShowWebhookSecret((show) => !show)}
|
||||||
>
|
>
|
||||||
{showWebhookSecret ? (
|
{showWebhookSecret ? (
|
||||||
<EyeOffIcon className="h-5 w-5" />
|
<EyeOffIcon className="w-5 h-5" />
|
||||||
) : (
|
) : (
|
||||||
<EyeIcon className="h-5 w-5" />
|
<EyeIcon className="w-5 h-5" />
|
||||||
)}
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -217,9 +219,9 @@ export default function SystemEnvironmentVariableSettings() {
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Divider component="li" className="!mt-4 !mb-2.5" />
|
<Divider component="li" className="!mb-2.5 !mt-4" />
|
||||||
|
|
||||||
<ListItem.Root className="grid grid-cols-2 justify-start px-4 lg:grid-cols-3">
|
<ListItem.Root className="grid justify-start grid-cols-2 px-4 lg:grid-cols-3">
|
||||||
<ListItem.Text>NHOST_JWT_SECRET</ListItem.Text>
|
<ListItem.Text>NHOST_JWT_SECRET</ListItem.Text>
|
||||||
|
|
||||||
<div className="grid grid-flow-row items-center justify-center gap-1.5 text-center md:grid-flow-col lg:col-span-2 lg:justify-start lg:text-left">
|
<div className="grid grid-flow-row items-center justify-center gap-1.5 text-center md:grid-flow-col lg:col-span-2 lg:justify-start lg:text-left">
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BasePermissionVariableFormProps,
|
BasePermissionVariableFormProps,
|
||||||
BasePermissionVariableFormValues,
|
BasePermissionVariableFormValues,
|
||||||
@@ -9,6 +12,7 @@ import {
|
|||||||
basePermissionVariableValidationSchema,
|
basePermissionVariableValidationSchema,
|
||||||
} from '@/features/projects/permissions/settings/components/BasePermissionVariableForm';
|
} from '@/features/projects/permissions/settings/components/BasePermissionVariableForm';
|
||||||
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetRolesPermissionsDocument,
|
GetRolesPermissionsDocument,
|
||||||
@@ -23,18 +27,20 @@ export interface CreatePermissionVariableFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreatePermissionVariableForm({
|
export default function CreatePermissionVariableForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: CreatePermissionVariableFormProps) {
|
}: CreatePermissionVariableFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { data, error, loading } = useGetRolesPermissionsQuery({
|
const { data, error, loading } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { customClaims: permissionVariables } =
|
const { customClaims: permissionVariables } =
|
||||||
@@ -51,6 +57,7 @@ export default function CreatePermissionVariableForm({
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -106,6 +113,18 @@ export default function CreatePermissionVariableForm({
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
await onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Creating permission variable...',
|
loadingMessage: 'Creating permission variable...',
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BasePermissionVariableFormProps,
|
BasePermissionVariableFormProps,
|
||||||
BasePermissionVariableFormValues,
|
BasePermissionVariableFormValues,
|
||||||
@@ -9,6 +12,7 @@ import {
|
|||||||
basePermissionVariableValidationSchema,
|
basePermissionVariableValidationSchema,
|
||||||
} from '@/features/projects/permissions/settings/components/BasePermissionVariableForm';
|
} from '@/features/projects/permissions/settings/components/BasePermissionVariableForm';
|
||||||
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { PermissionVariable } from '@/types/application';
|
import type { PermissionVariable } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -28,7 +32,7 @@ export interface EditPermissionVariableFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EditPermissionVariableForm({
|
export default function EditPermissionVariableForm({
|
||||||
@@ -36,11 +40,14 @@ export default function EditPermissionVariableForm({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: EditPermissionVariableFormProps) {
|
}: EditPermissionVariableFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { data, error, loading } = useGetRolesPermissionsQuery({
|
const { data, error, loading } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { customClaims: permissionVariables } =
|
const { customClaims: permissionVariables } =
|
||||||
@@ -57,6 +64,7 @@ export default function EditPermissionVariableForm({
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -132,6 +140,19 @@ export default function EditPermissionVariableForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Updating permission variable...',
|
loadingMessage: 'Updating permission variable...',
|
||||||
@@ -140,8 +161,6 @@ export default function EditPermissionVariableForm({
|
|||||||
'An error occurred while trying to update the permission variable.',
|
'An error occurred while trying to update the permission variable.',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await onSubmit?.();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -15,9 +16,11 @@ import { ListItem } from '@/components/ui/v2/ListItem';
|
|||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { CreatePermissionVariableForm } from '@/features/projects/permissions/settings/components/CreatePermissionVariableForm';
|
import { CreatePermissionVariableForm } from '@/features/projects/permissions/settings/components/CreatePermissionVariableForm';
|
||||||
import { EditPermissionVariableForm } from '@/features/projects/permissions/settings/components/EditPermissionVariableForm';
|
import { EditPermissionVariableForm } from '@/features/projects/permissions/settings/components/EditPermissionVariableForm';
|
||||||
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
import { getAllPermissionVariables } from '@/features/projects/permissions/settings/utils/getAllPermissionVariables';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { PermissionVariable } from '@/types/application';
|
import type { PermissionVariable } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -29,13 +32,15 @@ import { Fragment } from 'react';
|
|||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function PermissionVariableSettings() {
|
export default function PermissionVariableSettings() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { openDialog, openAlertDialog } = useDialog();
|
const { openDialog, openAlertDialog } = useDialog();
|
||||||
|
|
||||||
const { data, loading, error } = useGetRolesPermissionsQuery({
|
const { data, loading, error, refetch } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { customClaims: permissionVariables } =
|
const { customClaims: permissionVariables } =
|
||||||
@@ -43,6 +48,7 @@ export default function PermissionVariableSettings() {
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -55,6 +61,20 @@ export default function PermissionVariableSettings() {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showApplyChangesDialog() {
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleDeleteVariable({ id }: PermissionVariable) {
|
async function handleDeleteVariable({ id }: PermissionVariable) {
|
||||||
const updateConfigPromise = updateConfig({
|
const updateConfigPromise = updateConfig({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -79,6 +99,7 @@ export default function PermissionVariableSettings() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
showApplyChangesDialog();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Deleting permission variable...',
|
loadingMessage: 'Deleting permission variable...',
|
||||||
@@ -92,7 +113,7 @@ export default function PermissionVariableSettings() {
|
|||||||
function handleOpenCreator() {
|
function handleOpenCreator() {
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Create Permission Variable',
|
title: 'Create Permission Variable',
|
||||||
component: <CreatePermissionVariableForm />,
|
component: <CreatePermissionVariableForm onSubmit={refetch} />,
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
PaperProps: { className: 'max-w-sm' },
|
PaperProps: { className: 'max-w-sm' },
|
||||||
@@ -104,7 +125,10 @@ export default function PermissionVariableSettings() {
|
|||||||
openDialog({
|
openDialog({
|
||||||
title: 'Edit Permission Variable',
|
title: 'Edit Permission Variable',
|
||||||
component: (
|
component: (
|
||||||
<EditPermissionVariableForm originalVariable={originalVariable} />
|
<EditPermissionVariableForm
|
||||||
|
originalVariable={originalVariable}
|
||||||
|
onSubmit={refetch}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
@@ -140,10 +164,10 @@ export default function PermissionVariableSettings() {
|
|||||||
description="Permission variables are used to define permission rules in the GraphQL API."
|
description="Permission variables are used to define permission rules in the GraphQL API."
|
||||||
docsLink="https://docs.nhost.io/guides/api/permissions#permission-variables"
|
docsLink="https://docs.nhost.io/guides/api/permissions#permission-variables"
|
||||||
rootClassName="gap-0"
|
rootClassName="gap-0"
|
||||||
className="my-2 px-0"
|
className="px-0 my-2"
|
||||||
slotProps={{ submitButton: { className: 'hidden' } }}
|
slotProps={{ submitButton: { className: 'hidden' } }}
|
||||||
>
|
>
|
||||||
<Box className="grid grid-cols-2 border-b-1 px-4 py-3">
|
<Box className="grid grid-cols-2 px-4 py-3 border-b-1">
|
||||||
<Text className="font-medium">Field name</Text>
|
<Text className="font-medium">Field name</Text>
|
||||||
<Text className="font-medium">Path</Text>
|
<Text className="font-medium">Path</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -167,7 +191,7 @@ export default function PermissionVariableSettings() {
|
|||||||
!permissionVariable.isSystemVariable
|
!permissionVariable.isSystemVariable
|
||||||
}
|
}
|
||||||
hasDisabledChildren={permissionVariable.isSystemVariable}
|
hasDisabledChildren={permissionVariable.isSystemVariable}
|
||||||
className="absolute right-4 top-1/2 -translate-y-1/2"
|
className="absolute -translate-y-1/2 right-4 top-1/2"
|
||||||
>
|
>
|
||||||
<Dropdown.Trigger asChild hideChevron>
|
<Dropdown.Trigger asChild hideChevron>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -224,7 +248,7 @@ export default function PermissionVariableSettings() {
|
|||||||
<>
|
<>
|
||||||
X-Hasura-{permissionVariable.key}{' '}
|
X-Hasura-{permissionVariable.key}{' '}
|
||||||
{permissionVariable.isSystemVariable && (
|
{permissionVariable.isSystemVariable && (
|
||||||
<LockIcon className="h-4 w-4" />
|
<LockIcon className="w-4 h-4" />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -7,6 +8,7 @@ import { Box } from '@/components/ui/v2/Box';
|
|||||||
import { Divider } from '@/components/ui/v2/Divider';
|
import { Divider } from '@/components/ui/v2/Divider';
|
||||||
import { Link } from '@/components/ui/v2/Link';
|
import { Link } from '@/components/ui/v2/Link';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
||||||
import { ResourcesConfirmationDialog } from '@/features/projects/resources/settings/components/ResourcesConfirmationDialog';
|
import { ResourcesConfirmationDialog } from '@/features/projects/resources/settings/components/ResourcesConfirmationDialog';
|
||||||
import { ServiceResourcesFormFragment } from '@/features/projects/resources/settings/components/ServiceResourcesFormFragment';
|
import { ServiceResourcesFormFragment } from '@/features/projects/resources/settings/components/ServiceResourcesFormFragment';
|
||||||
@@ -14,6 +16,7 @@ import { TotalResourcesFormFragment } from '@/features/projects/resources/settin
|
|||||||
import { calculateBillableResources } from '@/features/projects/resources/settings/utils/calculateBillableResources';
|
import { calculateBillableResources } from '@/features/projects/resources/settings/utils/calculateBillableResources';
|
||||||
import type { ResourceSettingsFormValues } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
import type { ResourceSettingsFormValues } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||||
import { resourceSettingsValidationSchema } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
import { resourceSettingsValidationSchema } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import {
|
import {
|
||||||
RESOURCE_VCPU_MULTIPLIER,
|
RESOURCE_VCPU_MULTIPLIER,
|
||||||
RESOURCE_VCPU_PRICE,
|
RESOURCE_VCPU_PRICE,
|
||||||
@@ -44,6 +47,8 @@ function getInitialServiceResources(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ResourcesForm() {
|
export default function ResourcesForm() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { openDialog, closeDialog } = useDialog();
|
const { openDialog, closeDialog } = useDialog();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
@@ -55,6 +60,7 @@ export default function ResourcesForm() {
|
|||||||
variables: {
|
variables: {
|
||||||
appId: currentProject?.id,
|
appId: currentProject?.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -65,6 +71,7 @@ export default function ResourcesForm() {
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetResourcesDocument],
|
refetchQueries: [GetResourcesDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialDatabaseResources = getInitialServiceResources(data, 'postgres');
|
const initialDatabaseResources = getInitialServiceResources(data, 'postgres');
|
||||||
@@ -113,7 +120,7 @@ export default function ResourcesForm() {
|
|||||||
resolver: yupResolver(resourceSettingsValidationSchema),
|
resolver: yupResolver(resourceSettingsValidationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!proPlan && !proPlanLoading) {
|
if (isPlatform && !proPlan && !proPlanLoading) {
|
||||||
return (
|
return (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
Couldn't load the plan for this project. Please try again.
|
Couldn't load the plan for this project. Please try again.
|
||||||
@@ -121,7 +128,7 @@ export default function ResourcesForm() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading || proPlanLoading) {
|
if (isPlatform && (loading || proPlanLoading)) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
label="Loading resource settings..."
|
label="Loading resource settings..."
|
||||||
@@ -156,9 +163,10 @@ export default function ResourcesForm() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const initialPrice =
|
const initialPrice = isPlatform
|
||||||
proPlan.price +
|
? proPlan.price +
|
||||||
(billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) * RESOURCE_VCPU_PRICE;
|
(billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) * RESOURCE_VCPU_PRICE
|
||||||
|
: 0;
|
||||||
|
|
||||||
async function handleSubmit(formValues: ResourceSettingsFormValues) {
|
async function handleSubmit(formValues: ResourceSettingsFormValues) {
|
||||||
const updateConfigPromise = updateConfig({
|
const updateConfigPromise = updateConfig({
|
||||||
@@ -217,6 +225,18 @@ export default function ResourcesForm() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Updating resources...',
|
loadingMessage: 'Updating resources...',
|
||||||
@@ -260,7 +280,12 @@ export default function ResourcesForm() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleConfirm(formValues: ResourceSettingsFormValues) {
|
async function handleConfirm(formValues: ResourceSettingsFormValues) {
|
||||||
|
if (!isPlatform) {
|
||||||
|
await handleSubmit(formValues);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
openDialog({
|
openDialog({
|
||||||
title: formValues.enabled
|
title: formValues.enabled
|
||||||
? 'Confirm Dedicated Resources'
|
? 'Confirm Dedicated Resources'
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
|
|||||||
import { Link } from '@/components/ui/v2/Link';
|
import { Link } from '@/components/ui/v2/Link';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
||||||
import { calculateBillableResources } from '@/features/projects/resources/settings/utils/calculateBillableResources';
|
import { calculateBillableResources } from '@/features/projects/resources/settings/utils/calculateBillableResources';
|
||||||
import type { ResourceSettingsFormValues } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
import type { ResourceSettingsFormValues } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||||
@@ -16,6 +17,8 @@ import {
|
|||||||
import { useFormState, useWatch } from 'react-hook-form';
|
import { useFormState, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
export default function ResourcesFormFooter() {
|
export default function ResourcesFormFooter() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: proPlan,
|
data: proPlan,
|
||||||
loading: proPlanLoading,
|
loading: proPlanLoading,
|
||||||
@@ -63,17 +66,27 @@ export default function ResourcesFormFooter() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedPrice = enabled
|
const computeUpdatedPrice = () => {
|
||||||
? Math.max(
|
if (!isPlatform) {
|
||||||
priceForTotalAvailableVCPU,
|
return 0;
|
||||||
(billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) *
|
}
|
||||||
RESOURCE_VCPU_PRICE,
|
|
||||||
) + proPlan.price
|
if (enabled) {
|
||||||
: proPlan.price;
|
return (
|
||||||
|
Math.max(
|
||||||
|
priceForTotalAvailableVCPU,
|
||||||
|
(billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) *
|
||||||
|
RESOURCE_VCPU_PRICE,
|
||||||
|
) + proPlan.price
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return proPlan.price;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
className="grid items-center gap-4 border-t px-4 pt-4 lg:grid-flow-col lg:justify-between lg:gap-2"
|
className="grid items-center gap-4 px-4 pt-4 border-t lg:grid-flow-col lg:justify-between lg:gap-2"
|
||||||
component="footer"
|
component="footer"
|
||||||
>
|
>
|
||||||
<Text>
|
<Text>
|
||||||
@@ -86,20 +99,22 @@ export default function ResourcesFormFooter() {
|
|||||||
className="font-medium"
|
className="font-medium"
|
||||||
>
|
>
|
||||||
Compute Resources
|
Compute Resources
|
||||||
<ArrowSquareOutIcon className="ml-1 h-4 w-4" />
|
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{(enabled || isDirty) && (
|
{(enabled || isDirty) && (
|
||||||
<Box className="grid grid-flow-col items-center justify-between gap-4">
|
<Box className="grid items-center justify-between grid-flow-col gap-4">
|
||||||
<Box className="grid grid-flow-col items-center gap-1.5">
|
<Box className="grid grid-flow-col items-center gap-1.5">
|
||||||
<Text>
|
<Text>
|
||||||
Approximate cost:{' '}
|
Approximate cost:{' '}
|
||||||
<span className="font-medium">${updatedPrice.toFixed(2)}/mo</span>
|
<span className="font-medium">
|
||||||
|
${computeUpdatedPrice().toFixed(2)}/mo
|
||||||
|
</span>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Tooltip title="$0.0012/minute for every 1 vCPU and 2 GiB of RAM">
|
<Tooltip title="$0.0012/minute for every 1 vCPU and 2 GiB of RAM">
|
||||||
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
|
<InfoIcon aria-label="Info" className="w-4 h-4" color="primary" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Box } from '@/components/ui/v2/Box';
|
|||||||
import { ArrowRightIcon } from '@/components/ui/v2/icons/ArrowRightIcon';
|
import { ArrowRightIcon } from '@/components/ui/v2/icons/ArrowRightIcon';
|
||||||
import { Slider, sliderClasses } from '@/components/ui/v2/Slider';
|
import { Slider, sliderClasses } from '@/components/ui/v2/Slider';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
import { useProPlan } from '@/features/projects/common/hooks/useProPlan';
|
||||||
import { getAllocatedResources } from '@/features/projects/resources/settings/utils/getAllocatedResources';
|
import { getAllocatedResources } from '@/features/projects/resources/settings/utils/getAllocatedResources';
|
||||||
import { prettifyMemory } from '@/features/projects/resources/settings/utils/prettifyMemory';
|
import { prettifyMemory } from '@/features/projects/resources/settings/utils/prettifyMemory';
|
||||||
@@ -38,6 +39,8 @@ const StyledAvailableCpuSlider = styled(Slider)(({ theme }) => ({
|
|||||||
export default function TotalResourcesFormFragment({
|
export default function TotalResourcesFormFragment({
|
||||||
initialPrice,
|
initialPrice,
|
||||||
}: TotalResourcesFormFragmentProps) {
|
}: TotalResourcesFormFragmentProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: proPlan,
|
data: proPlan,
|
||||||
error: proPlanError,
|
error: proPlanError,
|
||||||
@@ -46,7 +49,7 @@ export default function TotalResourcesFormFragment({
|
|||||||
const { setValue } = useFormContext<ResourceSettingsFormValues>();
|
const { setValue } = useFormContext<ResourceSettingsFormValues>();
|
||||||
const formValues = useWatch<ResourceSettingsFormValues>();
|
const formValues = useWatch<ResourceSettingsFormValues>();
|
||||||
|
|
||||||
if (!proPlan && !proPlanLoading) {
|
if (isPlatform && !proPlan && !proPlanLoading) {
|
||||||
return (
|
return (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
Couldn't load the plan for this projectee. Please try again.
|
Couldn't load the plan for this projectee. Please try again.
|
||||||
@@ -62,7 +65,9 @@ export default function TotalResourcesFormFragment({
|
|||||||
(formValues.totalAvailableVCPU / RESOURCE_VCPU_MULTIPLIER) *
|
(formValues.totalAvailableVCPU / RESOURCE_VCPU_MULTIPLIER) *
|
||||||
RESOURCE_VCPU_PRICE;
|
RESOURCE_VCPU_PRICE;
|
||||||
|
|
||||||
const updatedPrice = priceForTotalAvailableVCPU + proPlan.price;
|
const updatedPrice = isPlatform
|
||||||
|
? priceForTotalAvailableVCPU + proPlan.price
|
||||||
|
: 0;
|
||||||
|
|
||||||
const { vcpu: allocatedVCPU, memory: allocatedMemory } =
|
const { vcpu: allocatedVCPU, memory: allocatedMemory } =
|
||||||
getAllocatedResources(formValues);
|
getAllocatedResources(formValues);
|
||||||
@@ -102,8 +107,8 @@ export default function TotalResourcesFormFragment({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="px-4 pb-4">
|
<Box className="px-4 pb-4">
|
||||||
<Box className="rounded-md border">
|
<Box className="border rounded-md">
|
||||||
<Box className="flex flex-col gap-4 bg-transparent p-4">
|
<Box className="flex flex-col gap-4 p-4 bg-transparent">
|
||||||
<Box className="flex flex-row items-center justify-between gap-4">
|
<Box className="flex flex-row items-center justify-between gap-4">
|
||||||
<Text color="secondary">
|
<Text color="secondary">
|
||||||
Total available compute for your project:
|
Total available compute for your project:
|
||||||
@@ -151,7 +156,7 @@ export default function TotalResourcesFormFragment({
|
|||||||
severity={
|
severity={
|
||||||
hasUnusedResources || hasOverallocatedResources ? 'warning' : 'info'
|
hasUnusedResources || hasOverallocatedResources ? 'warning' : 'info'
|
||||||
}
|
}
|
||||||
className="grid grid-flow-row gap-2 rounded-t-none rounded-b-[5px] text-left"
|
className="grid grid-flow-row gap-2 rounded-b-[5px] rounded-t-none text-left"
|
||||||
>
|
>
|
||||||
{hasUnusedResources && !hasOverallocatedResources && (
|
{hasUnusedResources && !hasOverallocatedResources && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseRoleFormProps,
|
BaseRoleFormProps,
|
||||||
BaseRoleFormValues,
|
BaseRoleFormValues,
|
||||||
@@ -9,6 +12,7 @@ import {
|
|||||||
baseRoleFormValidationSchema,
|
baseRoleFormValidationSchema,
|
||||||
} from '@/features/projects/roles/settings/components/BaseRoleForm';
|
} from '@/features/projects/roles/settings/components/BaseRoleForm';
|
||||||
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetRolesPermissionsDocument,
|
GetRolesPermissionsDocument,
|
||||||
@@ -23,17 +27,20 @@ export interface CreateRoleFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreateRoleForm({
|
export default function CreateRoleForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: CreateRoleFormProps) {
|
}: CreateRoleFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { data, loading, error } = useGetRolesPermissionsQuery({
|
const { data, loading, error } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
const { allowed: allowedRoles } = data?.config?.auth?.user?.roles || {};
|
const { allowed: allowedRoles } = data?.config?.auth?.user?.roles || {};
|
||||||
|
|
||||||
@@ -45,6 +52,7 @@ export default function CreateRoleForm({
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -85,7 +93,19 @@ export default function CreateRoleForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Creating role...',
|
loadingMessage: 'Creating role...',
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseRoleFormProps,
|
BaseRoleFormProps,
|
||||||
BaseRoleFormValues,
|
BaseRoleFormValues,
|
||||||
@@ -9,6 +12,7 @@ import {
|
|||||||
baseRoleFormValidationSchema,
|
baseRoleFormValidationSchema,
|
||||||
} from '@/features/projects/roles/settings/components/BaseRoleForm';
|
} from '@/features/projects/roles/settings/components/BaseRoleForm';
|
||||||
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { Role } from '@/types/application';
|
import type { Role } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -28,7 +32,7 @@ export interface EditRoleFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EditRoleForm({
|
export default function EditRoleForm({
|
||||||
@@ -36,10 +40,13 @@ export default function EditRoleForm({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: EditRoleFormProps) {
|
}: EditRoleFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { data, loading, error } = useGetRolesPermissionsQuery({
|
const { data, loading, error } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { allowed: allowedRoles, default: defaultRole } =
|
const { allowed: allowedRoles, default: defaultRole } =
|
||||||
@@ -55,6 +62,7 @@ export default function EditRoleForm({
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -114,7 +122,19 @@ export default function EditRoleForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Updating role...',
|
loadingMessage: 'Updating role...',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
@@ -15,9 +16,11 @@ import { List } from '@/components/ui/v2/List';
|
|||||||
import { ListItem } from '@/components/ui/v2/ListItem';
|
import { ListItem } from '@/components/ui/v2/ListItem';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { CreateRoleForm } from '@/features/projects/roles/settings/components/CreateRoleForm';
|
import { CreateRoleForm } from '@/features/projects/roles/settings/components/CreateRoleForm';
|
||||||
import { EditRoleForm } from '@/features/projects/roles/settings/components/EditRoleForm';
|
import { EditRoleForm } from '@/features/projects/roles/settings/components/EditRoleForm';
|
||||||
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { Role } from '@/types/application';
|
import type { Role } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -40,13 +43,15 @@ export interface RoleSettingsFormValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function RoleSettings() {
|
export default function RoleSettings() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { openDialog, openAlertDialog } = useDialog();
|
const { openDialog, openAlertDialog } = useDialog();
|
||||||
|
|
||||||
const { data, loading, error } = useGetRolesPermissionsQuery({
|
const { data, loading, error, refetch } = useGetRolesPermissionsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { allowed: allowedRoles, default: defaultRole } =
|
const { allowed: allowedRoles, default: defaultRole } =
|
||||||
@@ -54,6 +59,7 @@ export default function RoleSettings() {
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetRolesPermissionsDocument],
|
refetchQueries: [GetRolesPermissionsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -64,6 +70,20 @@ export default function RoleSettings() {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function showApplyChangesDialog() {
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSetAsDefault({ name }: Role) {
|
async function handleSetAsDefault({ name }: Role) {
|
||||||
const updateConfigPromise = updateConfig({
|
const updateConfigPromise = updateConfig({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -84,6 +104,7 @@ export default function RoleSettings() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
showApplyChangesDialog();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Updating default role...',
|
loadingMessage: 'Updating default role...',
|
||||||
@@ -114,6 +135,7 @@ export default function RoleSettings() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
showApplyChangesDialog();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Deleting allowed role...',
|
loadingMessage: 'Deleting allowed role...',
|
||||||
@@ -127,7 +149,7 @@ export default function RoleSettings() {
|
|||||||
function handleOpenCreator() {
|
function handleOpenCreator() {
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Create Allowed Role',
|
title: 'Create Allowed Role',
|
||||||
component: <CreateRoleForm />,
|
component: <CreateRoleForm onSubmit={refetch} />,
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
PaperProps: { className: 'max-w-sm' },
|
PaperProps: { className: 'max-w-sm' },
|
||||||
@@ -138,7 +160,9 @@ export default function RoleSettings() {
|
|||||||
function handleOpenEditor(originalRole: Role) {
|
function handleOpenEditor(originalRole: Role) {
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Edit Allowed Role',
|
title: 'Edit Allowed Role',
|
||||||
component: <EditRoleForm originalRole={originalRole} />,
|
component: (
|
||||||
|
<EditRoleForm originalRole={originalRole} onSubmit={refetch} />
|
||||||
|
),
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
PaperProps: { className: 'max-w-sm' },
|
PaperProps: { className: 'max-w-sm' },
|
||||||
@@ -177,7 +201,7 @@ export default function RoleSettings() {
|
|||||||
)}
|
)}
|
||||||
slotProps={{ submitButton: { className: 'hidden' } }}
|
slotProps={{ submitButton: { className: 'hidden' } }}
|
||||||
>
|
>
|
||||||
<Box className="border-b-1 px-4 py-3">
|
<Box className="px-4 py-3 border-b-1">
|
||||||
<Text className="font-medium">Name</Text>
|
<Text className="font-medium">Name</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -193,7 +217,7 @@ export default function RoleSettings() {
|
|||||||
<Dropdown.Trigger
|
<Dropdown.Trigger
|
||||||
asChild
|
asChild
|
||||||
hideChevron
|
hideChevron
|
||||||
className="absolute right-4 top-1/2 -translate-y-1/2"
|
className="absolute -translate-y-1/2 right-4 top-1/2"
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
@@ -252,7 +276,7 @@ export default function RoleSettings() {
|
|||||||
<>
|
<>
|
||||||
{role.name}
|
{role.name}
|
||||||
|
|
||||||
{role.isSystemRole && <LockIcon className="h-4 w-4" />}
|
{role.isSystemRole && <LockIcon className="w-4 h-4" />}
|
||||||
|
|
||||||
{defaultRole === role.name && (
|
{defaultRole === role.name && (
|
||||||
<Chip
|
<Chip
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseSecretFormProps,
|
BaseSecretFormProps,
|
||||||
BaseSecretFormValues,
|
BaseSecretFormValues,
|
||||||
@@ -7,6 +10,7 @@ import {
|
|||||||
BaseSecretForm,
|
BaseSecretForm,
|
||||||
baseSecretFormValidationSchema,
|
baseSecretFormValidationSchema,
|
||||||
} from '@/features/projects/secrets/settings/components/BaseSecretForm';
|
} from '@/features/projects/secrets/settings/components/BaseSecretForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetSecretsDocument,
|
GetSecretsDocument,
|
||||||
@@ -20,13 +24,17 @@ export interface CreateSecretFormProps
|
|||||||
/**
|
/**
|
||||||
* Function to be called when the form is submitted.
|
* Function to be called when the form is submitted.
|
||||||
*/
|
*/
|
||||||
onSubmit?: () => Promise<void>;
|
onSubmit?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreateSecretForm({
|
export default function CreateSecretForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: CreateSecretFormProps) {
|
}: CreateSecretFormProps) {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const form = useForm<BaseSecretFormValues>({
|
const form = useForm<BaseSecretFormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -39,6 +47,7 @@ export default function CreateSecretForm({
|
|||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [insertSecret] = useInsertSecretMutation({
|
const [insertSecret] = useInsertSecretMutation({
|
||||||
refetchQueries: [GetSecretsDocument],
|
refetchQueries: [GetSecretsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleSubmit({ name, value }: BaseSecretFormValues) {
|
async function handleSubmit({ name, value }: BaseSecretFormValues) {
|
||||||
@@ -56,7 +65,19 @@ export default function CreateSecretForm({
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await insertSecretPromise;
|
await insertSecretPromise;
|
||||||
onSubmit?.();
|
await onSubmit?.();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Creating secret...',
|
loadingMessage: 'Creating secret...',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import type {
|
import type {
|
||||||
BaseSecretFormProps,
|
BaseSecretFormProps,
|
||||||
BaseSecretFormValues,
|
BaseSecretFormValues,
|
||||||
@@ -7,6 +8,7 @@ import {
|
|||||||
BaseSecretForm,
|
BaseSecretForm,
|
||||||
baseSecretFormValidationSchema,
|
baseSecretFormValidationSchema,
|
||||||
} from '@/features/projects/secrets/settings/components/BaseSecretForm';
|
} from '@/features/projects/secrets/settings/components/BaseSecretForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { Secret } from '@/types/application';
|
import type { Secret } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -33,6 +35,9 @@ export default function EditSecretForm({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
...props
|
...props
|
||||||
}: EditSecretFormProps) {
|
}: EditSecretFormProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const form = useForm<BaseSecretFormValues>({
|
const form = useForm<BaseSecretFormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: originalSecret.name,
|
name: originalSecret.name,
|
||||||
@@ -45,6 +50,7 @@ export default function EditSecretForm({
|
|||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateSecret] = useUpdateSecretMutation({
|
const [updateSecret] = useUpdateSecretMutation({
|
||||||
refetchQueries: [GetSecretsDocument],
|
refetchQueries: [GetSecretsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleSubmit({ name, value }: BaseSecretFormValues) {
|
async function handleSubmit({ name, value }: BaseSecretFormValues) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { Alert } from '@/components/ui/v2/Alert';
|
import { Alert } from '@/components/ui/v2/Alert';
|
||||||
@@ -12,6 +13,7 @@ import { Text } from '@/components/ui/v2/Text';
|
|||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
import { useHostName } from '@/features/projects/common/hooks/useHostName';
|
import { useHostName } from '@/features/projects/common/hooks/useHostName';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { InfoCard } from '@/features/projects/overview/components/InfoCard';
|
import { InfoCard } from '@/features/projects/overview/components/InfoCard';
|
||||||
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
|
||||||
import { ComputeFormSection } from '@/features/services/components/ServiceForm/components/ComputeFormSection';
|
import { ComputeFormSection } from '@/features/services/components/ServiceForm/components/ComputeFormSection';
|
||||||
@@ -25,6 +27,7 @@ import {
|
|||||||
type ServiceFormProps,
|
type ServiceFormProps,
|
||||||
type ServiceFormValues,
|
type ServiceFormValues,
|
||||||
} from '@/features/services/components/ServiceForm/ServiceFormTypes';
|
} from '@/features/services/components/ServiceForm/ServiceFormTypes';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
@@ -50,11 +53,15 @@ export default function ServiceForm({
|
|||||||
location,
|
location,
|
||||||
}: ServiceFormProps) {
|
}: ServiceFormProps) {
|
||||||
const hostName = useHostName();
|
const hostName = useHostName();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
|
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
|
||||||
const [insertRunService] = useInsertRunServiceMutation();
|
const [insertRunService] = useInsertRunServiceMutation();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
|
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
|
||||||
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation();
|
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation({
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
|
});
|
||||||
const [detailsServiceId, setDetailsServiceId] = useState('');
|
const [detailsServiceId, setDetailsServiceId] = useState('');
|
||||||
const [detailsServiceSubdomain, setDetailsServiceSubdomain] = useState(
|
const [detailsServiceSubdomain, setDetailsServiceSubdomain] = useState(
|
||||||
initialData?.subdomain,
|
initialData?.subdomain,
|
||||||
@@ -145,6 +152,18 @@ export default function ServiceForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
setDetailsServiceId(serviceID);
|
setDetailsServiceId(serviceID);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Insert service config
|
// Insert service config
|
||||||
const {
|
const {
|
||||||
@@ -197,7 +216,12 @@ export default function ServiceForm({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirm = (values: ServiceFormValues) => {
|
const handleConfirm = async (values: ServiceFormValues) => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
await handleSubmit(formValues);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Confirm Resources',
|
title: 'Confirm Resources',
|
||||||
component: (
|
component: (
|
||||||
@@ -213,26 +237,34 @@ export default function ServiceForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
if (!isPlatform) {
|
||||||
if (detailsServiceId) {
|
return;
|
||||||
openDialog({
|
}
|
||||||
title: 'Service Details',
|
|
||||||
component: (
|
if (detailsServiceId) {
|
||||||
<ServiceDetailsDialog
|
openDialog({
|
||||||
serviceID={detailsServiceId}
|
title: 'Service Details',
|
||||||
subdomain={detailsServiceSubdomain}
|
component: (
|
||||||
ports={formValues.ports}
|
<ServiceDetailsDialog
|
||||||
/>
|
serviceID={detailsServiceId}
|
||||||
),
|
subdomain={detailsServiceSubdomain}
|
||||||
props: {
|
ports={formValues.ports}
|
||||||
PaperProps: {
|
/>
|
||||||
className: 'max-w-2xl',
|
),
|
||||||
},
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
})();
|
}
|
||||||
}, [detailsServiceId, detailsServiceSubdomain, formValues, openDialog]);
|
}, [
|
||||||
|
detailsServiceId,
|
||||||
|
detailsServiceSubdomain,
|
||||||
|
formValues,
|
||||||
|
openDialog,
|
||||||
|
isPlatform,
|
||||||
|
]);
|
||||||
|
|
||||||
const pricingExplanation = () => {
|
const pricingExplanation = () => {
|
||||||
const vCPUs = `${formValues.compute.cpu / RESOURCE_VCPU_MULTIPLIER} vCPUs`;
|
const vCPUs = `${formValues.compute.cpu / RESOURCE_VCPU_MULTIPLIER} vCPUs`;
|
||||||
@@ -271,7 +303,7 @@ export default function ServiceForm({
|
|||||||
<Tooltip title="Name of the service, must be unique per project.">
|
<Tooltip title="Name of the service, must be unique per project.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -311,7 +343,7 @@ export default function ServiceForm({
|
|||||||
>
|
>
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -325,8 +357,8 @@ export default function ServiceForm({
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* This shows only when trying to edit a service */}
|
{/* This shows only when trying to edit a service and when running against the nhost platform */}
|
||||||
{serviceID && serviceImage && (
|
{isPlatform && serviceID && serviceImage && (
|
||||||
<InfoCard
|
<InfoCard
|
||||||
title="Private registry"
|
title="Private registry"
|
||||||
value={`registry.${currentProject.region.awsName}.${currentProject.region.domain}/${serviceID}`}
|
value={`registry.${currentProject.region.awsName}.${currentProject.region.domain}/${serviceID}`}
|
||||||
@@ -342,7 +374,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.">
|
<Tooltip title="Command to run when to start the service. This is optional as the image may already have a baked-in command.">
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
aria-label="Info"
|
aria-label="Info"
|
||||||
className="h-4 w-4"
|
className="w-4 h-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -356,22 +388,24 @@ export default function ServiceForm({
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Alert
|
{isPlatform ? (
|
||||||
severity="info"
|
<Alert
|
||||||
className="flex items-center justify-between space-x-2"
|
severity="info"
|
||||||
>
|
className="flex items-center justify-between space-x-2"
|
||||||
<span>{pricingExplanation()}</span>
|
>
|
||||||
<b>
|
<span>{pricingExplanation()}</span>
|
||||||
$
|
<b>
|
||||||
{parseFloat(
|
$
|
||||||
(
|
{parseFloat(
|
||||||
formValues.compute.cpu *
|
(
|
||||||
formValues.replicas *
|
formValues.compute.cpu *
|
||||||
COST_PER_VCPU
|
formValues.replicas *
|
||||||
).toFixed(2),
|
COST_PER_VCPU
|
||||||
)}
|
).toFixed(2),
|
||||||
</b>
|
)}
|
||||||
</Alert>
|
</b>
|
||||||
|
</Alert>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<ComputeFormSection showTooltip />
|
<ComputeFormSection showTooltip />
|
||||||
|
|
||||||
@@ -388,7 +422,7 @@ export default function ServiceForm({
|
|||||||
{createServiceFormError && (
|
{createServiceFormError && (
|
||||||
<Alert
|
<Alert
|
||||||
severity="error"
|
severity="error"
|
||||||
className="grid grid-flow-col items-center justify-between px-4 py-3"
|
className="grid items-center justify-between grid-flow-col px-4 py-3"
|
||||||
>
|
>
|
||||||
<span className="text-left">
|
<span className="text-left">
|
||||||
<strong>Error:</strong> {createServiceFormError.message}
|
<strong>Error:</strong> {createServiceFormError.message}
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ import { UserIcon } from '@/components/ui/v2/icons/UserIcon';
|
|||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
import { Tooltip } from '@/components/ui/v2/Tooltip';
|
||||||
import { DeleteServiceModal } from '@/features/projects/common/components/DeleteServiceModal';
|
import { DeleteServiceModal } from '@/features/projects/common/components/DeleteServiceModal';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { ServiceForm } from '@/features/services/components/ServiceForm';
|
import { ServiceForm } from '@/features/services/components/ServiceForm';
|
||||||
import { type PortTypes } from '@/features/services/components/ServiceForm/components/PortsFormSection/PortsFormSectionTypes';
|
import { type PortTypes } from '@/features/services/components/ServiceForm/components/PortsFormSection/PortsFormSectionTypes';
|
||||||
|
import { type RunService } from '@/hooks/useRunServices';
|
||||||
import { copy } from '@/utils/copy';
|
import { copy } from '@/utils/copy';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import type { RunService } from 'pages/[workspaceSlug]/[appSlug]/services';
|
|
||||||
|
|
||||||
interface ServicesListProps {
|
interface ServicesListProps {
|
||||||
/**
|
/**
|
||||||
@@ -42,19 +43,20 @@ export default function ServicesList({
|
|||||||
onCreateOrUpdate,
|
onCreateOrUpdate,
|
||||||
onDelete,
|
onDelete,
|
||||||
}: ServicesListProps) {
|
}: ServicesListProps) {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { openDrawer, openDialog, closeDialog } = useDialog();
|
const { openDrawer, openDialog, closeDialog } = useDialog();
|
||||||
|
|
||||||
const viewService = async (service: RunService) => {
|
const viewService = async (service: RunService) => {
|
||||||
openDrawer({
|
openDrawer({
|
||||||
title: (
|
title: (
|
||||||
<Box className="flex flex-row items-center space-x-2">
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
<CubeIcon className="h-5 w-5" />
|
<CubeIcon className="w-5 h-5" />
|
||||||
<Text>Edit {service.config?.name ?? 'unset'}</Text>
|
<Text>Edit {service.config?.name ?? 'unset'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
component: (
|
component: (
|
||||||
<ServiceForm
|
<ServiceForm
|
||||||
serviceID={service.id}
|
serviceID={service.id ?? service.serviceID}
|
||||||
initialData={{
|
initialData={{
|
||||||
...service.config,
|
...service.config,
|
||||||
image: service.config?.image?.image,
|
image: service.config?.image?.image,
|
||||||
@@ -94,50 +96,52 @@ export default function ServicesList({
|
|||||||
<Box className="flex flex-col">
|
<Box className="flex flex-col">
|
||||||
{services.map((service) => (
|
{services.map((service) => (
|
||||||
<Box
|
<Box
|
||||||
key={service.id}
|
key={service.id ?? service.serviceID}
|
||||||
className="flex h-[64px] w-full cursor-pointer items-center justify-between space-x-4 border-b-1 px-4 py-2 transition-colors"
|
className="flex h-[64px] w-full cursor-pointer items-center justify-between space-x-4 border-b-1 px-4 py-2 transition-colors"
|
||||||
sx={{
|
sx={{
|
||||||
[`&:hover`]: {
|
[`&:hover`]: {
|
||||||
backgroundColor: 'action.hover',
|
backgroundColor: 'action.hover',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
onClick={() => viewService(service)}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
onClick={() => viewService(service)}
|
className="flex flex-row justify-between w-full"
|
||||||
className="flex w-full flex-row justify-between"
|
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-1 flex-row items-center space-x-4">
|
<div className="flex flex-row items-center flex-1 space-x-4">
|
||||||
<CubeIcon className="h-5 w-5" />
|
<CubeIcon className="w-5 h-5" />
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Text variant="h4" className="font-semibold">
|
<Text variant="h4" className="font-semibold">
|
||||||
{service.config?.name ?? 'unset'}
|
{service.config?.name ?? 'unset'}
|
||||||
</Text>
|
</Text>
|
||||||
<Tooltip title={service.updatedAt}>
|
{isPlatform ? (
|
||||||
<span className="hidden cursor-pointer text-sm text-slate-500 xs+:flex">
|
<Tooltip title={service.updatedAt}>
|
||||||
Deployed {formatDistanceToNow(new Date(service.updatedAt))}{' '}
|
<span className="hidden cursor-pointer text-sm text-slate-500 xs+:flex">
|
||||||
ago
|
Deployed{' '}
|
||||||
</span>
|
{formatDistanceToNow(new Date(service.updatedAt))} ago
|
||||||
</Tooltip>
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="hidden flex-row items-center space-x-2 md:flex">
|
<div className="flex-row items-center hidden space-x-2 md:flex">
|
||||||
<Text variant="subtitle1" className="font-mono text-xs">
|
<Text variant="subtitle1" className="font-mono text-xs">
|
||||||
{service.id}
|
{service.id ?? service.serviceID}
|
||||||
</Text>
|
</Text>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
copy(service.id, 'Service Id');
|
copy(service.id ?? service.serviceID, 'Service Id');
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
aria-label="Service Id"
|
aria-label="Service Id"
|
||||||
>
|
>
|
||||||
<CopyIcon className="h-4 w-4" />
|
<CopyIcon className="w-4 h-4" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -167,7 +171,7 @@ export default function ServicesList({
|
|||||||
onClick={() => viewService(service)}
|
onClick={() => viewService(service)}
|
||||||
className="z-50 grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
|
className="z-50 grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
|
||||||
>
|
>
|
||||||
<UserIcon className="h-4 w-4" />
|
<UserIcon className="w-4 h-4" />
|
||||||
<Text className="font-medium">View Service</Text>
|
<Text className="font-medium">View Service</Text>
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
<Divider component="li" />
|
<Divider component="li" />
|
||||||
@@ -175,8 +179,9 @@ export default function ServicesList({
|
|||||||
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
|
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
|
||||||
sx={{ color: 'error.main' }}
|
sx={{ color: 'error.main' }}
|
||||||
onClick={() => deleteService(service)}
|
onClick={() => deleteService(service)}
|
||||||
|
disabled={!isPlatform}
|
||||||
>
|
>
|
||||||
<TrashIcon className="h-4 w-4" />
|
<TrashIcon className="w-4 h-4" />
|
||||||
<Text className="font-medium" color="error">
|
<Text className="font-medium" color="error">
|
||||||
Delete Service
|
Delete Service
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
import { ControlledAutocomplete } from '@/components/form/ControlledAutocomplete';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetStorageSettingsDocument,
|
GetStorageSettingsDocument,
|
||||||
Software_Type_Enum,
|
Software_Type_Enum,
|
||||||
@@ -11,8 +14,10 @@ import {
|
|||||||
useGetStorageSettingsQuery,
|
useGetStorageSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -30,21 +35,26 @@ export type StorageServiceVersionFormValues = Yup.InferType<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export default function StorageServiceVersionSettings() {
|
export default function StorageServiceVersionSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetStorageSettingsDocument],
|
refetchQueries: [GetStorageSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetStorageSettingsQuery({
|
const { data, loading, error } = useGetStorageSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-only',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: storageVersionsData } = useGetSoftwareVersionsQuery({
|
const { data: storageVersionsData } = useGetSoftwareVersionsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
software: Software_Type_Enum.Storage,
|
software: Software_Type_Enum.Storage,
|
||||||
},
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { version } = data?.config?.storage || {};
|
const { version } = data?.config?.storage || {};
|
||||||
@@ -52,6 +62,7 @@ export default function StorageServiceVersionSettings() {
|
|||||||
const availableVersions = Array.from(
|
const availableVersions = Array.from(
|
||||||
new Set(versions.map((el) => el.version)).add(version),
|
new Set(versions.map((el) => el.version)).add(version),
|
||||||
)
|
)
|
||||||
|
.filter((v) => !!v)
|
||||||
.sort()
|
.sort()
|
||||||
.reverse()
|
.reverse()
|
||||||
.map((availableVersion) => ({
|
.map((availableVersion) => ({
|
||||||
@@ -61,10 +72,21 @@ export default function StorageServiceVersionSettings() {
|
|||||||
|
|
||||||
const form = useForm<StorageServiceVersionFormValues>({
|
const form = useForm<StorageServiceVersionFormValues>({
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
defaultValues: { version: { label: version, value: version } },
|
defaultValues: { version: { label: '', value: '' } },
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
version: {
|
||||||
|
label: version,
|
||||||
|
value: version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, version, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -99,6 +121,18 @@ export default function StorageServiceVersionSettings() {
|
|||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Storage version is being updated...',
|
loadingMessage: 'Storage version is being updated...',
|
||||||
@@ -123,12 +157,20 @@ export default function StorageServiceVersionSettings() {
|
|||||||
}}
|
}}
|
||||||
docsLink="https://github.com/nhost/hasura-storage/releases"
|
docsLink="https://github.com/nhost/hasura-storage/releases"
|
||||||
docsTitle="the latest releases"
|
docsTitle="the latest releases"
|
||||||
className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
|
className="grid grid-flow-row px-4 gap-x-4 gap-y-2 lg:grid-cols-5"
|
||||||
>
|
>
|
||||||
<ControlledAutocomplete
|
<ControlledAutocomplete
|
||||||
id="version"
|
id="version"
|
||||||
name="version"
|
name="version"
|
||||||
autoHighlight
|
autoHighlight
|
||||||
|
freeSolo
|
||||||
|
getOptionLabel={(option) => {
|
||||||
|
if (typeof option === 'string') {
|
||||||
|
return option || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return option.value;
|
||||||
|
}}
|
||||||
isOptionEqualToValue={() => false}
|
isOptionEqualToValue={() => false}
|
||||||
filterOptions={(options, { inputValue }) => {
|
filterOptions={(options, { inputValue }) => {
|
||||||
const inputValueLower = inputValue.toLowerCase();
|
const inputValueLower = inputValue.toLowerCase();
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetHasuraSettingsDocument,
|
GetHasuraSettingsDocument,
|
||||||
useGetStorageSettingsQuery,
|
useGetStorageSettingsQuery,
|
||||||
useUpdateConfigMutation,
|
useUpdateConfigMutation,
|
||||||
} from '@/generated/graphql';
|
} from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
@@ -20,16 +25,20 @@ const validationSchema = Yup.object({
|
|||||||
export type HasuraStorageAVFormValues = Yup.InferType<typeof validationSchema>;
|
export type HasuraStorageAVFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
|
|
||||||
export default function HasuraStorageAVSettings() {
|
export default function HasuraStorageAVSettings() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
const { currentProject, refetch: refetchWorkspaceAndProject } =
|
||||||
useCurrentWorkspaceAndProject();
|
useCurrentWorkspaceAndProject();
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetHasuraSettingsDocument],
|
refetchQueries: [GetHasuraSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, loading, error } = useGetStorageSettingsQuery({
|
const { data, loading, error } = useGetStorageSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'cache-first',
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { server } = data?.config?.storage?.antivirus || {};
|
const { server } = data?.config?.storage?.antivirus || {};
|
||||||
@@ -42,6 +51,14 @@ export default function HasuraStorageAVSettings() {
|
|||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
|
form.reset({
|
||||||
|
enabled: !!server,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [loading, server, form]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator
|
<ActivityIndicator
|
||||||
@@ -81,6 +98,18 @@ export default function HasuraStorageAVSettings() {
|
|||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
form.reset(formValues);
|
form.reset(formValues);
|
||||||
await refetchWorkspaceAndProject();
|
await refetchWorkspaceAndProject();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Antivirus settings are being updated...',
|
loadingMessage: 'Antivirus settings are being updated...',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ query getGraphiteAutoEmbeddingsConfigurations($limit: Int!, $offset: Int!) {
|
|||||||
graphiteAutoEmbeddingsConfigurations(limit: $limit, offset: $offset) {
|
graphiteAutoEmbeddingsConfigurations(limit: $limit, offset: $offset) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
model
|
||||||
schemaName
|
schemaName
|
||||||
tableName
|
tableName
|
||||||
columnName
|
columnName
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mutation insertGraphiteAutoEmbeddingsConfiguration(
|
mutation insertGraphiteAutoEmbeddingsConfiguration(
|
||||||
$name: String
|
$name: String
|
||||||
|
$model: embedding_model_enum
|
||||||
$schemaName: String
|
$schemaName: String
|
||||||
$tableName: String
|
$tableName: String
|
||||||
$columnName: String
|
$columnName: String
|
||||||
@@ -9,6 +10,7 @@ mutation insertGraphiteAutoEmbeddingsConfiguration(
|
|||||||
insertGraphiteAutoEmbeddingsConfiguration(
|
insertGraphiteAutoEmbeddingsConfiguration(
|
||||||
object: {
|
object: {
|
||||||
name: $name
|
name: $name
|
||||||
|
model: $model
|
||||||
schemaName: $schemaName
|
schemaName: $schemaName
|
||||||
tableName: $tableName
|
tableName: $tableName
|
||||||
columnName: $columnName
|
columnName: $columnName
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
mutation updateGraphiteAutoEmbeddingsConfiguration(
|
mutation updateGraphiteAutoEmbeddingsConfiguration(
|
||||||
$id: uuid!
|
$id: uuid!
|
||||||
$name: String
|
$name: String
|
||||||
|
$model: embedding_model_enum
|
||||||
$schemaName: String
|
$schemaName: String
|
||||||
$tableName: String
|
$tableName: String
|
||||||
$columnName: String
|
$columnName: String
|
||||||
@@ -11,6 +12,7 @@ mutation updateGraphiteAutoEmbeddingsConfiguration(
|
|||||||
pk_columns: { id: $id }
|
pk_columns: { id: $id }
|
||||||
_set: {
|
_set: {
|
||||||
name: $name
|
name: $name
|
||||||
|
model: $model
|
||||||
schemaName: $schemaName
|
schemaName: $schemaName
|
||||||
tableName: $tableName
|
tableName: $tableName
|
||||||
columnName: $columnName
|
columnName: $columnName
|
||||||
@@ -20,6 +22,7 @@ mutation updateGraphiteAutoEmbeddingsConfiguration(
|
|||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
model
|
||||||
schemaName
|
schemaName
|
||||||
tableName
|
tableName
|
||||||
columnName
|
columnName
|
||||||
|
|||||||
@@ -1,3 +1,40 @@
|
|||||||
|
fragment RunServiceConfig on ConfigRunServiceConfig {
|
||||||
|
name
|
||||||
|
image {
|
||||||
|
image
|
||||||
|
}
|
||||||
|
command
|
||||||
|
resources {
|
||||||
|
compute {
|
||||||
|
cpu
|
||||||
|
memory
|
||||||
|
}
|
||||||
|
storage {
|
||||||
|
name
|
||||||
|
path
|
||||||
|
capacity
|
||||||
|
}
|
||||||
|
replicas
|
||||||
|
}
|
||||||
|
environment {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
ports {
|
||||||
|
port
|
||||||
|
type
|
||||||
|
publish
|
||||||
|
ingresses {
|
||||||
|
fqdn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
healthCheck {
|
||||||
|
port
|
||||||
|
initialDelaySeconds
|
||||||
|
probePeriodSeconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query getRunServices(
|
query getRunServices(
|
||||||
$appID: uuid!
|
$appID: uuid!
|
||||||
$resolve: Boolean!
|
$resolve: Boolean!
|
||||||
@@ -11,40 +48,7 @@ query getRunServices(
|
|||||||
updatedAt
|
updatedAt
|
||||||
subdomain
|
subdomain
|
||||||
config(resolve: $resolve) {
|
config(resolve: $resolve) {
|
||||||
name
|
...RunServiceConfig
|
||||||
image {
|
|
||||||
image
|
|
||||||
}
|
|
||||||
command
|
|
||||||
resources {
|
|
||||||
compute {
|
|
||||||
cpu
|
|
||||||
memory
|
|
||||||
}
|
|
||||||
storage {
|
|
||||||
name
|
|
||||||
path
|
|
||||||
capacity
|
|
||||||
}
|
|
||||||
replicas
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
name
|
|
||||||
value
|
|
||||||
}
|
|
||||||
ports {
|
|
||||||
port
|
|
||||||
type
|
|
||||||
publish
|
|
||||||
ingresses {
|
|
||||||
fqdn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
healthCheck {
|
|
||||||
port
|
|
||||||
initialDelaySeconds
|
|
||||||
probePeriodSeconds
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runServices_aggregate {
|
runServices_aggregate {
|
||||||
@@ -54,3 +58,12 @@ query getRunServices(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query getLocalRunServiceConfigs($appID: uuid!, $resolve: Boolean!) {
|
||||||
|
runServiceConfigs(appID: $appID, resolve: $resolve) {
|
||||||
|
serviceID
|
||||||
|
config {
|
||||||
|
...RunServiceConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
1
dashboard/src/hooks/useLocalMimirClient/index.ts
Normal file
1
dashboard/src/hooks/useLocalMimirClient/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { default as useLocalMimirClient } from './useLocalMimirClient';
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It creates a new Apollo Client instance that connects to the local mimir when running the a local nhost project
|
||||||
|
* @returns A function that returns a new ApolloClient instance.
|
||||||
|
*/
|
||||||
|
export default function useLocalMimirClient() {
|
||||||
|
return useMemo(
|
||||||
|
() =>
|
||||||
|
new ApolloClient({
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
link: new HttpLink({
|
||||||
|
uri: 'https://local.dashboard.nhost.run/v1/configserver/graphql',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
2
dashboard/src/hooks/useRunServices/index.ts
Normal file
2
dashboard/src/hooks/useRunServices/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './useRunServices';
|
||||||
|
export { default as useRunServices } from './useRunServices';
|
||||||
109
dashboard/src/hooks/useRunServices/useRunServices.ts
Normal file
109
dashboard/src/hooks/useRunServices/useRunServices.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
|
import {
|
||||||
|
useGetLocalRunServiceConfigsQuery,
|
||||||
|
useGetRunServicesQuery,
|
||||||
|
type GetRunServicesQuery,
|
||||||
|
} from '@/utils/__generated__/graphql';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export type RunService = Pick<
|
||||||
|
GetRunServicesQuery['app']['runServices'][0],
|
||||||
|
'config'
|
||||||
|
> & {
|
||||||
|
id?: string;
|
||||||
|
serviceID?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
subdomain?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RunServiceConfig = Omit<
|
||||||
|
GetRunServicesQuery['app']['runServices'][0]['config'],
|
||||||
|
'__typename'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export default function useRunServices() {
|
||||||
|
const limit = useRef(25);
|
||||||
|
const router = useRouter();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
|
const [nrOfPages, setNrOfPages] = useState(0);
|
||||||
|
const [totalServicesCount, setTotalServicesCount] = useState(0);
|
||||||
|
const [currentPage, setCurrentPage] = useState(
|
||||||
|
parseInt(router.query.page as string, 10) || 1,
|
||||||
|
);
|
||||||
|
const offset = useMemo(() => currentPage - 1, [currentPage]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
loading: loadingPlatformServices,
|
||||||
|
refetch: refetchPlatformServices,
|
||||||
|
} = useGetRunServicesQuery({
|
||||||
|
variables: {
|
||||||
|
appID: currentProject.id,
|
||||||
|
resolve: false,
|
||||||
|
limit: limit.current,
|
||||||
|
offset,
|
||||||
|
},
|
||||||
|
skip: !isPlatform,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
loading: loadingLocalServices,
|
||||||
|
data: localServicesData,
|
||||||
|
refetch: refetchLocalServices,
|
||||||
|
} = useGetLocalRunServiceConfigsQuery({
|
||||||
|
variables: { appID: currentProject.id as any, resolve: false },
|
||||||
|
skip: isPlatform,
|
||||||
|
client: localMimirClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
const platformServices = useMemo(
|
||||||
|
() => data?.app?.runServices.map((service) => service) ?? [],
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
|
||||||
|
const localServices = useMemo(
|
||||||
|
() => localServicesData?.runServiceConfigs.map((service) => service) ?? [],
|
||||||
|
[localServicesData],
|
||||||
|
);
|
||||||
|
|
||||||
|
const services: RunService[] = isPlatform ? platformServices : localServices;
|
||||||
|
const loading = isPlatform ? loadingPlatformServices : loadingLocalServices;
|
||||||
|
const refetch = isPlatform ? refetchPlatformServices : refetchLocalServices;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isPlatform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userCount = data?.app?.runServices_aggregate.aggregate.count ?? 0;
|
||||||
|
|
||||||
|
setTotalServicesCount(
|
||||||
|
data?.app?.runServices_aggregate.aggregate.count ?? 0,
|
||||||
|
);
|
||||||
|
setNrOfPages(Math.ceil(userCount / limit.current));
|
||||||
|
}, [data, loading, isPlatform]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
services,
|
||||||
|
loading,
|
||||||
|
refetch,
|
||||||
|
|
||||||
|
limit,
|
||||||
|
totalServicesCount,
|
||||||
|
nrOfPages,
|
||||||
|
|
||||||
|
currentPage,
|
||||||
|
setCurrentPage,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,75 +9,34 @@ import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
|
|||||||
import { ServicesIcon } from '@/components/ui/v2/icons/ServicesIcon';
|
import { ServicesIcon } from '@/components/ui/v2/icons/ServicesIcon';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
import type { GetRunServicesQuery } from '@/utils/__generated__/graphql';
|
|
||||||
import { useGetRunServicesQuery } from '@/utils/__generated__/graphql';
|
|
||||||
|
|
||||||
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { ServiceForm } from '@/features/services/components/ServiceForm';
|
import { ServiceForm } from '@/features/services/components/ServiceForm';
|
||||||
import { type PortTypes } from '@/features/services/components/ServiceForm/components/PortsFormSection/PortsFormSectionTypes';
|
import { type PortTypes } from '@/features/services/components/ServiceForm/components/PortsFormSection/PortsFormSectionTypes';
|
||||||
import ServicesList from '@/features/services/components/ServicesList/ServicesList';
|
import ServicesList from '@/features/services/components/ServicesList/ServicesList';
|
||||||
|
import { useRunServices, type RunServiceConfig } from '@/hooks/useRunServices';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import {
|
import { useCallback, useEffect, type ReactElement } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
type ReactElement,
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
export type RunService = Omit<
|
|
||||||
GetRunServicesQuery['app']['runServices'][0],
|
|
||||||
'__typename'
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type RunServiceConfig = Omit<
|
|
||||||
GetRunServicesQuery['app']['runServices'][0]['config'],
|
|
||||||
'__typename'
|
|
||||||
>;
|
|
||||||
|
|
||||||
export default function ServicesPage() {
|
export default function ServicesPage() {
|
||||||
const limit = useRef(25);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { openDrawer, openAlertDialog } = useDialog();
|
const { openDrawer, openAlertDialog } = useDialog();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const isPlanFree = currentProject?.plan?.isFree;
|
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(
|
|
||||||
parseInt(router.query.page as string, 10) || 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [nrOfPages, setNrOfPages] = useState(0);
|
|
||||||
|
|
||||||
const offset = useMemo(() => currentPage - 1, [currentPage]);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
|
||||||
loading,
|
loading,
|
||||||
refetch: refetchServices,
|
services,
|
||||||
} = useGetRunServicesQuery({
|
totalServicesCount,
|
||||||
variables: {
|
limit,
|
||||||
appID: currentProject.id,
|
nrOfPages,
|
||||||
resolve: false,
|
currentPage,
|
||||||
limit: limit.current,
|
setCurrentPage,
|
||||||
offset,
|
refetch,
|
||||||
},
|
} = useRunServices();
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
const isPlanFree = currentProject?.plan?.isFree;
|
||||||
if (loading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userCount = data?.app?.runServices_aggregate.aggregate.count ?? 0;
|
|
||||||
|
|
||||||
setNrOfPages(Math.ceil(userCount / limit.current));
|
|
||||||
}, [data, loading]);
|
|
||||||
|
|
||||||
const services = useMemo(
|
|
||||||
() => data?.app?.runServices.map((service) => service) ?? [],
|
|
||||||
[data],
|
|
||||||
);
|
|
||||||
|
|
||||||
const checkConfigFromQuery = useCallback(
|
const checkConfigFromQuery = useCallback(
|
||||||
(base64Config: string) => {
|
(base64Config: string) => {
|
||||||
@@ -89,7 +48,7 @@ export default function ServicesPage() {
|
|||||||
openDrawer({
|
openDrawer({
|
||||||
title: (
|
title: (
|
||||||
<Box className="flex flex-row items-center space-x-2">
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
<CubeIcon className="h-5 w-5" />
|
<CubeIcon className="w-5 h-5" />
|
||||||
<Text>Create a new run service</Text>
|
<Text>Create a new run service</Text>
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
@@ -111,7 +70,7 @@ export default function ServicesPage() {
|
|||||||
replicas: parsedConfig?.resources?.replicas,
|
replicas: parsedConfig?.resources?.replicas,
|
||||||
storage: parsedConfig?.resources?.storage,
|
storage: parsedConfig?.resources?.storage,
|
||||||
}}
|
}}
|
||||||
onSubmit={refetchServices}
|
onSubmit={refetch}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
@@ -127,7 +86,7 @@ export default function ServicesPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[router.query.config, openDrawer, refetchServices, openAlertDialog],
|
[router.query.config, openDrawer, refetch, openAlertDialog],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,18 +96,23 @@ export default function ServicesPage() {
|
|||||||
}, [checkConfigFromQuery, router.query]);
|
}, [checkConfigFromQuery, router.query]);
|
||||||
|
|
||||||
const openCreateServiceDialog = () => {
|
const openCreateServiceDialog = () => {
|
||||||
|
// creating services using the local dashboard is not supported
|
||||||
|
if (isPlatform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
openDrawer({
|
openDrawer({
|
||||||
title: (
|
title: (
|
||||||
<Box className="flex flex-row items-center space-x-2">
|
<Box className="flex flex-row items-center space-x-2">
|
||||||
<CubeIcon className="h-5 w-5" />
|
<CubeIcon className="w-5 h-5" />
|
||||||
<Text>Create a new service</Text>
|
<Text>Create a new service</Text>
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
component: <ServiceForm onSubmit={refetchServices} />,
|
component: <ServiceForm onSubmit={refetch} />,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isPlanFree) {
|
if (isPlatform && isPlanFree) {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<UpgradeNotification
|
<UpgradeNotification
|
||||||
@@ -159,41 +123,44 @@ export default function ServicesPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data?.app.runServices.length === 0 && !loading) {
|
if (services.length === 0 && !loading) {
|
||||||
return (
|
return (
|
||||||
<Container className="mx-auto max-w-9xl space-y-5 overflow-x-hidden">
|
<Container className="mx-auto space-y-5 overflow-x-hidden max-w-9xl">
|
||||||
<div className="flex flex-row place-content-end">
|
<div className="flex flex-row place-content-end">
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={openCreateServiceDialog}
|
onClick={openCreateServiceDialog}
|
||||||
startIcon={<PlusIcon className="h-4 w-4" />}
|
startIcon={<PlusIcon className="w-4 h-4" />}
|
||||||
|
disabled={!isPlatform}
|
||||||
>
|
>
|
||||||
Add service
|
Add service
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Box className="flex flex-col items-center justify-center space-y-5 rounded-lg border px-48 py-12 shadow-sm">
|
<Box className="flex flex-col items-center justify-center px-48 py-12 space-y-5 border rounded-lg shadow-sm">
|
||||||
<ServicesIcon className="h-10 w-10" />
|
<ServicesIcon className="w-10 h-10" />
|
||||||
<div className="flex flex-col space-y-1">
|
<div className="flex flex-col space-y-1">
|
||||||
<Text className="text-center font-medium" variant="h3">
|
<Text className="font-medium text-center" variant="h3">
|
||||||
No custom services are available
|
No custom services are available
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="subtitle1" className="text-center">
|
<Text variant="subtitle1" className="text-center">
|
||||||
All your project’s custom services will be listed here.
|
All your project's custom services will be listed here.
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row place-content-between rounded-lg ">
|
{isPlatform ? (
|
||||||
<Button
|
<div className="flex flex-row rounded-lg place-content-between ">
|
||||||
variant="contained"
|
<Button
|
||||||
color="primary"
|
variant="contained"
|
||||||
className="w-full"
|
color="primary"
|
||||||
onClick={openCreateServiceDialog}
|
className="w-full"
|
||||||
startIcon={<PlusIcon className="h-4 w-4" />}
|
onClick={openCreateServiceDialog}
|
||||||
>
|
startIcon={<PlusIcon className="w-4 h-4" />}
|
||||||
Add service
|
>
|
||||||
</Button>
|
Add service
|
||||||
</div>
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
@@ -201,12 +168,13 @@ export default function ServicesPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Box className="flex flex-row place-content-end border-b-1 p-4">
|
<Box className="flex flex-row p-4 place-content-end border-b-1">
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={openCreateServiceDialog}
|
onClick={openCreateServiceDialog}
|
||||||
startIcon={<PlusIcon className="h-4 w-4" />}
|
startIcon={<PlusIcon className="w-4 h-4" />}
|
||||||
|
disabled={!isPlatform}
|
||||||
>
|
>
|
||||||
Add service
|
Add service
|
||||||
</Button>
|
</Button>
|
||||||
@@ -214,42 +182,42 @@ export default function ServicesPage() {
|
|||||||
<Box className="space-y-4">
|
<Box className="space-y-4">
|
||||||
<ServicesList
|
<ServicesList
|
||||||
services={services}
|
services={services}
|
||||||
onDelete={() => refetchServices()}
|
onDelete={() => refetch()}
|
||||||
onCreateOrUpdate={() => refetchServices()}
|
onCreateOrUpdate={() => refetch()}
|
||||||
/>
|
/>
|
||||||
<Pagination
|
{isPlatform ? (
|
||||||
className="px-2"
|
<Pagination
|
||||||
totalNrOfPages={nrOfPages}
|
className="px-2"
|
||||||
currentPageNumber={currentPage}
|
totalNrOfPages={nrOfPages}
|
||||||
totalNrOfElements={
|
currentPageNumber={currentPage}
|
||||||
data?.app?.runServices_aggregate.aggregate.count ?? 0
|
totalNrOfElements={totalServicesCount}
|
||||||
}
|
itemsLabel="services"
|
||||||
itemsLabel="services"
|
elementsPerPage={limit.current}
|
||||||
elementsPerPage={limit.current}
|
onPrevPageClick={async () => {
|
||||||
onPrevPageClick={async () => {
|
setCurrentPage((page) => page - 1);
|
||||||
setCurrentPage((page) => page - 1);
|
if (currentPage - 1 !== 1) {
|
||||||
if (currentPage - 1 !== 1) {
|
await router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { ...router.query, page: currentPage - 1 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onNextPageClick={async () => {
|
||||||
|
setCurrentPage((page) => page + 1);
|
||||||
await router.push({
|
await router.push({
|
||||||
pathname: router.pathname,
|
pathname: router.pathname,
|
||||||
query: { ...router.query, page: currentPage - 1 },
|
query: { ...router.query, page: currentPage + 1 },
|
||||||
});
|
});
|
||||||
}
|
}}
|
||||||
}}
|
onPageChange={async (page) => {
|
||||||
onNextPageClick={async () => {
|
setCurrentPage(page);
|
||||||
setCurrentPage((page) => page + 1);
|
await router.push({
|
||||||
await router.push({
|
pathname: router.pathname,
|
||||||
pathname: router.pathname,
|
query: { ...router.query, page },
|
||||||
query: { ...router.query, page: currentPage + 1 },
|
});
|
||||||
});
|
}}
|
||||||
}}
|
/>
|
||||||
onPageChange={async (page) => {
|
) : null}
|
||||||
setCurrentPage(page);
|
|
||||||
await router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: { ...router.query, page },
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type { ReactElement } from 'react';
|
|||||||
export default function StorageSettingsPage() {
|
export default function StorageSettingsPage() {
|
||||||
const { currentProject, loading, error } = useCurrentWorkspaceAndProject();
|
const { currentProject, loading, error } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
if (currentProject.plan.isFree) {
|
if (currentProject?.plan?.isFree) {
|
||||||
return (
|
return (
|
||||||
<Box className="p-4" sx={{ backgroundColor: 'background.default' }}>
|
<Box className="p-4" sx={{ backgroundColor: 'background.default' }}>
|
||||||
<UpgradeToProBanner
|
<UpgradeToProBanner
|
||||||
@@ -43,7 +43,7 @@ export default function StorageSettingsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent"
|
className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"
|
||||||
rootClassName="bg-transparent"
|
rootClassName="bg-transparent"
|
||||||
>
|
>
|
||||||
<AISettings />
|
<AISettings />
|
||||||
|
|||||||
@@ -11,15 +11,20 @@ import { GravatarSettings } from '@/features/authentication/settings/components/
|
|||||||
import { MFASettings } from '@/features/authentication/settings/components/MFASettings';
|
import { MFASettings } from '@/features/authentication/settings/components/MFASettings';
|
||||||
import { SessionSettings } from '@/features/authentication/settings/components/SessionSettings';
|
import { SessionSettings } from '@/features/authentication/settings/components/SessionSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { useGetAuthenticationSettingsQuery } from '@/utils/__generated__/graphql';
|
import { useGetAuthenticationSettingsQuery } from '@/utils/__generated__/graphql';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function SettingsAuthenticationPage() {
|
export default function SettingsAuthenticationPage() {
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
|
||||||
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
const { data, loading, error } = useGetAuthenticationSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
skip: !currentProject,
|
skip: !currentProject,
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data && loading) {
|
if (!data && loading) {
|
||||||
@@ -38,7 +43,7 @@ export default function SettingsAuthenticationPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent"
|
className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"
|
||||||
rootClassName="bg-transparent"
|
rootClassName="bg-transparent"
|
||||||
>
|
>
|
||||||
<AuthServiceVersionSettings />
|
<AuthServiceVersionSettings />
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { type ReactElement } from 'react';
|
|||||||
export default function CustomDomains() {
|
export default function CustomDomains() {
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
if (currentProject.plan.isFree) {
|
if (currentProject?.plan?.isFree) {
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid grid-flow-row gap-6 bg-transparent"
|
className="grid grid-flow-row gap-6 bg-transparent"
|
||||||
@@ -35,7 +35,7 @@ export default function CustomDomains() {
|
|||||||
className="grid max-w-5xl grid-flow-row gap-6 bg-transparent"
|
className="grid max-w-5xl grid-flow-row gap-6 bg-transparent"
|
||||||
rootClassName="bg-transparent"
|
rootClassName="bg-transparent"
|
||||||
>
|
>
|
||||||
<Box className="flex flex-row items-center gap-4 overflow-hidden rounded-lg border-1 p-4">
|
<Box className="flex flex-row items-center gap-4 p-4 overflow-hidden rounded-lg border-1">
|
||||||
<div className="flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
<Text className="text-lg font-semibold">Custom Domains</Text>
|
<Text className="text-lg font-semibold">Custom Domains</Text>
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export default function CustomDomains() {
|
|||||||
className="ml-1 font-medium"
|
className="ml-1 font-medium"
|
||||||
>
|
>
|
||||||
Custom Domains
|
Custom Domains
|
||||||
<ArrowSquareOutIcon className="ml-1 h-4 w-4" />
|
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,15 +6,20 @@ import { DatabaseServiceVersionSettings } from '@/features/database/settings/com
|
|||||||
import { DatabaseStorageCapacity } from '@/features/database/settings/components/DatabaseStorageCapacity';
|
import { DatabaseStorageCapacity } from '@/features/database/settings/components/DatabaseStorageCapacity';
|
||||||
import { ResetDatabasePasswordSettings } from '@/features/database/settings/components/ResetDatabasePasswordSettings';
|
import { ResetDatabasePasswordSettings } from '@/features/database/settings/components/ResetDatabasePasswordSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useGetPostgresSettingsQuery } from '@/generated/graphql';
|
import { useGetPostgresSettingsQuery } from '@/generated/graphql';
|
||||||
|
import useLocalMimirClient from '@/hooks/useLocalMimirClient/useLocalMimirClient';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function DatabaseSettingsPage() {
|
export default function DatabaseSettingsPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { loading, error } = useGetPostgresSettingsQuery({
|
const { loading, error } = useGetPostgresSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
skip: !currentProject,
|
skip: !currentProject,
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -38,8 +43,13 @@ export default function DatabaseSettingsPage() {
|
|||||||
>
|
>
|
||||||
<DatabaseServiceVersionSettings />
|
<DatabaseServiceVersionSettings />
|
||||||
<DatabaseStorageCapacity />
|
<DatabaseStorageCapacity />
|
||||||
<DatabaseConnectionInfo />
|
|
||||||
<ResetDatabasePasswordSettings />
|
{isPlatform && (
|
||||||
|
<>
|
||||||
|
<DatabaseConnectionInfo />
|
||||||
|
<ResetDatabasePasswordSettings />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,20 @@ import { Container } from '@/components/layout/Container';
|
|||||||
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { EnvironmentVariableSettings } from '@/features/projects/environmentVariables/settings/components/EnvironmentVariableSettings';
|
import { EnvironmentVariableSettings } from '@/features/projects/environmentVariables/settings/components/EnvironmentVariableSettings';
|
||||||
import { SystemEnvironmentVariableSettings } from '@/features/projects/environmentVariables/settings/components/SystemEnvironmentVariableSettings';
|
import { SystemEnvironmentVariableSettings } from '@/features/projects/environmentVariables/settings/components/SystemEnvironmentVariableSettings';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { useGetEnvironmentVariablesQuery } from '@/utils/__generated__/graphql';
|
import { useGetEnvironmentVariablesQuery } from '@/utils/__generated__/graphql';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function EnvironmentVariablesPage() {
|
export default function EnvironmentVariablesPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
const { loading, error } = useGetEnvironmentVariablesQuery({
|
const { loading, error } = useGetEnvironmentVariablesQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Input } from '@/components/ui/v2/Input';
|
|||||||
import { RemoveApplicationModal } from '@/features/projects/common/components/RemoveApplicationModal';
|
import { RemoveApplicationModal } from '@/features/projects/common/components/RemoveApplicationModal';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCurrentUserOwner';
|
import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCurrentUserOwner';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import {
|
import {
|
||||||
GetAllWorkspacesAndProjectsDocument,
|
GetAllWorkspacesAndProjectsDocument,
|
||||||
useDeleteApplicationMutation,
|
useDeleteApplicationMutation,
|
||||||
@@ -42,6 +43,7 @@ export default function SettingsGeneralPage() {
|
|||||||
loading,
|
loading,
|
||||||
refetch: refetchWorkspaceAndProject,
|
refetch: refetchWorkspaceAndProject,
|
||||||
} = useCurrentWorkspaceAndProject();
|
} = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const isOwner = useIsCurrentUserOwner();
|
const isOwner = useIsCurrentUserOwner();
|
||||||
const { openDialog, openAlertDialog, closeDialog } = useDialog();
|
const { openDialog, openAlertDialog, closeDialog } = useDialog();
|
||||||
const [updateApp] = useUpdateApplicationMutation();
|
const [updateApp] = useUpdateApplicationMutation();
|
||||||
@@ -56,6 +58,8 @@ export default function SettingsGeneralPage() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
|
||||||
const form = useForm<ProjectNameValidationSchema>({
|
const form = useForm<ProjectNameValidationSchema>({
|
||||||
mode: 'onSubmit',
|
mode: 'onSubmit',
|
||||||
reValidateMode: 'onSubmit',
|
reValidateMode: 'onSubmit',
|
||||||
@@ -173,7 +177,8 @@ export default function SettingsGeneralPage() {
|
|||||||
className="grid grid-flow-row px-4 lg:grid-cols-4"
|
className="grid grid-flow-row px-4 lg:grid-cols-4"
|
||||||
slotProps={{
|
slotProps={{
|
||||||
submitButton: {
|
submitButton: {
|
||||||
disabled: !formState.isDirty || maintenanceActive,
|
disabled:
|
||||||
|
!formState.isDirty || maintenanceActive || !isPlatform,
|
||||||
loading: formState.isSubmitting,
|
loading: formState.isSubmitting,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -194,7 +199,7 @@ export default function SettingsGeneralPage() {
|
|||||||
</Form>
|
</Form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
|
|
||||||
{currentProject?.plan.isFree && (
|
{currentProject?.plan?.isFree && (
|
||||||
<SettingsContainer
|
<SettingsContainer
|
||||||
title="Pause Project"
|
title="Pause Project"
|
||||||
description="While your project is paused, it will not be accessible. You can wake it up anytime after."
|
description="While your project is paused, it will not be accessible. You can wake it up anytime after."
|
||||||
|
|||||||
@@ -11,15 +11,20 @@ import { HasuraPoolSizeSettings } from '@/features/hasura/settings/components/Ha
|
|||||||
import { HasuraRemoteSchemaPermissionsSettings } from '@/features/hasura/settings/components/HasuraRemoteSchemaPermissionsSettings';
|
import { HasuraRemoteSchemaPermissionsSettings } from '@/features/hasura/settings/components/HasuraRemoteSchemaPermissionsSettings';
|
||||||
import { HasuraServiceVersionSettings } from '@/features/hasura/settings/components/HasuraServiceVersionSettings';
|
import { HasuraServiceVersionSettings } from '@/features/hasura/settings/components/HasuraServiceVersionSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { useGetHasuraSettingsQuery } from '@/utils/__generated__/graphql';
|
import { useGetHasuraSettingsQuery } from '@/utils/__generated__/graphql';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function HasuraSettingsPage() {
|
export default function HasuraSettingsPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { data, loading, error } = useGetHasuraSettingsQuery({
|
const { data, loading, error } = useGetHasuraSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
skip: !currentProject,
|
skip: !currentProject,
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data && loading) {
|
if (!data && loading) {
|
||||||
@@ -38,7 +43,7 @@ export default function HasuraSettingsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent"
|
className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"
|
||||||
rootClassName="bg-transparent"
|
rootClassName="bg-transparent"
|
||||||
>
|
>
|
||||||
<HasuraServiceVersionSettings />
|
<HasuraServiceVersionSettings />
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default function ResourceSettingsPage() {
|
|||||||
return <ActivityIndicator delay={1000} label="Loading project..." />;
|
return <ActivityIndicator delay={1000} label="Loading project..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentProject?.plan.isFree) {
|
if (currentProject?.plan?.isFree) {
|
||||||
return (
|
return (
|
||||||
<UpgradeNotification message="Unlock Compute settings by upgrading your project to the Pro plan." />
|
<UpgradeNotification message="Unlock Compute settings by upgrading your project to the Pro plan." />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,17 +2,23 @@ import { Container } from '@/components/layout/Container';
|
|||||||
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { PermissionVariableSettings } from '@/features/projects/permissions/settings/components/PermissionVariableSettings';
|
import { PermissionVariableSettings } from '@/features/projects/permissions/settings/components/PermissionVariableSettings';
|
||||||
import { RoleSettings } from '@/features/projects/roles/settings/components/RoleSettings';
|
import { RoleSettings } from '@/features/projects/roles/settings/components/RoleSettings';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { useGetRolesPermissionsQuery } from '@/utils/__generated__/graphql';
|
import { useGetRolesPermissionsQuery } from '@/utils/__generated__/graphql';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function RolesAndPermissionsPage() {
|
export default function RolesAndPermissionsPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { loading, error } = useGetRolesPermissionsQuery({
|
const { loading, error } = useGetRolesPermissionsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
appId: currentProject?.id,
|
appId: currentProject?.id,
|
||||||
},
|
},
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
import { useDialog } from '@/components/common/DialogProvider';
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { Container } from '@/components/layout/Container';
|
import { Container } from '@/components/layout/Container';
|
||||||
@@ -16,8 +17,10 @@ import { List } from '@/components/ui/v2/List';
|
|||||||
import { ListItem } from '@/components/ui/v2/ListItem';
|
import { ListItem } from '@/components/ui/v2/ListItem';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { CreateSecretForm } from '@/features/projects/secrets/settings/components/CreateSecretForm';
|
import { CreateSecretForm } from '@/features/projects/secrets/settings/components/CreateSecretForm';
|
||||||
import { EditSecretForm } from '@/features/projects/secrets/settings/components/EditSecretForm';
|
import { EditSecretForm } from '@/features/projects/secrets/settings/components/EditSecretForm';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { Secret } from '@/types/application';
|
import type { Secret } from '@/types/application';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
@@ -30,16 +33,20 @@ import { Fragment } from 'react';
|
|||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export default function SecretsPage() {
|
export default function SecretsPage() {
|
||||||
const { openDialog, openAlertDialog } = useDialog();
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
|
const { openDialog, openAlertDialog } = useDialog();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { data, loading, error } = useGetSecretsQuery({
|
const { data, loading, error, refetch } = useGetSecretsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const [deleteSecret] = useDeleteSecretMutation({
|
const [deleteSecret] = useDeleteSecretMutation({
|
||||||
refetchQueries: [GetSecretsDocument],
|
refetchQueries: [GetSecretsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -61,6 +68,19 @@ export default function SecretsPage() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await deleteSecretPromise;
|
await deleteSecretPromise;
|
||||||
|
await refetch();
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'Deleting secret...',
|
loadingMessage: 'Deleting secret...',
|
||||||
@@ -73,7 +93,7 @@ export default function SecretsPage() {
|
|||||||
function handleOpenCreator() {
|
function handleOpenCreator() {
|
||||||
openDialog({
|
openDialog({
|
||||||
title: 'Create Secret',
|
title: 'Create Secret',
|
||||||
component: <CreateSecretForm />,
|
component: <CreateSecretForm onSubmit={refetch} />,
|
||||||
props: {
|
props: {
|
||||||
titleProps: { className: '!pb-0' },
|
titleProps: { className: '!pb-0' },
|
||||||
PaperProps: { className: 'gap-2 max-w-md' },
|
PaperProps: { className: 'gap-2 max-w-md' },
|
||||||
@@ -136,7 +156,7 @@ export default function SecretsPage() {
|
|||||||
footer: { className: 'hidden' },
|
footer: { className: 'hidden' },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box className="grid grid-cols-2 gap-2 border-b-1 px-4 py-3">
|
<Box className="grid grid-cols-2 gap-2 px-4 py-3 border-b-1">
|
||||||
<Text className="font-medium">Secret Name</Text>
|
<Text className="font-medium">Secret Name</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -152,7 +172,7 @@ export default function SecretsPage() {
|
|||||||
<Dropdown.Trigger
|
<Dropdown.Trigger
|
||||||
asChild
|
asChild
|
||||||
hideChevron
|
hideChevron
|
||||||
className="absolute right-4 top-1/2 -translate-y-1/2"
|
className="absolute -translate-y-1/2 right-4 top-1/2"
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
|
|||||||
@@ -19,15 +19,20 @@ import { WebAuthnSettings } from '@/features/authentication/settings/components/
|
|||||||
import { WindowsLiveProviderSettings } from '@/features/authentication/settings/components/WindowsLiveProviderSettings';
|
import { WindowsLiveProviderSettings } from '@/features/authentication/settings/components/WindowsLiveProviderSettings';
|
||||||
import { WorkOsProviderSettings } from '@/features/authentication/settings/components/WorkOsProviderSettings';
|
import { WorkOsProviderSettings } from '@/features/authentication/settings/components/WorkOsProviderSettings';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { useGetSignInMethodsQuery } from '@/generated/graphql';
|
import { useGetSignInMethodsQuery } from '@/generated/graphql';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function SettingsSignInMethodsPage() {
|
export default function SettingsSignInMethodsPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { loading, error } = useGetSignInMethodsQuery({
|
const { loading, error } = useGetSignInMethodsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
fetchPolicy: 'network-only',
|
fetchPolicy: 'network-only',
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ApplyLocalSettingsDialog } from '@/components/common/ApplyLocalSettingsDialog';
|
||||||
|
import { useDialog } from '@/components/common/DialogProvider';
|
||||||
import { useUI } from '@/components/common/UIProvider';
|
import { useUI } from '@/components/common/UIProvider';
|
||||||
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
import { ControlledCheckbox } from '@/components/form/ControlledCheckbox';
|
||||||
import { Form } from '@/components/form/Form';
|
import { Form } from '@/components/form/Form';
|
||||||
@@ -8,6 +10,8 @@ import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
|||||||
import { Input } from '@/components/ui/v2/Input';
|
import { Input } from '@/components/ui/v2/Input';
|
||||||
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
import { UpgradeNotification } from '@/features/projects/common/components/UpgradeNotification';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||||
import {
|
import {
|
||||||
GetSmtpSettingsDocument,
|
GetSmtpSettingsDocument,
|
||||||
@@ -45,11 +49,15 @@ const smtpValidationSchema = yup
|
|||||||
export type SmtpFormValues = yup.InferType<typeof smtpValidationSchema>;
|
export type SmtpFormValues = yup.InferType<typeof smtpValidationSchema>;
|
||||||
|
|
||||||
export default function SMTPSettingsPage() {
|
export default function SMTPSettingsPage() {
|
||||||
|
const { openDialog } = useDialog();
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
const { maintenanceActive } = useUI();
|
const { maintenanceActive } = useUI();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { data, loading, error } = useGetSmtpSettingsQuery({
|
const { data, loading, error } = useGetSmtpSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { secure, host, port, user, method, sender } =
|
const { secure, host, port, user, method, sender } =
|
||||||
@@ -85,9 +93,10 @@ export default function SMTPSettingsPage() {
|
|||||||
|
|
||||||
const [updateConfig] = useUpdateConfigMutation({
|
const [updateConfig] = useUpdateConfigMutation({
|
||||||
refetchQueries: [GetSmtpSettingsDocument],
|
refetchQueries: [GetSmtpSettingsDocument],
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentProject.plan.isFree) {
|
if (isPlatform && currentProject?.plan?.isFree) {
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid max-w-5xl grid-flow-row gap-4 bg-transparent"
|
className="grid max-w-5xl grid-flow-row gap-4 bg-transparent"
|
||||||
@@ -129,6 +138,18 @@ export default function SMTPSettingsPage() {
|
|||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await updateConfigPromise;
|
await updateConfigPromise;
|
||||||
|
|
||||||
|
if (!isPlatform) {
|
||||||
|
openDialog({
|
||||||
|
title: 'Apply your changes',
|
||||||
|
component: <ApplyLocalSettingsDialog />,
|
||||||
|
props: {
|
||||||
|
PaperProps: {
|
||||||
|
className: 'max-w-2xl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loadingMessage: 'SMTP settings are being updated...',
|
loadingMessage: 'SMTP settings are being updated...',
|
||||||
|
|||||||
@@ -2,17 +2,22 @@ import { Container } from '@/components/layout/Container';
|
|||||||
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
import { SettingsLayout } from '@/components/layout/SettingsLayout';
|
||||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||||
|
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
|
||||||
import { StorageServiceVersionSettings } from '@/features/storage/settings/components/HasuraServiceVersionSettings';
|
import { StorageServiceVersionSettings } from '@/features/storage/settings/components/HasuraServiceVersionSettings';
|
||||||
import { HasuraStorageAVSettings } from '@/features/storage/settings/components/HasuraStorageAVSettings';
|
import { HasuraStorageAVSettings } from '@/features/storage/settings/components/HasuraStorageAVSettings';
|
||||||
|
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
|
||||||
import { useGetStorageSettingsQuery } from '@/utils/__generated__/graphql';
|
import { useGetStorageSettingsQuery } from '@/utils/__generated__/graphql';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
export default function StorageSettingsPage() {
|
export default function StorageSettingsPage() {
|
||||||
|
const isPlatform = useIsPlatform();
|
||||||
|
const localMimirClient = useLocalMimirClient();
|
||||||
const { currentProject } = useCurrentWorkspaceAndProject();
|
const { currentProject } = useCurrentWorkspaceAndProject();
|
||||||
|
|
||||||
const { loading, error } = useGetStorageSettingsQuery({
|
const { loading, error } = useGetStorageSettingsQuery({
|
||||||
variables: { appId: currentProject?.id },
|
variables: { appId: currentProject?.id },
|
||||||
skip: !currentProject,
|
skip: !currentProject,
|
||||||
|
...(!isPlatform ? { client: localMimirClient } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -31,7 +36,7 @@ export default function StorageSettingsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent"
|
className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"
|
||||||
rootClassName="bg-transparent"
|
rootClassName="bg-transparent"
|
||||||
>
|
>
|
||||||
<StorageServiceVersionSettings />
|
<StorageServiceVersionSettings />
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user