1+ // This file is part of MinIO Console Server
2+ // Copyright (c) 2022 MinIO, Inc.
3+ //
4+ // This program is free software: you can redistribute it and/or modify
5+ // it under the terms of the GNU Affero General Public License as published by
6+ // the Free Software Foundation, either version 3 of the License, or
7+ // (at your option) any later version.
8+ //
9+ // This program is distributed in the hope that it will be useful,
10+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ // GNU Affero General Public License for more details.
13+ //
14+ // You should have received a copy of the GNU Affero General Public License
15+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+ import React , { Fragment , useState } from "react" ;
18+ import { Theme } from "@mui/material/styles" ;
19+ import createStyles from "@mui/styles/createStyles" ;
20+ import withStyles from "@mui/styles/withStyles" ;
21+ import {
22+ formFieldStyles ,
23+ modalStyleUtils ,
24+ } from "../Common/FormComponents/common/styleLibrary" ;
25+ import Grid from "@mui/material/Grid" ;
26+ import { Button , Box } from "@mui/material" ;
27+ import PageHeader from "../Common/PageHeader/PageHeader" ;
28+ import history from "../../../../src/history" ;
29+ import PageLayout from "../Common/Layout/PageLayout" ;
30+ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper" ;
31+ import AddPolicyHelpBox from "./AddPolicyHelpBox" ;
32+ import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper" ;
33+ import BackLink from "../../../common/BackLink" ;
34+ import { connect } from "react-redux" ;
35+ import { AddAccessRuleIcon } from "../../../icons" ;
36+ import { IAM_PAGES } from "../../../common/SecureComponent/permissions" ;
37+ import { ErrorResponseHandler } from "../../../../src/common/types" ;
38+ import api from "../../../../src/common/api" ;
39+ import { setErrorSnackMessage } from "../../../../src/actions" ;
40+
41+ interface IAddPolicyProps {
42+ classes : any ;
43+ setErrorSnackMessage : typeof setErrorSnackMessage ;
44+ }
45+
46+ const styles = ( theme : Theme ) =>
47+ createStyles ( {
48+ buttonContainer : {
49+ textAlign : "right" ,
50+ } ,
51+ bottomContainer : {
52+ display : "flex" ,
53+ flexGrow : 1 ,
54+ alignItems : "center" ,
55+ margin : "auto" ,
56+ justifyContent : "center" ,
57+ "& div" : {
58+ width : 150 ,
59+ "@media (max-width: 900px)" : {
60+ flexFlow : "column" ,
61+ } ,
62+ } ,
63+ } ,
64+ factorElements : {
65+ display : "flex" ,
66+ justifyContent : "flex-start" ,
67+ marginLeft : 30 ,
68+ } ,
69+ sizeNumber : {
70+ fontSize : 35 ,
71+ fontWeight : 700 ,
72+ textAlign : "center" ,
73+ } ,
74+ sizeDescription : {
75+ fontSize : 14 ,
76+ color : "#777" ,
77+ textAlign : "center" ,
78+ } ,
79+ pageBox : {
80+ border : "1px solid #EAEAEA" ,
81+ borderTop : 0 ,
82+ } ,
83+ addPoolTitle : {
84+ border : "1px solid #EAEAEA" ,
85+ borderBottom : 0 ,
86+ } ,
87+ headTitle : {
88+ fontWeight : "bold" ,
89+ fontSize : 20 ,
90+ paddingLeft : 20 ,
91+ paddingBottom : 40 ,
92+ paddingTop : 8 ,
93+ textAlign : "end" ,
94+ } ,
95+ headIcon : {
96+ fontWeight : "bold" ,
97+ size : "50" ,
98+ } ,
99+ ...formFieldStyles ,
100+ ...modalStyleUtils ,
101+ } ) ;
102+
103+ const AddPolicyScreen = ( {
104+ classes,
105+ setErrorSnackMessage,
106+ } : IAddPolicyProps ) => {
107+ const [ addLoading , setAddLoading ] = useState < boolean > ( false ) ;
108+ const [ policyName , setPolicyName ] = useState < string > ( "" ) ;
109+ const [ policyDefinition , setPolicyDefinition ] = useState < string > ( "" ) ;
110+
111+ const addRecord = ( event : React . FormEvent ) => {
112+ event . preventDefault ( ) ;
113+ if ( addLoading ) {
114+ return ;
115+ }
116+ setAddLoading ( true ) ;
117+ api
118+ . invoke ( "POST" , "/api/v1/policies" , {
119+ name : policyName ,
120+ policy : policyDefinition ,
121+ } )
122+ . then ( ( res ) => {
123+ setAddLoading ( false ) ;
124+ history . push ( `${ IAM_PAGES . POLICIES } ` ) ;
125+ } )
126+ . catch ( ( err : ErrorResponseHandler ) => {
127+ setAddLoading ( false ) ;
128+ setErrorSnackMessage ( err ) ;
129+ } ) ;
130+ } ;
131+
132+
133+ const resetForm = ( ) => {
134+ setPolicyName ( "" ) ;
135+ setPolicyDefinition ( "" ) ;
136+ } ;
137+
138+ const validSave = policyName . trim ( ) !== "" ;
139+
140+
141+
142+ return (
143+ < Fragment >
144+ < Grid item xs = { 12 } >
145+ < PageHeader
146+ label = { < BackLink to = { IAM_PAGES . POLICIES } label = { "Policies" } /> }
147+ />
148+ < PageLayout >
149+ < Grid
150+ item
151+ xs = { 12 }
152+ container
153+ className = { classes . title }
154+ align-items = "stretch"
155+ >
156+ < Grid item className = { classes . headIcon } >
157+ < AddAccessRuleIcon />
158+ </ Grid >
159+ < Grid item className = { classes . headTitle } >
160+ Create Policy
161+ </ Grid >
162+ </ Grid >
163+
164+ < Grid container align-items = "center" >
165+ < Grid item xs = { 8 } >
166+ < Box >
167+ < form noValidate
168+ autoComplete = "off"
169+ onSubmit = { ( e : React . FormEvent < HTMLFormElement > ) => {
170+ addRecord ( e ) ;
171+ } } >
172+ < Grid container item spacing = "20" >
173+
174+ < Grid item xs = { 12 } >
175+ < Grid container >
176+ < Grid item xs = { 12 } className = { classes . formFieldRow } >
177+ < InputBoxWrapper
178+ id = "policy-name"
179+ name = "policy-name"
180+ label = "Policy Name"
181+ autoFocus = { true }
182+ value = { policyName }
183+ onChange = { ( e : React . ChangeEvent < HTMLInputElement > ) => {
184+ setPolicyName ( e . target . value ) ;
185+ } }
186+ />
187+ </ Grid >
188+ < Grid item xs = { 12 } className = { classes . userSelector } >
189+ < CodeMirrorWrapper
190+ label = { "Write Policy" }
191+ value = { policyDefinition }
192+ onBeforeChange = { ( editor , data , value ) => {
193+ setPolicyDefinition ( value ) ;
194+ } }
195+ editorHeight = { "350px" }
196+ />
197+ </ Grid >
198+ </ Grid >
199+ < Grid item xs = { 12 } className = { classes . modalButtonBar } >
200+ < Button
201+ type = "button"
202+ variant = "outlined"
203+ color = "primary"
204+ className = { classes . spacerRight }
205+ onClick = { resetForm }
206+ >
207+ Clear
208+ </ Button >
209+
210+ < Button
211+ type = "submit"
212+ variant = "contained"
213+ color = "primary"
214+ disabled = { addLoading || ! validSave }
215+ >
216+ Save
217+ </ Button >
218+ </ Grid >
219+ </ Grid >
220+ </ Grid >
221+ </ form >
222+ </ Box >
223+ </ Grid >
224+ < Grid item xs = { 4 } >
225+ < Box >
226+ < AddPolicyHelpBox />
227+ </ Box >
228+ </ Grid >
229+ </ Grid >
230+ </ PageLayout >
231+ </ Grid >
232+ </ Fragment >
233+ ) ;
234+ } ;
235+
236+ const mapDispatchToProps = {
237+ setErrorSnackMessage,
238+ } ;
239+
240+ const connector = connect ( null , mapDispatchToProps ) ;
241+
242+ export default withStyles ( styles ) ( connector ( AddPolicyScreen ) ) ;
0 commit comments