feat: introduce application auth clients tab in the admin panel (#1423)
* feat: introduce application auth clients tab in the admin panel * feat: introduce improvements * feat: use loading state returned from useMutation * feat: use error returned by useMutation hook
This commit is contained in:
1
packages/types/index.d.ts
vendored
1
packages/types/index.d.ts
vendored
@@ -462,6 +462,7 @@ type AppAuthClient = {
|
||||
appConfigId: string;
|
||||
authDefaults: string;
|
||||
formattedAuthDefaults: IJSONObject;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
type Notification = {
|
||||
|
@@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import type { IField } from '@automatisch/types';
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { FieldValues, SubmitHandler } from 'react-hook-form';
|
||||
import type { UseFormProps } from 'react-hook-form';
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import InputCreator from 'components/InputCreator';
|
||||
import Switch from 'components/Switch';
|
||||
import TextField from 'components/TextField';
|
||||
|
||||
import { Form } from './style';
|
||||
|
||||
type AdminApplicationAuthClientDialogProps = {
|
||||
title: string;
|
||||
authFields?: IField[];
|
||||
defaultValues: UseFormProps['defaultValues'];
|
||||
loading: boolean;
|
||||
submitting: boolean;
|
||||
disabled?: boolean;
|
||||
error?: ApolloError;
|
||||
submitHandler: SubmitHandler<FieldValues>;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export default function AdminApplicationAuthClientDialog(
|
||||
props: AdminApplicationAuthClientDialogProps
|
||||
): React.ReactElement {
|
||||
const {
|
||||
error,
|
||||
onClose,
|
||||
title,
|
||||
loading,
|
||||
submitHandler,
|
||||
authFields,
|
||||
submitting,
|
||||
defaultValues,
|
||||
disabled = false,
|
||||
} = props;
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
return (
|
||||
<Dialog open={true} onClose={onClose}>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
{error && (
|
||||
<Alert
|
||||
severity="error"
|
||||
sx={{ mt: 1, fontWeight: 500, wordBreak: 'break-all' }}
|
||||
>
|
||||
{error.message}
|
||||
</Alert>
|
||||
)}
|
||||
<DialogContent>
|
||||
{loading ? (
|
||||
<CircularProgress
|
||||
data-test="search-for-app-loader"
|
||||
sx={{ display: 'block', margin: '20px auto' }}
|
||||
/>
|
||||
) : (
|
||||
<DialogContentText tabIndex={-1} component="div">
|
||||
<Form
|
||||
onSubmit={submitHandler}
|
||||
defaultValues={defaultValues}
|
||||
render={({ formState: { isDirty } }) => (
|
||||
<>
|
||||
<Switch
|
||||
name="active"
|
||||
label={formatMessage('authClient.inputActive')}
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="name"
|
||||
label={formatMessage('authClient.inputName')}
|
||||
fullWidth
|
||||
/>
|
||||
{authFields?.map((field: IField) => (
|
||||
<InputCreator key={field.key} schema={field} />
|
||||
))}
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
sx={{ boxShadow: 2 }}
|
||||
loading={submitting}
|
||||
disabled={disabled || !isDirty}
|
||||
>
|
||||
{formatMessage('authClient.buttonSubmit')}
|
||||
</LoadingButton>
|
||||
</>
|
||||
)}
|
||||
></Form>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
import { styled } from '@mui/material/styles';
|
||||
import BaseForm from 'components/Form';
|
||||
|
||||
export const Form = styled(BaseForm)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(2),
|
||||
paddingTop: theme.spacing(1),
|
||||
}));
|
@@ -0,0 +1,89 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActionArea from '@mui/material/CardActionArea';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Button from '@mui/material/Button';
|
||||
|
||||
import * as URLS from 'config/urls';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useAppAuthClients from 'hooks/useAppAuthClients.ee';
|
||||
|
||||
import NoResultFound from 'components/NoResultFound';
|
||||
|
||||
type AdminApplicationAuthClientsProps = {
|
||||
appKey: string;
|
||||
};
|
||||
|
||||
function AdminApplicationAuthClients(
|
||||
props: AdminApplicationAuthClientsProps
|
||||
): React.ReactElement {
|
||||
const { appKey } = props;
|
||||
const formatMessage = useFormatMessage();
|
||||
const { appAuthClients, loading } = useAppAuthClients({ appKey });
|
||||
|
||||
if (loading)
|
||||
return <CircularProgress sx={{ display: 'block', margin: '20px auto' }} />;
|
||||
|
||||
if (!appAuthClients?.length) {
|
||||
return (
|
||||
<NoResultFound
|
||||
to={URLS.ADMIN_APP_AUTH_CLIENTS_CREATE(appKey)}
|
||||
text={formatMessage('adminAppsAuthClients.noAuthClients')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const sortedAuthClients = appAuthClients.slice().sort((a, b) => {
|
||||
if (a.id < b.id) {
|
||||
return -1;
|
||||
}
|
||||
if (a.id > b.id) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{sortedAuthClients.map((client) => (
|
||||
<Card sx={{ mb: 1 }} key={client.id}>
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
to={URLS.ADMIN_APP_AUTH_CLIENT(appKey, client.id)}
|
||||
>
|
||||
<CardContent>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="h6" noWrap>
|
||||
{client.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
size="small"
|
||||
color={client?.active ? 'success' : 'info'}
|
||||
variant={client?.active ? 'filled' : 'outlined'}
|
||||
label={formatMessage(
|
||||
client?.active
|
||||
? 'adminAppsAuthClients.statusActive'
|
||||
: 'adminAppsAuthClients.statusInactive'
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
</Card>
|
||||
))}
|
||||
<Stack justifyContent="flex-end" direction="row">
|
||||
<Link to={URLS.ADMIN_APP_AUTH_CLIENTS_CREATE(appKey)}>
|
||||
<Button variant="contained" sx={{ mt: 2 }} component="div">
|
||||
{formatMessage('createAuthClient.button')}
|
||||
</Button>
|
||||
</Link>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminApplicationAuthClients;
|
@@ -0,0 +1,112 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { IApp } from '@automatisch/types';
|
||||
import { FieldValues, SubmitHandler } from 'react-hook-form';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { CREATE_APP_CONFIG } from 'graphql/mutations/create-app-config';
|
||||
import { CREATE_APP_AUTH_CLIENT } from 'graphql/mutations/create-app-auth-client';
|
||||
|
||||
import useAppConfig from 'hooks/useAppConfig.ee';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
|
||||
import AdminApplicationAuthClientDialog from 'components/AdminApplicationAuthClientDialog';
|
||||
|
||||
type AdminApplicationCreateAuthClientProps = {
|
||||
appKey: string;
|
||||
application: IApp;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export default function AdminApplicationCreateAuthClient(
|
||||
props: AdminApplicationCreateAuthClientProps
|
||||
): React.ReactElement {
|
||||
const { appKey, application, onClose } = props;
|
||||
const { auth } = application;
|
||||
const formatMessage = useFormatMessage();
|
||||
const { appConfig, loading: loadingAppConfig } = useAppConfig(appKey);
|
||||
const [
|
||||
createAppConfig,
|
||||
{ loading: loadingCreateAppConfig, error: createAppConfigError },
|
||||
] = useMutation(CREATE_APP_CONFIG, {
|
||||
refetchQueries: ['GetAppConfig'],
|
||||
context: { autoSnackbar: false },
|
||||
});
|
||||
const [
|
||||
createAppAuthClient,
|
||||
{ loading: loadingCreateAppAuthClient, error: createAppAuthClientError },
|
||||
] = useMutation(CREATE_APP_AUTH_CLIENT, {
|
||||
refetchQueries: ['GetAppAuthClients'],
|
||||
context: { autoSnackbar: false },
|
||||
});
|
||||
|
||||
const submitHandler: SubmitHandler<FieldValues> = async (values) => {
|
||||
let appConfigId = appConfig?.id;
|
||||
|
||||
if (!appConfigId) {
|
||||
const { data: appConfigData } = await createAppConfig({
|
||||
variables: {
|
||||
input: {
|
||||
key: appKey,
|
||||
allowCustomConnection: false,
|
||||
shared: false,
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
appConfigId = appConfigData.createAppConfig.id;
|
||||
}
|
||||
|
||||
const { name, active, ...formattedAuthDefaults } = values;
|
||||
|
||||
await createAppAuthClient({
|
||||
variables: {
|
||||
input: {
|
||||
appConfigId,
|
||||
name,
|
||||
active,
|
||||
formattedAuthDefaults,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
onClose();
|
||||
};
|
||||
|
||||
const getAuthFieldsDefaultValues = useCallback(() => {
|
||||
if (!auth?.fields) {
|
||||
return {};
|
||||
}
|
||||
const defaultValues: {
|
||||
[key: string]: any;
|
||||
} = {};
|
||||
auth.fields.forEach((field) => {
|
||||
if (field.value || field.type !== 'string') {
|
||||
defaultValues[field.key] = field.value;
|
||||
} else if (field.type === 'string') {
|
||||
defaultValues[field.key] = '';
|
||||
}
|
||||
});
|
||||
return defaultValues;
|
||||
}, [auth?.fields]);
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: '',
|
||||
active: false,
|
||||
...getAuthFieldsDefaultValues(),
|
||||
}),
|
||||
[getAuthFieldsDefaultValues]
|
||||
);
|
||||
|
||||
return (
|
||||
<AdminApplicationAuthClientDialog
|
||||
onClose={onClose}
|
||||
error={createAppConfigError || createAppAuthClientError}
|
||||
title={formatMessage('createAuthClient.title')}
|
||||
loading={loadingAppConfig}
|
||||
submitHandler={submitHandler}
|
||||
authFields={auth?.fields}
|
||||
submitting={loadingCreateAppConfig || loadingCreateAppAuthClient}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
);
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import type { IApp } from '@automatisch/types';
|
||||
import { FieldValues, SubmitHandler } from 'react-hook-form';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { UPDATE_APP_AUTH_CLIENT } from 'graphql/mutations/update-app-auth-client';
|
||||
|
||||
import useAppAuthClient from 'hooks/useAppAuthClient.ee';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import AdminApplicationAuthClientDialog from 'components/AdminApplicationAuthClientDialog';
|
||||
|
||||
type AdminApplicationUpdateAuthClientProps = {
|
||||
application: IApp;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export default function AdminApplicationUpdateAuthClient(
|
||||
props: AdminApplicationUpdateAuthClientProps
|
||||
): React.ReactElement {
|
||||
const { application, onClose } = props;
|
||||
const { auth } = application;
|
||||
const authFields = auth?.fields?.map((field) => ({
|
||||
...field,
|
||||
required: false,
|
||||
}));
|
||||
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
const { clientId } = useParams();
|
||||
const { appAuthClient, loading: loadingAuthClient } =
|
||||
useAppAuthClient(clientId);
|
||||
const [updateAppAuthClient, { loading: loadingUpdateAppAuthClient, error }] =
|
||||
useMutation(UPDATE_APP_AUTH_CLIENT, {
|
||||
refetchQueries: ['GetAppAuthClients'],
|
||||
context: { autoSnackbar: false },
|
||||
});
|
||||
|
||||
const submitHandler: SubmitHandler<FieldValues> = async (values) => {
|
||||
if (!appAuthClient) {
|
||||
return;
|
||||
}
|
||||
const { name, active, ...formattedAuthDefaults } = values;
|
||||
await updateAppAuthClient({
|
||||
variables: {
|
||||
input: {
|
||||
id: appAuthClient.id,
|
||||
name,
|
||||
active,
|
||||
formattedAuthDefaults,
|
||||
},
|
||||
},
|
||||
});
|
||||
onClose();
|
||||
};
|
||||
|
||||
const getAuthFieldsDefaultValues = useCallback(() => {
|
||||
if (!authFields) {
|
||||
return {};
|
||||
}
|
||||
const defaultValues: {
|
||||
[key: string]: any;
|
||||
} = {};
|
||||
authFields.forEach((field) => {
|
||||
if (field.value || field.type !== 'string') {
|
||||
defaultValues[field.key] = field.value;
|
||||
} else if (field.type === 'string') {
|
||||
defaultValues[field.key] = '';
|
||||
}
|
||||
});
|
||||
return defaultValues;
|
||||
}, [auth?.fields]);
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: appAuthClient?.name || '',
|
||||
active: appAuthClient?.active || false,
|
||||
...getAuthFieldsDefaultValues(),
|
||||
}),
|
||||
[appAuthClient, getAuthFieldsDefaultValues]
|
||||
);
|
||||
|
||||
return (
|
||||
<AdminApplicationAuthClientDialog
|
||||
onClose={onClose}
|
||||
error={error}
|
||||
title={formatMessage('updateAuthClient.title')}
|
||||
loading={loadingAuthClient}
|
||||
submitHandler={submitHandler}
|
||||
authFields={authFields}
|
||||
submitting={loadingUpdateAppAuthClient}
|
||||
defaultValues={defaultValues}
|
||||
disabled={!appAuthClient}
|
||||
/>
|
||||
);
|
||||
}
|
@@ -17,7 +17,7 @@ type AppAuthClientsDialogProps = {
|
||||
|
||||
export default function AppAuthClientsDialog(props: AppAuthClientsDialogProps) {
|
||||
const { appKey, onClientClick, onClose } = props;
|
||||
const { appAuthClients } = useAppAuthClients(appKey);
|
||||
const { appAuthClients } = useAppAuthClients({ appKey, active: true });
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
React.useEffect(
|
||||
|
@@ -107,6 +107,10 @@ export const ADMIN_APP_SETTINGS = (appKey: string) =>
|
||||
`${ADMIN_SETTINGS}/apps/${appKey}/settings`;
|
||||
export const ADMIN_APP_AUTH_CLIENTS = (appKey: string) =>
|
||||
`${ADMIN_SETTINGS}/apps/${appKey}/auth-clients`;
|
||||
export const ADMIN_APP_AUTH_CLIENT = (appKey: string, id: string) =>
|
||||
`${ADMIN_SETTINGS}/apps/${appKey}/auth-clients/${id}`;
|
||||
export const ADMIN_APP_AUTH_CLIENTS_CREATE = (appKey: string) =>
|
||||
`${ADMIN_SETTINGS}/apps/${appKey}/auth-clients/create`;
|
||||
|
||||
export const DASHBOARD = FLOWS;
|
||||
|
||||
|
12
packages/web/src/graphql/mutations/create-app-auth-client.ts
Normal file
12
packages/web/src/graphql/mutations/create-app-auth-client.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const CREATE_APP_AUTH_CLIENT = gql`
|
||||
mutation CreateAppAuthClient($input: CreateAppAuthClientInput) {
|
||||
createAppAuthClient(input: $input) {
|
||||
id
|
||||
appConfigId
|
||||
name
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
12
packages/web/src/graphql/mutations/update-app-auth-client.ts
Normal file
12
packages/web/src/graphql/mutations/update-app-auth-client.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_APP_AUTH_CLIENT = gql`
|
||||
mutation UpdateAppAuthClient($input: UpdateAppAuthClientInput) {
|
||||
updateAppAuthClient(input: $input) {
|
||||
id
|
||||
appConfigId
|
||||
name
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,28 +1,26 @@
|
||||
import { useLazyQuery } from '@apollo/client';
|
||||
import { AppConfig } from '@automatisch/types';
|
||||
import { AppAuthClient } from '@automatisch/types';
|
||||
import * as React from 'react';
|
||||
|
||||
import { GET_APP_AUTH_CLIENT } from 'graphql/queries/get-app-auth-client.ee';
|
||||
|
||||
type QueryResponse = {
|
||||
getAppAuthClient: AppConfig;
|
||||
}
|
||||
getAppAuthClient: AppAuthClient;
|
||||
};
|
||||
|
||||
export default function useAppAuthClient(id: string) {
|
||||
const [
|
||||
getAppAuthClient,
|
||||
{
|
||||
data,
|
||||
loading
|
||||
}
|
||||
] = useLazyQuery<QueryResponse>(GET_APP_AUTH_CLIENT);
|
||||
export default function useAppAuthClient(id?: string) {
|
||||
const [getAppAuthClient, { data, loading }] =
|
||||
useLazyQuery<QueryResponse>(GET_APP_AUTH_CLIENT);
|
||||
const appAuthClient = data?.getAppAuthClient;
|
||||
|
||||
React.useEffect(function fetchUponId() {
|
||||
if (!id) return;
|
||||
React.useEffect(
|
||||
function fetchUponId() {
|
||||
if (!id) return;
|
||||
|
||||
getAppAuthClient({ variables: { id } });
|
||||
}, [id]);
|
||||
getAppAuthClient({ variables: { id } });
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
return {
|
||||
appAuthClient,
|
||||
|
@@ -6,25 +6,33 @@ import { GET_APP_AUTH_CLIENTS } from 'graphql/queries/get-app-auth-clients.ee';
|
||||
|
||||
type QueryResponse = {
|
||||
getAppAuthClients: AppAuthClient[];
|
||||
}
|
||||
};
|
||||
|
||||
export default function useAppAuthClient(appKey: string) {
|
||||
const [
|
||||
getAppAuthClients,
|
||||
export default function useAppAuthClient({
|
||||
appKey,
|
||||
active,
|
||||
}: {
|
||||
appKey: string;
|
||||
active?: boolean;
|
||||
}) {
|
||||
const [getAppAuthClients, { data, loading }] = useLazyQuery<QueryResponse>(
|
||||
GET_APP_AUTH_CLIENTS,
|
||||
{
|
||||
data,
|
||||
loading
|
||||
context: { autoSnackbar: false },
|
||||
}
|
||||
] = useLazyQuery<QueryResponse>(GET_APP_AUTH_CLIENTS, {
|
||||
context: { autoSnackbar: false },
|
||||
});
|
||||
);
|
||||
const appAuthClients = data?.getAppAuthClients;
|
||||
|
||||
React.useEffect(function fetchUponAppKey() {
|
||||
if (!appKey) return;
|
||||
React.useEffect(
|
||||
function fetchUponAppKey() {
|
||||
if (!appKey) return;
|
||||
|
||||
getAppAuthClients({ variables: { appKey, active: true } });
|
||||
}, [appKey]);
|
||||
getAppAuthClients({
|
||||
variables: { appKey, ...(typeof active === 'boolean' && { active }) },
|
||||
});
|
||||
},
|
||||
[appKey]
|
||||
);
|
||||
|
||||
return {
|
||||
appAuthClients,
|
||||
|
@@ -256,5 +256,14 @@
|
||||
"adminAppsSettings.shared": "Shared",
|
||||
"adminAppsSettings.disabled": "Disabled",
|
||||
"adminAppsSettings.save": "Save",
|
||||
"adminAppsSettings.successfullySaved": "Settings have been saved."
|
||||
"adminAppsSettings.successfullySaved": "Settings have been saved.",
|
||||
"adminAppsAuthClients.noAuthClients": "You don't have any auth clients yet.",
|
||||
"adminAppsAuthClients.statusActive": "Active",
|
||||
"adminAppsAuthClients.statusInactive": "Inactive",
|
||||
"createAuthClient.button": "Create auth client",
|
||||
"createAuthClient.title": "Create auth client",
|
||||
"authClient.buttonSubmit": "Submit",
|
||||
"authClient.inputName": "Name",
|
||||
"authClient.inputActive": "Active",
|
||||
"updateAuthClient.title": "Update auth client"
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import {
|
||||
Routes,
|
||||
useParams,
|
||||
useMatch,
|
||||
useNavigate,
|
||||
} from 'react-router-dom';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
@@ -23,6 +24,9 @@ import AppIcon from 'components/AppIcon';
|
||||
import Container from 'components/Container';
|
||||
import PageTitle from 'components/PageTitle';
|
||||
import AdminApplicationSettings from 'components/AdminApplicationSettings';
|
||||
import AdminApplicationAuthClients from 'components/AdminApplicationAuthClients';
|
||||
import AdminApplicationCreateAuthClient from 'components/AdminApplicationCreateAuthClient';
|
||||
import AdminApplicationUpdateAuthClient from 'components/AdminApplicationUpdateAuthClient';
|
||||
|
||||
type AdminApplicationParams = {
|
||||
appKey: string;
|
||||
@@ -32,6 +36,7 @@ export default function AdminApplication(): React.ReactElement | null {
|
||||
const theme = useTheme();
|
||||
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const formatMessage = useFormatMessage();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const connectionsPathMatch = useMatch({
|
||||
path: URLS.ADMIN_APP_CONNECTIONS_PATTERN,
|
||||
@@ -51,79 +56,104 @@ export default function AdminApplication(): React.ReactElement | null {
|
||||
|
||||
const app = data?.getApp || {};
|
||||
|
||||
const goToAuthClientsPage = () => navigate('auth-clients');
|
||||
|
||||
if (loading) return null;
|
||||
|
||||
return (
|
||||
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
||||
<Grid container item xs={12} sm={10} md={9}>
|
||||
<Grid container sx={{ mb: 3 }} alignItems="center">
|
||||
<Grid item xs="auto" sx={{ mr: 3 }}>
|
||||
<AppIcon
|
||||
url={app.iconUrl}
|
||||
color={app.primaryColor}
|
||||
name={app.name}
|
||||
/>
|
||||
<>
|
||||
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
||||
<Grid container item xs={12} sm={10} md={9}>
|
||||
<Grid container sx={{ mb: 3 }} alignItems="center">
|
||||
<Grid item xs="auto" sx={{ mr: 3 }}>
|
||||
<AppIcon
|
||||
url={app.iconUrl}
|
||||
color={app.primaryColor}
|
||||
name={app.name}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<PageTitle>{app.name}</PageTitle>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<PageTitle>{app.name}</PageTitle>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||
<Tabs
|
||||
variant={matchSmallScreens ? 'fullWidth' : undefined}
|
||||
value={
|
||||
settingsPathMatch?.pattern?.path ||
|
||||
connectionsPathMatch?.pattern?.path ||
|
||||
authClientsPathMatch?.pattern?.path
|
||||
}
|
||||
>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.settings')}
|
||||
to={URLS.ADMIN_APP_SETTINGS(appKey)}
|
||||
value={URLS.ADMIN_APP_SETTINGS_PATTERN}
|
||||
component={Link}
|
||||
/>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.authClients')}
|
||||
to={URLS.ADMIN_APP_AUTH_CLIENTS(appKey)}
|
||||
value={URLS.ADMIN_APP_AUTH_CLIENTS_PATTERN}
|
||||
component={Link}
|
||||
/>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.connections')}
|
||||
to={URLS.ADMIN_APP_CONNECTIONS(appKey)}
|
||||
value={URLS.ADMIN_APP_CONNECTIONS_PATTERN}
|
||||
disabled={!app.supportsConnections}
|
||||
component={Link}
|
||||
/>
|
||||
</Tabs>
|
||||
</Box>
|
||||
<Grid container>
|
||||
<Grid item xs>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||
<Tabs
|
||||
variant={matchSmallScreens ? 'fullWidth' : undefined}
|
||||
value={
|
||||
settingsPathMatch?.pattern?.path ||
|
||||
connectionsPathMatch?.pattern?.path ||
|
||||
authClientsPathMatch?.pattern?.path
|
||||
}
|
||||
>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.settings')}
|
||||
to={URLS.ADMIN_APP_SETTINGS(appKey)}
|
||||
value={URLS.ADMIN_APP_SETTINGS_PATTERN}
|
||||
component={Link}
|
||||
/>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.authClients')}
|
||||
to={URLS.ADMIN_APP_AUTH_CLIENTS(appKey)}
|
||||
value={URLS.ADMIN_APP_AUTH_CLIENTS_PATTERN}
|
||||
component={Link}
|
||||
/>
|
||||
<Tab
|
||||
label={formatMessage('adminApps.connections')}
|
||||
to={URLS.ADMIN_APP_CONNECTIONS(appKey)}
|
||||
value={URLS.ADMIN_APP_CONNECTIONS_PATTERN}
|
||||
disabled={!app.supportsConnections}
|
||||
component={Link}
|
||||
/>
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<Routes>
|
||||
<Route
|
||||
path={`/settings/*`}
|
||||
element={<AdminApplicationSettings appKey={appKey} />}
|
||||
/>
|
||||
<Route
|
||||
path={`/auth-clients/*`}
|
||||
element={<div>Auth clients</div>}
|
||||
/>
|
||||
<Route
|
||||
path={`/connections/*`}
|
||||
element={<div>App connections</div>}
|
||||
/>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<Navigate to={URLS.ADMIN_APP_SETTINGS(appKey)} replace />
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
<Routes>
|
||||
<Route
|
||||
path={`/settings/*`}
|
||||
element={<AdminApplicationSettings appKey={appKey} />}
|
||||
/>
|
||||
<Route
|
||||
path={`/auth-clients/*`}
|
||||
element={<AdminApplicationAuthClients appKey={appKey} />}
|
||||
/>
|
||||
<Route
|
||||
path={`/connections/*`}
|
||||
element={<div>App connections</div>}
|
||||
/>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<Navigate to={URLS.ADMIN_APP_SETTINGS(appKey)} replace />
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
</Container>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/auth-clients/create"
|
||||
element={
|
||||
<AdminApplicationCreateAuthClient
|
||||
application={app}
|
||||
onClose={goToAuthClientsPage}
|
||||
appKey={appKey}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/auth-clients/:clientId"
|
||||
element={
|
||||
<AdminApplicationUpdateAuthClient
|
||||
application={app}
|
||||
onClose={goToAuthClientsPage}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user