0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

refactor(console): refactor tenant settings page (#4812)

This commit is contained in:
Xiao Yijun 2023-11-06 15:45:23 +08:00 committed by GitHub
parent daf7b36442
commit 83ca5caa64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 158 additions and 32 deletions

View file

@ -1,15 +1,11 @@
@use '@/scss/underscore' as _;
.tag {
display: flex;
align-items: center;
display: inline-block;
vertical-align: middle;
padding: 0 _.unit(1.5);
border-radius: _.unit(1);
height: 18px;
.text {
font: var(--font-label-3);
}
font: var(--font-label-3);
&.development {
background: var(--color-env-tag-development);
@ -22,4 +18,8 @@
&.production {
background: var(--color-env-tag-production);
}
&.large {
font: var(--font-label-1);
}
}

View file

@ -9,24 +9,34 @@ import * as styles from './index.module.scss';
type Props = {
tag: TenantTag;
className?: string;
isAbbreviated?: boolean;
size?: 'default' | 'large';
};
type TenantTagMap = {
[key in TenantTag]: AdminConsoleKey;
};
export const tenantTagMap = Object.freeze({
export const tenantAbbreviatedTagNameMap = Object.freeze({
[TenantTag.Development]: 'tenants.settings.environment_tag_development',
// Todo @xiaoyijun Remove staging tag before release
[TenantTag.Staging]: 'tenants.settings.environment_tag_staging',
[TenantTag.Production]: 'tenants.settings.environment_tag_production',
}) satisfies TenantTagMap;
function TenantEnvTag({ tag, className }: Props) {
const tenantTagNameMap = Object.freeze({
[TenantTag.Development]: 'tenants.full_env_tag.development',
// Todo @xiaoyijun Remove staging tag before release
[TenantTag.Staging]: 'tenants.settings.environment_tag_staging',
[TenantTag.Production]: 'tenants.full_env_tag.production',
}) satisfies TenantTagMap;
function TenantEnvTag({ tag, className, isAbbreviated = true, size = 'default' }: Props) {
const phrasesMap = isAbbreviated ? tenantAbbreviatedTagNameMap : tenantTagNameMap;
return (
<div className={classNames(styles.tag, styles[tag], className)}>
<div className={styles.text}>
<DynamicT forKey={tenantTagMap[tag]} />
</div>
<div className={classNames(styles.tag, styles[tag], styles[size], className)}>
<DynamicT forKey={phrasesMap[tag]} />
</div>
);
}

View file

@ -36,7 +36,6 @@ $dropdown-item-height: 40px;
}
.tag {
font: var(--font-body-3);
margin-right: _.unit(2);
}

View file

@ -10,3 +10,4 @@ export const reservationLink = buildUrl('https://calendly.com/logto/30min', {
// Note: month format is YYYY-MM
month: new Date().toISOString().slice(0, 7),
});
export const trustAndSecurityLink = 'https://logto.io/trust-and-security';

View file

@ -2,7 +2,7 @@ import classNames from 'classnames';
import { useTranslation, Trans } from 'react-i18next';
import { type TenantResponse } from '@/cloud/types/router';
import { tenantTagMap } from '@/components/TenantEnvTag';
import { tenantAbbreviatedTagNameMap } from '@/components/TenantEnvTag';
import { contactEmailLink } from '@/consts';
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
import TextLink from '@/ds-components/TextLink';
@ -38,7 +38,7 @@ function DeleteModal({ isOpen, isLoading, onClose, onDelete, tenant }: Props) {
<Trans components={{ span: <span className={styles.bold} /> }}>
{t('tenants.delete_modal.description_line1', {
name,
tag: t(tenantTagMap[tag], {}), // Referred to the use in DynamicT component.
tag: t(tenantAbbreviatedTagNameMap[tag], {}), // Referred to the use in DynamicT component.
})}
</Trans>
</p>

View file

@ -0,0 +1,13 @@
@use '@/scss/underscore' as _;
.container {
padding: _.unit(5.5) _.unit(6);
border: 1px solid var(--color-divider);
border-radius: 12px;
}
.description {
margin-top: _.unit(2);
font: var(--font-body-2);
color: var(--color-text-secondary);
}

View file

@ -0,0 +1,37 @@
import { TenantTag } from '@logto/schemas/lib/models/tenants.js';
import { Trans, useTranslation } from 'react-i18next';
import TenantEnvTag from '@/components/TenantEnvTag';
import TextLink from '@/ds-components/TextLink';
import * as styles from './index.module.scss';
type Props = {
tag: TenantTag;
};
function TenantEnvironment({ tag }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
return (
<div className={styles.container}>
<TenantEnvTag isAbbreviated={false} size="large" tag={tag} />
<div className={styles.description}>
<Trans
components={{
// Todo PRD-591 @xiaoyijun Add related link
a: <TextLink href="" target="_blank" rel="noopener" />,
}}
>
{t(
tag === TenantTag.Development
? 'tenants.settings.development_description'
: 'tenants.create_modal.production_description'
)}
</Trans>
</div>
</div>
);
}
export default TenantEnvironment;

View file

@ -0,0 +1,21 @@
@use '@/scss/underscore' as _;
.container {
padding: _.unit(5.5) _.unit(6);
border: 1px solid var(--color-divider);
border-radius: 12px;
}
.region {
font: var(--font-label-1);
.icon {
margin-right: _.unit(2);
}
}
.regionTip {
font: var(--font-body-2);
color: var(--color-text-secondary);
margin-top: _.unit(2);
}

View file

@ -0,0 +1,29 @@
import { Trans, useTranslation } from 'react-i18next';
import { trustAndSecurityLink } from '@/consts';
import TextLink from '@/ds-components/TextLink';
import * as styles from './index.module.scss';
function TenantRegion() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
return (
<div className={styles.container}>
<div className={styles.region}>
<span className={styles.icon}>🇪🇺</span>EU
</div>
<div className={styles.regionTip}>
<Trans
components={{
a: <TextLink href={trustAndSecurityLink} target="_blank" rel="noopener" />,
}}
>
{t('tenants.settings.tenant_region_tip', { region: 'EU' })}
</Trans>
</div>
</div>
);
}
export default TenantRegion;

View file

@ -4,6 +4,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import FormCard from '@/components/FormCard';
import { isDevFeaturesEnabled } from '@/consts/env';
import CopyToClipboard from '@/ds-components/CopyToClipboard';
import FormField from '@/ds-components/FormField';
import RadioGroup, { Radio } from '@/ds-components/RadioGroup';
@ -11,6 +12,8 @@ import TextInput from '@/ds-components/TextInput';
import { type TenantSettingsForm } from '../types.js';
import TenantEnvironment from './TenantEnvironment/index.js';
import TenantRegion from './TenantRegion/index.js';
import * as styles from './index.module.scss';
type Props = {
@ -41,6 +44,7 @@ function ProfileForm({ currentTenantId }: Props) {
control,
register,
formState: { errors },
getValues,
} = useFormContext<TenantSettingsForm>();
return (
@ -54,22 +58,34 @@ function ProfileForm({ currentTenantId }: Props) {
error={Boolean(errors.profile?.name)}
/>
</FormField>
<FormField title="tenants.settings.environment_tag">
<Controller
control={control}
name="profile.tag"
render={({ field: { onChange, value, name } }) => (
<RadioGroup type="small" value={value} name={name} onChange={onChange}>
{tagOptions.map(({ value: optionValue, title }) => (
<Radio key={optionValue} title={title} value={optionValue} />
))}
</RadioGroup>
)}
/>
<div className={styles.description}>
{t('tenants.settings.environment_tag_description')}
</div>
</FormField>
{isDevFeaturesEnabled && (
<FormField title="tenants.settings.tenant_region">
<TenantRegion />
</FormField>
)}
{!isDevFeaturesEnabled && (
<FormField title="tenants.settings.environment_tag">
<Controller
control={control}
name="profile.tag"
render={({ field: { onChange, value, name } }) => (
<RadioGroup type="small" value={value} name={name} onChange={onChange}>
{tagOptions.map(({ value: optionValue, title }) => (
<Radio key={optionValue} title={title} value={optionValue} />
))}
</RadioGroup>
)}
/>
<div className={styles.description}>
{t('tenants.settings.environment_tag_description')}
</div>
</FormField>
)}
{isDevFeaturesEnabled && (
<FormField title="tenants.settings.environment_tag">
<TenantEnvironment tag={getValues('profile.tag')} />
</FormField>
)}
</FormCard>
);
}