|
@@ -8,12 +8,12 @@ import upload from "assets/upload.svg";
|
|
|
import { keysIn } from "lodash";
|
|
import { keysIn } from "lodash";
|
|
|
|
|
|
|
|
export type KeyValueType = {
|
|
export type KeyValueType = {
|
|
|
- key: string;
|
|
|
|
|
- value: string;
|
|
|
|
|
- hidden: boolean;
|
|
|
|
|
- locked: boolean;
|
|
|
|
|
- deleted: boolean;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ key: string;
|
|
|
|
|
+ value: string;
|
|
|
|
|
+ hidden: boolean;
|
|
|
|
|
+ locked: boolean;
|
|
|
|
|
+ deleted: boolean;
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
type PropsType = {
|
|
type PropsType = {
|
|
|
label?: string;
|
|
label?: string;
|
|
@@ -40,10 +40,10 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
componentDidMount() {
|
|
|
- if (!this.props.values) {
|
|
|
|
|
- let _values = [] as KeyValueType[];
|
|
|
|
|
- this.props.setValues(_values)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!this.props.values) {
|
|
|
|
|
+ let _values = [] as KeyValueType[];
|
|
|
|
|
+ this.props.setValues(_values);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
renderDeleteButton = (i: number) => {
|
|
renderDeleteButton = (i: number) => {
|
|
@@ -51,8 +51,8 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
return (
|
|
return (
|
|
|
<DeleteButton
|
|
<DeleteButton
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- let _values = this.props.values
|
|
|
|
|
- _values[i].deleted = true
|
|
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
+ _values[i].deleted = true;
|
|
|
this.props.setValues(_values);
|
|
this.props.setValues(_values);
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
@@ -64,20 +64,20 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
|
|
|
|
|
renderHiddenOption = (hidden: boolean, locked: boolean, i: number) => {
|
|
renderHiddenOption = (hidden: boolean, locked: boolean, i: number) => {
|
|
|
if (this.props.secretOption) {
|
|
if (this.props.secretOption) {
|
|
|
- let icon = <i className="material-icons">lock_open</i>
|
|
|
|
|
|
|
+ let icon = <i className="material-icons">lock_open</i>;
|
|
|
|
|
|
|
|
if (hidden) {
|
|
if (hidden) {
|
|
|
- icon = <i className="material-icons">lock</i>
|
|
|
|
|
|
|
+ icon = <i className="material-icons">lock</i>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<HideButton
|
|
<HideButton
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- if (!locked) {
|
|
|
|
|
- let _values = this.props.values
|
|
|
|
|
- _values[i].hidden = !_values[i].hidden;
|
|
|
|
|
- this.props.setValues(_values)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!locked) {
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
+ _values[i].hidden = !_values[i].hidden;
|
|
|
|
|
+ this.props.setValues(_values);
|
|
|
|
|
+ }
|
|
|
}}
|
|
}}
|
|
|
disabled={locked}
|
|
disabled={locked}
|
|
|
>
|
|
>
|
|
@@ -91,38 +91,38 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
{this.props.values.map((entry: KeyValueType, i: number) => {
|
|
{this.props.values.map((entry: KeyValueType, i: number) => {
|
|
|
- if (!entry.deleted) {
|
|
|
|
|
- return (
|
|
|
|
|
- <InputWrapper key={i}>
|
|
|
|
|
- <Input
|
|
|
|
|
- placeholder="ex: key"
|
|
|
|
|
- width="270px"
|
|
|
|
|
- value={entry.key}
|
|
|
|
|
- onChange={(e: any) => {
|
|
|
|
|
- let _values = this.props.values
|
|
|
|
|
- _values[i].key = e.target.value;
|
|
|
|
|
- this.props.setValues(_values);
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={this.props.disabled || entry.locked}
|
|
|
|
|
- />
|
|
|
|
|
- <Spacer />
|
|
|
|
|
- <Input
|
|
|
|
|
- placeholder="ex: value"
|
|
|
|
|
- width="270px"
|
|
|
|
|
- value={entry.value}
|
|
|
|
|
- onChange={(e: any) => {
|
|
|
|
|
- let _values = this.props.values
|
|
|
|
|
- _values[i].value = e.target.value;
|
|
|
|
|
- this.props.setValues(_values);
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={this.props.disabled || entry.locked}
|
|
|
|
|
- type={entry.hidden ? "password" : "text"}
|
|
|
|
|
- />
|
|
|
|
|
- {this.renderHiddenOption(entry.hidden, entry.locked, i)}
|
|
|
|
|
- {this.renderDeleteButton(i)}
|
|
|
|
|
- </InputWrapper>
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!entry.deleted) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <InputWrapper key={i}>
|
|
|
|
|
+ <Input
|
|
|
|
|
+ placeholder="ex: key"
|
|
|
|
|
+ width="270px"
|
|
|
|
|
+ value={entry.key}
|
|
|
|
|
+ onChange={(e: any) => {
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
+ _values[i].key = e.target.value;
|
|
|
|
|
+ this.props.setValues(_values);
|
|
|
|
|
+ }}
|
|
|
|
|
+ disabled={this.props.disabled || entry.locked}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Spacer />
|
|
|
|
|
+ <Input
|
|
|
|
|
+ placeholder="ex: value"
|
|
|
|
|
+ width="270px"
|
|
|
|
|
+ value={entry.value}
|
|
|
|
|
+ onChange={(e: any) => {
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
+ _values[i].value = e.target.value;
|
|
|
|
|
+ this.props.setValues(_values);
|
|
|
|
|
+ }}
|
|
|
|
|
+ disabled={this.props.disabled || entry.locked}
|
|
|
|
|
+ type={entry.hidden ? "password" : "text"}
|
|
|
|
|
+ />
|
|
|
|
|
+ {this.renderHiddenOption(entry.hidden, entry.locked, i)}
|
|
|
|
|
+ {this.renderDeleteButton(i)}
|
|
|
|
|
+ </InputWrapper>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
})}
|
|
})}
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
@@ -145,121 +145,137 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // Parses src into an Object
|
|
|
|
|
|
|
+ // Parses src into an Object
|
|
|
parseEnv = (src: any, options: any) => {
|
|
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/
|
|
|
|
|
|
|
+ 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
|
|
// 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)
|
|
|
|
|
|
|
+ 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();
|
|
|
}
|
|
}
|
|
|
- } 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}`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ obj[key] = val;
|
|
|
|
|
+ } else if (debug) {
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `did not match key and value when parsing line ${idx + 1}: ${line}`
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- return obj
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return obj;
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
readFile = (env: string) => {
|
|
readFile = (env: string) => {
|
|
|
- let envObj = this.parseEnv(env, null)
|
|
|
|
|
|
|
+ let envObj = this.parseEnv(env, null);
|
|
|
let push = true;
|
|
let push = true;
|
|
|
- let _values = this.props.values
|
|
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
|
|
|
for (let key in envObj) {
|
|
for (let key in envObj) {
|
|
|
for (var i = 0; i < this.props.values.length; i++) {
|
|
for (var i = 0; i < this.props.values.length; i++) {
|
|
|
- let existingKey = this.props.values[i]["key"]
|
|
|
|
|
|
|
+ let existingKey = this.props.values[i]["key"];
|
|
|
if (key === existingKey) {
|
|
if (key === existingKey) {
|
|
|
- _values[i]["value"] = envObj[key]
|
|
|
|
|
|
|
+ _values[i]["value"] = envObj[key];
|
|
|
push = false;
|
|
push = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (push) {
|
|
if (push) {
|
|
|
- _values.push({ key, value: envObj[key], hidden: false, locked: false, deleted: false });
|
|
|
|
|
|
|
+ _values.push({
|
|
|
|
|
+ key,
|
|
|
|
|
+ value: envObj[key],
|
|
|
|
|
+ hidden: false,
|
|
|
|
|
+ locked: false,
|
|
|
|
|
+ deleted: false,
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this.props.setValues(_values);
|
|
this.props.setValues(_values);
|
|
|
- }
|
|
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
render() {
|
|
render() {
|
|
|
- if (this.props.values) {
|
|
|
|
|
- return (
|
|
|
|
|
- <>
|
|
|
|
|
- <StyledInputArray>
|
|
|
|
|
- <Label>{this.props.label}</Label>
|
|
|
|
|
- {this.props.values.length === 0 ? <></> : this.renderInputList()}
|
|
|
|
|
- {this.props.disabled ? (
|
|
|
|
|
- <></>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <InputWrapper>
|
|
|
|
|
- <AddRowButton
|
|
|
|
|
- onClick={() => {
|
|
|
|
|
- let _values = this.props.values
|
|
|
|
|
- _values.push({ key: "", value: "", hidden: false, locked: false, deleted: false });
|
|
|
|
|
- this.props.setValues(_values)
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- <i className="material-icons">add</i> Add Row
|
|
|
|
|
- </AddRowButton>
|
|
|
|
|
- <Spacer />
|
|
|
|
|
- {this.props.namespace && this.props.envLoader && (
|
|
|
|
|
- <LoadButton
|
|
|
|
|
- onClick={() =>
|
|
|
|
|
- this.setState({ showEnvModal: !this.state.showEnvModal })
|
|
|
|
|
- }
|
|
|
|
|
- >
|
|
|
|
|
- <img src={sliders} /> Load from Env Group
|
|
|
|
|
- </LoadButton>
|
|
|
|
|
- )}
|
|
|
|
|
- {this.props.fileUpload && (
|
|
|
|
|
- <UploadButton
|
|
|
|
|
- onClick={()=>{
|
|
|
|
|
- this.setState({ showEditorModal: true });
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- <img src={upload} /> Copy from File
|
|
|
|
|
- </UploadButton>
|
|
|
|
|
- )}
|
|
|
|
|
- </InputWrapper>
|
|
|
|
|
|
|
+ if (this.props.values) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <StyledInputArray>
|
|
|
|
|
+ <Label>{this.props.label}</Label>
|
|
|
|
|
+ {this.props.values.length === 0 ? <></> : this.renderInputList()}
|
|
|
|
|
+ {this.props.disabled ? (
|
|
|
|
|
+ <></>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <InputWrapper>
|
|
|
|
|
+ <AddRowButton
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ let _values = this.props.values;
|
|
|
|
|
+ _values.push({
|
|
|
|
|
+ key: "",
|
|
|
|
|
+ value: "",
|
|
|
|
|
+ hidden: false,
|
|
|
|
|
+ locked: false,
|
|
|
|
|
+ deleted: false,
|
|
|
|
|
+ });
|
|
|
|
|
+ this.props.setValues(_values);
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <i className="material-icons">add</i> Add Row
|
|
|
|
|
+ </AddRowButton>
|
|
|
|
|
+ <Spacer />
|
|
|
|
|
+ {this.props.namespace && this.props.envLoader && (
|
|
|
|
|
+ <LoadButton
|
|
|
|
|
+ onClick={() =>
|
|
|
|
|
+ this.setState({ showEnvModal: !this.state.showEnvModal })
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <img src={sliders} /> Load from Env Group
|
|
|
|
|
+ </LoadButton>
|
|
|
)}
|
|
)}
|
|
|
- </StyledInputArray>
|
|
|
|
|
- {this.renderEditorModal()}
|
|
|
|
|
- </>
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ {this.props.fileUpload && (
|
|
|
|
|
+ <UploadButton
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ this.setState({ showEditorModal: true });
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <img src={upload} /> Copy from File
|
|
|
|
|
+ </UploadButton>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </InputWrapper>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </StyledInputArray>
|
|
|
|
|
+ {this.renderEditorModal()}
|
|
|
|
|
+ </>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return null
|
|
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -358,12 +374,14 @@ const HideButton = styled(DeleteButton)`
|
|
|
margin-top: -5px;
|
|
margin-top: -5px;
|
|
|
> i {
|
|
> i {
|
|
|
font-size: 19px;
|
|
font-size: 19px;
|
|
|
- cursor: ${(props : {disabled: boolean}) => props.disabled ? "default" : "pointer"};
|
|
|
|
|
|
|
+ cursor: ${(props: { disabled: boolean }) =>
|
|
|
|
|
+ props.disabled ? "default" : "pointer"};
|
|
|
:hover {
|
|
:hover {
|
|
|
- color: ${(props : {disabled: boolean}) => props.disabled ? "#ffffff44" : "#ffffff88"};
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ color: ${(props: { disabled: boolean }) =>
|
|
|
|
|
+ props.disabled ? "#ffffff44" : "#ffffff88"};
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-`
|
|
|
|
|
|
|
+`;
|
|
|
|
|
|
|
|
const InputWrapper = styled.div`
|
|
const InputWrapper = styled.div`
|
|
|
display: flex;
|
|
display: flex;
|