diff --git a/src/containers/apps/ProjectDetailsEdit.tsx b/src/containers/apps/ProjectDetailsEdit.tsx index 08f4081d..e3bee755 100644 --- a/src/containers/apps/ProjectDetailsEdit.tsx +++ b/src/containers/apps/ProjectDetailsEdit.tsx @@ -1,16 +1,20 @@ -import { Button, Card, Input, Row } from 'antd' +import { EditFilled, EditOutlined } from '@ant-design/icons' +import { Button, Card, Col, Input, Row, Tooltip } from 'antd' import { RefObject } from 'react' import { connect } from 'react-redux' import { RouteComponentProps } from 'react-router' import ProjectSelector from '../../components/ProjectSelector' import { IMobileComponent } from '../../models/ContainerProps' +import { IHashMapGeneric } from '../../models/IHashMapGeneric' import ProjectDefinition from '../../models/ProjectDefinition' import { localize } from '../../utils/Language' import Toaster from '../../utils/Toaster' import Utils from '../../utils/Utils' import ApiComponent from '../global/ApiComponent' import CenteredSpinner from '../global/CenteredSpinner' +import CodeEdit from '../global/CodeEdit' import ErrorRetry from '../global/ErrorRetry' +import { IAppEnvVar } from './AppDefinition' interface PropsInterface extends RouteComponentProps { mainContainer: RefObject @@ -25,6 +29,8 @@ class ProjectDetailsEdit extends ApiComponent< isLoading: boolean selectedProject: ProjectDefinition | undefined allProjects: ProjectDefinition[] + envVarBulkEdit: boolean + envVarBulkVals: string } > { constructor(props: any) { @@ -34,9 +40,197 @@ class ProjectDetailsEdit extends ApiComponent< isLoading: true, selectedProject: undefined, allProjects: [], + envVarBulkEdit: false, + envVarBulkVals: '', } } + parseEnvVars(src: string): IHashMapGeneric { + const obj: IHashMapGeneric = {} + src.toString() + .split('\n') + .forEach(function (line) { + const keyValueArr = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/) + if (!!keyValueArr) { + const key = keyValueArr[1] + let value = keyValueArr[2] || '' + const len = value ? value.length : 0 + if ( + len > 0 && + value.charAt(0) === '"' && + value.charAt(len - 1) === '"' + ) { + value = value.replace(/\\n/gm, '\n') + } + value = value.replace(/(^['"]|['"]$)/g, '').trim() + obj[key] = value + } + }) + return obj + } + + convertEnvVarsToBulk(envVars: IAppEnvVar[]): string { + return envVars + .map((e) => { + let val = e.value + if (val.indexOf('\n') >= 0) { + val = `"${val.split('\n').join('\\n')}"` + } + return `${e.key}=${val}` + }) + .join('\n') + } + + createEnvVarSection() { + const self = this + const selectedProject = self.state.selectedProject! + const envVars = selectedProject.envVars || [] + + const updateEnvVars = (updated: IAppEnvVar[]) => { + const newData = Utils.copyObject(selectedProject) + newData.envVars = updated + self.setState({ selectedProject: newData }) + } + + const toggleIcon = self.state.envVarBulkEdit ? ( + + + self.setState({ + envVarBulkEdit: false, + envVarBulkVals: '', + }) + } + /> + + ) : ( + + + self.setState({ + envVarBulkEdit: true, + envVarBulkVals: + self.convertEnvVarsToBulk(envVars), + }) + } + /> + + ) + + if (self.state.envVarBulkEdit) { + return ( +
+ + + { + const keyVals = self.parseEnvVars( + e.target.value + ) + const parsed: IAppEnvVar[] = [] + Object.keys(keyVals).forEach((k) => { + parsed.push({ + key: k, + value: keyVals[k], + }) + }) + updateEnvVars(parsed) + self.setState({ + envVarBulkVals: e.target.value, + }) + }} + /> + + + {toggleIcon} +
+ ) + } + + const rows = envVars.map((value, index) => ( + + + { + const updated = Utils.copyObject(envVars) + updated[index].key = e.target.value + updateEnvVars(updated) + }} + /> + + + { + const updated = Utils.copyObject(envVars) + updated[index].value = e.target.value + updateEnvVars(updated) + }} + /> + + + + + + )) + + return ( +
+ {rows} + + + {toggleIcon} + +
+ ) + } + goBackToApps() { this.props.history.push('/apps') } @@ -67,7 +261,7 @@ class ProjectDetailsEdit extends ApiComponent<

{localize( 'projects.edit_project_hint', - 'You can set the name, description and the parent of this project.' + 'You can set the name, description, parent, and environment variables for this project.' )}

@@ -158,6 +352,24 @@ class ProjectDetailsEdit extends ApiComponent< }) }} /> +
+ {localize( + 'projects.env_vars', + 'Environment Variables' + )} +
+

+ {localize( + 'projects.env_vars_hint', + 'Apps and sub-projects inside this project will inherit these variables. Apps can override them by defining their own variable with the same key.' + )} +

+ {self.createEnvVarSection()}