|
@@ -2,8 +2,11 @@ import React, { Component } from "react";
|
|
|
import styled from "styled-components";
|
|
import styled from "styled-components";
|
|
|
import Modal from "../../main/home/modals/Modal";
|
|
import Modal from "../../main/home/modals/Modal";
|
|
|
import LoadEnvGroupModal from "../../main/home/modals/LoadEnvGroupModal";
|
|
import LoadEnvGroupModal from "../../main/home/modals/LoadEnvGroupModal";
|
|
|
|
|
+import EnvEditorModal from "../../main/home/modals/EnvEditorModal";
|
|
|
|
|
|
|
|
import sliders from "assets/sliders.svg";
|
|
import sliders from "assets/sliders.svg";
|
|
|
|
|
+import upload from "assets/upload.svg";
|
|
|
|
|
+import { keysIn } from "lodash";
|
|
|
|
|
|
|
|
type PropsType = {
|
|
type PropsType = {
|
|
|
label?: string;
|
|
label?: string;
|
|
@@ -14,17 +17,20 @@ type PropsType = {
|
|
|
namespace?: string;
|
|
namespace?: string;
|
|
|
clusterId?: number;
|
|
clusterId?: number;
|
|
|
envLoader?: boolean;
|
|
envLoader?: boolean;
|
|
|
|
|
+ fileUpload?: boolean;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
type StateType = {
|
|
type StateType = {
|
|
|
values: any[];
|
|
values: any[];
|
|
|
showEnvModal: boolean;
|
|
showEnvModal: boolean;
|
|
|
|
|
+ showEditorModal: boolean;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
state = {
|
|
state = {
|
|
|
values: [] as any[],
|
|
values: [] as any[],
|
|
|
showEnvModal: false,
|
|
showEnvModal: false,
|
|
|
|
|
+ showEditorModal: false,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
componentDidMount() {
|
|
@@ -137,6 +143,92 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ renderEditorModal = () => {
|
|
|
|
|
+ if (this.state.showEditorModal) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Modal
|
|
|
|
|
+ onRequestClose={() => this.setState({ showEditorModal: false })}
|
|
|
|
|
+ width="60%"
|
|
|
|
|
+ height="80%"
|
|
|
|
|
+ >
|
|
|
|
|
+ <EnvEditorModal
|
|
|
|
|
+ closeModal={() => this.setState({ showEditorModal: false })}
|
|
|
|
|
+ setEnvVariables={(envFile: string) => this.readFile(envFile)}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Parses src into an Object
|
|
|
|
|
+ parseEnv = (src: any, options: any) => {
|
|
|
|
|
+ const debug = Boolean(options && options.debug)
|
|
|
|
|
+ const obj = {} as Record<string, string>
|
|
|
|
|
+ const NEWLINE = '\n'
|
|
|
|
|
+ const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
|
|
|
|
|
+ const RE_NEWLINES = /\\n/g
|
|
|
|
|
+ const NEWLINES_MATCH = /\n|\r|\r\n/
|
|
|
|
|
+
|
|
|
|
|
+ // convert Buffers before splitting into lines and processing
|
|
|
|
|
+ src.toString().split(NEWLINES_MATCH).forEach(function (line: any, idx: any) {
|
|
|
|
|
+ // matching "KEY' and 'VAL' in 'KEY=VAL'
|
|
|
|
|
+ const keyValueArr = line.match(RE_INI_KEY_VAL)
|
|
|
|
|
+ // matched?
|
|
|
|
|
+ if (keyValueArr != null) {
|
|
|
|
|
+ const key = keyValueArr[1]
|
|
|
|
|
+ // default undefined or missing values to empty string
|
|
|
|
|
+ let val = (keyValueArr[2] || '')
|
|
|
|
|
+ const end = val.length - 1
|
|
|
|
|
+ const isDoubleQuoted = val[0] === '"' && val[end] === '"'
|
|
|
|
|
+ const isSingleQuoted = val[0] === "'" && val[end] === "'"
|
|
|
|
|
+
|
|
|
|
|
+ // if single or double quoted, remove quotes
|
|
|
|
|
+ if (isSingleQuoted || isDoubleQuoted) {
|
|
|
|
|
+ val = val.substring(1, end)
|
|
|
|
|
+
|
|
|
|
|
+ // if double quoted, expand newlines
|
|
|
|
|
+ if (isDoubleQuoted) {
|
|
|
|
|
+ val = val.replace(RE_NEWLINES, NEWLINE)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // remove surrounding whitespace
|
|
|
|
|
+ val = val.trim()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ obj[key] = val
|
|
|
|
|
+ } else if (debug) {
|
|
|
|
|
+ console.log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return obj
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ readFile = (env: string) => {
|
|
|
|
|
+ let envObj = this.parseEnv(env, null)
|
|
|
|
|
+ let push = true;
|
|
|
|
|
+
|
|
|
|
|
+ for (let key in envObj) {
|
|
|
|
|
+ for (var i = 0; i < this.state.values.length; i++) {
|
|
|
|
|
+ let existingKey = this.state.values[i]["key"]
|
|
|
|
|
+ if (key === existingKey) {
|
|
|
|
|
+ this.state.values[i]["value"] = envObj[key]
|
|
|
|
|
+ push = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (push) {
|
|
|
|
|
+ this.state.values.push({ key, value: envObj[key] });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.setState({ values: this.state.values }, () => {
|
|
|
|
|
+ let obj = this.valuesToObject();
|
|
|
|
|
+ this.props.setValues(obj);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
render() {
|
|
render() {
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
@@ -165,36 +257,25 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
<img src={sliders} /> Load from Env Group
|
|
<img src={sliders} /> Load from Env Group
|
|
|
</LoadButton>
|
|
</LoadButton>
|
|
|
)}
|
|
)}
|
|
|
|
|
+ {this.props.fileUpload && (
|
|
|
|
|
+ <UploadButton
|
|
|
|
|
+ onClick={()=>{
|
|
|
|
|
+ this.setState({ showEditorModal: true });
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <img src={upload} /> Copy from File
|
|
|
|
|
+ </UploadButton>
|
|
|
|
|
+ )}
|
|
|
</InputWrapper>
|
|
</InputWrapper>
|
|
|
)}
|
|
)}
|
|
|
</StyledInputArray>
|
|
</StyledInputArray>
|
|
|
{this.renderEnvModal()}
|
|
{this.renderEnvModal()}
|
|
|
|
|
+ {this.renderEditorModal()}
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const CloseOverlay = styled.div`
|
|
|
|
|
- position: fixed;
|
|
|
|
|
- top: 0;
|
|
|
|
|
- left: 0;
|
|
|
|
|
- width: 100vw;
|
|
|
|
|
- height: 100vh;
|
|
|
|
|
- z-index: 999;
|
|
|
|
|
- background: #202227;
|
|
|
|
|
- animation: fadeIn 0.2s 0s;
|
|
|
|
|
- opacity: 0;
|
|
|
|
|
- animation-fill-mode: forwards;
|
|
|
|
|
- @keyframes fadeIn {
|
|
|
|
|
- from {
|
|
|
|
|
- opacity: 0;
|
|
|
|
|
- }
|
|
|
|
|
- to {
|
|
|
|
|
- opacity: 1;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-`;
|
|
|
|
|
-
|
|
|
|
|
const Spacer = styled.div`
|
|
const Spacer = styled.div`
|
|
|
width: 10px;
|
|
width: 10px;
|
|
|
height: 20px;
|
|
height: 20px;
|
|
@@ -244,6 +325,26 @@ const LoadButton = styled(AddRowButton)`
|
|
|
}
|
|
}
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
|
|
+const UploadButton = styled(AddRowButton)`
|
|
|
|
|
+ background: none;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ border: 1px solid #ffffff55;
|
|
|
|
|
+ > i {
|
|
|
|
|
+ color: #ffffff44;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ margin-left: 8px;
|
|
|
|
|
+ margin-right: 10px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ > img {
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ margin-left: 10px;
|
|
|
|
|
+ margin-right: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+`;
|
|
|
|
|
+
|
|
|
const DeleteButton = styled.div`
|
|
const DeleteButton = styled.div`
|
|
|
width: 15px;
|
|
width: 15px;
|
|
|
height: 15px;
|
|
height: 15px;
|