Files
deployment-portal-fe/src/coreform/BaseForm.tsx
2023-06-15 18:39:35 +05:30

298 lines
9.4 KiB
TypeScript

import * as React from 'react';
import {makeStyles, Theme} from '@material-ui/core/styles';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import ManifestForm from './ManifestForm'
import DatabaseForm from './database/DatabaseForm'
import ElasticCacheForm from './elasticcache/ElasticCacheForm'
import * as _m from '../models/Manifest'
import { Form, Formik, FormikValues, useFormikContext, validateYupSchema, yupToFormErrors } from 'formik'
import {manifestValidationSchema} from "../models/ManifestValidationSchema";
import {tabA11yProps, TabPanel} from './FormUtil';
import Configuration from './configuration/ConfigurationForm';
import S3BucketForm from './s3bucket/S3BucketForm';
import { Button, Divider, Snackbar, TextField, Typography } from '@material-ui/core'
import {Alert} from "@material-ui/lab";
import DeploymentForm from './deployment/DeploymentForm';
import AWSAccessForm from './awsaccess/AWSAccessForm';
import ServiceMonitorForm from "./servicemonitor/ServiceMonitorForm";
import DocumentDbForm from "./documentdb/DocumentDbForm";
import ElasticSearchForm from "./elasticsearch/ElasticSearchForm";
import { Dispatch, SetStateAction } from 'react';
import DynamoDbForm from "./dynamodb/DynamoDbForm";
import {store} from "../store/store";
import { getBreachedValues } from '../helper/ChangeRequest'
import Popup from '../components/common/Popup'
const useStyles = makeStyles((theme: Theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
display: 'flex',
},
tabs: {
borderRight: `1px solid ${theme.palette.divider}`,
}
}));
interface BaseFormProps {
initData: any,
setFormInitData: Dispatch<SetStateAction<object>>,
onSubmit: (values: any, afterSubmitCallback: Function) => void,
manifestLimits: any,
hasPendingCr: boolean,
crDescription: string,
setCrDescription: Dispatch<SetStateAction<string>>,
}
interface FormTab {
name: string
displayName: any
component: React.ReactNode
errorCheckFn: Function
}
const tabList: Array<FormTab> = [
{
name: 'deployment',
displayName: 'deployment',
component: <DeploymentForm />,
errorCheckFn: _m.hasDeployment,
},
{
name: 'database',
displayName: 'database',
component: <DatabaseForm />,
errorCheckFn: _m.hasDatabase
},
{
name: 'docdb',
displayName: 'document db',
component: <DocumentDbForm />,
errorCheckFn: _m.hasDocumentDb
},
{
name: 'elastic Cache',
displayName: 'elastic Cache',
component: <ElasticCacheForm />,
errorCheckFn: _m.hasElasticCache
},
{
name: 's3 bucket',
displayName: 's3 bucket',
component: <S3BucketForm />,
errorCheckFn: _m.hasS3Bucket
},
{
name: 'configuration',
displayName: 'configuration',
component: <Configuration />,
errorCheckFn: _m.hasConfiguration
},
{
name: 'aws access',
displayName: 'aws access',
component: <AWSAccessForm />,
errorCheckFn: _m.hasAwsAccess
},
{
name: 'Service Monitor',
displayName: 'service monitor',
component: <ServiceMonitorForm />,
errorCheckFn: _m.hasServiceMonitor
},
{
name: 'Elastic Search',
displayName: 'elastic search',
component: <ElasticSearchForm />,
errorCheckFn: _m.hasElasticSearch
},
{
name: 'DynamoDB',
displayName: 'DynamoDB',
component: <DynamoDbForm />,
errorCheckFn: _m.hasDynamoDb
},
]
const tabHasErrors = (tab: FormTab, errors: any) => {
return tab.errorCheckFn(errors)
}
const ErrorSnackBar = (props: { errors: any }) => {
const { errors } = props
const errorData = Object.entries(errors).slice(0, 4)
return (
<Snackbar open={errorData.length > 0} autoHideDuration={5000}>
<Alert severity="error">
{errorData.map((data, idx) => {
return (
<Typography
variant="subtitle2"
color="secondary"
key={idx} >
{ JSON.stringify(data)}
</Typography>
);
})}
</Alert>
</Snackbar>)
}
const BaseForm = (props: BaseFormProps) => {
const classes = useStyles();
const defaultSubmitButtonLabel = "Submit";
const submitChangeRequestLabel = "Submit Change Request"
const defaultSubmitButtonStyle = { alignItems: "flex-end", display: "flex", justifyContent: "flex-end", float: "right" };
const submitChangeRequestStyle = {...defaultSubmitButtonStyle, backgroundColor: '#fd7700'};
const { setCrDescription } = props
const [currentTab, setCurrentTab] = React.useState(0);
const { initData, onSubmit } = props
const { manifestLimits, hasPendingCr } = props;
const setFormInitData = props.setFormInitData;
const [manifestVersion, setManifestVersion] = React.useState()
const [versionListData, setVersionListData] = React.useState<any>([]);
const [isSubmitButtonDisabled, disableSubmitButton] = React.useState(false);
const { state } = React.useContext(store);
const [rolloutPopupOpen, setRolloutPopupOpen] = React.useState(false);
const [isCrRequired, setCrRequired] = React.useState(false);
const isDisabled = () => {
if (!isSubmitButtonDisabled &&
(manifestVersion === Math.max(...versionListData)
|| manifestVersion === undefined
|| manifestVersion === 'None')) {
disableSubmitButton(false)
} else {
disableSubmitButton(true)
}
return isSubmitButtonDisabled
}
const handleTabChange = (e: React.ChangeEvent<{}>, newValue: number) => {
setCurrentTab(newValue);
};
const submitButton = (
style: {},
label: string,
type: "submit" | "button" = "submit",
onClick: () => void = () => {}
) => (
<Button
disabled={isDisabled()}
color="secondary"
type={type}
variant="contained"
size="large"
style={style}
onClick={onClick}
>
{label}
</Button>
);
const submitCrButton = (
type: "submit" | "button" = "button",
style = submitChangeRequestStyle,
onClick: () => void = () => {}
) => submitButton(submitChangeRequestStyle, submitChangeRequestLabel, type, onClick);
const submitManifestButton = () => submitButton(defaultSubmitButtonStyle, defaultSubmitButtonLabel)
const renderSubmitButton = () => {
if (isCrRequired) {
return submitCrButton("button", submitChangeRequestStyle, () => setRolloutPopupOpen(true));
} else {
return submitManifestButton();
}
};
const handleSubmit = (values: FormikValues) => {
disableSubmitButton(true);
onSubmit(values, () => {
setCrRequired(false);
disableSubmitButton(false);
});
}
return (
<div style={{ marginBottom: 20 }}>
<Formik
enableReinitialize
initialValues={initData}
validate={async value => {
const breachedValues = getBreachedValues(manifestLimits[`${value.environment}`], value, state.preChangeManifest)
setCrRequired(breachedValues.length !== 0);
try {
await validateYupSchema(value, manifestValidationSchema, false, value);
} catch (err) {
return yupToFormErrors(err); //for rendering validation errors
}
return {};
}}
validateOnChange={false}
onSubmit={values => handleSubmit(values)}
>
{
props => (
<Form>
<ManifestForm manifest={props.values}
setFormInitData={setFormInitData}
setManifestVersion={setManifestVersion}
setVersionListData={setVersionListData}
versionListData={versionListData}
hasPendingCr={hasPendingCr}/>
<Divider />
<div className={classes.root}>
<Tabs orientation="vertical" variant="scrollable" value={currentTab} onChange={handleTabChange}
aria-label="Vertical tabs " className={classes.tabs} >
{
tabList.map((tab, index) => (
<Tab key={index} style={{ backgroundColor: tabHasErrors(tab, props.errors) ? '#ffb3bf' : 'white' }}
label={tab.displayName} {...tabA11yProps(index, 'vertical')} />
))
}
</Tabs>
{
tabList.map((tab, index) => (
<TabPanel key={index} value={currentTab} index={index} tabtype='vertical'>
{tab.component}
</TabPanel>
))
}
</div>
{renderSubmitButton()}
<Popup
open={rolloutPopupOpen}
onClose={() => setRolloutPopupOpen(false)}
title="Submit change request"
>
<TextField
style={{ textAlign: "center" }}
type="text"
fullWidth
placeholder="Please describe changes in the CR."
variant="outlined"
onBlur={({ target: { value } }) => setCrDescription(value)}
multiline
/>
{submitCrButton("submit", {...submitChangeRequestStyle},
() => {
handleSubmit(props.values);
setRolloutPopupOpen(false);
})}
</Popup>
{/*<Debug {...props} />*/}
<ErrorSnackBar errors={props.errors} />
</Form>
)}
</Formik>
</div>
);
}
export default BaseForm