Add User Service Account screen (#1947)
This commit is contained in:
@@ -126,6 +126,8 @@ export const IAM_PAGES = {
|
|||||||
GROUPS_VIEW: "/identity/groups/:groupName+",
|
GROUPS_VIEW: "/identity/groups/:groupName+",
|
||||||
ACCOUNT: "/identity/account",
|
ACCOUNT: "/identity/account",
|
||||||
ACCOUNT_ADD: "/identity/new-account",
|
ACCOUNT_ADD: "/identity/new-account",
|
||||||
|
USER_ACCOUNT: "/identity/new-user-sa",
|
||||||
|
USER_ACCOUNT_ADD: "/identity/new-user-sa/:userName+",
|
||||||
/* Access */
|
/* Access */
|
||||||
POLICIES: "/access/policies",
|
POLICIES: "/access/policies",
|
||||||
POLICY_ADD: "/access/add-policy",
|
POLICY_ADD: "/access/add-policy",
|
||||||
@@ -314,6 +316,12 @@ export const IAM_PAGES_PERMISSIONS = {
|
|||||||
IAM_SCOPES.ADMIN_DISABLE_USER,
|
IAM_SCOPES.ADMIN_DISABLE_USER,
|
||||||
IAM_SCOPES.ADMIN_DELETE_USER,
|
IAM_SCOPES.ADMIN_DELETE_USER,
|
||||||
],
|
],
|
||||||
|
[IAM_PAGES.USER_ACCOUNT_ADD]: [
|
||||||
|
IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_UPDATE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_REMOVE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_LIST_SERVICEACCOUNTS,
|
||||||
|
],
|
||||||
[IAM_PAGES.USER_ADD]: [IAM_SCOPES.ADMIN_CREATE_USER], // displays create user button
|
[IAM_PAGES.USER_ADD]: [IAM_SCOPES.ADMIN_CREATE_USER], // displays create user button
|
||||||
[IAM_PAGES.ACCOUNT_ADD]: [IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT],
|
[IAM_PAGES.ACCOUNT_ADD]: [IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT],
|
||||||
[IAM_PAGES.DASHBOARD]: [
|
[IAM_PAGES.DASHBOARD]: [
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ const Account = React.lazy(() => import("./Account/Account"));
|
|||||||
const AccountCreate = React.lazy(
|
const AccountCreate = React.lazy(
|
||||||
() => import("./Account/AddServiceAccountScreen")
|
() => import("./Account/AddServiceAccountScreen")
|
||||||
);
|
);
|
||||||
|
const UserSACreate = React.lazy(
|
||||||
|
() => import("./Users/AddUserServiceAccountScreen")
|
||||||
|
);
|
||||||
const Users = React.lazy(() => import("./Users/Users"));
|
const Users = React.lazy(() => import("./Users/Users"));
|
||||||
const Groups = React.lazy(() => import("./Groups/Groups"));
|
const Groups = React.lazy(() => import("./Groups/Groups"));
|
||||||
|
|
||||||
@@ -419,6 +422,11 @@ const Console = ({
|
|||||||
path: IAM_PAGES.ACCOUNT_ADD,
|
path: IAM_PAGES.ACCOUNT_ADD,
|
||||||
forceDisplay: true, // user has implicit access to service-accounts
|
forceDisplay: true, // user has implicit access to service-accounts
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: UserSACreate,
|
||||||
|
path: IAM_PAGES.USER_ACCOUNT_ADD,
|
||||||
|
forceDisplay: true, // user has implicit access to service-accounts
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: License,
|
component: License,
|
||||||
path: IAM_PAGES.LICENSE,
|
path: IAM_PAGES.LICENSE,
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
import React from "react";
|
||||||
|
import { Box } from "@mui/material";
|
||||||
|
import {
|
||||||
|
HelpIconFilled,
|
||||||
|
ServiceAccountIcon,
|
||||||
|
PasswordKeyIcon,
|
||||||
|
IAMPoliciesIcon,
|
||||||
|
} from "../../../icons";
|
||||||
|
|
||||||
|
const FeatureItem = ({
|
||||||
|
icon,
|
||||||
|
description,
|
||||||
|
}: {
|
||||||
|
icon: any;
|
||||||
|
description: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
"& .min-icon": {
|
||||||
|
marginRight: "10px",
|
||||||
|
height: "23px",
|
||||||
|
width: "23px",
|
||||||
|
marginBottom: "10px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon}{" "}
|
||||||
|
<div style={{ fontSize: "14px", fontStyle: "italic", color: "#5E5E5E" }}>
|
||||||
|
{description}
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const AddUserServiceAccountHelpBox = () => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
border: "1px solid #eaeaea",
|
||||||
|
borderRadius: "2px",
|
||||||
|
display: "flex",
|
||||||
|
flexFlow: "column",
|
||||||
|
padding: "20px",
|
||||||
|
marginTop: {
|
||||||
|
xs: "0px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: 600,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: "16px",
|
||||||
|
paddingBottom: "20px",
|
||||||
|
|
||||||
|
"& .min-icon": {
|
||||||
|
height: "21px",
|
||||||
|
width: "21px",
|
||||||
|
marginRight: "15px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<HelpIconFilled />
|
||||||
|
<div>Learn more about Service Accounts</div>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ fontSize: "14px", marginBottom: "15px" }}>
|
||||||
|
<Box sx={{ paddingBottom: "20px" }}>
|
||||||
|
<FeatureItem
|
||||||
|
icon={<ServiceAccountIcon />}
|
||||||
|
description={`Create Service Accounts`}
|
||||||
|
/>
|
||||||
|
<Box sx={{ paddingTop: "20px" }}>
|
||||||
|
Service Accounts inherit the policies explicitly attached to the
|
||||||
|
parent user, and the policies attached to each group in which the
|
||||||
|
parent user has membership.
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ paddingBottom: "20px" }}>
|
||||||
|
<FeatureItem
|
||||||
|
icon={<PasswordKeyIcon />}
|
||||||
|
description={`Assign Custom Credentials`}
|
||||||
|
/>
|
||||||
|
<Box sx={{ paddingTop: "10px" }}>
|
||||||
|
Randomized access credentials are recommended, and provided by
|
||||||
|
default. You may use your own custom Access Key and Secret Key by
|
||||||
|
replacing the default values. After creation of any Service Account,
|
||||||
|
you will be given the opportunity to view and download the account
|
||||||
|
credentials.
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ paddingTop: "10px" }}>
|
||||||
|
Service Accounts support programmatic access by applications. You
|
||||||
|
cannot use a Service Account to log into the MinIO Console.
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ paddingBottom: "20px" }}>
|
||||||
|
<FeatureItem
|
||||||
|
icon={<IAMPoliciesIcon />}
|
||||||
|
description={`Assign Access Policies`}
|
||||||
|
/>
|
||||||
|
<Box sx={{ paddingTop: "10px" }}>
|
||||||
|
You can specify an optional JSON-formatted IAM policy to further
|
||||||
|
restrict Service Account access to a subset of the actions and
|
||||||
|
resources explicitly allowed for the parent user. Additional access
|
||||||
|
beyond that of the parent user cannot be implemented through these
|
||||||
|
policies.
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ paddingTop: "10px" }}>
|
||||||
|
You cannot modify the optional Service Account IAM policy after
|
||||||
|
saving.
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexFlow: "column",
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddUserServiceAccountHelpBox;
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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 } from "@mui/material";
|
||||||
|
import { PasswordKeyIcon, ServiceAccountCredentialsIcon } from "../../../icons";
|
||||||
|
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||||
|
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 FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||||
|
import BackLink from "../../../common/BackLink";
|
||||||
|
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { IAMPoliciesIcon } from "../../../icons";
|
||||||
|
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||||
|
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||||
|
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||||
|
import { ErrorResponseHandler } from "../../../../src/common/types";
|
||||||
|
import api from "../../../../src/common/api";
|
||||||
|
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||||
|
import { setErrorSnackMessage } from "../../../../src/actions";
|
||||||
|
import SectionTitle from "../Common/SectionTitle";
|
||||||
|
import { getRandomString } from "../../../screens/Console/Tenants/utils";
|
||||||
|
import AddUserServiceAccountHelpBox from "./AddUserServiceAccountHelpBox";
|
||||||
|
|
||||||
|
interface IAddServiceAccountProps {
|
||||||
|
classes: any;
|
||||||
|
match: any;
|
||||||
|
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = (theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
bottomContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexGrow: 1,
|
||||||
|
alignItems: "center",
|
||||||
|
margin: "auto",
|
||||||
|
justifyContent: "center",
|
||||||
|
"& div": {
|
||||||
|
width: 150,
|
||||||
|
"@media (max-width: 900px)": {
|
||||||
|
flexFlow: "column",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...formFieldStyles,
|
||||||
|
...modalStyleUtils,
|
||||||
|
});
|
||||||
|
|
||||||
|
const AddServiceAccount = ({
|
||||||
|
classes,
|
||||||
|
match,
|
||||||
|
setErrorSnackMessage,
|
||||||
|
}: IAddServiceAccountProps) => {
|
||||||
|
const [addSending, setAddSending] = useState<boolean>(false);
|
||||||
|
const [accessKey, setAccessKey] = useState<string>(getRandomString(16));
|
||||||
|
const [secretKey, setSecretKey] = useState<string>(getRandomString(32));
|
||||||
|
const [isRestrictedByPolicy, setIsRestrictedByPolicy] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
const [newServiceAccount, setNewServiceAccount] =
|
||||||
|
useState<NewServiceAccount | null>(null);
|
||||||
|
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||||
|
const [policyJSON, setPolicyJSON] = useState<string>("");
|
||||||
|
|
||||||
|
const userName = match.params["userName"];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (addSending) {
|
||||||
|
api
|
||||||
|
.invoke(
|
||||||
|
"POST",
|
||||||
|
`/api/v1/user/${userName}/service-account-credentials`,
|
||||||
|
{
|
||||||
|
policy: policyJSON,
|
||||||
|
accessKey: accessKey,
|
||||||
|
secretKey: secretKey,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
setAddSending(false);
|
||||||
|
setNewServiceAccount({
|
||||||
|
accessKey: res.accessKey || "",
|
||||||
|
secretKey: res.secretKey || "",
|
||||||
|
url: res.url || "",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err: ErrorResponseHandler) => {
|
||||||
|
setAddSending(false);
|
||||||
|
setErrorSnackMessage(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
addSending,
|
||||||
|
setAddSending,
|
||||||
|
setErrorSnackMessage,
|
||||||
|
policyJSON,
|
||||||
|
userName,
|
||||||
|
accessKey,
|
||||||
|
secretKey,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const addUserServiceAccount = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setAddSending(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
setNewServiceAccount(null);
|
||||||
|
setAccessKey("");
|
||||||
|
setSecretKey("");
|
||||||
|
setShowPassword(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeCredentialsModal = () => {
|
||||||
|
setNewServiceAccount(null);
|
||||||
|
history.push(`${IAM_PAGES.USERS}/${userName}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{newServiceAccount !== null && (
|
||||||
|
<CredentialsPrompt
|
||||||
|
newServiceAccount={newServiceAccount}
|
||||||
|
open={newServiceAccount !== null}
|
||||||
|
closeModal={() => {
|
||||||
|
closeCredentialsModal();
|
||||||
|
}}
|
||||||
|
entity="Service Account"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<PageHeader
|
||||||
|
label={
|
||||||
|
<BackLink
|
||||||
|
to={`${IAM_PAGES.USERS}/${userName}`}
|
||||||
|
label={"User Details - " + userName}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<PageLayout>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "grid",
|
||||||
|
padding: "25px",
|
||||||
|
gap: "25px",
|
||||||
|
gridTemplateColumns: {
|
||||||
|
md: "2fr 1.2fr",
|
||||||
|
xs: "1fr",
|
||||||
|
},
|
||||||
|
border: "1px solid #eaeaea",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box>
|
||||||
|
<SectionTitle icon={<ServiceAccountCredentialsIcon />}>
|
||||||
|
Create Service Account for {userName}
|
||||||
|
</SectionTitle>
|
||||||
|
|
||||||
|
<form
|
||||||
|
noValidate
|
||||||
|
autoComplete="off"
|
||||||
|
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
addUserServiceAccount(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Grid container item spacing="20" sx={{ marginTop: 1 }}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Grid container item spacing="20">
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<PasswordKeyIcon />
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Grid container item spacing="20">
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{" "}
|
||||||
|
<div className={classes.stackedInputs}>
|
||||||
|
<InputBoxWrapper
|
||||||
|
value={accessKey}
|
||||||
|
label={"Access Key"}
|
||||||
|
id={"accessKey"}
|
||||||
|
name={"accessKey"}
|
||||||
|
placeholder={"Enter Access Key"}
|
||||||
|
onChange={(e) => {
|
||||||
|
setAccessKey(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<div className={classes.stackedInputs}>
|
||||||
|
<InputBoxWrapper
|
||||||
|
value={secretKey}
|
||||||
|
label={"Secret Key"}
|
||||||
|
id={"secretKey"}
|
||||||
|
name={"secretKey"}
|
||||||
|
type={showPassword ? "text" : "password"}
|
||||||
|
placeholder={"Enter Secret Key"}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSecretKey(e.target.value);
|
||||||
|
}}
|
||||||
|
overlayIcon={
|
||||||
|
showPassword ? (
|
||||||
|
<VisibilityOffIcon />
|
||||||
|
) : (
|
||||||
|
<RemoveRedEyeIcon />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
overlayAction={() =>
|
||||||
|
setShowPassword(!showPassword)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container item spacing="20">
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<IAMPoliciesIcon />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={11}>
|
||||||
|
<FormSwitchWrapper
|
||||||
|
value="serviceAccountPolicy"
|
||||||
|
id="serviceAccountPolicy"
|
||||||
|
name="serviceAccountPolicy"
|
||||||
|
checked={isRestrictedByPolicy}
|
||||||
|
onChange={(
|
||||||
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
|
) => {
|
||||||
|
setIsRestrictedByPolicy(event.target.checked);
|
||||||
|
}}
|
||||||
|
label={"Restrict beyond user policy"}
|
||||||
|
tooltip={
|
||||||
|
"You can specify an optional JSON-formatted IAM policy to further restrict Service Account access to a subset of the actions and resources explicitly allowed for the parent user. Additional access beyond that of the parent user cannot be implemented through these policies."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{isRestrictedByPolicy && (
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
className={classes.codeMirrorContainer}
|
||||||
|
>
|
||||||
|
|
||||||
|
<Grid item xs={12} className={classes.formScrollable}>
|
||||||
|
<CodeMirrorWrapper
|
||||||
|
label={"Policy"}
|
||||||
|
value={policyJSON}
|
||||||
|
onBeforeChange={(editor, data, value) => {
|
||||||
|
setPolicyJSON(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={resetForm}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button type="submit" variant="contained" color="primary">
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Box>
|
||||||
|
<AddUserServiceAccountHelpBox />
|
||||||
|
</Box>
|
||||||
|
</PageLayout>
|
||||||
|
</Grid>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
setErrorSnackMessage,
|
||||||
|
};
|
||||||
|
|
||||||
|
const connector = connect(null, mapDispatchToProps);
|
||||||
|
|
||||||
|
export default withStyles(styles)(connector(AddServiceAccount));
|
||||||
@@ -317,6 +317,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
|||||||
<UserServiceAccountsPanel
|
<UserServiceAccountsPanel
|
||||||
user={userName}
|
user={userName}
|
||||||
hasPolicy={hasPolicy}
|
hasPolicy={hasPolicy}
|
||||||
|
history={history}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -41,12 +41,17 @@ import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
|||||||
import DeleteMultipleServiceAccounts from "./DeleteMultipleServiceAccounts";
|
import DeleteMultipleServiceAccounts from "./DeleteMultipleServiceAccounts";
|
||||||
import { selectSAs } from "../../Console/Configurations/utils";
|
import { selectSAs } from "../../Console/Configurations/utils";
|
||||||
import ServiceAccountPolicy from "../Account/ServiceAccountPolicy";
|
import ServiceAccountPolicy from "../Account/ServiceAccountPolicy";
|
||||||
|
import { IAM_PAGES,
|
||||||
|
CONSOLE_UI_RESOURCE,
|
||||||
|
IAM_SCOPES } from "../../../common/SecureComponent/permissions";
|
||||||
|
import { SecureComponent } from "../../../common/SecureComponent";
|
||||||
|
|
||||||
interface IUserServiceAccountsProps {
|
interface IUserServiceAccountsProps {
|
||||||
classes: any;
|
classes: any;
|
||||||
user: string;
|
user: string;
|
||||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||||
hasPolicy: boolean;
|
hasPolicy: boolean;
|
||||||
|
history: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
const styles = (theme: Theme) =>
|
||||||
@@ -64,6 +69,7 @@ const UserServiceAccountsPanel = ({
|
|||||||
user,
|
user,
|
||||||
setErrorSnackMessage,
|
setErrorSnackMessage,
|
||||||
hasPolicy,
|
hasPolicy,
|
||||||
|
history,
|
||||||
}: IUserServiceAccountsProps) => {
|
}: IUserServiceAccountsProps) => {
|
||||||
const [records, setRecords] = useState<string[]>([]);
|
const [records, setRecords] = useState<string[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
@@ -228,6 +234,15 @@ const UserServiceAccountsPanel = ({
|
|||||||
disabled={selectedSAs.length === 0}
|
disabled={selectedSAs.length === 0}
|
||||||
variant={"outlined"}
|
variant={"outlined"}
|
||||||
/>
|
/>
|
||||||
|
<SecureComponent
|
||||||
|
scopes={[IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_UPDATE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_REMOVE_SERVICEACCOUNT,
|
||||||
|
IAM_SCOPES.ADMIN_LIST_SERVICEACCOUNTS]}
|
||||||
|
resource={CONSOLE_UI_RESOURCE}
|
||||||
|
matchAll
|
||||||
|
errorProps={{ disabled: true }}
|
||||||
|
>
|
||||||
<RBIconButton
|
<RBIconButton
|
||||||
tooltip={"Create service account"}
|
tooltip={"Create service account"}
|
||||||
text={"Create service account"}
|
text={"Create service account"}
|
||||||
@@ -235,12 +250,11 @@ const UserServiceAccountsPanel = ({
|
|||||||
color="primary"
|
color="primary"
|
||||||
icon={<AddIcon />}
|
icon={<AddIcon />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAddScreenOpen(true);
|
history.push(`${IAM_PAGES.USER_ACCOUNT}/${user}`);
|
||||||
setAddScreenOpen(true);
|
|
||||||
setSelectedServiceAccount(null);
|
|
||||||
}}
|
}}
|
||||||
disabled={!hasPolicy}
|
disabled={!hasPolicy}
|
||||||
/>
|
/>
|
||||||
|
</SecureComponent>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.tableBlock}>
|
<div className={classes.tableBlock}>
|
||||||
|
|||||||
Reference in New Issue
Block a user