From 19939811c1ad8c71de471e1a1748816e9c94e78a Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Tue, 26 Sep 2023 11:02:05 +0800 Subject: [PATCH] refactor(console,phrases): hide role type selection on creation modal by default (#4581) --- .../RadioGroup/Radio.module.scss | 29 ++++-- .../src/ds-components/RadioGroup/Radio.tsx | 3 + .../CreateRoleForm/index.module.scss | 20 +++++ .../Roles/components/CreateRoleForm/index.tsx | 88 +++++++++++++++---- .../de/translation/admin-console/roles.ts | 4 + .../en/translation/admin-console/roles.ts | 4 + .../es/translation/admin-console/roles.ts | 4 + .../fr/translation/admin-console/roles.ts | 4 + .../it/translation/admin-console/roles.ts | 4 + .../ja/translation/admin-console/roles.ts | 4 + .../ko/translation/admin-console/roles.ts | 4 + .../pl-pl/translation/admin-console/roles.ts | 4 + .../pt-br/translation/admin-console/roles.ts | 4 + .../pt-pt/translation/admin-console/roles.ts | 4 + .../ru/translation/admin-console/roles.ts | 4 + .../tr-tr/translation/admin-console/roles.ts | 4 + .../zh-cn/translation/admin-console/roles.ts | 4 + .../zh-hk/translation/admin-console/roles.ts | 4 + .../zh-tw/translation/admin-console/roles.ts | 4 + 19 files changed, 177 insertions(+), 23 deletions(-) diff --git a/packages/console/src/ds-components/RadioGroup/Radio.module.scss b/packages/console/src/ds-components/RadioGroup/Radio.module.scss index 706819139..38d210bcf 100644 --- a/packages/console/src/ds-components/RadioGroup/Radio.module.scss +++ b/packages/console/src/ds-components/RadioGroup/Radio.module.scss @@ -31,7 +31,8 @@ } } - .icon { + .icon, + .trailingIcon { margin-right: _.unit(2); color: var(--color-text-secondary); @@ -39,6 +40,11 @@ display: block; } } + + .trailingIcon { + margin-right: unset; + margin-left: _.unit(2); + } } } @@ -74,7 +80,8 @@ } } - .icon { + .icon, + .trailingIcon { margin-right: _.unit(2); vertical-align: middle; color: var(--color-text-secondary); @@ -84,6 +91,11 @@ } } + .trailingIcon { + margin-right: unset; + margin-left: _.unit(2); + } + .disabledLabel { background: var(--color-neutral-90); padding: _.unit(0.5) _.unit(2); @@ -123,6 +135,10 @@ .icon { margin-right: _.unit(4); } + + .trailingIcon { + margin-left: _.unit(4); + } } } @@ -188,7 +204,8 @@ background-color: var(--color-hover-variant); .content { - .icon { + .icon, + .trailingIcon { color: var(--color-primary); } } @@ -248,7 +265,8 @@ background-color: var(--color-layer-2); .content { - .icon { + .icon, + .trailingIcon { color: var(--color-text-secondary); } } @@ -272,7 +290,8 @@ border-color: var(--color-primary); .content { - .icon { + .icon, + .trailingIcon { color: var(--color-primary); } } diff --git a/packages/console/src/ds-components/RadioGroup/Radio.tsx b/packages/console/src/ds-components/RadioGroup/Radio.tsx index b38e2bd53..b540cc36e 100644 --- a/packages/console/src/ds-components/RadioGroup/Radio.tsx +++ b/packages/console/src/ds-components/RadioGroup/Radio.tsx @@ -32,6 +32,7 @@ export type Props = { isDisabled?: boolean; disabledLabel?: AdminConsoleKey; icon?: ReactNode; + trailingIcon?: ReactNode; hasCheckIconForCard?: boolean; }; @@ -48,6 +49,7 @@ function Radio({ isDisabled, disabledLabel, icon, + trailingIcon, hasCheckIconForCard = true, }: Props) { const handleKeyPress: KeyboardEventHandler = useCallback( @@ -90,6 +92,7 @@ function Radio({ {type === 'plain' &&
} {icon && {icon}} {title && (typeof title === 'string' ? : title)} + {trailingIcon && {trailingIcon}} {isDisabled && disabledLabel && (
diff --git a/packages/console/src/pages/Roles/components/CreateRoleForm/index.module.scss b/packages/console/src/pages/Roles/components/CreateRoleForm/index.module.scss index 2aaef3ad4..d4b7a13ad 100644 --- a/packages/console/src/pages/Roles/components/CreateRoleForm/index.module.scss +++ b/packages/console/src/pages/Roles/components/CreateRoleForm/index.module.scss @@ -4,3 +4,23 @@ display: flex; gap: _.unit(6); } + +.roleTypeSelectionSwitch { + margin-top: _.unit(2); +} + +.trailingIcon { + width: 16px; + height: 16px; + + > svg { + width: 100%; + height: 100%; + } +} + +.proTag { + margin: 0; + display: flex; + align-items: center; +} diff --git a/packages/console/src/pages/Roles/components/CreateRoleForm/index.tsx b/packages/console/src/pages/Roles/components/CreateRoleForm/index.tsx index a4d55a000..4ed947fa0 100644 --- a/packages/console/src/pages/Roles/components/CreateRoleForm/index.tsx +++ b/packages/console/src/pages/Roles/components/CreateRoleForm/index.tsx @@ -2,15 +2,18 @@ import { type AdminConsoleKey } from '@logto/phrases'; import type { Role, ScopeResponse } from '@logto/schemas'; import { RoleType, internalRolePrefix } from '@logto/schemas'; import { conditional } from '@silverhand/essentials'; -import { useContext } from 'react'; +import { useContext, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { Trans, useTranslation } from 'react-i18next'; +import KeyboardArrowDown from '@/assets/icons/keyboard-arrow-down.svg'; +import KeyboardArrowUp from '@/assets/icons/keyboard-arrow-up.svg'; import ContactUsPhraseLink from '@/components/ContactUsPhraseLink'; import PlanName from '@/components/PlanName'; +import ProTag from '@/components/ProTag'; import QuotaGuardFooter from '@/components/QuotaGuardFooter'; import RoleScopesTransfer from '@/components/RoleScopesTransfer'; -import { isDevFeaturesEnabled } from '@/consts/env'; +import { isCloud, isDevFeaturesEnabled } from '@/consts/env'; import { TenantsContext } from '@/contexts/TenantsProvider'; import Button from '@/ds-components/Button'; import DynamicT from '@/ds-components/DynamicT'; @@ -20,14 +23,15 @@ import RadioGroup, { Radio } from '@/ds-components/RadioGroup'; import TextInput from '@/ds-components/TextInput'; import useApi from '@/hooks/use-api'; import useSubscriptionPlan from '@/hooks/use-subscription-plan'; +import { ReservedPlanName } from '@/types/subscriptions'; import { trySubmitSafe } from '@/utils/form'; import { hasReachedQuotaLimit } from '@/utils/quota'; import * as styles from './index.module.scss'; -const radioOptions: Array<{ key: AdminConsoleKey; value: RoleType }> = [ - { key: 'roles.type_user', value: RoleType.User }, - { key: 'roles.type_machine_to_machine', value: RoleType.MachineToMachine }, +const radioOptions: Array<{ key: AdminConsoleKey; value: RoleType; proTagCheck: boolean }> = [ + { key: 'roles.type_user', value: RoleType.User, proTagCheck: false }, + { key: 'roles.type_machine_to_machine', value: RoleType.MachineToMachine, proTagCheck: true }, ]; export type Props = { @@ -45,8 +49,10 @@ type CreateRolePayload = Pick & { function CreateRoleForm({ totalRoleCount, onClose }: Props) { const { currentTenantId } = useContext(TenantsContext); + const [isTypeSelectorVisible, setIsTypeSelectorVisible] = useState(false); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { data: currentPlan } = useSubscriptionPlan(currentTenantId); + const isM2mDisabledForCurrentPlan = isCloud && currentPlan?.quota.machineToMachineLimit === 0; const { control, handleSubmit, @@ -100,9 +106,25 @@ function CreateRoleForm({ totalRoleCount, onClose }: Props) { subtitle="roles.create_role_description" learnMoreLink="https://docs.logto.io/docs/recipes/rbac/manage-permissions-and-roles#manage-roles" size="large" - footer={ - <> - {isRolesReachLimit && currentPlan && ( + footer={(() => { + if ( + currentPlan?.name === ReservedPlanName.Free && + watch('type') === RoleType.MachineToMachine + ) { + return ( + + , + }} + > + {t('upsell.paywall.machine_to_machine_feature')} + + + ); + } + if (isRolesReachLimit && currentPlan) { + return ( - )} - {isScopesPerReachLimit && currentPlan && !isRolesReachLimit && ( + ); + } + if (isScopesPerReachLimit && currentPlan && !isRolesReachLimit) { + return ( - )} - {!isRolesReachLimit && !isScopesPerReachLimit && ( + ); + } + if (!isRolesReachLimit && !isScopesPerReachLimit) { + return (
+ } + className={styles.roleTypeSelectionSwitch} + onClick={() => { + setIsTypeSelectorVisible(!isTypeSelectorVisible); + }} + /> - {isDevFeaturesEnabled && ( + {isDevFeaturesEnabled && isTypeSelectorVisible && ( - {radioOptions.map(({ key, value }) => ( - } value={value} /> + {radioOptions.map(({ key, value, proTagCheck }) => ( + } + value={value} + trailingIcon={ + proTagCheck && + isM2mDisabledForCurrentPlan && + } + /> ))} )} diff --git a/packages/phrases/src/locales/de/translation/admin-console/roles.ts b/packages/phrases/src/locales/de/translation/admin-console/roles.ts index fac774aec..0198c6866 100644 --- a/packages/phrases/src/locales/de/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/de/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Rolle erstellen', role_name: 'Rollenname', role_type: 'Rollenart', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Benutzerrolle', type_machine_to_machine: 'Maschinen-zu-Maschinen-App-Rolle', role_description: 'Beschreibung', diff --git a/packages/phrases/src/locales/en/translation/admin-console/roles.ts b/packages/phrases/src/locales/en/translation/admin-console/roles.ts index 02e73cc90..3ae15e7a4 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Create Role', role_name: 'Role name', role_type: 'Role type', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'User role', type_machine_to_machine: 'Machine-to-machine app role', role_description: 'Description', diff --git a/packages/phrases/src/locales/es/translation/admin-console/roles.ts b/packages/phrases/src/locales/es/translation/admin-console/roles.ts index c9af2ad79..3a919ed4f 100644 --- a/packages/phrases/src/locales/es/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/es/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Crear Rol', role_name: 'Nombre de rol', role_type: 'Tipo de rol', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Rol de usuario', type_machine_to_machine: 'Rol de aplicación de máquina a máquina', role_description: 'Descripción', diff --git a/packages/phrases/src/locales/fr/translation/admin-console/roles.ts b/packages/phrases/src/locales/fr/translation/admin-console/roles.ts index 1e2a76c42..cb80ac741 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Créer un rôle', role_name: 'Nom du rôle', role_type: 'Type de rôle', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Rôle utilisateur', type_machine_to_machine: "Rôle d'application machine-à-machine", role_description: 'Description', diff --git a/packages/phrases/src/locales/it/translation/admin-console/roles.ts b/packages/phrases/src/locales/it/translation/admin-console/roles.ts index 91821c3e4..640b8fb0f 100644 --- a/packages/phrases/src/locales/it/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/it/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Crea Ruolo', role_name: 'Nome ruolo', role_type: 'Tipo ruolo', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Ruolo utente', type_machine_to_machine: 'Ruolo app M2M', role_description: 'Descrizione', diff --git a/packages/phrases/src/locales/ja/translation/admin-console/roles.ts b/packages/phrases/src/locales/ja/translation/admin-console/roles.ts index 3e9951850..ce4d599e1 100644 --- a/packages/phrases/src/locales/ja/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/ja/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'ロールを作成する', role_name: '役割名', role_type: '役割タイプ', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'ユーザーの役割', type_machine_to_machine: 'マシン対マシンアプリの役割', role_description: '説明', diff --git a/packages/phrases/src/locales/ko/translation/admin-console/roles.ts b/packages/phrases/src/locales/ko/translation/admin-console/roles.ts index 97e2f41a3..22a79c205 100644 --- a/packages/phrases/src/locales/ko/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/ko/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: '역할 생성', role_name: '역할 이름', role_type: '역할 유형', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: '사용자 역할', type_machine_to_machine: '기계 간 앱 역할', role_description: '설명', diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts index 77520e5f6..01a70895d 100644 --- a/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Utwórz rolę', role_name: 'Nazwa roli', role_type: 'Typ roli', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Rola użytkownika', type_machine_to_machine: 'Rola aplikacji Machine-to-Machine', role_description: 'Opis', diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/roles.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/roles.ts index 297562018..e603d1ff3 100644 --- a/packages/phrases/src/locales/pt-br/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/pt-br/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Criar função', role_name: 'Nome da função', role_type: 'Tipo de função', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Função do usuário', type_machine_to_machine: 'Função do aplicativo de máquina para máquina', role_description: 'Descrição', diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/roles.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/roles.ts index d251513e5..af3bd43cd 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Criar papel', role_name: 'Nome do papel', role_type: 'Tipo de papel', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Função de usuário', type_machine_to_machine: 'Função de aplicação máquina-a-máquina', role_description: 'Descrição', diff --git a/packages/phrases/src/locales/ru/translation/admin-console/roles.ts b/packages/phrases/src/locales/ru/translation/admin-console/roles.ts index f825b4b4c..4f504ac07 100644 --- a/packages/phrases/src/locales/ru/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/ru/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Создать роль', role_name: 'Имя роли', role_type: 'Тип роли', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Роль пользователя', type_machine_to_machine: 'Роль приложения между машинами', role_description: 'Описание', diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/roles.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/roles.ts index d77fd69e3..1591d894e 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: 'Rol Oluştur', role_name: 'Rol adı', role_type: 'Rol tipi', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: 'Kullanıcı rolü', type_machine_to_machine: 'Makine-makine uygulama rolü', role_description: 'Açıklama', diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/roles.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/roles.ts index 2a1330a7a..9e9e913a9 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: '创建角色', role_name: '角色名称', role_type: '角色类型', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: '用户角色', type_machine_to_machine: '机器对机器应用程序角色', role_description: '描述', diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/roles.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/roles.ts index 515c2069f..e854ff9e9 100644 --- a/packages/phrases/src/locales/zh-hk/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: '創建角色', role_name: '角色名稱', role_type: '角色類型', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: '用戶角色', type_machine_to_machine: '機器到機器應用程式角色', role_description: '描述', diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/roles.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/roles.ts index e1ea0da3d..77027ed9d 100644 --- a/packages/phrases/src/locales/zh-tw/translation/admin-console/roles.ts +++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/roles.ts @@ -6,6 +6,10 @@ const roles = { create: '建立角色', role_name: '角色名稱', role_type: '角色類型', + /** UNTRANSLATED */ + show_role_type_button_text: 'Show more options', + /** UNTRANSLATED */ + hide_role_type_button_text: 'Hide more options', type_user: '使用者角色', type_machine_to_machine: '機器對機器應用角色', role_description: '描述',