0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-13 21:30:30 -05:00

refactor: update per review

This commit is contained in:
Gao Sun 2024-07-29 17:47:26 +08:00
parent 01df8f46a2
commit e67187126d
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
11 changed files with 43 additions and 35 deletions

View file

@ -1,18 +1,30 @@
import type { Nullable } from '@silverhand/essentials'; import { type Nullable } from '@silverhand/essentials';
import { isValid } from 'date-fns'; import { isValid } from 'date-fns';
type Props = { const parseDate = (date: Nullable<string | number | Date>) => {
readonly children: Nullable<string | number>; if (!date) {
}; return;
function DateTime({ children }: Props) {
const date = children && new Date(children);
if (!date || !isValid(date)) {
return <span>-</span>;
} }
return <span>{date.toLocaleDateString()}</span>; const parsed = new Date(date);
return isValid(parsed) ? parsed : undefined;
};
type Props = {
readonly children: Nullable<string | number | Date>;
};
/**
* Safely display a date in the user's locale. If the date is invalid, it will display a dash.
*/
export function LocaleDate({ children }: Props) {
return <span>{parseDate(children)?.toLocaleDateString() ?? '-'}</span>;
} }
export default DateTime; /**
* Safely display a date and time in the user's locale. If the date is invalid, it will display a
* dash.
*/
export function LocaleDateTime({ children }: Props) {
return <span>{parseDate(children)?.toLocaleString() ?? '-'}</span>;
}

View file

@ -7,6 +7,7 @@ import { type GuideMetadata } from '@/assets/docs/guides/types';
import Button from '@/ds-components/Button'; import Button from '@/ds-components/Button';
import OverlayScrollbar from '@/ds-components/OverlayScrollbar'; import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
import MdxProvider from '@/mdx-components/MdxProvider'; import MdxProvider from '@/mdx-components/MdxProvider';
import { type ApplicationSecretRow } from '@/pages/ApplicationDetails/ApplicationDetailsContent/EndpointsAndCredentials';
import NotFound from '@/pages/NotFound'; import NotFound from '@/pages/NotFound';
import StepsSkeleton from './StepsSkeleton'; import StepsSkeleton from './StepsSkeleton';
@ -19,6 +20,7 @@ export type GuideContextType = {
| ((props: { readonly className?: string }) => JSX.Element); | ((props: { readonly className?: string }) => JSX.Element);
isCompact: boolean; isCompact: boolean;
app?: ApplicationResponse; app?: ApplicationResponse;
secrets?: ApplicationSecretRow[];
endpoint?: string; endpoint?: string;
redirectUris?: string[]; redirectUris?: string[];
postLogoutRedirectUris?: string[]; postLogoutRedirectUris?: string[];
@ -40,6 +42,7 @@ export const GuideContext = createContext<GuideContextType>({
metadata: {} as GuideMetadata, metadata: {} as GuideMetadata,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, no-restricted-syntax // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, no-restricted-syntax
app: {} as ApplicationResponse, app: {} as ApplicationResponse,
secrets: [],
endpoint: '', endpoint: '',
redirectUris: [], redirectUris: [],
postLogoutRedirectUris: [], postLogoutRedirectUris: [],

View file

@ -72,11 +72,6 @@
} }
.dot { .dot {
flex-shrink: 0; -webkit-text-stroke: 1px var(--color-text);
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--color-text-secondary);
} }
} }

View file

@ -60,10 +60,7 @@ function CopyToClipboard(
return value; return value;
} }
return Array.from({ length: Math.max(Math.floor((value.length / 5) * 3), 1) }).map( return <span className={styles.dot}>{'•'.repeat(value.length)}</span>;
// eslint-disable-next-line react/no-array-index-key -- No need to persist the key
(_, index) => <span key={index} className={styles.dot} />
);
}, [hasVisibilityToggle, showHiddenContent, value]); }, [hasVisibilityToggle, showHiddenContent, value]);
useEffect(() => { useEffect(() => {

View file

@ -9,8 +9,8 @@ import TextLink from '@/ds-components/TextLink';
import styles from './index.module.scss'; import styles from './index.module.scss';
function ApplicationCredentials() { function ApplicationCredentials() {
const { app } = useContext(GuideContext); const { app, secrets } = useContext(GuideContext);
const { id, secret } = app ?? {}; const { id } = app ?? {};
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
return ( return (
@ -37,12 +37,12 @@ function ApplicationCredentials() {
<CopyToClipboard displayType="block" value={id} variant="border" /> <CopyToClipboard displayType="block" value={id} variant="border" />
</FormField> </FormField>
)} )}
{secret && ( {secrets?.[0] && (
<FormField title="application_details.application_secret"> <FormField title="application_details.application_secret">
<CopyToClipboard <CopyToClipboard
hasVisibilityToggle hasVisibilityToggle
displayType="block" displayType="block"
value={secret} value={secrets[0].value}
variant="border" variant="border"
/> />
</FormField> </FormField>

View file

@ -31,7 +31,7 @@ button.add {
} }
.expired { .expired {
color: var(--color-text-secondary); color: var(--color-placeholder);
} }
.copyToClipboard { .copyToClipboard {

View file

@ -4,6 +4,7 @@ import { useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ActionsButton from '@/components/ActionsButton'; import ActionsButton from '@/components/ActionsButton';
import { LocaleDateTime } from '@/components/DateTime';
import CopyToClipboard from '@/ds-components/CopyToClipboard'; import CopyToClipboard from '@/ds-components/CopyToClipboard';
import { type Column } from '@/ds-components/Table/types'; import { type Column } from '@/ds-components/Table/types';
import { Tooltip } from '@/ds-components/Tip'; import { Tooltip } from '@/ds-components/Tip';
@ -68,7 +69,7 @@ export const useSecretTableColumns = ({ appId, onUpdated }: UseSecretTableColumn
compareDesc(expiresAt, new Date()) === 1 ? ( compareDesc(expiresAt, new Date()) === 1 ? (
<Expired expiresAt={new Date(expiresAt)} /> <Expired expiresAt={new Date(expiresAt)} />
) : ( ) : (
new Date(expiresAt).toLocaleString() <LocaleDateTime>{expiresAt}</LocaleDateTime>
) )
) : ( ) : (
t('application_details.secrets.never') t('application_details.secrets.never')

View file

@ -6,7 +6,7 @@ import useSWR from 'swr';
import Plus from '@/assets/icons/plus.svg?react'; import Plus from '@/assets/icons/plus.svg?react';
import ActionsButton from '@/components/ActionsButton'; import ActionsButton from '@/components/ActionsButton';
import DateTime from '@/components/DateTime'; import { LocaleDate } from '@/components/DateTime';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import UserPreview from '@/components/ItemPreview/UserPreview'; import UserPreview from '@/components/ItemPreview/UserPreview';
import { RoleOption } from '@/components/OrganizationRolesSelect'; import { RoleOption } from '@/components/OrganizationRolesSelect';
@ -96,7 +96,7 @@ function Members() {
dataIndex: 'lastSignInAt', dataIndex: 'lastSignInAt',
title: t('users.latest_sign_in'), title: t('users.latest_sign_in'),
colSpan: 5, colSpan: 5,
render: ({ lastSignInAt }) => <DateTime>{lastSignInAt}</DateTime>, render: ({ lastSignInAt }) => <LocaleDate>{lastSignInAt}</LocaleDate>,
}, },
{ {
dataIndex: 'actions', dataIndex: 'actions',

View file

@ -9,7 +9,7 @@ import useSWR from 'swr';
import Delete from '@/assets/icons/delete.svg?react'; import Delete from '@/assets/icons/delete.svg?react';
import Plus from '@/assets/icons/plus.svg?react'; import Plus from '@/assets/icons/plus.svg?react';
import ApplicationName from '@/components/ApplicationName'; import ApplicationName from '@/components/ApplicationName';
import DateTime from '@/components/DateTime'; import { LocaleDate } from '@/components/DateTime';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import UserPreview from '@/components/ItemPreview/UserPreview'; import UserPreview from '@/components/ItemPreview/UserPreview';
import { defaultPageSize } from '@/consts'; import { defaultPageSize } from '@/consts';
@ -103,7 +103,7 @@ function RoleUsers() {
title: t('role_details.users.latest_sign_in_column'), title: t('role_details.users.latest_sign_in_column'),
dataIndex: 'latestSignIn', dataIndex: 'latestSignIn',
colSpan: 5, colSpan: 5,
render: ({ lastSignInAt }) => <DateTime>{lastSignInAt}</DateTime>, render: ({ lastSignInAt }) => <LocaleDate>{lastSignInAt}</LocaleDate>,
}, },
{ {
title: null, title: null,

View file

@ -8,7 +8,7 @@ import Plus from '@/assets/icons/plus.svg?react';
import UsersEmptyDark from '@/assets/images/users-empty-dark.svg?react'; import UsersEmptyDark from '@/assets/images/users-empty-dark.svg?react';
import UsersEmpty from '@/assets/images/users-empty.svg?react'; import UsersEmpty from '@/assets/images/users-empty.svg?react';
import ApplicationName from '@/components/ApplicationName'; import ApplicationName from '@/components/ApplicationName';
import DateTime from '@/components/DateTime'; import { LocaleDate } from '@/components/DateTime';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import ItemPreview from '@/components/ItemPreview'; import ItemPreview from '@/components/ItemPreview';
import ListPage from '@/components/ListPage'; import ListPage from '@/components/ListPage';
@ -104,7 +104,7 @@ function Users() {
title: t('users.latest_sign_in'), title: t('users.latest_sign_in'),
dataIndex: 'lastSignInAt', dataIndex: 'lastSignInAt',
colSpan: 5, colSpan: 5,
render: ({ lastSignInAt }) => <DateTime>{lastSignInAt}</DateTime>, render: ({ lastSignInAt }) => <LocaleDate>{lastSignInAt}</LocaleDate>,
}, },
], ],
filter: ( filter: (

View file

@ -179,7 +179,7 @@ const application_details = {
expiration: 'Expiration', expiration: 'Expiration',
expiration_description: 'The secret will expire at {{date}}.', expiration_description: 'The secret will expire at {{date}}.',
expiration_description_never: expiration_description_never:
'The secret will never expire. We recommend setting an expiration date for better security.', 'The secret will never expire. We recommend setting an expiration date for enhanced security.',
days: '{{count}} day', days: '{{count}} day',
days_other: '{{count}} days', days_other: '{{count}} days',
}, },