Skip to content

Commit

Permalink
adapt new role logic in all the places
Browse files Browse the repository at this point in the history
  • Loading branch information
nunogois committed Jun 13, 2023
1 parent 2f1fc82 commit 83d59c3
Show file tree
Hide file tree
Showing 24 changed files with 394 additions and 173 deletions.
28 changes: 8 additions & 20 deletions frontend/src/component/admin/groups/GroupForm/GroupForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FC } from 'react';
import { Autocomplete, Box, Button, styled, TextField } from '@mui/material';
import { Box, Button, styled } from '@mui/material';
import { UG_DESC_ID, UG_NAME_ID } from 'utils/testIds';
import Input from 'component/common/Input/Input';
import { IGroupUser } from 'interfaces/group';
Expand All @@ -10,9 +10,10 @@ 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 { IProjectRole } from 'interfaces/role';
import IRole, { IProjectRole } 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';

const StyledForm = styled('form')(() => ({
display: 'flex',
Expand Down Expand Up @@ -128,10 +129,8 @@ export const GroupForm: FC<IGroupForm> = ({

const groupRootRolesEnabled = Boolean(uiConfig.flags.groupRootRoles);

const roleIdToRole = (rootRoleId: number | null): IProjectRole | null => {
return (
roles.find((role: IProjectRole) => role.id === rootRoleId) || null
);
const roleIdToRole = (rootRoleId: number | null): IRole | null => {
return roles.find((role: IRole) => role.id === rootRoleId) || null;
};

const renderRoleOption = (
Expand Down Expand Up @@ -214,23 +213,12 @@ export const GroupForm: FC<IGroupForm> = ({
</Box>
</StyledInputDescription>
<StyledAutocompleteWrapper>
<Autocomplete
<RoleSelect
data-testid="GROUP_ROOT_ROLE"
size="small"
openOnFocus
value={roleIdToRole(rootRole)}
onChange={(_, newValue) =>
setRootRole(newValue?.id || null)
setValue={role =>
setRootRole(role?.id || null)
}
options={roles.filter(
(role: IProjectRole) =>
role.name !== 'Viewer'
)}
renderOption={renderRoleOption}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} label="Role" />
)}
/>
</StyledAutocompleteWrapper>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars';
import { Badge } from 'component/common/Badge/Badge';
import { GroupCardActions } from './GroupCardActions/GroupCardActions';
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
import { IProjectRole } from 'interfaces/role';
import { RoleBadge } from 'component/common/RoleBadge/RoleBadge';

const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
Expand Down Expand Up @@ -86,14 +86,12 @@ const InfoBadgeDescription = styled('span')(({ theme }) => ({

interface IGroupCardProps {
group: IGroup;
rootRoles: IProjectRole[];
onEditUsers: (group: IGroup) => void;
onRemoveGroup: (group: IGroup) => void;
}

export const GroupCard = ({
group,
rootRoles,
onEditUsers,
onRemoveGroup,
}: IGroupCardProps) => {
Expand All @@ -117,17 +115,7 @@ export const GroupCard = ({
show={
<InfoBadgeDescription>
<p>Root role:</p>
<Badge
color="success"
icon={<TopicOutlinedIcon />}
>
{
rootRoles.find(
(role: IProjectRole) =>
role.id === group.rootRole
)?.name
}
</Badge>
<RoleBadge roleId={group.rootRole!} />
</InfoBadgeDescription>
}
/>
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/component/admin/groups/GroupsList/GroupsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { Add } from '@mui/icons-material';
import { NAVIGATE_TO_CREATE_GROUP } from 'utils/testIds';
import { EditGroupUsers } from '../Group/EditGroupUsers/EditGroupUsers';
import { RemoveGroup } from '../RemoveGroup/RemoveGroup';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import { IProjectRole } from 'interfaces/role';

type PageQueryType = Partial<Record<'search', string>>;

Expand Down Expand Up @@ -51,7 +49,6 @@ export const GroupsList: VFC = () => {
const [searchValue, setSearchValue] = useState(
searchParams.get('search') || ''
);
const { roles } = useUsers();

const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));

Expand Down Expand Up @@ -85,10 +82,6 @@ export const GroupsList: VFC = () => {
setRemoveOpen(true);
};

const getBindableRootRoles = () => {
return roles.filter((role: IProjectRole) => role.type === 'root');
};

return (
<PageContent
isLoading={loading}
Expand Down Expand Up @@ -141,7 +134,6 @@ export const GroupsList: VFC = () => {
<Grid key={group.id} item xs={12} md={6}>
<GroupCard
group={group}
rootRoles={getBindableRootRoles()}
onEditUsers={onEditUsers}
onRemoveGroup={onRemoveGroup}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import FormTemplate from 'component/common/FormTemplate/FormTemplate';
import { UpdateButton } from 'component/common/UpdateButton/UpdateButton';
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import { useRolesApi } from 'hooks/api/actions/useRolesApi/useRolesApi';
import useProjectRole from 'hooks/api/getters/useProjectRole/useProjectRole';
import { useRole } from 'hooks/api/getters/useRole/useRole';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import useToast from 'hooks/useToast';
import { useNavigate } from 'react-router-dom';
Expand All @@ -16,7 +16,7 @@ const EditProjectRole = () => {
const { uiConfig } = useUiConfig();
const { setToastData, setToastApiError } = useToast();
const roleId = useRequiredPathParam('id');
const { role } = useProjectRole(roleId);
const { role, refetch } = useRole(roleId);

const navigate = useNavigate();
const {
Expand All @@ -35,18 +35,17 @@ const EditProjectRole = () => {
validateName,
clearErrors,
getRoleKey,
} = useProjectRoleForm(role.name, role.description, role?.permissions);
} = useProjectRoleForm(role?.name, role?.description, role?.permissions);

const formatApiCode = () => {
return `curl --location --request PUT '${
uiConfig.unleashUrl
}/api/admin/roles/${role.id}' \\
}/api/admin/roles/${role?.id}' \\
--header 'Authorization: INSERT_API_KEY' \\
--header 'Content-Type: application/json' \\
--data-raw '${JSON.stringify(getProjectRolePayload(), undefined, 2)}'`;
};

const { refetch } = useProjectRole(roleId);
const { updateRole, loading } = useRolesApi();

const onSubmit = async (e: Event) => {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/component/admin/roles/RoleForm/RoleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const RoleForm = ({
</StyledInputDescription>
{[...categories].map(category => (
<PermissionAccordion
key={category}
title={`${category} permissions`}
context={category.toLowerCase()}
Icon={<UserIcon color="disabled" sx={{ mr: 1 }} />}
Expand Down
15 changes: 11 additions & 4 deletions frontend/src/component/admin/roles/RoleModal/RoleModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Button, styled } from '@mui/material';
import { SidebarModal } from 'component/common/SidebarModal/SidebarModal';
import IRole from 'interfaces/role';
import { useRoleForm } from '../RoleForm/useRoleForm';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
Expand All @@ -10,6 +9,7 @@ import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { FormEvent } from 'react';
import { useRolesApi } from 'hooks/api/actions/useRolesApi/useRolesApi';
import { useRole } from 'hooks/api/getters/useRole/useRole';

const StyledForm = styled('form')(() => ({
display: 'flex',
Expand All @@ -29,12 +29,14 @@ const StyledCancelButton = styled(Button)(({ theme }) => ({
}));

interface IRoleModalProps {
role?: IRole;
roleId?: number;
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
}

export const RoleModal = ({ role, open, setOpen }: IRoleModalProps) => {
export const RoleModal = ({ roleId, open, setOpen }: IRoleModalProps) => {
const { role, refetch: refetchRole } = useRole(roleId?.toString());

const {
name,
setName,
Expand All @@ -53,7 +55,7 @@ export const RoleModal = ({ role, open, setOpen }: IRoleModalProps) => {
clearError,
ErrorField,
} = useRoleForm(role?.name, role?.description, role?.permissions);
const { refetch } = useRoles();
const { refetch: refetchRoles } = useRoles();
const { addRole, updateRole, loading } = useRolesApi();
const { setToastData, setToastApiError } = useToast();
const { uiConfig } = useUiConfig();
Expand Down Expand Up @@ -82,6 +84,11 @@ export const RoleModal = ({ role, open, setOpen }: IRoleModalProps) => {
setName(name);
};

const refetch = () => {
refetchRoles();
refetchRole();
};

const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import IRole from 'interfaces/role';
import { RoleDeleteDialogUsers } from './RoleDeleteDialogUsers/RoleDeleteDialogUsers';
import { RoleDeleteDialogServiceAccounts } from './RoleDeleteDialogServiceAccounts/RoleDeleteDialogServiceAccounts';
import { useGroups } from 'hooks/api/getters/useGroups/useGroups';
import { RoleDeleteDialogGroups } from './RoleDeleteDialogGroups/RoleDeleteDialogGroups';

const StyledTableContainer = styled('div')(({ theme }) => ({
marginTop: theme.spacing(1.5),
Expand All @@ -30,11 +32,13 @@ export const RoleDeleteDialog = ({
}: IRoleDeleteDialogProps) => {
const { users } = useUsers();
const { serviceAccounts } = useServiceAccounts();
const { groups } = useGroups();

const roleUsers = users.filter(({ rootRole }) => rootRole === role?.id);
const roleServiceAccounts = serviceAccounts.filter(
({ rootRole }) => rootRole === role?.id
);
const roleGroups = groups?.filter(({ rootRole }) => rootRole === role?.id);

const deleteMessage = (
<>
Expand All @@ -55,14 +59,16 @@ export const RoleDeleteDialog = ({
>
<ConditionallyRender
condition={Boolean(
roleUsers.length || roleServiceAccounts.length
roleUsers.length ||
roleServiceAccounts.length ||
roleGroups?.length
)}
show={
<>
<Alert severity="error">
If you delete this role, all current accounts
If you delete this role, all current entities
associated with it will be automatically assigned
the preconfigured <strong>Viewer</strong> role.
the predefined <strong>Viewer</strong> role.
</Alert>
<StyledLabel>{deleteMessage}</StyledLabel>
<ConditionallyRender
Expand Down Expand Up @@ -98,6 +104,21 @@ export const RoleDeleteDialog = ({
</>
}
/>
<ConditionallyRender
condition={Boolean(roleGroups?.length)}
show={
<>
<StyledLabel>
Groups ({roleGroups?.length}):
</StyledLabel>
<StyledTableContainer>
<RoleDeleteDialogGroups
groups={roleGroups!}
/>
</StyledTableContainer>
</>
}
/>
</>
}
elseShow={<p>{deleteMessage}</p>}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { VirtualizedTable } from 'component/common/Table';
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
import { useMemo, useState } from 'react';
import { useTable, useSortBy, useFlexLayout, Column } from 'react-table';
import { sortTypes } from 'utils/sortTypes';
import { IGroup } from 'interfaces/group';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';

export type PageQueryType = Partial<
Record<'sort' | 'order' | 'search', string>
>;

interface IRoleDeleteDialogGroupsProps {
groups: IGroup[];
}

export const RoleDeleteDialogGroups = ({
groups,
}: IRoleDeleteDialogGroupsProps) => {
const [initialState] = useState(() => ({
sortBy: [{ id: 'createdAt' }],
}));

console.log(groups);

const columns = useMemo(
() =>
[
{
id: 'name',
Header: 'Name',
accessor: (row: any) => row.name || '',
minWidth: 200,
Cell: ({ row: { original: group } }: any) => (
<HighlightCell
value={group.name}
subtitle={group.description}
/>
),
},
{
Header: 'Created',
accessor: 'createdAt',
Cell: DateCell,
sortType: 'date',
width: 120,
maxWidth: 120,
},
{
id: 'users',
Header: 'Users',
accessor: (row: IGroup) =>
row.users.length === 1
? '1 user'
: `${row.users.length} users`,
Cell: TextCell,
maxWidth: 150,
},
] as Column<IGroup>[],
[]
);

const { headerGroups, rows, prepareRow } = useTable(
{
columns,
data: groups,
initialState,
sortTypes,
autoResetHiddenColumns: false,
autoResetSortBy: false,
disableSortRemove: true,
disableMultiSort: true,
},
useSortBy,
useFlexLayout
);

return (
<VirtualizedTable
rows={rows}
headerGroups={headerGroups}
prepareRow={prepareRow}
/>
);
};
Loading

0 comments on commit 83d59c3

Please sign in to comment.