mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
fix(console): fix application refresh token settings (#5244)
This commit is contained in:
parent
d04bc9d19d
commit
61e5d7f21c
4 changed files with 272 additions and 250 deletions
|
@ -0,0 +1,231 @@
|
|||
import {
|
||||
ApplicationType,
|
||||
type Application,
|
||||
type ApplicationResponse,
|
||||
type SnakeCaseOidcConfig,
|
||||
} from '@logto/schemas';
|
||||
import { useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import Delete from '@/assets/icons/delete.svg';
|
||||
import File from '@/assets/icons/file.svg';
|
||||
import ApplicationIcon from '@/components/ApplicationIcon';
|
||||
import DetailsForm from '@/components/DetailsForm';
|
||||
import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader';
|
||||
import Drawer from '@/components/Drawer';
|
||||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
||||
import { ApplicationDetailsTabs } from '@/consts';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
|
||||
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
|
||||
import TabWrapper from '@/ds-components/TabWrapper';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
import { trySubmitSafe } from '@/utils/form';
|
||||
|
||||
import Branding from '../components/Branding';
|
||||
import EndpointsAndCredentials from '../components/EndpointsAndCredentials';
|
||||
import GuideDrawer from '../components/GuideDrawer';
|
||||
import MachineLogs from '../components/MachineLogs';
|
||||
import MachineToMachineApplicationRoles from '../components/MachineToMachineApplicationRoles';
|
||||
import Permissions from '../components/Permissions';
|
||||
import RefreshTokenSettings from '../components/RefreshTokenSettings';
|
||||
import Settings from '../components/Settings';
|
||||
import * as styles from '../index.module.scss';
|
||||
import { type ApplicationForm, applicationFormDataParser } from '../utils';
|
||||
|
||||
type Props = {
|
||||
data: ApplicationResponse;
|
||||
oidcConfig: SnakeCaseOidcConfig;
|
||||
onApplicationUpdated: () => void;
|
||||
};
|
||||
|
||||
function ApplicationDetailsContent({ data, oidcConfig, onApplicationUpdated }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { tab } = useParams();
|
||||
const { navigate } = useTenantPathname();
|
||||
|
||||
const formMethods = useForm<ApplicationForm>({
|
||||
defaultValues: applicationFormDataParser.fromResponse(data),
|
||||
});
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = formMethods;
|
||||
|
||||
const [isReadmeOpen, setIsReadmeOpen] = useState(false);
|
||||
const [isDeleteFormOpen, setIsDeleteFormOpen] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [isDeleted, setIsDeleted] = useState(false);
|
||||
const api = useApi();
|
||||
|
||||
const onSubmit = handleSubmit(
|
||||
trySubmitSafe(async (formData) => {
|
||||
if (isSubmitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
await api
|
||||
.patch(`api/applications/${data.id}`, {
|
||||
json: applicationFormDataParser.toUpdateApplicationData(formData),
|
||||
})
|
||||
.json<Application>();
|
||||
reset(formData);
|
||||
onApplicationUpdated();
|
||||
toast.success(t('general.saved'));
|
||||
})
|
||||
);
|
||||
|
||||
const onDelete = async () => {
|
||||
if (isDeleting) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await api.delete(`api/applications/${data.id}`);
|
||||
setIsDeleted(true);
|
||||
setIsDeleting(false);
|
||||
setIsDeleteFormOpen(false);
|
||||
toast.success(t('application_details.application_deleted', { name: data.name }));
|
||||
navigate(`/applications`);
|
||||
} catch {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onCloseDrawer = () => {
|
||||
setIsReadmeOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DetailsPageHeader
|
||||
icon={<ApplicationIcon type={data.type} />}
|
||||
title={data.name}
|
||||
primaryTag={t(`${applicationTypeI18nKey[data.type]}.title`)}
|
||||
identifier={{ name: 'App ID', value: data.id }}
|
||||
additionalActionButton={{
|
||||
title: 'application_details.check_guide',
|
||||
icon: <File />,
|
||||
onClick: () => {
|
||||
setIsReadmeOpen(true);
|
||||
},
|
||||
}}
|
||||
actionMenuItems={[
|
||||
{
|
||||
type: 'danger',
|
||||
title: 'general.delete',
|
||||
icon: <Delete />,
|
||||
onClick: () => {
|
||||
setIsDeleteFormOpen(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Drawer isOpen={isReadmeOpen} onClose={onCloseDrawer}>
|
||||
<GuideDrawer app={data} onClose={onCloseDrawer} />
|
||||
</Drawer>
|
||||
<DeleteConfirmModal
|
||||
isOpen={isDeleteFormOpen}
|
||||
isLoading={isDeleting}
|
||||
expectedInput={data.name}
|
||||
inputPlaceholder={t('application_details.enter_your_application_name')}
|
||||
className={styles.deleteConfirm}
|
||||
onCancel={() => {
|
||||
setIsDeleteFormOpen(false);
|
||||
}}
|
||||
onConfirm={onDelete}
|
||||
>
|
||||
<div className={styles.description}>
|
||||
<Trans components={{ span: <span className={styles.highlight} /> }}>
|
||||
{t('application_details.delete_description', { name: data.name })}
|
||||
</Trans>
|
||||
</div>
|
||||
</DeleteConfirmModal>
|
||||
<TabNav>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Settings}`}>
|
||||
{t('application_details.settings')}
|
||||
</TabNavItem>
|
||||
{data.type === ApplicationType.MachineToMachine && (
|
||||
<>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Roles}`}>
|
||||
{t('application_details.application_roles')}
|
||||
</TabNavItem>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Logs}`}>
|
||||
{t('application_details.machine_logs')}
|
||||
</TabNavItem>
|
||||
</>
|
||||
)}
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
<>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Permissions}`}>
|
||||
{t('application_details.permissions.name')}
|
||||
</TabNavItem>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Branding}`}>
|
||||
{t('application_details.branding.name')}
|
||||
</TabNavItem>
|
||||
</>
|
||||
)}
|
||||
</TabNav>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Settings}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<FormProvider {...formMethods}>
|
||||
<DetailsForm
|
||||
isDirty={isDirty}
|
||||
isSubmitting={isSubmitting}
|
||||
onDiscard={reset}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<Settings data={data} />
|
||||
<EndpointsAndCredentials app={data} oidcConfig={oidcConfig} />
|
||||
{data.type !== ApplicationType.MachineToMachine && <RefreshTokenSettings data={data} />}
|
||||
</DetailsForm>
|
||||
</FormProvider>
|
||||
</TabWrapper>
|
||||
|
||||
{data.type === ApplicationType.MachineToMachine && (
|
||||
<>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Roles}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<MachineToMachineApplicationRoles application={data} />
|
||||
</TabWrapper>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Logs}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<MachineLogs applicationId={data.id} />
|
||||
</TabWrapper>
|
||||
</>
|
||||
)}
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
<>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Permissions}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<Permissions application={data} />
|
||||
</TabWrapper>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Branding}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<Branding application={data} />
|
||||
</TabWrapper>
|
||||
</>
|
||||
)}
|
||||
<UnsavedChangesAlertModal hasUnsavedChanges={!isDeleted && isDirty} onConfirm={reset} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ApplicationDetailsContent;
|
|
@ -37,4 +37,3 @@
|
|||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,63 +1,22 @@
|
|||
import { withAppInsights } from '@logto/app-insights/react';
|
||||
import {
|
||||
type Application,
|
||||
type ApplicationResponse,
|
||||
type SnakeCaseOidcConfig,
|
||||
customClientMetadataDefault,
|
||||
ApplicationType,
|
||||
} from '@logto/schemas';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { type ApplicationResponse, type SnakeCaseOidcConfig } from '@logto/schemas';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Delete from '@/assets/icons/delete.svg';
|
||||
import File from '@/assets/icons/file.svg';
|
||||
import ApplicationIcon from '@/components/ApplicationIcon';
|
||||
import DetailsForm from '@/components/DetailsForm';
|
||||
import DetailsPage from '@/components/DetailsPage';
|
||||
import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader';
|
||||
import Drawer from '@/components/Drawer';
|
||||
import PageMeta from '@/components/PageMeta';
|
||||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
||||
import { ApplicationDetailsTabs } from '@/consts';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import { openIdProviderConfigPath } from '@/consts/oidc';
|
||||
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
|
||||
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
|
||||
import TabWrapper from '@/ds-components/TabWrapper';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
import { trySubmitSafe } from '@/utils/form';
|
||||
|
||||
import Branding from './components/Branding';
|
||||
import EndpointsAndCredentials from './components/EndpointsAndCredentials';
|
||||
import GuideDrawer from './components/GuideDrawer';
|
||||
import ApplicationDetailsContent from './ApplicationDetailsContent';
|
||||
import GuideModal from './components/GuideModal';
|
||||
import MachineLogs from './components/MachineLogs';
|
||||
import MachineToMachineApplicationRoles from './components/MachineToMachineApplicationRoles';
|
||||
import Permissions from './components/Permissions';
|
||||
import RefreshTokenSettings from './components/RefreshTokenSettings';
|
||||
import Settings from './components/Settings';
|
||||
import * as styles from './index.module.scss';
|
||||
import { type ApplicationForm, applicationFormDataParser } from './utils';
|
||||
|
||||
const mapToUriFormatArrays = (value?: string[]) =>
|
||||
value?.filter(Boolean).map((uri) => decodeURIComponent(uri));
|
||||
|
||||
const mapToUriOriginFormatArrays = (value?: string[]) =>
|
||||
value?.filter(Boolean).map((uri) => decodeURIComponent(uri.replace(/\/*$/, '')));
|
||||
|
||||
function ApplicationDetails() {
|
||||
const { id, guideId, tab } = useParams();
|
||||
const { id, guideId } = useParams();
|
||||
const { navigate, match } = useTenantPathname();
|
||||
const isGuideView = !!id && !!guideId && match(`/applications/${id}/guide/${guideId}`);
|
||||
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data, error, mutate } = useSWR<ApplicationResponse, RequestError>(
|
||||
id && `api/applications/${id}`
|
||||
);
|
||||
|
@ -70,85 +29,6 @@ function ApplicationDetails() {
|
|||
|
||||
const isLoading = (!data && !error) || (!oidcConfig && !fetchOidcConfigError);
|
||||
const requestError = error ?? fetchOidcConfigError;
|
||||
const [isReadmeOpen, setIsReadmeOpen] = useState(false);
|
||||
const [isDeleteFormOpen, setIsDeleteFormOpen] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [isDeleted, setIsDeleted] = useState(false);
|
||||
const api = useApi();
|
||||
const formMethods = useForm<ApplicationForm>({
|
||||
defaultValues: { customClientMetadata: customClientMetadataDefault, isAdmin: false },
|
||||
});
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = formMethods;
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
reset(applicationFormDataParser.fromResponse(data));
|
||||
}, [data, isDirty, reset]);
|
||||
|
||||
const onSubmit = handleSubmit(
|
||||
trySubmitSafe(async (formData) => {
|
||||
if (!data || isSubmitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
await api
|
||||
.patch(`api/applications/${data.id}`, {
|
||||
json: {
|
||||
...formData,
|
||||
oidcClientMetadata: {
|
||||
...formData.oidcClientMetadata,
|
||||
redirectUris: mapToUriFormatArrays(formData.oidcClientMetadata.redirectUris),
|
||||
postLogoutRedirectUris: mapToUriFormatArrays(
|
||||
formData.oidcClientMetadata.postLogoutRedirectUris
|
||||
),
|
||||
},
|
||||
customClientMetadata: {
|
||||
...formData.customClientMetadata,
|
||||
corsAllowedOrigins: mapToUriOriginFormatArrays(
|
||||
formData.customClientMetadata.corsAllowedOrigins
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
.json<Application>();
|
||||
reset(formData);
|
||||
void mutate();
|
||||
toast.success(t('general.saved'));
|
||||
})
|
||||
);
|
||||
|
||||
const onDelete = async () => {
|
||||
if (!data || isDeleting) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await api.delete(`api/applications/${data.id}`);
|
||||
setIsDeleted(true);
|
||||
setIsDeleting(false);
|
||||
setIsDeleteFormOpen(false);
|
||||
toast.success(t('application_details.application_deleted', { name: data.name }));
|
||||
navigate(`/applications`);
|
||||
} catch {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onCloseDrawer = () => {
|
||||
setIsReadmeOpen(false);
|
||||
};
|
||||
|
||||
if (isGuideView) {
|
||||
return (
|
||||
|
@ -175,131 +55,12 @@ function ApplicationDetails() {
|
|||
>
|
||||
<PageMeta titleKey="application_details.page_title" />
|
||||
{data && oidcConfig && (
|
||||
<>
|
||||
<DetailsPageHeader
|
||||
icon={<ApplicationIcon type={data.type} />}
|
||||
title={data.name}
|
||||
primaryTag={t(`${applicationTypeI18nKey[data.type]}.title`)}
|
||||
identifier={{ name: 'App ID', value: data.id }}
|
||||
additionalActionButton={{
|
||||
title: 'application_details.check_guide',
|
||||
icon: <File />,
|
||||
onClick: () => {
|
||||
setIsReadmeOpen(true);
|
||||
},
|
||||
}}
|
||||
actionMenuItems={[
|
||||
{
|
||||
type: 'danger',
|
||||
title: 'general.delete',
|
||||
icon: <Delete />,
|
||||
onClick: () => {
|
||||
setIsDeleteFormOpen(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Drawer isOpen={isReadmeOpen} onClose={onCloseDrawer}>
|
||||
<GuideDrawer app={data} onClose={onCloseDrawer} />
|
||||
</Drawer>
|
||||
<DeleteConfirmModal
|
||||
isOpen={isDeleteFormOpen}
|
||||
isLoading={isDeleting}
|
||||
expectedInput={data.name}
|
||||
inputPlaceholder={t('application_details.enter_your_application_name')}
|
||||
className={styles.deleteConfirm}
|
||||
onCancel={() => {
|
||||
setIsDeleteFormOpen(false);
|
||||
}}
|
||||
onConfirm={onDelete}
|
||||
>
|
||||
<div className={styles.description}>
|
||||
<Trans components={{ span: <span className={styles.highlight} /> }}>
|
||||
{t('application_details.delete_description', { name: data.name })}
|
||||
</Trans>
|
||||
</div>
|
||||
</DeleteConfirmModal>
|
||||
<TabNav>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Settings}`}>
|
||||
{t('application_details.settings')}
|
||||
</TabNavItem>
|
||||
{data.type === ApplicationType.MachineToMachine && (
|
||||
<>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Roles}`}>
|
||||
{t('application_details.application_roles')}
|
||||
</TabNavItem>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Logs}`}>
|
||||
{t('application_details.machine_logs')}
|
||||
</TabNavItem>
|
||||
</>
|
||||
)}
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
<>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Permissions}`}>
|
||||
{t('application_details.permissions.name')}
|
||||
</TabNavItem>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Branding}`}>
|
||||
{t('application_details.branding.name')}
|
||||
</TabNavItem>
|
||||
</>
|
||||
)}
|
||||
</TabNav>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Settings}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<FormProvider {...formMethods}>
|
||||
<DetailsForm
|
||||
isDirty={isDirty}
|
||||
isSubmitting={isSubmitting}
|
||||
onDiscard={reset}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<Settings data={data} />
|
||||
<EndpointsAndCredentials app={data} oidcConfig={oidcConfig} />
|
||||
{data.type !== ApplicationType.MachineToMachine && (
|
||||
<RefreshTokenSettings data={data} />
|
||||
)}
|
||||
</DetailsForm>
|
||||
</FormProvider>
|
||||
</TabWrapper>
|
||||
|
||||
{data.type === ApplicationType.MachineToMachine && (
|
||||
<>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Roles}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<MachineToMachineApplicationRoles application={data} />
|
||||
</TabWrapper>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Logs}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<MachineLogs applicationId={data.id} />
|
||||
</TabWrapper>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
<>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Permissions}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<Permissions application={data} />
|
||||
</TabWrapper>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Branding}
|
||||
className={styles.tabContainer}
|
||||
>
|
||||
<Branding application={data} />
|
||||
</TabWrapper>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
<ApplicationDetailsContent
|
||||
data={data}
|
||||
oidcConfig={oidcConfig}
|
||||
onApplicationUpdated={mutate}
|
||||
/>
|
||||
)}
|
||||
<UnsavedChangesAlertModal hasUnsavedChanges={!isDeleted && isDirty} onConfirm={reset} />
|
||||
</DetailsPage>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
import { type ApplicationResponse } from '@logto/schemas';
|
||||
import {
|
||||
customClientMetadataDefault,
|
||||
type ApplicationResponse,
|
||||
type Application,
|
||||
} from '@logto/schemas';
|
||||
|
||||
export type ApplicationForm = Pick<
|
||||
ApplicationResponse,
|
||||
'name' | 'description' | 'oidcClientMetadata' | 'customClientMetadata' | 'isAdmin'
|
||||
>;
|
||||
|
||||
const mapToUriFormatArrays = (value?: string[]) =>
|
||||
value?.filter(Boolean).map((uri) => decodeURIComponent(uri)) ?? [];
|
||||
|
||||
const mapToUriOriginFormatArrays = (value?: string[]) =>
|
||||
value?.filter(Boolean).map((uri) => decodeURIComponent(uri.replace(/\/*$/, ''))) ?? [];
|
||||
|
||||
export const applicationFormDataParser = {
|
||||
fromResponse: (data: ApplicationResponse): ApplicationForm => {
|
||||
const { name, description, oidcClientMetadata, customClientMetadata, isAdmin } = data;
|
||||
|
@ -13,8 +23,29 @@ export const applicationFormDataParser = {
|
|||
name,
|
||||
description,
|
||||
oidcClientMetadata,
|
||||
customClientMetadata,
|
||||
customClientMetadata: {
|
||||
...customClientMetadataDefault,
|
||||
...customClientMetadata,
|
||||
},
|
||||
isAdmin,
|
||||
};
|
||||
},
|
||||
toUpdateApplicationData: (formData: ApplicationForm): Partial<Application> => {
|
||||
return {
|
||||
...formData,
|
||||
oidcClientMetadata: {
|
||||
...formData.oidcClientMetadata,
|
||||
redirectUris: mapToUriFormatArrays(formData.oidcClientMetadata.redirectUris),
|
||||
postLogoutRedirectUris: mapToUriFormatArrays(
|
||||
formData.oidcClientMetadata.postLogoutRedirectUris
|
||||
),
|
||||
},
|
||||
customClientMetadata: {
|
||||
...formData.customClientMetadata,
|
||||
corsAllowedOrigins: mapToUriOriginFormatArrays(
|
||||
formData.customClientMetadata.corsAllowedOrigins
|
||||
),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue