From 74d4c4a3e6ef32f26c0fa355f62f95f3d59e5497 Mon Sep 17 00:00:00 2001
From: jinapurapu <65002498+jinapurapu@users.noreply.github.com>
Date: Fri, 22 Apr 2022 20:50:31 -0700
Subject: [PATCH] Create Add Group screen (#1890)
---
.../src/common/SecureComponent/permissions.ts | 5 +
portal-ui/src/screens/Console/Console.tsx | 9 +-
.../Console/Groups/AddGroupHelpBox.tsx | 119 ++++++++
.../screens/Console/Groups/AddGroupScreen.tsx | 258 ++++++++++++++++++
.../src/screens/Console/Groups/Groups.tsx | 7 +-
5 files changed, 393 insertions(+), 5 deletions(-)
create mode 100644 portal-ui/src/screens/Console/Groups/AddGroupHelpBox.tsx
create mode 100644 portal-ui/src/screens/Console/Groups/AddGroupScreen.tsx
diff --git a/portal-ui/src/common/SecureComponent/permissions.ts b/portal-ui/src/common/SecureComponent/permissions.ts
index fb4f927be..a1364a552 100644
--- a/portal-ui/src/common/SecureComponent/permissions.ts
+++ b/portal-ui/src/common/SecureComponent/permissions.ts
@@ -121,6 +121,7 @@ export const IAM_PAGES = {
USERS: "/identity/users",
USERS_VIEW: "/identity/users/:userName+",
GROUPS: "/identity/groups",
+ GROUPS_ADD: "/identity/create-group",
GROUPS_VIEW: "/identity/groups/:groupName+",
ACCOUNT: "/identity/account",
ACCOUNT_ADD: "/identity/new-account",
@@ -296,6 +297,10 @@ export const IAM_PAGES_PERMISSIONS = {
IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP, // display "edit members" button in groups detail page
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY, // display "set policy" button in groups details page
],
+ [IAM_PAGES.GROUPS_ADD]: [
+ IAM_SCOPES.ADMIN_LIST_USERS, // displays users
+ IAM_SCOPES.ADMIN_CREATE_USER, // displays create user button
+ ],
[IAM_PAGES.USERS]: [
IAM_SCOPES.ADMIN_LIST_USERS, // displays users
IAM_SCOPES.ADMIN_CREATE_USER, // displays create user button
diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx
index bf4aa6fbd..4b07b48a9 100644
--- a/portal-ui/src/screens/Console/Console.tsx
+++ b/portal-ui/src/screens/Console/Console.tsx
@@ -120,6 +120,9 @@ const ConfigurationOptions = React.lazy(
const AddPool = React.lazy(
() => import("./Tenants/TenantDetails/Pools/AddPool/AddPool")
);
+const AddGroupScreen = React.lazy(
+ () => import("./Groups/AddGroupScreen")
+);
const SiteReplication = React.lazy(
() => import("./Configurations/SiteReplication/SiteReplication")
);
@@ -289,6 +292,10 @@ const Console = ({
path: IAM_PAGES.GROUPS,
fsHidden: ldapIsEnabled,
},
+ {
+ component: AddGroupScreen,
+ path: IAM_PAGES.GROUPS_ADD,
+ },
{
component: GroupsDetails,
path: IAM_PAGES.GROUPS_VIEW,
@@ -394,7 +401,7 @@ const Console = ({
{
component: Account,
path: IAM_PAGES.ACCOUNT,
- forceDisplay: true, // user has implicit access to service-accounts
+ // user has implicit access to service-accounts
},
{
component: AccountCreate,
diff --git a/portal-ui/src/screens/Console/Groups/AddGroupHelpBox.tsx b/portal-ui/src/screens/Console/Groups/AddGroupHelpBox.tsx
new file mode 100644
index 000000000..9cdc24aab
--- /dev/null
+++ b/portal-ui/src/screens/Console/Groups/AddGroupHelpBox.tsx
@@ -0,0 +1,119 @@
+// This file is part of MinIO Console Server
+// Copyright (c) 2022 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React from "react";
+import { Box } from "@mui/material";
+import {
+ HelpIconFilled,
+ GroupsIcon,
+ IAMPoliciesIcon,
+} from "../../../icons";
+
+const FeatureItem = ({
+ icon,
+ description,
+}: {
+ icon: any;
+ description: string;
+}) => {
+ return (
+
+ {icon}{" "}
+
+ {description}
+
+
+ );
+};
+const AddGroupHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
+ return (
+
+
+
+ Learn more about Groups
+
+
+ Adding groups lets you assign IAM policies to multiple users at once.
+
+ Users inherit access permissions to data and resources through the groups they belong to.
+
+
+
+ A user can be a member of multiple groups.
+
+
+
+ Groups provide a simplified method for managing shared permissions among users with common access patterns and workloads. Client’s cannot authenticate to a MinIO deployment using a group as an identity.
+
+
+
+
+
+ } description={`Add Users to Group`} />
+ } description={`Assign Custom IAM Policies for Group`} />
+
+
+
+
+ );
+};
+
+export default AddGroupHelpBox;
\ No newline at end of file
diff --git a/portal-ui/src/screens/Console/Groups/AddGroupScreen.tsx b/portal-ui/src/screens/Console/Groups/AddGroupScreen.tsx
new file mode 100644
index 000000000..f119dc3be
--- /dev/null
+++ b/portal-ui/src/screens/Console/Groups/AddGroupScreen.tsx
@@ -0,0 +1,258 @@
+// This file is part of MinIO Console Server
+// Copyright (c) 2022 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+import React, { Fragment, useState, useEffect } from "react";
+import { Theme } from "@mui/material/styles";
+import createStyles from "@mui/styles/createStyles";
+import withStyles from "@mui/styles/withStyles";
+import {
+ formFieldStyles,
+ modalStyleUtils,
+} from "../Common/FormComponents/common/styleLibrary";
+import Grid from "@mui/material/Grid";
+import { Button, Box, LinearProgress } from "@mui/material";
+import PageHeader from "../Common/PageHeader/PageHeader";
+import PageLayout from "../Common/Layout/PageLayout";
+import history from "../../../../src/history";
+import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
+import AddGroupHelpBox from "./AddGroupHelpBox";
+import UsersSelectors from "./UsersSelectors";
+import BackLink from "../../../common/BackLink";
+import { connect } from "react-redux";
+import { CreateGroupIcon } from "../../../icons";
+import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
+import { ErrorResponseHandler } from "../../../../src/common/types";
+import api from "../../../../src/common/api";
+import { setErrorSnackMessage } from "../../../../src/actions";
+
+interface IAddGroupProps {
+ classes: any;
+ setErrorSnackMessage: typeof setErrorSnackMessage;
+}
+
+const styles = (theme: Theme) =>
+ createStyles({
+ buttonContainer: {
+ textAlign: "right",
+ },
+ bottomContainer: {
+ display: "flex",
+ flexGrow: 1,
+ alignItems: "center",
+ margin: "auto",
+ justifyContent: "center",
+ "& div": {
+ width: 150,
+ "@media (max-width: 900px)": {
+ flexFlow: "column",
+ },
+ },
+ },
+ factorElements: {
+ display: "flex",
+ justifyContent: "flex-start",
+ marginLeft: 30,
+ },
+ sizeNumber: {
+ fontSize: 35,
+ fontWeight: 700,
+ textAlign: "center",
+ },
+ sizeDescription: {
+ fontSize: 14,
+ color: "#777",
+ textAlign: "center",
+ },
+ pageBox: {
+ border: "1px solid #EAEAEA",
+ borderTop: 0,
+ },
+ addPoolTitle: {
+ border: "1px solid #EAEAEA",
+ borderBottom: 0,
+ },
+ headTitle: {
+ fontWeight: "bold",
+ fontSize: 20,
+ paddingLeft: 20,
+ paddingBottom: 40,
+ paddingTop: 10,
+ textAlign: "end",
+ },
+ headIcon: {
+ fontWeight: "bold",
+ size: "50",
+ },
+ ...formFieldStyles,
+ ...modalStyleUtils,
+ });
+
+const AddGroupScreen = ({
+ classes,
+ setErrorSnackMessage,
+}: IAddGroupProps) => {
+ const [groupName, setGroupName] = useState("");
+ const [saving, isSaving] = useState(false);
+ const [selectedUsers, setSelectedUsers] = useState([]);
+ const [validGroup, setValidGroup] = useState(false);
+
+
+ useEffect(() => {
+ setValidGroup(groupName.trim() !== "");
+ }, [groupName, selectedUsers]);
+
+ useEffect(() => {
+ if (saving) {
+ const saveRecord = () => {
+
+ api
+ .invoke("POST", "/api/v1/groups", {
+ group: groupName,
+ members: selectedUsers,
+ })
+ .then((res) => {
+ isSaving(false);
+ history.push(`${IAM_PAGES.GROUPS}`);
+ })
+ .catch((err: ErrorResponseHandler) => {
+ isSaving(false);
+ setErrorSnackMessage(err);
+ });
+ }
+
+ saveRecord();
+ }
+
+ }, [
+ saving,
+ groupName,
+ selectedUsers,
+ setErrorSnackMessage,
+ ]);
+
+ //Fetch Actions
+ const setSaving = (event: React.FormEvent) => {
+ event.preventDefault();
+
+ isSaving(true);
+ };
+
+ const resetForm = () => {
+ setGroupName("");
+ setSelectedUsers([]);
+ };
+
+
+
+ return (
+
+
+ }
+ />
+
+
+
+
+
+
+ Create Group
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const mapDispatchToProps = {
+ setErrorSnackMessage,
+};
+
+const connector = connect(null, mapDispatchToProps);
+
+export default withStyles(styles)(connector(AddGroupScreen));
diff --git a/portal-ui/src/screens/Console/Groups/Groups.tsx b/portal-ui/src/screens/Console/Groups/Groups.tsx
index dadc508f1..02fde4162 100644
--- a/portal-ui/src/screens/Console/Groups/Groups.tsx
+++ b/portal-ui/src/screens/Console/Groups/Groups.tsx
@@ -36,7 +36,6 @@ import api from "../../../common/api";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
import PageHeader from "../Common/PageHeader/PageHeader";
import HelpBox from "../../../common/HelpBox";
-import history from "../../../history";
import AButton from "../Common/AButton/AButton";
import PageLayout from "../Common/Layout/PageLayout";
import SearchBox from "../Common/SearchBox";
@@ -63,6 +62,7 @@ interface IGroupsProps {
classes: any;
openGroupModal: any;
setErrorSnackMessage: typeof setErrorSnackMessage;
+ history: any;
}
const styles = (theme: Theme) =>
@@ -79,7 +79,7 @@ const styles = (theme: Theme) =>
...containerForHeader(theme.spacing(4)),
});
-const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
+const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
const [addGroupOpen, setGroupOpen] = useState(false);
const [selectedGroup, setSelectedGroup] = useState(null);
const [deleteOpen, setDeleteOpen] = useState(false);
@@ -232,8 +232,7 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
color="primary"
icon={}
onClick={() => {
- setSelectedGroup(null);
- setGroupOpen(true);
+ history.push(`${IAM_PAGES.GROUPS_ADD}`);
}}
/>