Skip to content

Commit

Permalink
feat: use new role components in project access (#4018)
Browse files Browse the repository at this point in the history
https://linear.app/unleash/issue/2-1143/adapt-project-roles-to-use-the-new-role-selector-and-role-description

This PR further unifies roles, by having a single `IRole` interface to
cover both types, and re-using the same components for project roles.
  • Loading branch information
nunogois committed Jun 21, 2023
1 parent a5ee50c commit a9e9ae8
Show file tree
Hide file tree
Showing 28 changed files with 49 additions and 331 deletions.
Expand Up @@ -10,7 +10,7 @@ import { ItemList } from 'component/common/ItemList/ItemList';
import useAuthSettings from 'hooks/api/getters/useAuthSettings/useAuthSettings';
import { Link } from 'react-router-dom';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { RoleSelect } from 'component/common/RoleSelect/RoleSelect';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/admin/roles/RoleForm/useRoleForm.ts
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { IPermission, ICheckedPermissions } from 'interfaces/permissions';
import IRole, { PredefinedRoleType } from 'interfaces/role';
import { IRole, PredefinedRoleType } from 'interfaces/role';
import { useRoles } from 'hooks/api/getters/useRoles/useRoles';
import { permissionsToCheckedPermissions } from 'utils/permissions';
import { ROOT_ROLE_TYPE } from '@server/util/constants';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/admin/roles/Roles.tsx
Expand Up @@ -17,7 +17,7 @@ import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { Add } from '@mui/icons-material';
import { UPDATE_ROLE } from '@server/types/permissions';
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';

const StyledPageContent = styled(PageContent)(({ theme }) => ({
'& .page-header': {
Expand Down
Expand Up @@ -3,7 +3,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { useServiceAccounts } from 'hooks/api/getters/useServiceAccounts/useServiceAccounts';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { RoleDeleteDialogUsers } from './RoleDeleteDialogUsers/RoleDeleteDialogUsers';
import { RoleDeleteDialogServiceAccounts } from './RoleDeleteDialogServiceAccounts/RoleDeleteDialogServiceAccounts';
import { useGroups } from 'hooks/api/getters/useGroups/useGroups';
Expand Down
@@ -1,7 +1,7 @@
import { VFC } from 'react';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { useRole } from 'hooks/api/getters/useRole/useRole';
import { RoleDescription } from 'component/common/RoleDescription/RoleDescription';
import { PREDEFINED_ROLE_TYPES } from '@server/util/constants';
Expand Down
Expand Up @@ -3,7 +3,7 @@ import { Box, styled } from '@mui/material';
import { PREDEFINED_ROLE_TYPES } from '@server/util/constants';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { VFC } from 'react';

const StyledBox = styled(Box)(() => ({
Expand Down
@@ -1,7 +1,7 @@
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Badge } from 'component/common/Badge/Badge';
import { styled } from '@mui/material';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
import { PREDEFINED_ROLE_TYPES } from '@server/util/constants';

Expand Down
@@ -1,7 +1,7 @@
import { useMemo, useState } from 'react';
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import IRole, { PredefinedRoleType } from 'interfaces/role';
import { IRole, PredefinedRoleType } from 'interfaces/role';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { PageContent } from 'component/common/PageContent/PageContent';
Expand Down
Expand Up @@ -33,7 +33,7 @@ import { INewPersonalAPIToken } from 'interfaces/personalAPIToken';
import { ServiceAccountTokens } from './ServiceAccountTokens/ServiceAccountTokens';
import { IServiceAccount } from 'interfaces/service-account';
import { RoleSelect } from 'component/common/RoleSelect/RoleSelect';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';

const StyledForm = styled('form')(() => ({
display: 'flex',
Expand Down
@@ -1,7 +1,7 @@
import { useMemo, useState } from 'react';
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { PageContent } from 'component/common/PageContent/PageContent';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/admin/users/UserForm/UserForm.tsx
Expand Up @@ -5,7 +5,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { EDIT } from 'constants/misc';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { RoleSelect } from 'component/common/RoleSelect/RoleSelect';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';

const StyledForm = styled('form')(() => ({
display: 'flex',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/admin/users/UsersList/UsersList.tsx
Expand Up @@ -7,7 +7,7 @@ import ConfirmUserAdded from '../ConfirmUserAdded/ConfirmUserAdded';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import useAdminUsersApi from 'hooks/api/actions/useAdminUsersApi/useAdminUsersApi';
import { IUser } from 'interfaces/user';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useUsersPlan } from 'hooks/useUsersPlan';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/admin/users/hooks/useAddUserForm.ts
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import IRole from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { useRoles } from 'hooks/api/getters/useRoles/useRoles';

const useCreateUserForm = (
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/component/common/RoleSelect/RoleSelect.tsx
Expand Up @@ -5,9 +5,10 @@ import {
styled,
} from '@mui/material';
import { useRoles } from 'hooks/api/getters/useRoles/useRoles';
import IRole from 'interfaces/role';
import { IRole, PredefinedRoleType } from 'interfaces/role';
import { RoleDescription } from '../RoleDescription/RoleDescription';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { ROOT_ROLE_TYPE } from '@server/util/constants';

const StyledRoleOption = styled('div')(({ theme }) => ({
display: 'flex',
Expand All @@ -20,18 +21,22 @@ const StyledRoleOption = styled('div')(({ theme }) => ({

interface IRoleSelectProps
extends Partial<AutocompleteProps<IRole, false, false, false>> {
type?: PredefinedRoleType;
value: IRole | null;
setValue: (role: IRole | null) => void;
required?: boolean;
}

export const RoleSelect = ({
type = ROOT_ROLE_TYPE,
value,
setValue,
required,
...rest
}: IRoleSelectProps) => {
const { roles } = useRoles();
const { roles: rootRoles, projectRoles } = useRoles();

const roles = type === ROOT_ROLE_TYPE ? rootRoles : projectRoles;

const renderRoleOption = (
props: React.HTMLAttributes<HTMLLIElement>,
Expand Down
Expand Up @@ -16,7 +16,7 @@ import useProjectAccess, {
ENTITY_TYPE,
IProjectAccess,
} from 'hooks/api/getters/useProjectAccess/useProjectAccess';
import { IProjectRole } from 'interfaces/role';
import { IRole } from 'interfaces/role';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
Expand All @@ -25,7 +25,6 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { IUser } from 'interfaces/user';
import { IGroup } from 'interfaces/group';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ProjectRoleDescription } from './ProjectRoleDescription/ProjectRoleDescription';
import { useNavigate } from 'react-router-dom';
import { GO_BACK } from 'constants/navigate';
import {
Expand All @@ -36,6 +35,8 @@ import {
} from 'utils/testIds';
import { caseInsensitiveSearch } from 'utils/search';
import { IServiceAccount } from 'interfaces/service-account';
import { RoleSelect } from 'component/common/RoleSelect/RoleSelect';
import { PROJECT_ROLE_TYPE } from '@server/util/constants';

const StyledForm = styled('form')(() => ({
display: 'flex',
Expand Down Expand Up @@ -82,15 +83,6 @@ const StyledUserOption = styled('div')(({ theme }) => ({
},
}));

const StyledRoleOption = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
'& > span:last-of-type': {
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.secondary,
},
}));

interface IAccessOption {
id: number;
entity: IUser | IGroup;
Expand All @@ -103,7 +95,7 @@ interface IProjectAccessAssignProps {
users: IUser[];
serviceAccounts: IServiceAccount[];
groups: IGroup[];
roles: IProjectRole[];
roles: IRole[];
}

export const ProjectAccessAssign = ({
Expand Down Expand Up @@ -190,7 +182,7 @@ export const ProjectAccessAssign = ({
id === selected?.entity.id && type === selected?.type
)
);
const [role, setRole] = useState<IProjectRole | null>(
const [role, setRole] = useState<IRole | null>(
roles.find(({ id }) => id === selected?.entity.roleId) ?? null
);

Expand Down Expand Up @@ -317,18 +309,6 @@ export const ProjectAccessAssign = ({
);
};

const renderRoleOption = (
props: React.HTMLAttributes<HTMLLIElement>,
option: IProjectRole
) => (
<li {...props}>
<StyledRoleOption>
<span>{option.name}</span>
<span>{option.description}</span>
</StyledRoleOption>
</li>
);

const isValid = selectedOptions.length > 0 && role;

return (
Expand Down Expand Up @@ -451,29 +431,13 @@ export const ProjectAccessAssign = ({
Select the role to assign for this project
</StyledInputDescription>
<StyledAutocompleteWrapper>
<Autocomplete
<RoleSelect
data-testid={PA_ROLE_ID}
size="small"
openOnFocus
type={PROJECT_ROLE_TYPE}
value={role}
onChange={(_, newValue) => setRole(newValue)}
options={roles}
renderOption={renderRoleOption}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} label="Role" />
)}
setValue={role => setRole(role || null)}
/>
</StyledAutocompleteWrapper>
<ConditionallyRender
condition={Boolean(role?.id)}
show={
<ProjectRoleDescription
roleId={role?.id!}
projectId={projectId}
/>
}
/>
</div>

<StyledButtonContainer>
Expand Down

0 comments on commit a9e9ae8

Please sign in to comment.