From cf49950385938b85eef105e42f98a9cae5cba796 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Tue, 2 Apr 2024 00:51:02 +0800 Subject: [PATCH 1/2] fix(console): reset form as soon as JWT customizer is created --- .../CustomizeJwtDetails/MainContent/index.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx b/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx index 6330028055c..27d5846491a 100644 --- a/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx +++ b/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx @@ -56,14 +56,18 @@ function MainContent({ await api.put(getApiPath(tokenType), { json: payload }); - if (action === 'create') { - navigate(-1); - return; - } - const result = await mutate(); reset(formatResponseDataToFormData(tokenType, result)); + + /** + * Should `reset` (to set `isDirty` to false) before navigating back to the custom JWT listing page. + * Otherwise, the unsaved changes alert modal will be triggered on clicking `create` button, which + * is not expected. + */ + if (action === 'create') { + navigate(-1); + } }) ); From fd7cc634d1f0c9cf8e9f2e963cadf93d5dea6a13 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Tue, 2 Apr 2024 01:33:35 +0800 Subject: [PATCH 2/2] fix(console): reset form as soon as JWT customizer is created --- .../CustomizeJwt/CustomizerItem/index.tsx | 7 +-- .../pages/CustomizeJwt/use-jwt-customizer.ts | 53 +++++++------------ .../src/pages/CustomizeJwt/utils/path.ts | 9 +++- .../CustomizeJwtDetails/MainContent/index.tsx | 4 ++ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/packages/console/src/pages/CustomizeJwt/CustomizerItem/index.tsx b/packages/console/src/pages/CustomizeJwt/CustomizerItem/index.tsx index e566dec0e36..b2f0f15f713 100644 --- a/packages/console/src/pages/CustomizeJwt/CustomizerItem/index.tsx +++ b/packages/console/src/pages/CustomizeJwt/CustomizerItem/index.tsx @@ -1,7 +1,6 @@ import { LogtoJwtTokenPath } from '@logto/schemas'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { useSWRConfig } from 'swr'; import DeletIcon from '@/assets/icons/delete.svg'; import EditIcon from '@/assets/icons/edit.svg'; @@ -11,6 +10,8 @@ import { useConfirmModal } from '@/hooks/use-confirm-modal'; import useTenantPathname from '@/hooks/use-tenant-pathname'; import { getApiPath, getPagePath } from '@/pages/CustomizeJwt/utils/path'; +import useJwtCustomizer from '../use-jwt-customizer'; + import * as styles from './index.module.scss'; type Props = { @@ -23,7 +24,7 @@ function CustomizerItem({ tokenType }: Props) { const editLink = getPagePath(tokenType, 'edit'); const { navigate } = useTenantPathname(); const { show } = useConfirmModal(); - const { mutate } = useSWRConfig(); + const { mutate } = useJwtCustomizer(); const api = useApi(); @@ -36,7 +37,7 @@ function CustomizerItem({ tokenType }: Props) { if (confirm) { await api.delete(apiLink); - await mutate(apiLink, undefined); + await mutate(); } }, [api, apiLink, mutate, show, t]); diff --git a/packages/console/src/pages/CustomizeJwt/use-jwt-customizer.ts b/packages/console/src/pages/CustomizeJwt/use-jwt-customizer.ts index 31a7ba4ee9a..d3d0f2b1893 100644 --- a/packages/console/src/pages/CustomizeJwt/use-jwt-customizer.ts +++ b/packages/console/src/pages/CustomizeJwt/use-jwt-customizer.ts @@ -1,57 +1,40 @@ -import { - LogtoJwtTokenPath, - type AccessTokenJwtCustomizer, - type ClientCredentialsJwtCustomizer, -} from '@logto/schemas'; +import { LogtoJwtTokenKey, type JwtCustomizerConfigs } from '@logto/schemas'; import { type ResponseError } from '@withtyped/client'; import { useMemo } from 'react'; import useSWR from 'swr'; import useApi from '@/hooks/use-api'; import useSwrFetcher from '@/hooks/use-swr-fetcher'; -import { shouldRetryOnError } from '@/utils/request'; import { getApiPath } from './utils/path'; function useJwtCustomizer() { const fetchApi = useApi({ hideErrorToast: true }); - const accessTokenFetcher = useSwrFetcher(fetchApi); - const clientCredentialsFetcher = useSwrFetcher(fetchApi); + const fetcher = useSwrFetcher(fetchApi); const { - data: accessTokenJwtCustomizer, - isLoading: isAccessTokenJwtDataLoading, - error: accessTokenError, - } = useSWR(getApiPath(LogtoJwtTokenPath.AccessToken), { - fetcher: accessTokenFetcher, - shouldRetryOnError: shouldRetryOnError({ ignore: [404] }), + data, + isLoading: isDataLoading, + error, + mutate, + } = useSWR(getApiPath(), { + fetcher, }); + const isLoading = isDataLoading && !error; - const { - data: clientCredentialsJwtCustomizer, - isLoading: isClientCredentialsJwtDataLoading, - error: clientCredentialsError, - } = useSWR( - getApiPath(LogtoJwtTokenPath.ClientCredentials), - { - fetcher: clientCredentialsFetcher, - shouldRetryOnError: shouldRetryOnError({ ignore: [404] }), - } - ); - - // Show global loading status only if any of the fetchers are loading and no errors are present - const isLoading = - (isAccessTokenJwtDataLoading && !accessTokenError) || - (isClientCredentialsJwtDataLoading && !clientCredentialsError); + return useMemo(() => { + const { value: accessTokenJwtCustomizer } = + data?.find(({ key }) => key === LogtoJwtTokenKey.AccessToken) ?? {}; + const { value: clientCredentialsJwtCustomizer } = + data?.find(({ key }) => key === LogtoJwtTokenKey.ClientCredentials) ?? {}; - return useMemo( - () => ({ + return { accessTokenJwtCustomizer, clientCredentialsJwtCustomizer, isLoading, - }), - [accessTokenJwtCustomizer, clientCredentialsJwtCustomizer, isLoading] - ); + mutate, + }; + }, [data, isLoading, mutate]); } export default useJwtCustomizer; diff --git a/packages/console/src/pages/CustomizeJwt/utils/path.ts b/packages/console/src/pages/CustomizeJwt/utils/path.ts index eb8ae2974a1..0b398690b5b 100644 --- a/packages/console/src/pages/CustomizeJwt/utils/path.ts +++ b/packages/console/src/pages/CustomizeJwt/utils/path.ts @@ -2,8 +2,13 @@ import { type LogtoJwtTokenPath } from '@logto/schemas'; import { type Action } from './type'; -export const getApiPath = (tokenType: LogtoJwtTokenPath) => - `api/configs/jwt-customizer/${tokenType}`; +export const getApiPath = (tokenType?: LogtoJwtTokenPath) => { + if (!tokenType) { + return 'api/configs/jwt-customizer'; + } + + return `api/configs/jwt-customizer/${tokenType}`; +}; export const getPagePath = (tokenType?: LogtoJwtTokenPath, action?: Action) => { if (!tokenType) { diff --git a/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx b/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx index 27d5846491a..05bc972a579 100644 --- a/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx +++ b/packages/console/src/pages/CustomizeJwtDetails/MainContent/index.tsx @@ -9,6 +9,7 @@ import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal'; import useApi from '@/hooks/use-api'; import { trySubmitSafe } from '@/utils/form'; +import useJwtCustomizer from '../../CustomizeJwt/use-jwt-customizer'; import { type Action, type JwtCustomizer, type JwtCustomizerForm } from '../type'; import { formatFormDataToRequestData, formatResponseDataToFormData } from '../utils/format'; import { getApiPath } from '../utils/path'; @@ -34,6 +35,7 @@ function MainContent({ }: Props) { const api = useApi(); const navigate = useNavigate(); + const { mutate: mutateJwtCustomizers } = useJwtCustomizer(); const methods = useForm({ defaultValues: formatResponseDataToFormData(token, data), @@ -66,6 +68,8 @@ function MainContent({ * is not expected. */ if (action === 'create') { + // Refresh the JWT customizers list to reflect the latest changes. + await mutateJwtCustomizers(); navigate(-1); } })