From db1525c96e1a23372c7e25bc9f379b799040dd89 Mon Sep 17 00:00:00 2001 From: DonOmalVindula Date: Thu, 26 Oct 2023 22:26:23 +0530 Subject: [PATCH 1/3] Improve roles UI in sub-organizations --- apps/console/src/features/roles/api/roles.ts | 11 +- .../edit-role/edit-role-permission.tsx | 252 +++++++++++------- .../roles/components/edit-role/edit-role.tsx | 9 +- .../features/roles/components/role-list.tsx | 33 ++- .../src/features/roles/pages/role-edit.tsx | 8 +- .../console/src/features/roles/pages/role.tsx | 14 +- .../i18n/src/models/namespaces/console-ns.ts | 7 +- .../src/translations/en-US/portals/console.ts | 9 +- .../src/translations/fr-FR/portals/console.ts | 9 +- .../src/translations/si-LK/portals/console.ts | 9 +- 10 files changed, 239 insertions(+), 122 deletions(-) diff --git a/apps/console/src/features/roles/api/roles.ts b/apps/console/src/features/roles/api/roles.ts index 9edd793b309..26daf2c4d9b 100644 --- a/apps/console/src/features/roles/api/roles.ts +++ b/apps/console/src/features/roles/api/roles.ts @@ -478,7 +478,8 @@ export const useRolesList = ( - filter?: string + filter?: string, + shouldFetch: boolean = true ): RequestResultInterface => { const requestConfig: RequestConfigInterface = { @@ -499,7 +500,7 @@ export const useAPIResourcesList = (requestConfig); + } = useRequest(shouldFetch ? requestConfig : null); return { data, @@ -519,7 +520,8 @@ export const useAPIResourcesList = ( - apiResourceId: string + apiResourceId: string, + shouldFetch: boolean = true ): RequestResultInterface => { const requestConfig: RequestConfigInterface = { @@ -534,7 +536,8 @@ export const useAPIResourceDetails = (apiResourceId ? requestConfig : null); + const { data, error, isValidating, mutate } = useRequest((apiResourceId && shouldFetch) + ? requestConfig : null); return { data, diff --git a/apps/console/src/features/roles/components/edit-role/edit-role-permission.tsx b/apps/console/src/features/roles/components/edit-role/edit-role-permission.tsx index 29c5bed25c7..3c25dafe6e1 100644 --- a/apps/console/src/features/roles/components/edit-role/edit-role-permission.tsx +++ b/apps/console/src/features/roles/components/edit-role/edit-role-permission.tsx @@ -16,8 +16,13 @@ * under the License. */ +import Autocomplete, { + AutocompleteRenderGetTagProps, + AutocompleteRenderInputParams +} from "@oxygen-ui/react/Autocomplete"; import Button from "@oxygen-ui/react/Button"; import Grid from "@oxygen-ui/react/Grid"; +import TextField from "@oxygen-ui/react/TextField"; import { AlertInterface, AlertLevels, @@ -29,11 +34,20 @@ import { addAlert } from "@wso2is/core/store"; import { Field, Form } from "@wso2is/form"; import { EmphasizedSegment, Heading } from "@wso2is/react-components"; import debounce, { DebouncedFunc } from "lodash-es/debounce"; -import React, { FunctionComponent, ReactElement, SyntheticEvent, useCallback, useEffect, useState } from "react"; +import React, { + FunctionComponent, + ReactElement, + ReactNode, + SyntheticEvent, + useCallback, + useEffect, + useState +} from "react"; import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; import { Dispatch } from "redux"; import { DropdownProps } from "semantic-ui-react"; +import { RenderChip } from "./edit-role-common/render-chip"; import { RoleAPIResourcesListItem } from "./edit-role-common/role-api-resources-list-item"; import { getAPIResourceDetailsBulk, updateRoleDetails, useAPIResourceDetails, useAPIResourcesList } from "../../api"; import { RoleConstants } from "../../constants/role-constants"; @@ -94,7 +108,7 @@ export const UpdatedRolePermissionDetails: FunctionComponent { - getExistingAPIResources(); + !isReadOnly && getExistingAPIResources(); }, [ role ]); /** @@ -341,105 +355,155 @@ export const UpdatedRolePermissionDetails: FunctionComponent ( + + +
+ + +
+ + { + selectedAPIResources?.length > 0 + ? ( +
+ + + { + selectedAPIResources?.map((apiResource: APIResourceInterface) => { + return ( + + selectedPermission.apiResourceId === apiResource?.id) + ?.scopes + } + selectedPermissions={ selectedPermissions?.find( + (selectedPermission: SelectedPermissionsInterface) => + selectedPermission.apiResourceId === apiResource?.id) + ?.scopes + } + /> + ); + }) + } + +
+ ) : null + } +
+
+ ); + + const readOnlyPermissionList = (): ReactNode => ( + scope.display } + renderInput={ (params: AutocompleteRenderInputParams) => ( + + ) } + renderTags={ ( + value: RolePermissionInterface[], + getTagProps: AutocompleteRenderGetTagProps + ) => value.map((option: RolePermissionInterface, index: number) => ( + null } + variant="solid" + /> + )) } + /> + ); + return ( { t("console:manage.features.roles.edit.permissions.heading") } - - { t("console:manage.features.roles.edit.permissions.subHeading") } - + { + isReadOnly ? ( + + { t("console:manage.features.roles.edit.permissions.readOnlySubHeading") } + + ) : ( + + { t("console:manage.features.roles.edit.permissions.subHeading") } + + ) + } - - -
{ + updateRolePermissions(); + } } + data-componentid={ `${ componentId }-update-button` } > - - -
- - { - selectedAPIResources?.length > 0 - ? ( -
- - - { - selectedAPIResources?.map((apiResource: APIResourceInterface) => { - return ( - - selectedPermission.apiResourceId === apiResource?.id) - ?.scopes - } - selectedPermissions={ selectedPermissions?.find( - (selectedPermission: SelectedPermissionsInterface) => - selectedPermission.apiResourceId === apiResource?.id) - ?.scopes - } - /> - ); - }) - } - -
- ) : null - } -
-
- + { t("common:update") } + + ) + }
); }; diff --git a/apps/console/src/features/roles/components/edit-role/edit-role.tsx b/apps/console/src/features/roles/components/edit-role/edit-role.tsx index 3d458925691..ab58334a705 100644 --- a/apps/console/src/features/roles/components/edit-role/edit-role.tsx +++ b/apps/console/src/features/roles/components/edit-role/edit-role.tsx @@ -16,6 +16,7 @@ * under the License. */ +import { OrganizationType } from "@wso2is/common"; import { RoleConstants } from "@wso2is/core/constants"; import { hasRequiredScopes } from "@wso2is/core/helpers"; import { RolesInterface, SBACInterface } from "@wso2is/core/models"; @@ -28,6 +29,7 @@ import { RoleGroupsList } from "./edit-role-groups"; import { UpdatedRolePermissionDetails } from "./edit-role-permission"; import { RoleUsersList } from "./edit-role-users"; import { AppState, FeatureConfigInterface } from "../../../core"; +import { useGetOrganizationType } from "../../../organizations/hooks/use-get-organization-type"; /** * Captures props needed for edit role component @@ -66,12 +68,15 @@ export const EditRole: FunctionComponent = (props: EditRoleProps) } = props; const { t } = useTranslation(); + const orgType: OrganizationType = useGetOrganizationType(); const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state?.config?.ui?.features); const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes); const [ isAdminRole, setIsAdminRole ] = useState(false); + const isSubOrg: boolean = orgType === OrganizationType.SUBORGANIZATION; + /** * Set the if the role is `Internal/admin`. */ @@ -89,7 +94,7 @@ export const EditRole: FunctionComponent = (props: EditRoleProps) render: () => ( = (props: EditRoleProps) render: () => ( = (props: RoleList const { handleRoleDelete, + isSubOrg, onEmptyListPlaceholderActionClick, onSearchQueryClear, roleList, @@ -131,7 +136,7 @@ export const RoleList: React.FunctionComponent = (props: RoleList return ( = (props: RoleList ) } image={ getEmptyPlaceholderIllustrations().newList } imageSize="tiny" - title={ t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.title", + title={ !isSubOrg && t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.title", { type: "role" }) } - subtitle={ [ - t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.0", - { type: "roles" }), - t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.1", - { type: "role" }), - t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.2", - { type: "role" }) - ] } + subtitle={ isSubOrg + ? [ + t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.0", + { type: "roles" }) + ] + : [ + t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.0", + { type: "roles" }), + t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.1", + { type: "role" }), + t("console:manage.features.roles.list.emptyPlaceholders.emptyRoleList.subtitles.2", + { type: "role" }) + ] + } /> ); } @@ -260,7 +271,7 @@ export const RoleList: React.FunctionComponent = (props: RoleList renderer: "semantic-icon" }, { - hidden: (role: RolesInterface) => (role?.displayName === RoleConstants.ADMIN_ROLE || + hidden: (role: RolesInterface) => isSubOrg || (role?.displayName === RoleConstants.ADMIN_ROLE || role?.displayName === RoleConstants.ADMIN_GROUP) || !hasRequiredScopes(featureConfig?.roles, featureConfig?.roles?.scopes?.delete, allowedScopes), icon: (): SemanticICONS => "trash alternate", diff --git a/apps/console/src/features/roles/pages/role-edit.tsx b/apps/console/src/features/roles/pages/role-edit.tsx index b32e85faa48..9addf09f9a7 100644 --- a/apps/console/src/features/roles/pages/role-edit.tsx +++ b/apps/console/src/features/roles/pages/role-edit.tsx @@ -137,8 +137,12 @@ const RoleEditPage: FunctionComponent = ( description={ ( - { `${t("console:manage.features.roles.list.columns.managedBy.label")} - ${roleObject?.audience?.type}` } + { + RoleAudienceTypes.ORGANIZATION === roleObject?.audience?.type.toUpperCase() + ? t("console:manage.features.roles.list.columns.managedByOrg.label") + : t("console:manage.features.roles.list.columns.managedByApp.label") + } + { roleObject?.audience?.type }