Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(console): update role-related content and components #6091

Merged
merged 1 commit into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 12 additions & 42 deletions packages/console/src/assets/icons/role-feature.svg
charIeszhao marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 0 additions & 13 deletions packages/console/src/assets/icons/user-role-dark.svg

This file was deleted.

13 changes: 0 additions & 13 deletions packages/console/src/assets/icons/user-role.svg

This file was deleted.

6 changes: 3 additions & 3 deletions packages/console/src/components/ItemPreview/UserPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ type Props = {
/**
* Whether to provide a link to user details page. Explicitly set to `false` to hide it.
*/
readonly hasUserDetailsLink?: false;
readonly showLink?: false;
};

/** A component that renders a preview of a user. It's useful for displaying a user in a list. */
function UserPreview({ user, hasUserDetailsLink }: Props) {
function UserPreview({ user, showLink }: Props) {
return (
<ItemPreview
title={getUserTitle(user)}
subtitle={getUserSubtitle(user)}
icon={<UserAvatar size="large" user={user} />}
to={conditional(hasUserDetailsLink !== false && `/users/${user.id}`)}
to={conditional(showLink !== false && `/users/${user.id}`)}
suffix={conditional(user.isSuspended && <SuspendedTag />)}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type OrganizationRole, type RoleType } from '@logto/schemas';
import classNames from 'classnames';

import RoleIcon from '@/assets/icons/role-feature.svg';
import RoleIcon from '@/assets/icons/organization-role-feature.svg';
import MultiSelect, { type Option } from '@/ds-components/Select/MultiSelect';
import useSearchValues from '@/hooks/use-search-values';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,7 @@ function RoleAssignmentModal({ entity, onClose, type, isSkippable }: Props) {
a: <TextLink to="/roles/create" />,
}}
>
{t(
isForUser
? 'user_details.roles.create_user_role_hint'
: 'applications.m2m_role_assignment.role_creation_hint'
)}
{t('roles.role_creation_hint')}
</Trans>
</div>
</ModalLayout>
Expand Down
20 changes: 20 additions & 0 deletions packages/console/src/components/RoleIcon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Theme } from '@logto/schemas';
import { type ReactNode } from 'react';

import UserRoleIconDark from '@/assets/icons/role-feature-dark.svg';
import UserRoleIcon from '@/assets/icons/role-feature.svg';
import useTheme from '@/hooks/use-theme';

const themeToRoleIcon = Object.freeze({
[Theme.Light]: <UserRoleIcon />,
[Theme.Dark]: <UserRoleIconDark />,
} satisfies Record<Theme, ReactNode>);

/** Render a role icon according to the current theme. */
const RoleIcon = () => {
const theme = useTheme();

return themeToRoleIcon[theme];
};

export default RoleIcon;
2 changes: 1 addition & 1 deletion packages/console/src/components/RolesTransfer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function RolesTransfer({ entityId, type, value, onChange }: Props) {
</Trans>
</InlineNotification>
)}
<FormField title={isM2mRole ? 'roles.assign_m2m_roles' : 'roles.assign_user_roles'}>
<FormField title="roles.assign_roles">
<div className={classNames(transferLayout.container, styles.rolesTransfer)}>
<SourceRolesBox
entityId={entityId}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import type { Application, Role } from '@logto/schemas';
import { RoleType, Theme, roleTypeToKey } from '@logto/schemas';
import { RoleType, roleTypeToKey } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import useSWR from 'swr';

import Delete from '@/assets/icons/delete.svg';
import MachineToMachineRoleIconDark from '@/assets/icons/m2m-role-dark.svg';
import MachineToMachineRoleIcon from '@/assets/icons/m2m-role.svg';
import Plus from '@/assets/icons/plus.svg';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import ItemPreview from '@/components/ItemPreview';
import RoleAssignmentModal from '@/components/RoleAssignmentModal';
import RoleIcon from '@/components/RoleIcon';
import { defaultPageSize } from '@/consts';
import Button from '@/ds-components/Button';
import ConfirmModal from '@/ds-components/ConfirmModal';
Expand Down Expand Up @@ -90,17 +89,7 @@ function MachineToMachineApplicationRoles({ application }: Props) {
dataIndex: 'name',
colSpan: 6,
render: ({ id, name }) => (
<ItemPreview
title={name}
to={`/roles/${id}`}
icon={
theme === Theme.Dark ? (
<MachineToMachineRoleIconDark />
) : (
<MachineToMachineRoleIcon />
)
}
/>
<ItemPreview title={name} to={`/roles/${id}`} icon={<RoleIcon />} />
),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Outlet, useLocation, useParams } from 'react-router-dom';
import useSWR, { useSWRConfig } from 'swr';

import Delete from '@/assets/icons/delete.svg';
import OrgRoleIcon from '@/assets/icons/role-feature.svg';
import OrgRoleIcon from '@/assets/icons/organization-role-feature.svg';
import DetailsPage from '@/components/DetailsPage';
import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader';
import PageMeta from '@/components/PageMeta';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import useSWR from 'swr';

import OrgRoleIcon from '@/assets/icons/organization-role-feature.svg';
import Plus from '@/assets/icons/plus.svg';
import OrgRoleIcon from '@/assets/icons/role-feature.svg';
import RolesEmptyDark from '@/assets/images/roles-empty-dark.svg';
import RolesEmpty from '@/assets/images/roles-empty.svg';
import Breakable from '@/components/Breakable';
Expand Down Expand Up @@ -68,6 +68,14 @@ function OrganizationRoles() {
return <ItemPreview title={name} icon={<ThemedIcon for={OrgRoleIcon} />} to={id} />;
},
},
{
title: <DynamicT forKey="roles.col_type" />,
dataIndex: 'type',
colSpan: 4,
render: ({ type }) => {
return <DynamicT forKey={`roles.type_${roleTypeToKey[type]}`} />;
},
},
{
title: <DynamicT forKey="organization_template.roles.permissions_column" />,
dataIndex: 'scopes',
Expand All @@ -88,14 +96,6 @@ function OrganizationRoles() {
);
},
},
{
title: <DynamicT forKey="organization_template.roles.type_column" />,
dataIndex: 'type',
colSpan: 4,
render: ({ type }) => {
return <DynamicT forKey={`roles.type_${roleTypeToKey[type]}`} />;
},
},
]}
rowClickHandler={({ id }) => {
navigate(id);
Expand Down
15 changes: 3 additions & 12 deletions packages/console/src/pages/RoleDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Role } from '@logto/schemas';
import { Theme, RoleType } from '@logto/schemas';
import { RoleType } from '@logto/schemas';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import { toast } from 'react-hot-toast';
Expand All @@ -8,12 +8,9 @@ import { Outlet, useLocation, useParams } from 'react-router-dom';
import useSWR, { useSWRConfig } from 'swr';

import Delete from '@/assets/icons/delete.svg';
import MachineToMachineRoleIconDark from '@/assets/icons/m2m-role-dark.svg';
import MachineToMachineRoleIcon from '@/assets/icons/m2m-role.svg';
import UserRoleIconDark from '@/assets/icons/user-role-dark.svg';
import UserRoleIcon from '@/assets/icons/user-role.svg';
import DetailsPage from '@/components/DetailsPage';
import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader';
import RoleIcon from '@/components/RoleIcon';
import { RoleDetailsTabs } from '@/consts/page-tabs';
import ConfirmModal from '@/ds-components/ConfirmModal';
import InlineNotification from '@/ds-components/InlineNotification';
Expand All @@ -28,18 +25,12 @@ import useUserPreferences from '@/hooks/use-user-preferences';
import * as styles from './index.module.scss';
import { type RoleDetailsOutletContext } from './types';

const icons = {
[Theme.Light]: { UserIcon: UserRoleIcon, MachineToMachineIcon: MachineToMachineRoleIcon },
[Theme.Dark]: { UserIcon: UserRoleIconDark, MachineToMachineIcon: MachineToMachineRoleIconDark },
};

function RoleDetails() {
const { pathname } = useLocation();
const { id } = useParams();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { navigate } = useTenantPathname();
const theme = useTheme();
const { UserIcon, MachineToMachineIcon } = icons[theme];

const isPageHasTable =
pathname.endsWith(RoleDetailsTabs.Permissions) ||
Expand Down Expand Up @@ -119,7 +110,7 @@ function RoleDetails() {
{data && (
<>
<DetailsPageHeader
icon={isM2mRole ? <MachineToMachineIcon /> : <UserIcon />}
icon={<RoleIcon />}
title={data.name}
primaryTag={t(
isM2mRole ? 'role_details.type_m2m_role_tag' : 'role_details.type_user_role_tag'
Expand Down
22 changes: 3 additions & 19 deletions packages/console/src/pages/Roles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { RoleType, roleTypeToKey, type RoleResponse } from '@logto/schemas';
import { Theme } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import useSWR from 'swr';

import MachineToMachineRoleIconDark from '@/assets/icons/m2m-role-dark.svg';
import MachineToMachineRoleIcon from '@/assets/icons/m2m-role.svg';
import Plus from '@/assets/icons/plus.svg';
import UserRoleIconDark from '@/assets/icons/user-role-dark.svg';
import UserRoleIcon from '@/assets/icons/user-role.svg';
import RolesEmptyDark from '@/assets/images/roles-empty-dark.svg';
import RolesEmpty from '@/assets/images/roles-empty.svg';
import Breakable from '@/components/Breakable';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import ItemPreview from '@/components/ItemPreview';
import ListPage from '@/components/ListPage';
import RoleIcon from '@/components/RoleIcon';
import { defaultPageSize } from '@/consts';
import Button from '@/ds-components/Button';
import Search from '@/ds-components/Search';
Expand All @@ -36,14 +32,6 @@ const buildDetailsPathname = (id: string) => `${rolesPathname}/${id}`;

const pageSize = defaultPageSize;

const getRoleIcon = (type: RoleType, isDarkMode: boolean) => {
if (type === RoleType.User) {
return isDarkMode ? <UserRoleIconDark /> : <UserRoleIcon />;
}

return isDarkMode ? <MachineToMachineRoleIconDark /> : <MachineToMachineRoleIcon />;
};

function Roles() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { search } = useLocation();
Expand Down Expand Up @@ -96,12 +84,8 @@ function Roles() {
title: t('roles.col_roles'),
dataIndex: 'roles',
colSpan: 5,
render: ({ id, name, type }) => (
<ItemPreview
title={name}
to={buildDetailsPathname(id)}
icon={getRoleIcon(type, theme === Theme.Dark)}
/>
render: ({ id, name }) => (
<ItemPreview title={name} to={buildDetailsPathname(id)} icon={<RoleIcon />} />
),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function Members() {
dataIndex: 'user',
title: t('user'),
colSpan: 4,
render: (user) => <UserPreview user={user} hasUserDetailsLink={false} />,
render: (user) => <UserPreview user={user} showLink={false} />,
},
{
dataIndex: 'roles',
Expand Down
11 changes: 3 additions & 8 deletions packages/console/src/pages/UserDetails/UserRoles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Role } from '@logto/schemas';
import { RoleType, Theme } from '@logto/schemas';
import { RoleType } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
Expand All @@ -9,11 +9,10 @@ import useSWR from 'swr';

import Delete from '@/assets/icons/delete.svg';
import Plus from '@/assets/icons/plus.svg';
import UserRoleIconDark from '@/assets/icons/user-role-dark.svg';
import UserRoleIcon from '@/assets/icons/user-role.svg';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import ItemPreview from '@/components/ItemPreview';
import RoleAssignmentModal from '@/components/RoleAssignmentModal';
import RoleIcon from '@/components/RoleIcon';
import { defaultPageSize } from '@/consts';
import Button from '@/ds-components/Button';
import ConfirmModal from '@/ds-components/ConfirmModal';
Expand Down Expand Up @@ -92,11 +91,7 @@ function UserRoles() {
dataIndex: 'name',
colSpan: 6,
render: ({ id, name }) => (
<ItemPreview
title={name}
to={`/roles/${id}`}
icon={theme === Theme.Dark ? <UserRoleIconDark /> : <UserRoleIcon />}
/>
<ItemPreview title={name} to={`/roles/${id}`} icon={<RoleIcon />} />
),
},
{
Expand Down
Loading
Loading