198 lines
5.4 KiB
TypeScript
198 lines
5.4 KiB
TypeScript
import { CodeEditor } from "../../../elements/CodeEditor";
|
|
import { Component, createRef, JSX } from "preact";
|
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
|
import { SecretTitleElement } from "../SecretTitleElement";
|
|
import { setErrorText } from "../../../../pageUtils";
|
|
import { sortedObjectMap } from "../../../../utils";
|
|
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
|
import Hjson from "hjson";
|
|
import JSON5 from "json5";
|
|
import yaml from "js-yaml";
|
|
import i18next from "i18next";
|
|
|
|
// todo: put this in settings
|
|
const defaultIndent = 2;
|
|
|
|
function parseData(data: string, syntax: string = "json"): Record<string, unknown> {
|
|
if (syntax == "json") {
|
|
return JSON.parse(data);
|
|
} else if (syntax == "json5") {
|
|
return JSON5.parse(data);
|
|
} else if (syntax == "hjson") {
|
|
return Hjson.parse(data);
|
|
} else if (syntax == "yaml") {
|
|
return yaml.load(data) as Record<string, unknown>;
|
|
}
|
|
}
|
|
|
|
function dumpData(data: Record<string, unknown>, space: number = defaultIndent, syntax: string = "json"): string {
|
|
if (syntax == "json") {
|
|
return JSON.stringify(data, null, space);
|
|
} else if (syntax == "json5") {
|
|
return JSON5.stringify(data, null, space);
|
|
} else if (syntax == "hjson") {
|
|
return Hjson.stringify(data, { space: space });
|
|
} else if (syntax == "yaml") {
|
|
return yaml.dump(data, { indent: space });
|
|
}
|
|
}
|
|
|
|
export function validateData(str: string, syntax: string = "json"): boolean {
|
|
try {
|
|
parseData(str, syntax);
|
|
} catch (e) {
|
|
console.log(e);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export type KVEditProps = DefaultPageProps & {
|
|
baseMount: string;
|
|
secretPath: string[];
|
|
secretItem: string;
|
|
};
|
|
|
|
type KVEditState =
|
|
| {
|
|
dataLoaded: false;
|
|
syntax: string;
|
|
}
|
|
| {
|
|
dataLoaded: true;
|
|
kvData: Record<string, unknown>;
|
|
code: string;
|
|
syntax: string;
|
|
};
|
|
|
|
export class KVEditor extends Component<KVEditProps, KVEditState> {
|
|
constructor() {
|
|
super();
|
|
// TODO: add a global syntax option to settings for default
|
|
this.state = {
|
|
dataLoaded: false,
|
|
syntax: "json",
|
|
};
|
|
}
|
|
|
|
async editorSave(): Promise<void> {
|
|
if (!this.state.dataLoaded) return;
|
|
const editorContent = this.state.code;
|
|
|
|
if (!validateData(editorContent, this.state.syntax)) {
|
|
setErrorText(i18next.t("kv_sec_edit_invalid_json_err"));
|
|
return;
|
|
}
|
|
|
|
await this.props.api.createOrUpdateSecret(
|
|
this.props.baseMount,
|
|
this.props.secretPath.map((e) => e + "/"),
|
|
this.props.secretItem,
|
|
parseData(editorContent, this.state.syntax),
|
|
);
|
|
window.history.back();
|
|
}
|
|
|
|
onCodeUpdate(code: string): void {
|
|
this.setState({
|
|
code: code,
|
|
});
|
|
}
|
|
|
|
async loadData() {
|
|
let kvData = await this.props.api.getSecret(
|
|
this.props.baseMount,
|
|
this.props.secretPath.map((e) => e + "/"),
|
|
this.props.secretItem,
|
|
)
|
|
this.setState({
|
|
dataLoaded: true,
|
|
kvData: kvData,
|
|
code: this.getStringKVData(kvData)
|
|
});
|
|
}
|
|
|
|
async componentDidMount() {
|
|
if (!this.state.dataLoaded) {
|
|
await this.loadData();
|
|
}
|
|
}
|
|
|
|
getStringKVData(data: Record<string, unknown>): string {
|
|
return dumpData(Object.fromEntries(sortedObjectMap(data)), defaultIndent, this.state.syntax);
|
|
}
|
|
|
|
syntaxSelectRef = createRef<HTMLSelectElement>()
|
|
|
|
render(): JSX.Element {
|
|
if (!this.state.dataLoaded) {
|
|
return <p>{i18next.t("content_loading")}</p>;
|
|
}
|
|
|
|
let codeEditorLanguage: string;
|
|
|
|
if (this.state.syntax == "json") {
|
|
codeEditorLanguage = "json"
|
|
} else if (this.state.syntax == "json5") {
|
|
codeEditorLanguage = "json5"
|
|
}else if (this.state.syntax == "hjson") {
|
|
codeEditorLanguage = "js"
|
|
} else if (this.state.syntax == "yaml") {
|
|
codeEditorLanguage = "yaml"
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<InputWithTitle title={i18next.t("kv_sec_edit_syntax")}>
|
|
<select ref={this.syntaxSelectRef} class="uk-select uk-form-width-medium" onChange={() => {
|
|
this.setState({ syntax: this.syntaxSelectRef.current.value })
|
|
|
|
}}>
|
|
<option label="JSON" value="json" />
|
|
<option label="JSON5" value="json5" />
|
|
<option label="Hjson" value="hjson" />
|
|
<option label="Yaml" value="yaml" />
|
|
</select>
|
|
</InputWithTitle>
|
|
<p class="uk-text-danger" id="errorText" />
|
|
<CodeEditor
|
|
language={codeEditorLanguage}
|
|
tabSize={defaultIndent}
|
|
code={this.getStringKVData(this.state.kvData)}
|
|
onUpdate={(code) => this.onCodeUpdate(code)}
|
|
/>
|
|
<button class="uk-button uk-button-primary" onClick={() => this.editorSave()}>
|
|
{i18next.t("common_edit")}
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export class KeyValueEdit extends Component<DefaultPageProps> {
|
|
render() {
|
|
const baseMount = this.props.matches["baseMount"];
|
|
const secretPath = this.props.matches["secretPath"].split("/");
|
|
const item = this.props.matches["item"];
|
|
|
|
return (
|
|
<>
|
|
<SecretTitleElement
|
|
type="kv"
|
|
baseMount={baseMount}
|
|
secretPath={secretPath}
|
|
item={this.props.matches["item"]}
|
|
suffix={i18next.t("kv_sec_edit_suffix")}
|
|
/>
|
|
<KVEditor
|
|
settings={this.props.settings}
|
|
api={this.props.api}
|
|
baseMount={baseMount}
|
|
secretPath={secretPath}
|
|
secretItem={item}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
}
|