Added tooltips, button permission UI, for Groups, GroupDetails screens (#2353)
This commit is contained in:
@@ -449,11 +449,15 @@ export const permissionTooltipHelper = (scopes: string[], name: string) => {
|
||||
};
|
||||
|
||||
export const listUsersPermissions = [IAM_SCOPES.ADMIN_LIST_USERS];
|
||||
export const viewUserPermissions = [IAM_SCOPES.ADMIN_GET_USER];
|
||||
|
||||
export const addUserToGroupPermissions = [IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP];
|
||||
|
||||
export const deleteUserPermissions = [IAM_SCOPES.ADMIN_DELETE_USER];
|
||||
|
||||
export const enableUserPermissions = [IAM_SCOPES.ADMIN_ENABLE_USER];
|
||||
|
||||
export const disableUserPermissions = [IAM_SCOPES.ADMIN_DISABLE_USER];
|
||||
|
||||
export const assignIAMPolicyPermissions = [
|
||||
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY,
|
||||
IAM_SCOPES.ADMIN_LIST_USER_POLICIES,
|
||||
@@ -479,3 +483,35 @@ export const editServiceAccountPermissions = [
|
||||
IAM_SCOPES.ADMIN_UPDATE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_REMOVE_SERVICEACCOUNT,
|
||||
];
|
||||
|
||||
export const applyPolicyPermissions = [
|
||||
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY,
|
||||
IAM_SCOPES.ADMIN_LIST_USER_POLICIES,
|
||||
];
|
||||
|
||||
export const deleteGroupPermissions = [IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP];
|
||||
|
||||
export const displayGroupsPermissions = [IAM_SCOPES.ADMIN_LIST_GROUPS];
|
||||
|
||||
export const createGroupPermissions = [
|
||||
IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
|
||||
IAM_SCOPES.ADMIN_LIST_USERS,
|
||||
];
|
||||
|
||||
export const viewUserPermissions = [
|
||||
IAM_SCOPES.ADMIN_GET_USER,
|
||||
IAM_SCOPES.ADMIN_LIST_USERS,
|
||||
];
|
||||
export const editGroupMembersPermissions = [
|
||||
IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
|
||||
IAM_SCOPES.ADMIN_LIST_USERS,
|
||||
];
|
||||
export const setGroupPoliciesPermissions = [
|
||||
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY,
|
||||
IAM_SCOPES.ADMIN_LIST_USER_POLICIES,
|
||||
];
|
||||
export const viewPolicyPermissions = [IAM_SCOPES.ADMIN_GET_POLICY];
|
||||
export const enableDisableGroupPermissions = [
|
||||
IAM_SCOPES.ADMIN_ENABLE_GROUP,
|
||||
IAM_SCOPES.ADMIN_DISABLE_GROUP,
|
||||
];
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
TableRowPredefStyles,
|
||||
} from "../FormComponents/common/styleLibrary";
|
||||
import Loader from "../Loader/Loader";
|
||||
import TooltipWrapper from "../TooltipWrapper/TooltipWrapper";
|
||||
|
||||
//Interfaces for table Items
|
||||
|
||||
@@ -111,6 +112,7 @@ interface TableWrapperProps {
|
||||
index: number;
|
||||
}) => "deleted" | "" | React.CSSProperties;
|
||||
parentClassName?: string;
|
||||
tooltip?: any;
|
||||
}
|
||||
|
||||
const borderColor = "#9c9c9c80";
|
||||
@@ -465,6 +467,7 @@ const TableWrapper = ({
|
||||
onSelectAll,
|
||||
rowStyle,
|
||||
parentClassName = "",
|
||||
tooltip,
|
||||
}: TableWrapperProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -558,235 +561,249 @@ const TableWrapper = ({
|
||||
|
||||
return (
|
||||
<Grid item xs={12} className={parentClassName}>
|
||||
<Paper
|
||||
className={`${classes.paper} ${noBackground ? classes.noBackground : ""}
|
||||
<TooltipWrapper tooltip={tooltip ? tooltip : ""}>
|
||||
<Paper
|
||||
className={`${classes.paper} ${
|
||||
noBackground ? classes.noBackground : ""
|
||||
}
|
||||
${disabled ? classes.disabled : ""}
|
||||
${
|
||||
customPaperHeight !== ""
|
||||
? customPaperHeight
|
||||
: classes.defaultPaperHeight
|
||||
}`}
|
||||
>
|
||||
{isLoading && (
|
||||
<Grid container className={classes.loadingBox}>
|
||||
<Grid item xs={12} style={{ textAlign: "center" }}>
|
||||
{loadingMessage}
|
||||
>
|
||||
{isLoading && (
|
||||
<Grid container className={classes.loadingBox}>
|
||||
<Grid item xs={12} style={{ textAlign: "center" }}>
|
||||
{loadingMessage}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
{columnsSelector && !isLoading && records.length > 0 && (
|
||||
<div className={classes.overlayColumnSelection}>
|
||||
{columnsSelection(columns)}
|
||||
</div>
|
||||
)}
|
||||
{records && !isLoading && records.length > 0 ? (
|
||||
// @ts-ignore
|
||||
<InfiniteLoader
|
||||
isRowLoaded={({ index }) => !!records[index]}
|
||||
loadMoreRows={
|
||||
infiniteScrollConfig
|
||||
? infiniteScrollConfig.loadMoreRecords
|
||||
: () => new Promise(() => true)
|
||||
}
|
||||
rowCount={
|
||||
infiniteScrollConfig
|
||||
? infiniteScrollConfig.recordsCount
|
||||
: records.length
|
||||
}
|
||||
>
|
||||
{({ onRowsRendered, registerChild }) => (
|
||||
// @ts-ignore
|
||||
<AutoSizer>
|
||||
{({ width, height }: any) => {
|
||||
const optionsWidth = calculateOptionsSize(
|
||||
width,
|
||||
itemActions
|
||||
? itemActions.filter((el) => el.type !== "view").length
|
||||
: 0
|
||||
);
|
||||
const hasSelect: boolean = !!(onSelect && selectedItems);
|
||||
const hasOptions: boolean = !!(
|
||||
(itemActions && itemActions.length > 1) ||
|
||||
(itemActions &&
|
||||
itemActions.length === 1 &&
|
||||
itemActions[0].type !== "view")
|
||||
);
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Table
|
||||
ref={registerChild}
|
||||
disableHeader={false}
|
||||
headerClassName={"headerItem"}
|
||||
headerHeight={40}
|
||||
height={height}
|
||||
noRowsRenderer={() => (
|
||||
<Fragment>
|
||||
{customEmptyMessage !== ""
|
||||
? customEmptyMessage
|
||||
: `There are no ${entityName} yet.`}
|
||||
</Fragment>
|
||||
)}
|
||||
overscanRowCount={10}
|
||||
rowHeight={40}
|
||||
width={width}
|
||||
rowCount={records.length}
|
||||
rowGetter={({ index }) => records[index]}
|
||||
onRowClick={({ rowData }) => {
|
||||
clickAction(rowData);
|
||||
}}
|
||||
rowClassName={`rowLine ${findView ? "canClick" : ""} ${
|
||||
!findView && textSelectable ? "canSelectText" : ""
|
||||
}`}
|
||||
onRowsRendered={onRowsRendered}
|
||||
sort={sortConfig ? sortConfig.triggerSort : undefined}
|
||||
sortBy={sortConfig ? sortConfig.currentSort : undefined}
|
||||
sortDirection={
|
||||
sortConfig ? sortConfig.currentDirection : undefined
|
||||
}
|
||||
scrollToIndex={
|
||||
autoScrollToBottom ? records.length - 1 : -1
|
||||
}
|
||||
rowStyle={(r) => {
|
||||
if (rowStyle) {
|
||||
const returnElement = rowStyle(r);
|
||||
)}
|
||||
{columnsSelector && !isLoading && records.length > 0 && (
|
||||
<div className={classes.overlayColumnSelection}>
|
||||
{columnsSelection(columns)}
|
||||
</div>
|
||||
)}
|
||||
{records && !isLoading && records.length > 0 ? (
|
||||
// @ts-ignore
|
||||
<InfiniteLoader
|
||||
isRowLoaded={({ index }) => !!records[index]}
|
||||
loadMoreRows={
|
||||
infiniteScrollConfig
|
||||
? infiniteScrollConfig.loadMoreRecords
|
||||
: () => new Promise(() => true)
|
||||
}
|
||||
rowCount={
|
||||
infiniteScrollConfig
|
||||
? infiniteScrollConfig.recordsCount
|
||||
: records.length
|
||||
}
|
||||
>
|
||||
{({ onRowsRendered, registerChild }) => (
|
||||
// @ts-ignore
|
||||
<AutoSizer>
|
||||
{({ width, height }: any) => {
|
||||
const optionsWidth = calculateOptionsSize(
|
||||
width,
|
||||
itemActions
|
||||
? itemActions.filter((el) => el.type !== "view").length
|
||||
: 0
|
||||
);
|
||||
const hasSelect: boolean = !!(onSelect && selectedItems);
|
||||
const hasOptions: boolean = !!(
|
||||
(itemActions && itemActions.length > 1) ||
|
||||
(itemActions &&
|
||||
itemActions.length === 1 &&
|
||||
itemActions[0].type !== "view")
|
||||
);
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Table
|
||||
ref={registerChild}
|
||||
disableHeader={false}
|
||||
headerClassName={"headerItem"}
|
||||
headerHeight={40}
|
||||
height={height}
|
||||
noRowsRenderer={() => (
|
||||
<Fragment>
|
||||
{customEmptyMessage !== ""
|
||||
? customEmptyMessage
|
||||
: `There are no ${entityName} yet.`}
|
||||
</Fragment>
|
||||
)}
|
||||
overscanRowCount={10}
|
||||
rowHeight={40}
|
||||
width={width}
|
||||
rowCount={records.length}
|
||||
rowGetter={({ index }) => records[index]}
|
||||
onRowClick={({ rowData }) => {
|
||||
clickAction(rowData);
|
||||
}}
|
||||
rowClassName={`rowLine ${findView ? "canClick" : ""} ${
|
||||
!findView && textSelectable ? "canSelectText" : ""
|
||||
}`}
|
||||
onRowsRendered={onRowsRendered}
|
||||
sort={sortConfig ? sortConfig.triggerSort : undefined}
|
||||
sortBy={sortConfig ? sortConfig.currentSort : undefined}
|
||||
sortDirection={
|
||||
sortConfig ? sortConfig.currentDirection : undefined
|
||||
}
|
||||
scrollToIndex={
|
||||
autoScrollToBottom ? records.length - 1 : -1
|
||||
}
|
||||
rowStyle={(r) => {
|
||||
if (rowStyle) {
|
||||
const returnElement = rowStyle(r);
|
||||
|
||||
if (typeof returnElement === "string") {
|
||||
return get(TableRowPredefStyles, returnElement, {});
|
||||
if (typeof returnElement === "string") {
|
||||
return get(
|
||||
TableRowPredefStyles,
|
||||
returnElement,
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
return returnElement;
|
||||
}
|
||||
|
||||
return returnElement;
|
||||
}
|
||||
return {};
|
||||
}}
|
||||
>
|
||||
{hasSelect && (
|
||||
// @ts-ignore
|
||||
<Column
|
||||
headerRenderer={() => (
|
||||
<Fragment>
|
||||
{onSelectAll ? (
|
||||
<div className={classes.checkAllWrapper}>
|
||||
<CheckboxWrapper
|
||||
label={""}
|
||||
onChange={onSelectAll}
|
||||
value="all"
|
||||
id={"selectAll"}
|
||||
name={"selectAll"}
|
||||
checked={
|
||||
selectedItems?.length === records.length
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Fragment>Select</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
dataKey={`select-${idField}`}
|
||||
width={selectWidth}
|
||||
disableSort
|
||||
cellRenderer={({ rowData }) => {
|
||||
const isSelected = selectedItems
|
||||
? selectedItems.includes(
|
||||
isString(rowData)
|
||||
? rowData
|
||||
: rowData[idField]
|
||||
)
|
||||
: false;
|
||||
|
||||
return {};
|
||||
}}
|
||||
>
|
||||
{hasSelect && (
|
||||
// @ts-ignore
|
||||
<Column
|
||||
headerRenderer={() => (
|
||||
<Fragment>
|
||||
{onSelectAll ? (
|
||||
<div className={classes.checkAllWrapper}>
|
||||
<CheckboxWrapper
|
||||
label={""}
|
||||
onChange={onSelectAll}
|
||||
value="all"
|
||||
id={"selectAll"}
|
||||
name={"selectAll"}
|
||||
checked={
|
||||
selectedItems?.length === records.length
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Fragment>Select</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
dataKey={`select-${idField}`}
|
||||
width={selectWidth}
|
||||
disableSort
|
||||
cellRenderer={({ rowData }) => {
|
||||
const isSelected = selectedItems
|
||||
? selectedItems.includes(
|
||||
isString(rowData) ? rowData : rowData[idField]
|
||||
)
|
||||
: false;
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
value={
|
||||
isString(rowData) ? rowData : rowData[idField]
|
||||
}
|
||||
color="primary"
|
||||
inputProps={{
|
||||
"aria-label": "secondary checkbox",
|
||||
}}
|
||||
className="TableCheckbox"
|
||||
checked={isSelected}
|
||||
onChange={onSelect}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
checkedIcon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioSelectedIcon
|
||||
: classes.checkedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
icon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioUnselectedIcon
|
||||
: classes.unCheckedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{generateColumnsMap(
|
||||
columns,
|
||||
width,
|
||||
optionsWidth,
|
||||
hasSelect,
|
||||
hasOptions,
|
||||
selectedItems || [],
|
||||
idField,
|
||||
columnsSelector,
|
||||
columnsShown,
|
||||
sortConfig ? sortConfig.currentSort : "",
|
||||
sortConfig ? sortConfig.currentDirection : undefined
|
||||
)}
|
||||
{hasOptions && (
|
||||
// @ts-ignore
|
||||
<Column
|
||||
dataKey={idField}
|
||||
width={optionsWidth}
|
||||
headerClassName="optionsAlignment"
|
||||
className="optionsAlignment"
|
||||
cellRenderer={({ rowData }) => {
|
||||
const isSelected = selectedItems
|
||||
? selectedItems.includes(
|
||||
isString(rowData) ? rowData : rowData[idField]
|
||||
)
|
||||
: false;
|
||||
return elementActions(
|
||||
itemActions || [],
|
||||
rowData,
|
||||
isSelected,
|
||||
idField
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Table>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
) : (
|
||||
<Fragment>
|
||||
{!isLoading && (
|
||||
<div id={"empty-results"}>
|
||||
{customEmptyMessage !== ""
|
||||
? customEmptyMessage
|
||||
: `There are no ${entityName} yet.`}
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Paper>
|
||||
return (
|
||||
<Checkbox
|
||||
value={
|
||||
isString(rowData)
|
||||
? rowData
|
||||
: rowData[idField]
|
||||
}
|
||||
color="primary"
|
||||
inputProps={{
|
||||
"aria-label": "secondary checkbox",
|
||||
}}
|
||||
className="TableCheckbox"
|
||||
checked={isSelected}
|
||||
onChange={onSelect}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
checkedIcon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioSelectedIcon
|
||||
: classes.checkedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
icon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioUnselectedIcon
|
||||
: classes.unCheckedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{generateColumnsMap(
|
||||
columns,
|
||||
width,
|
||||
optionsWidth,
|
||||
hasSelect,
|
||||
hasOptions,
|
||||
selectedItems || [],
|
||||
idField,
|
||||
columnsSelector,
|
||||
columnsShown,
|
||||
sortConfig ? sortConfig.currentSort : "",
|
||||
sortConfig ? sortConfig.currentDirection : undefined
|
||||
)}
|
||||
{hasOptions && (
|
||||
// @ts-ignore
|
||||
<Column
|
||||
dataKey={idField}
|
||||
width={optionsWidth}
|
||||
headerClassName="optionsAlignment"
|
||||
className="optionsAlignment"
|
||||
cellRenderer={({ rowData }) => {
|
||||
const isSelected = selectedItems
|
||||
? selectedItems.includes(
|
||||
isString(rowData)
|
||||
? rowData
|
||||
: rowData[idField]
|
||||
)
|
||||
: false;
|
||||
return elementActions(
|
||||
itemActions || [],
|
||||
rowData,
|
||||
isSelected,
|
||||
idField
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Table>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
) : (
|
||||
<Fragment>
|
||||
{!isLoading && (
|
||||
<div id={"empty-results"}>
|
||||
{customEmptyMessage !== ""
|
||||
? customEmptyMessage
|
||||
: `There are no ${entityName} yet.`}
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Paper>
|
||||
</TooltipWrapper>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -49,7 +49,12 @@ import SearchBox from "../Common/SearchBox";
|
||||
import {
|
||||
CONSOLE_UI_RESOURCE,
|
||||
IAM_PAGES,
|
||||
IAM_SCOPES,
|
||||
permissionTooltipHelper,
|
||||
applyPolicyPermissions,
|
||||
displayGroupsPermissions,
|
||||
deleteGroupPermissions,
|
||||
getGroupPermissions,
|
||||
createGroupPermissions,
|
||||
} from "../../../common/SecureComponent/permissions";
|
||||
import {
|
||||
hasPermission,
|
||||
@@ -107,17 +112,23 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
isLoading(true);
|
||||
}, []);
|
||||
|
||||
const displayGroups = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_LIST_GROUPS,
|
||||
]);
|
||||
const displayGroups = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
displayGroupsPermissions
|
||||
);
|
||||
|
||||
const deleteGroup = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP,
|
||||
]);
|
||||
const deleteGroup = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
deleteGroupPermissions
|
||||
);
|
||||
|
||||
const getGroup = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_GET_GROUP,
|
||||
]);
|
||||
const getGroup = hasPermission(CONSOLE_UI_RESOURCE, getGroupPermissions);
|
||||
|
||||
const applyPolicy = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
applyPolicyPermissions,
|
||||
true
|
||||
);
|
||||
|
||||
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { target: { value = "", checked = false } = {} } = e;
|
||||
@@ -217,7 +228,7 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_LIST_GROUPS]}
|
||||
scopes={displayGroupsPermissions}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<SearchBox
|
||||
@@ -234,11 +245,22 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY]}
|
||||
scopes={applyPolicyPermissions}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={"Select Policy"}>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
checkedGroups.length < 1
|
||||
? "Please select Groups on which you want to apply Policies"
|
||||
: applyPolicy
|
||||
? "Select Policy"
|
||||
: permissionTooltipHelper(
|
||||
applyPolicyPermissions,
|
||||
"apply policies to Groups"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"assign-policy"}
|
||||
onClick={() => {
|
||||
@@ -246,18 +268,29 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
}}
|
||||
label={"Assign Policy"}
|
||||
icon={<IAMPoliciesIcon />}
|
||||
disabled={checkedGroups.length < 1}
|
||||
disabled={checkedGroups.length < 1 || !applyPolicy}
|
||||
variant={"regular"}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP]}
|
||||
scopes={deleteGroupPermissions}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={"Delete Selected"}>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
checkedGroups.length === 0
|
||||
? "Select Groups to delete"
|
||||
: getGroup
|
||||
? "Delete Selected"
|
||||
: permissionTooltipHelper(
|
||||
getGroupPermissions,
|
||||
"delete Groups"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id="delete-selected-groups"
|
||||
onClick={() => {
|
||||
@@ -266,16 +299,13 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
label={"Delete Selected"}
|
||||
icon={<DeleteIcon />}
|
||||
variant="secondary"
|
||||
disabled={checkedGroups.length === 0}
|
||||
disabled={checkedGroups.length === 0 || !getGroup}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
|
||||
IAM_SCOPES.ADMIN_LIST_USERS,
|
||||
]}
|
||||
scopes={createGroupPermissions}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
@@ -298,24 +328,37 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
<Fragment>
|
||||
{records.length > 0 && (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_LIST_GROUPS]}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "" }]}
|
||||
isLoading={loading}
|
||||
selectedItems={checkedGroups}
|
||||
onSelect={deleteGroup ? selectionChanged : undefined}
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
/>
|
||||
</SecureComponent>
|
||||
</Grid>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
getGroup
|
||||
? ""
|
||||
: permissionTooltipHelper(
|
||||
getGroupPermissions,
|
||||
"view Group details"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={displayGroupsPermissions}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "" }]}
|
||||
isLoading={loading}
|
||||
selectedItems={checkedGroups}
|
||||
onSelect={
|
||||
deleteGroup || getGroup ? selectionChanged : undefined
|
||||
}
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
/>
|
||||
</SecureComponent>
|
||||
</Grid>
|
||||
</TooltipWrapper>
|
||||
<Grid item xs={12} marginTop={"25px"}>
|
||||
<HelpBox
|
||||
title={"Groups"}
|
||||
@@ -362,10 +405,7 @@ const Groups = ({ classes }: IGroupsProps) => {
|
||||
permissions on the MinIO Tenant.
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP,
|
||||
IAM_SCOPES.ADMIN_LIST_USERS,
|
||||
]}
|
||||
scopes={createGroupPermissions}
|
||||
matchAll
|
||||
>
|
||||
<br />
|
||||
|
||||
@@ -32,9 +32,18 @@ import PageLayout from "../Common/Layout/PageLayout";
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
import {
|
||||
addUserToGroupPermissions,
|
||||
CONSOLE_UI_RESOURCE,
|
||||
createGroupPermissions,
|
||||
editGroupMembersPermissions,
|
||||
enableDisableGroupPermissions,
|
||||
getGroupPermissions,
|
||||
IAM_PAGES,
|
||||
IAM_SCOPES,
|
||||
listUsersPermissions,
|
||||
permissionTooltipHelper,
|
||||
setGroupPoliciesPermissions,
|
||||
viewPolicyPermissions,
|
||||
viewUserPermissions,
|
||||
} from "../../../common/SecureComponent/permissions";
|
||||
import {
|
||||
hasPermission,
|
||||
@@ -130,6 +139,12 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
elementItem.includes(memberFilter)
|
||||
);
|
||||
|
||||
const viewUser = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
viewUserPermissions,
|
||||
true
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (groupName) {
|
||||
fetchGroupInfo();
|
||||
@@ -141,9 +156,28 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
const isGroupEnabled = groupEnabled === "enabled";
|
||||
const memberActionText = members.length > 0 ? "Edit Members" : "Add Members";
|
||||
|
||||
const getGroupDetails = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_GET_GROUP,
|
||||
]);
|
||||
const getGroupDetails = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
getGroupPermissions
|
||||
);
|
||||
|
||||
const canEditGroupMembers = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
editGroupMembersPermissions,
|
||||
true
|
||||
);
|
||||
|
||||
const canSetPolicies = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
setGroupPoliciesPermissions,
|
||||
true
|
||||
);
|
||||
|
||||
const canViewPolicy = hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
viewPolicyPermissions,
|
||||
true
|
||||
);
|
||||
|
||||
function fetchGroupInfo() {
|
||||
if (getGroupDetails) {
|
||||
@@ -188,10 +222,19 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
/>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP]}
|
||||
scopes={addUserToGroupPermissions}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={memberActionText}>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canEditGroupMembers
|
||||
? memberActionText
|
||||
: permissionTooltipHelper(
|
||||
createGroupPermissions,
|
||||
"edit Group membership"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"add-user-group"}
|
||||
label={memberActionText}
|
||||
@@ -200,6 +243,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
onClick={() => {
|
||||
setUsersOpen(true);
|
||||
}}
|
||||
disabled={!canEditGroupMembers}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
@@ -208,7 +252,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
<div className={classes.tableBlock}>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_LIST_USERS]}
|
||||
scopes={listUsersPermissions}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
@@ -218,6 +262,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
onClick: (userName) => {
|
||||
navigate(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`);
|
||||
},
|
||||
disableButtonFunction: () => !viewUser,
|
||||
},
|
||||
]}
|
||||
columns={[{ label: "Access Key", elementKey: "" }]}
|
||||
@@ -226,6 +271,14 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
records={filteredMembers}
|
||||
entityName="Users"
|
||||
idField=""
|
||||
tooltip={
|
||||
viewUser
|
||||
? ""
|
||||
: permissionTooltipHelper(
|
||||
viewUserPermissions,
|
||||
"view User details"
|
||||
)
|
||||
}
|
||||
/>
|
||||
</SecureComponent>
|
||||
</div>
|
||||
@@ -236,7 +289,16 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
<React.Fragment>
|
||||
<div className={classes.actionsTray}>
|
||||
<PanelTitle>Policies</PanelTitle>
|
||||
<TooltipWrapper tooltip={"Set Policies"}>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canSetPolicies
|
||||
? "Set Policies"
|
||||
: permissionTooltipHelper(
|
||||
setGroupPoliciesPermissions,
|
||||
"assign Policies"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"set-policies"}
|
||||
label={`Set Policies`}
|
||||
@@ -245,6 +307,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
onClick={() => {
|
||||
setPolicyOpen(true);
|
||||
}}
|
||||
disabled={!canSetPolicies}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
@@ -256,6 +319,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
onClick: (policy) => {
|
||||
navigate(`${IAM_PAGES.POLICIES}/${encodeURLString(policy)}`);
|
||||
},
|
||||
disableButtonFunction: () => !canViewPolicy,
|
||||
},
|
||||
]}
|
||||
columns={[{ label: "Policy", elementKey: "" }]}
|
||||
@@ -263,6 +327,14 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
records={groupPolicies}
|
||||
entityName="Policies"
|
||||
idField=""
|
||||
tooltip={
|
||||
canViewPolicy
|
||||
? ""
|
||||
: permissionTooltipHelper(
|
||||
viewPolicyPermissions,
|
||||
"view Policy details"
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
@@ -287,46 +359,52 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
<span id="group-status" className={classes.statusValue}>
|
||||
{isGroupEnabled ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_ENABLE_GROUP,
|
||||
IAM_SCOPES.ADMIN_DISABLE_GROUP,
|
||||
]}
|
||||
errorProps={{ disabled: true }}
|
||||
matchAll
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
enableDisableGroupPermissions,
|
||||
true
|
||||
)
|
||||
? ""
|
||||
: permissionTooltipHelper(
|
||||
enableDisableGroupPermissions,
|
||||
"enable or disable Groups"
|
||||
)
|
||||
}
|
||||
>
|
||||
<FormSwitchWrapper
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
checked={isGroupEnabled}
|
||||
value={"group_enabled"}
|
||||
id="group-status"
|
||||
name="group-status"
|
||||
onChange={() => {
|
||||
toggleGroupStatus(!isGroupEnabled);
|
||||
}}
|
||||
switchOnly
|
||||
/>
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={enableDisableGroupPermissions}
|
||||
errorProps={{ disabled: true }}
|
||||
matchAll
|
||||
>
|
||||
<FormSwitchWrapper
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
checked={isGroupEnabled}
|
||||
value={"group_enabled"}
|
||||
id="group-status"
|
||||
name="group-status"
|
||||
onChange={() => {
|
||||
toggleGroupStatus(!isGroupEnabled);
|
||||
}}
|
||||
switchOnly
|
||||
/>
|
||||
</SecureComponent>
|
||||
</TooltipWrapper>
|
||||
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP]}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<div className={classes.spacerLeft}>
|
||||
<TooltipWrapper tooltip={"Delete Group"}>
|
||||
<Button
|
||||
id={"delete-user-group"}
|
||||
variant="secondary"
|
||||
icon={<TrashIcon />}
|
||||
onClick={() => {
|
||||
setDeleteOpen(true);
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</SecureComponent>
|
||||
<div className={classes.spacerLeft}>
|
||||
<TooltipWrapper tooltip={"Delete Group"}>
|
||||
<Button
|
||||
id={"delete-user-group"}
|
||||
variant="secondary"
|
||||
icon={<TrashIcon />}
|
||||
onClick={() => {
|
||||
setDeleteOpen(true);
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user