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

chore(console,experience): add changeset for organization updates #5763

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
chore(console,experience): remove dev flags and add changeset for org…
…anization updates
  • Loading branch information
xiaoyijun committed May 13, 2024
commit 49e10e1128c1cec2542631dab68a4b639bcd13af
12 changes: 12 additions & 0 deletions .changeset/loud-mice-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@logto/console": minor
---

support adding API resource permissions to organization roles and organization permissions in 3rd-party applications

## Updates

- Separated the "Organization template" from the "Organization" page, establishing it as a standalone page for clearer navigation and functionality.
- Enhanced the "Organization template" page by adding functionality that allows users to click on an organization role, which then navigates to the organization role details page where users can view its corresponding permissions and general settings.
- Enabled the assignment of API resource permissions directly from the organization role details page, improving role management and access control.
- Split the permission list for third-party apps into two separate lists: user permissions and organization permissions. Users can now add user profile permissions and API resource permissions for users under user permissions, and add organization permissions and API resource permissions for organizations under organization permissions.
xiaoyijun marked this conversation as resolved.
Show resolved Hide resolved

This file was deleted.

2 changes: 1 addition & 1 deletion packages/console/src/components/TemplateTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Props<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValue
readonly errorMessage?: string;
};

export const pageSize = 10;
const pageSize = 10;

/**
* The table component for organization template editing, such as permissions and roles.
Expand Down
2 changes: 1 addition & 1 deletion packages/console/src/consts/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { yes } from '@silverhand/essentials';
const isProduction = process.env.NODE_ENV === 'production';
export const isCloud = yes(process.env.IS_CLOUD);
export const adminEndpoint = process.env.ADMIN_ENDPOINT;

// eslint-disable-next-line import/no-unused-modules
export const isDevFeaturesEnabled =
!isProduction || yes(process.env.DEV_FEATURES_ENABLED) || yes(process.env.INTEGRATION_TEST);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Role from '@/assets/icons/role.svg';
import SecurityLock from '@/assets/icons/security-lock.svg';
import EnterpriseSso from '@/assets/icons/single-sign-on.svg';
import Web from '@/assets/icons/web.svg';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { isCloud } from '@/consts/env';

type SidebarItem = {
Icon: FC;
Expand Down Expand Up @@ -103,7 +103,6 @@ export const useSidebarMenuItems = (): {
{
Icon: OrganizationTemplate,
title: 'organization_template',
isHidden: !isDevFeaturesEnabled,
},
],
},
Expand Down
23 changes: 3 additions & 20 deletions packages/console/src/hooks/use-console-routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { condArray } from '@silverhand/essentials';
import { useMemo } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';
import { type RouteObject } from 'react-router-dom';

import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { isCloud } from '@/consts/env';
import Dashboard from '@/pages/Dashboard';
import GetStarted from '@/pages/GetStarted';
import Mfa from '@/pages/Mfa';
import NotFound from '@/pages/NotFound';
import OrganizationGuide from '@/pages/Organizations/Guide';
import Introduction from '@/pages/Organizations/Guide/Introduction';
import OrganizationInfo from '@/pages/Organizations/Guide/OrganizationInfo';
import OrganizationPermissions from '@/pages/Organizations/Guide/OrganizationPermissions';
import OrganizationRoles from '@/pages/Organizations/Guide/OrganizationRoles';
import { steps } from '@/pages/Organizations/Guide/const';
import SigningKeys from '@/pages/SigningKeys';

import { apiResources } from './routes/api-resources';
Expand Down Expand Up @@ -48,19 +42,8 @@ export const useConsoleRoutes = () => {
users,
auditLogs,
roles,
isDevFeaturesEnabled && organizationTemplate,
organizationTemplate,
organizations,
!isDevFeaturesEnabled && {
path: 'organization-guide/*',
element: <OrganizationGuide />,
children: [
{ index: true, element: <Navigate replace to={steps.introduction} /> },
{ path: steps.introduction, element: <Introduction /> },
{ path: steps.permissions, element: <OrganizationPermissions /> },
{ path: steps.roles, element: <OrganizationRoles /> },
{ path: steps.organizationInfo, element: <OrganizationInfo /> },
],
},
{ path: 'signing-keys', element: <SigningKeys /> },
isCloud && tenantSettings,
customizeJwt
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { condArray } from '@silverhand/essentials';
import { Navigate, type RouteObject } from 'react-router-dom';

import { isDevFeaturesEnabled } from '@/consts/env';
import OrganizationDetails from '@/pages/OrganizationDetails';
import Members from '@/pages/OrganizationDetails/Members';
import Settings from '@/pages/OrganizationDetails/Settings';
Expand All @@ -13,10 +12,6 @@ export const organizations: RouteObject = {
children: condArray(
{ index: true, element: <Organizations /> },
{ path: 'create', element: <Organizations /> },
!isDevFeaturesEnabled && {
path: 'template',
element: <Organizations tab="template" />,
},
{
path: ':id/*',
element: <OrganizationDetails />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,6 @@ import { ApplicationUserConsentScopeType } from '@logto/schemas';

import { type PermissionTabType } from './type';

export const allLevelPermissionTabs: PermissionTabType = Object.freeze({
[ApplicationUserConsentScopeType.UserScopes]: {
title: 'application_details.permissions.user_profile',
key: ApplicationUserConsentScopeType.UserScopes,
},
[ApplicationUserConsentScopeType.ResourceScopes]: {
title: 'application_details.permissions.api_permissions',
key: ApplicationUserConsentScopeType.ResourceScopes,
},
[ApplicationUserConsentScopeType.OrganizationScopes]: {
title: 'application_details.permissions.organization',
key: ApplicationUserConsentScopeType.OrganizationScopes,
},
});

export const userLevelPermissionsTabs: PermissionTabType = Object.freeze({
[ApplicationUserConsentScopeType.UserScopes]: {
title: 'application_details.permissions.user_profile',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ import DataTransferBox from '@/ds-components/DataTransferBox';
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
import TabWrapper from '@/ds-components/TabWrapper';

import {
allLevelPermissionTabs,
organizationLevelPermissionsTab,
userLevelPermissionsTabs,
} from './constants';
import { organizationLevelPermissionsTab, userLevelPermissionsTabs } from './constants';
import { ScopeLevel } from './type';
import useApplicationScopesAssignment from './use-application-scopes-assignment';

Expand Down Expand Up @@ -50,47 +46,33 @@ function ApplicationScopesAssignmentModal({ isOpen, onClose, applicationId, scop
[scopesAssignment]
);

const tabs = useMemo(() => {
const getPermissionTabs = () => {
if (scopeLevel === ScopeLevel.All) {
return allLevelPermissionTabs;
}

return scopeLevel === ScopeLevel.User
? userLevelPermissionsTabs
: organizationLevelPermissionsTab;
};

return Object.values(getPermissionTabs()).map(({ title, key }) => {
const selectedDataCount = scopesAssignment[key].selectedData.length;

return (
<TabNavItem
key={key}
isActive={key === activeTab}
onClick={() => {
setActiveTab(key);
}}
>
{`${String(t(title))}${selectedDataCount ? ` (${selectedDataCount})` : ''}`}
</TabNavItem>
);
});
}, [activeTab, scopeLevel, scopesAssignment, setActiveTab, t]);
const tabs = useMemo(
() =>
Object.values(
scopeLevel === ScopeLevel.User ? userLevelPermissionsTabs : organizationLevelPermissionsTab
).map(({ title, key }) => {
const selectedDataCount = scopesAssignment[key].selectedData.length;

return (
<TabNavItem
key={key}
isActive={key === activeTab}
onClick={() => {
setActiveTab(key);
}}
>
{`${String(t(title))}${selectedDataCount ? ` (${selectedDataCount})` : ''}`}
</TabNavItem>
);
}),
[activeTab, scopeLevel, scopesAssignment, setActiveTab, t]
);

const modalText = useMemo<{
title: AdminConsoleKey;
subtitle: AdminConsoleKey;
saveButton: AdminConsoleKey;
}>(() => {
if (scopeLevel === ScopeLevel.All) {
return {
title: 'application_details.permissions.table_name',
subtitle: 'application_details.permissions.permissions_assignment_description',
saveButton: 'general.save',
};
}

const scopeLevelPhrase = scopeLevel === ScopeLevel.User ? 'user' : 'organization';

return {
Expand All @@ -115,7 +97,7 @@ function ApplicationScopesAssignmentModal({ isOpen, onClose, applicationId, scop
onConfirm={onSubmitHandler}
>
<TabNav>{tabs}</TabNav>
{(scopeLevel === ScopeLevel.All || scopeLevel === ScopeLevel.User) && (
{scopeLevel === ScopeLevel.User && (
<>
<TabWrapper
key={ApplicationUserConsentScopeType.UserScopes}
Expand All @@ -133,25 +115,25 @@ function ApplicationScopesAssignmentModal({ isOpen, onClose, applicationId, scop
</TabWrapper>
</>
)}
{(scopeLevel === ScopeLevel.All || scopeLevel === ScopeLevel.Organization) && (
<TabWrapper
key={ApplicationUserConsentScopeType.OrganizationScopes}
isActive={ApplicationUserConsentScopeType.OrganizationScopes === activeTab}
>
<DataTransferBox
{...scopesAssignment[ApplicationUserConsentScopeType.OrganizationScopes]}
/>
</TabWrapper>
)}
{scopeLevel === ScopeLevel.Organization && (
<TabWrapper
key={ApplicationUserConsentScopeType.OrganizationResourceScopes}
isActive={ApplicationUserConsentScopeType.OrganizationResourceScopes === activeTab}
>
<DataTransferBox
{...scopesAssignment[ApplicationUserConsentScopeType.OrganizationResourceScopes]}
/>
</TabWrapper>
<>
<TabWrapper
key={ApplicationUserConsentScopeType.OrganizationScopes}
isActive={ApplicationUserConsentScopeType.OrganizationScopes === activeTab}
>
<DataTransferBox
{...scopesAssignment[ApplicationUserConsentScopeType.OrganizationScopes]}
/>
</TabWrapper>
<TabWrapper
key={ApplicationUserConsentScopeType.OrganizationResourceScopes}
isActive={ApplicationUserConsentScopeType.OrganizationResourceScopes === activeTab}
>
<DataTransferBox
{...scopesAssignment[ApplicationUserConsentScopeType.OrganizationResourceScopes]}
/>
</TabWrapper>
</>
)}
</ConfirmModal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ export type ScopeAssignmentHook<
export enum ScopeLevel {
User = 'user',
Organization = 'organization',
/**
* Only used when the new organization resource scope feature is not ready.
* Todo @xiaoyijun remove this when the new organization resource scope feature is ready.
*/
All = 'all',
}

export type PermissionTabType = Partial<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,13 @@ function PermissionsCard({ applicationId, scopeLevel }: Props) {
const rowGroups = useMemo(() => {
const { userLevelRowGroups, organizationLevelGroups } = parseRowGroup(data);

if (scopeLevel === ScopeLevel.All) {
return [...userLevelRowGroups, ...organizationLevelGroups];
}

return scopeLevel === ScopeLevel.User ? userLevelRowGroups : organizationLevelGroups;
}, [data, parseRowGroup, scopeLevel]);

const displayTextProps = useMemo<{
formCard: Omit<FormCardProps, 'children'>;
tableName: AdminConsoleKey;
}>(() => {
if (scopeLevel === ScopeLevel.All) {
return {
formCard: {
title: 'application_details.permissions.name',
description: 'application_details.permissions.description',
learnMoreLink: {
href: getDocumentationUrl(logtoThirdPartyAppPermissionsLink),
targetBlank: 'noopener',
},
},
tableName: 'application_details.permissions.table_name',
};
}

const scopeLevelPhrase = scopeLevel === ScopeLevel.User ? 'user' : 'organization';

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import {
type ApplicationUserConsentScopesResponse,
ApplicationUserConsentScopeType,
} from '@logto/schemas';
import { condArray } from '@silverhand/essentials';
import { useCallback, type ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import Tip from '@/assets/icons/tip.svg';
import { isDevFeaturesEnabled } from '@/consts/env';
import IconButton from '@/ds-components/IconButton';
import { ToggleTip } from '@/ds-components/Tip';
import useApi from '@/hooks/use-api';
Expand Down Expand Up @@ -143,14 +141,7 @@ const useScopesTable = () => {
organizationLevelGroups: [
// Hide the organization scopes group if there is no organization scopes
...(organizationScopesGroup.data.length > 0 ? [organizationScopesGroup] : []),
...condArray(
/**
* Hide the organization resource scopes group if the organization resource scopes feature is not ready
*/
isDevFeaturesEnabled &&
organizationResourceScopesGroup.length > 0 &&
organizationResourceScopesGroup
),
...(organizationResourceScopesGroup.length > 0 ? organizationResourceScopesGroup : []),
],
};
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { type Application } from '@logto/schemas';

import { isDevFeaturesEnabled } from '@/consts/env';

import PermissionsCard from './PermissionsCard';
import { ScopeLevel } from './PermissionsCard/ApplicationScopesAssignmentModal/type';
import * as styles from './index.module.scss';
Expand All @@ -11,13 +9,9 @@ type Props = {
};

function Permissions({ application }: Props) {
const displayScopeLevels = isDevFeaturesEnabled
? [ScopeLevel.User, ScopeLevel.Organization]
: [ScopeLevel.All];

return (
<div className={styles.container}>
{displayScopeLevels.map((scopeLevel) => (
{[ScopeLevel.User, ScopeLevel.Organization].map((scopeLevel) => (
<PermissionsCard key={scopeLevel} applicationId={application.id} scopeLevel={scopeLevel} />
))}
</div>
Expand Down