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:
parent
daf7b36442
commit
83ca5caa64
10 changed files with 158 additions and 32 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ $dropdown-item-height: 40px;
|
|||
}
|
||||
|
||||
.tag {
|
||||
font: var(--font-body-3);
|
||||
margin-right: _.unit(2);
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue