Adding SecureComponent to list groups and group details page (#1238)

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Lenin Alevski
2021-11-18 19:51:40 -08:00
committed by GitHub
parent f0d5398748
commit 7f5de2d70e
3 changed files with 188 additions and 94 deletions

View File

@@ -112,6 +112,11 @@ export const IAM_SCOPES = {
S3_GET_BUCKET_LOCATION: "s3:GetBucketLocation", S3_GET_BUCKET_LOCATION: "s3:GetBucketLocation",
S3_DELETE_BUCKET_POLICY: "s3:DeleteBucketPolicy", S3_DELETE_BUCKET_POLICY: "s3:DeleteBucketPolicy",
S3_ABORT_MULTIPART_UPLOAD: "s3:AbortMultipartUpload", S3_ABORT_MULTIPART_UPLOAD: "s3:AbortMultipartUpload",
ADMIN_ADD_USER_TO_GROUP: "admin:AddUserToGroup",
ADMIN_REMOVE_USER_FROM_GROUP: "admin:RemoveUserFromGroup",
ADMIN_GET_GROUP: "admin:GetGroup",
ADMIN_ENABLE_GROUP: "admin:EnableGroup",
ADMIN_DISABLE_GROUP: "admin:DisableGroup",
S3_ALL_ACTIONS: "s3:*", S3_ALL_ACTIONS: "s3:*",
ADMIN_ALL_ACTIONS: "admin:*", ADMIN_ALL_ACTIONS: "admin:*",
}; };

View File

@@ -43,6 +43,13 @@ import history from "../../../history";
import AButton from "../Common/AButton/AButton"; import AButton from "../Common/AButton/AButton";
import PageLayout from "../Common/Layout/PageLayout"; import PageLayout from "../Common/Layout/PageLayout";
import SearchBox from "../Common/SearchBox"; import SearchBox from "../Common/SearchBox";
import {
CONSOLE_UI_RESOURCE,
IAM_SCOPES,
} from "../../../common/SecureComponent/permissions";
import SecureComponent, {
hasPermission,
} from "../../../common/SecureComponent/SecureComponent";
interface IGroupsProps { interface IGroupsProps {
classes: any; classes: any;
@@ -85,27 +92,43 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
isLoading(true); isLoading(true);
}, []); }, []);
const displayGroups = hasPermission(CONSOLE_UI_RESOURCE, [
IAM_SCOPES.ADMIN_LIST_GROUPS,
]);
const deleteGroup = hasPermission(CONSOLE_UI_RESOURCE, [
IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP,
]);
const getGroup = hasPermission(CONSOLE_UI_RESOURCE, [
IAM_SCOPES.ADMIN_GET_GROUP,
]);
useEffect(() => { useEffect(() => {
if (loading) { if (loading) {
const fetchRecords = () => { if (displayGroups) {
api const fetchRecords = () => {
.invoke("GET", `/api/v1/groups`) api
.then((res: GroupsList) => { .invoke("GET", `/api/v1/groups`)
let resGroups: string[] = []; .then((res: GroupsList) => {
if (res.groups !== null) { let resGroups: string[] = [];
resGroups = res.groups.sort(stringSort); if (res.groups !== null) {
} resGroups = res.groups.sort(stringSort);
setRecords(resGroups); }
isLoading(false); setRecords(resGroups);
}) isLoading(false);
.catch((err: ErrorResponseHandler) => { })
setErrorSnackMessage(err); .catch((err: ErrorResponseHandler) => {
isLoading(false); setErrorSnackMessage(err);
}); isLoading(false);
}; });
fetchRecords(); };
fetchRecords();
} else {
isLoading(false);
}
} }
}, [loading, setErrorSnackMessage]); }, [loading, setErrorSnackMessage, displayGroups]);
const closeAddModalAndRefresh = () => { const closeAddModalAndRefresh = () => {
setGroupOpen(false); setGroupOpen(false);
@@ -134,8 +157,16 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
}; };
const tableActions = [ const tableActions = [
{ type: "view", onClick: viewAction }, {
{ type: "delete", onClick: deleteAction }, type: "view",
onClick: viewAction,
disableButtonFunction: () => !getGroup,
},
{
type: "delete",
onClick: deleteAction,
disableButtonFunction: () => !deleteGroup,
},
]; ];
return ( return (
@@ -173,19 +204,27 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
onChange={setFilter} onChange={setFilter}
classes={classes} classes={classes}
/> />
<Button <SecureComponent
variant="contained" resource={CONSOLE_UI_RESOURCE}
color="primary" scopes={[
endIcon={<AddIcon />} IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
onClick={() => { IAM_SCOPES.ADMIN_LIST_USERS,
setSelectedGroup(null); ]}
setGroupOpen(true); matchAll
}}
> >
Create Group <Button
</Button> variant="contained"
color="primary"
endIcon={<AddIcon />}
onClick={() => {
setSelectedGroup(null);
setGroupOpen(true);
}}
>
Create Group
</Button>
</SecureComponent>
</Grid> </Grid>
{loading && <LinearProgress />} {loading && <LinearProgress />}
{!loading && ( {!loading && (
<Fragment> <Fragment>
@@ -245,18 +284,27 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
users with membership in that group inherit that policy. users with membership in that group inherit that policy.
Groups support more simplified management of user Groups support more simplified management of user
permissions on the MinIO Tenant. permissions on the MinIO Tenant.
<br /> <SecureComponent
<br /> resource="console-ui"
To get started,{" "} scopes={[
<AButton IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
onClick={() => { IAM_SCOPES.ADMIN_LIST_USERS,
setSelectedGroup(null); ]}
setGroupOpen(true); matchAll
}}
> >
Create a Group <br />
</AButton> <br />
. To get started,{" "}
<AButton
onClick={() => {
setSelectedGroup(null);
setGroupOpen(true);
}}
>
Create a Group
</AButton>
.
</SecureComponent>
</Fragment> </Fragment>
} }
/> />

View File

@@ -33,6 +33,13 @@ import BackLink from "../../../common/BackLink";
import PanelTitle from "../Common/PanelTitle/PanelTitle"; import PanelTitle from "../Common/PanelTitle/PanelTitle";
import BoxIconButton from "../Common/BoxIconButton/BoxIconButton"; import BoxIconButton from "../Common/BoxIconButton/BoxIconButton";
import SearchBox from "../Common/SearchBox"; import SearchBox from "../Common/SearchBox";
import {
CONSOLE_UI_RESOURCE,
IAM_SCOPES,
} from "../../../common/SecureComponent/permissions";
import SecureComponent, {
hasPermission,
} from "../../../common/SecureComponent/SecureComponent";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
@@ -154,16 +161,22 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
const isGroupEnabled = groupEnabled === "enabled"; const isGroupEnabled = groupEnabled === "enabled";
const memberActionText = members.length > 0 ? "Edit Members" : "Add Members"; const memberActionText = members.length > 0 ? "Edit Members" : "Add Members";
const getGroupDetails = hasPermission(CONSOLE_UI_RESOURCE, [
IAM_SCOPES.ADMIN_GET_GROUP,
]);
function fetchGroupInfo() { function fetchGroupInfo() {
api if (getGroupDetails) {
.invoke("GET", `/api/v1/group?name=${encodeURI(groupName)}`) api
.then((res: any) => { .invoke("GET", `/api/v1/group?name=${encodeURI(groupName)}`)
setGroupDetails(res); .then((res: any) => {
}) setGroupDetails(res);
.catch((err) => { })
setModalErrorSnackMessage(err); .catch((err) => {
setGroupDetails({}); setModalErrorSnackMessage(err);
}); setGroupDetails({});
});
}
} }
function toggleGroupStatus(nextStatus: boolean) { function toggleGroupStatus(nextStatus: boolean) {
@@ -192,28 +205,40 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
}} }}
classes={classes} classes={classes}
/> />
<Button <SecureComponent
variant="contained" resource={CONSOLE_UI_RESOURCE}
color="primary" scopes={[IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP]}
endIcon={<UsersIcon />} errorProps={{ disabled: true }}
size="medium"
onClick={() => {
setUsersOpen(true);
}}
> >
{memberActionText} <Button
</Button> variant="contained"
color="primary"
endIcon={<UsersIcon />}
size="medium"
onClick={() => {
setUsersOpen(true);
}}
>
{memberActionText}
</Button>
</SecureComponent>
</div> </div>
<div className={classes.tableBlock}> <div className={classes.tableBlock}>
<TableWrapper <SecureComponent
columns={[{ label: "Access Key", elementKey: "" }]} resource={CONSOLE_UI_RESOURCE}
selectedItems={[]} scopes={[IAM_SCOPES.ADMIN_LIST_USERS]}
isLoading={false} errorProps={{ disabled: true }}
records={filteredMembers} >
entityName="Users" <TableWrapper
idField="" columns={[{ label: "Access Key", elementKey: "" }]}
/> selectedItems={[]}
isLoading={false}
records={filteredMembers}
entityName="Users"
idField=""
/>
</SecureComponent>
</div> </div>
</React.Fragment> </React.Fragment>
); );
@@ -274,31 +299,47 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
<span className={classes.statusValue}> <span className={classes.statusValue}>
{isGroupEnabled ? "Enabled" : "Disabled"} {isGroupEnabled ? "Enabled" : "Disabled"}
</span> </span>
<FormSwitchWrapper <SecureComponent
indicatorLabels={["Enabled", "Disabled"]} resource={CONSOLE_UI_RESOURCE}
checked={isGroupEnabled} scopes={[
value={"group_enabled"} IAM_SCOPES.ADMIN_ENABLE_GROUP,
id="group-status" IAM_SCOPES.ADMIN_DISABLE_GROUP,
name="group-status" ]}
onChange={() => { errorProps={{ disabled: true }}
toggleGroupStatus(!isGroupEnabled); matchAll
}} >
switchOnly <FormSwitchWrapper
/> indicatorLabels={["Enabled", "Disabled"]}
<Tooltip title="Delete Group"> checked={isGroupEnabled}
<div className={classes.spacerLeft}> value={"group_enabled"}
<BoxIconButton id="group-status"
color="primary" name="group-status"
aria-label="Delete Group" onChange={() => {
onClick={() => { toggleGroupStatus(!isGroupEnabled);
setDeleteOpen(true); }}
}} switchOnly
size="large" />
> </SecureComponent>
<TrashIcon />
</BoxIconButton> <SecureComponent
</div> resource={CONSOLE_UI_RESOURCE}
</Tooltip> scopes={[IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP]}
>
<Tooltip title="Delete Group">
<div className={classes.spacerLeft}>
<BoxIconButton
color="primary"
aria-label="Delete Group"
onClick={() => {
setDeleteOpen(true);
}}
size="large"
>
<TrashIcon />
</BoxIconButton>
</div>
</Tooltip>
</SecureComponent>
</Fragment> </Fragment>
} }
/> />