diff --git a/package.json b/package.json
index 19586cb..d16df9d 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,6 @@
"@babel/plugin-transform-runtime": "^7.16.8",
"@babel/preset-env": "^7.16.8",
"@types/file-saver": "^2.0.5",
- "@types/hjson": "^2.4.3",
"@types/js-yaml": "^4.0.5",
"@types/prismjs": "^1.16.6",
"@types/uikit": "^3.3.2",
@@ -41,7 +40,6 @@
"core-js": "^3.20.3",
"date-fns": "^2.28.0",
"file-saver": "^2.0.5",
- "hjson": "^3.2.2",
"i18next": "^21.6.6",
"js-yaml": "^4.1.0",
"json5": "^2.2.0",
diff --git a/src/pages.tsx b/src/pages.tsx
index 6738d58..f279cce 100644
--- a/src/pages.tsx
+++ b/src/pages.tsx
@@ -29,6 +29,7 @@ import { PolicyView } from "./ui/pages/Policies/PolicyView";
import { Secrets } from "./ui/pages/Secrets/SecretsHome";
import { SetLanguage } from "./ui/pages/SetLanguage";
import { SetVaultURL } from "./ui/pages/SetVaultURL";
+import { Settings } from "./ui/pages/Settings/Settings";
import { TOTPDelete } from "./ui/pages/Secrets/TOTP/TOTPDelete";
import { TOTPList } from "./ui/pages/Secrets/TOTP/TOTPList";
import { TOTPNew } from "./ui/pages/Secrets/TOTP/TOTPNew";
@@ -59,6 +60,7 @@ export const Main = () => (
+
diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts
index 37f3e09..138ad21 100644
--- a/src/settings/Settings.ts
+++ b/src/settings/Settings.ts
@@ -64,4 +64,24 @@ export class Settings {
this.storage.setItem("theme", value);
this.alertChange("theme");
}
+
+ get kvEditorDefaultLanguage(): string {
+ return this.storage.getItem("kvEditorDefaultLanguage") || "yaml";
+ }
+
+ set kvEditorDefaultLanguage(value: string) {
+ this.storage.setItem("kvEditorDefaultLanguage", value);
+ this.alertChange("kvEditorDefaultLanguage");
+ }
+
+ get kvEditorIndent(): number {
+ const value = this.storage.getItem("kvEditorIndent");
+ if (value) return parseInt(value);
+ return 2;
+ }
+
+ set kvEditorIndent(value: number) {
+ this.storage.setItem("kvEditorIndent", String(value));
+ this.alertChange("kvEditorIndent");
+ }
}
diff --git a/src/translations/en.js b/src/translations/en.js
index e4aafbc..4a139db 100644
--- a/src/translations/en.js
+++ b/src/translations/en.js
@@ -35,9 +35,9 @@ module.exports = {
not_implemented: "Not Yet Implemented",
// Copyable Modal
- copy_box_download_btn: "Download",
- copy_box_copy_btn: "Copy",
- copy_box_close_btn: "Close",
+ copy_modal_download_btn: "Download",
+ copy_modal_copy_btn: "Copy",
+ copy_modal_close_btn: "Close",
// Generic Loading Text
content_loading: "Loading..",
@@ -54,8 +54,7 @@ module.exports = {
me_seal_vault_btn: "Seal Vault",
me_copy_token_btn: "Copy Token",
me_renew_lease_btn: "Renew Token Lease",
- me_change_language_btn: "Change Language",
- me_set_vault_url_btn: "Set Vault URL",
+ me_settings_btn: "Settings",
// Home Page
home_page_title: "Home",
@@ -69,6 +68,23 @@ module.exports = {
home_policies_title: "Policies",
home_policies_description: "Manage policies and permissions.",
+ // Settings Page
+ settings_title: "Settings",
+
+ // General Settings
+ settings_general_title: "General",
+ settings_general_theme: "Theme",
+ settings_general_vault_url: "Vault API URL",
+ settings_general_language: "Language",
+ settings_general_page_direction: "Page Direction",
+ settings_general_page_direction_ltr: "Left to Right",
+ settings_general_page_direction_rtl: "Right to Left",
+
+ // Key/Value Editor Settings
+ settings_kveditor_title: "Key/Value Editor",
+ settings_kveditor_default_language: "Default Data Interchange Format",
+ settings_kveditor_default_indent: "Default Indent",
+
// Set Vault URL Page
set_vault_url_title: "Set Vault URL",
set_vault_url_placeholder: "Vault URL",
diff --git a/src/ui/pages/Me.tsx b/src/ui/pages/Me.tsx
index 28ffa94..8e125e3 100644
--- a/src/ui/pages/Me.tsx
+++ b/src/ui/pages/Me.tsx
@@ -1,6 +1,6 @@
+import { Button } from "../elements/Button";
import { Component, JSX, createRef } from "preact";
import { DefaultPageProps } from "../../types/DefaultPageProps";
-import { InputWithTitle } from "../elements/InputWithTitle";
import { PageTitle } from "../elements/PageTitle";
import { addClipboardNotifications, setErrorText } from "../../pageUtils";
import { route } from "preact-router";
@@ -103,30 +103,10 @@ export class Me extends Component {
)}
-
- {i18next.t("me_change_language_btn")}
-
-
- {i18next.t("me_set_vault_url_btn")}
-
-
-
-
+
+
+
>
)
diff --git a/src/ui/pages/Secrets/KeyValue/KeyValueEdit.tsx b/src/ui/pages/Secrets/KeyValue/KeyValueEdit.tsx
index 52a8a5e..cfb9613 100644
--- a/src/ui/pages/Secrets/KeyValue/KeyValueEdit.tsx
+++ b/src/ui/pages/Secrets/KeyValue/KeyValueEdit.tsx
@@ -6,38 +6,31 @@ import { InputWithTitle } from "../../../elements/InputWithTitle";
import { SecretTitleElement } from "../SecretTitleElement";
import { setErrorText } from "../../../../pageUtils";
import { sortedObjectMap } from "../../../../utils";
-import Hjson from "hjson";
import JSON5 from "json5";
import i18next from "i18next";
import yaml from "js-yaml";
-// todo: put this in settings
-const defaultIndent = 2;
-const defaultSyntax = "json";
+export const SupportedEditorLanguages = [
+ { name: "json", readable: "JSON" },
+ { name: "json5", readable: "JSON5" },
+ { name: "yaml", readable: "YAML" },
+];
function parseData(data: string, syntax = "json"): Record {
if (syntax == "json") {
return JSON.parse(data) as Record;
} else if (syntax == "json5") {
return JSON5.parse(data);
- } else if (syntax == "hjson") {
- return Hjson.parse(data) as Record;
} else if (syntax == "yaml") {
return yaml.load(data) as Record;
}
}
-function dumpData(
- data: Record,
- space: number = defaultIndent,
- syntax = "json",
-): string {
+function dumpData(data: Record, space = 4, syntax = "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 });
}
@@ -77,7 +70,7 @@ export class KVEditor extends Component {
super();
this.state = {
dataLoaded: false,
- syntax: defaultSyntax,
+ syntax: "",
};
}
@@ -119,13 +112,18 @@ export class KVEditor extends Component {
}
async componentDidMount() {
+ this.setState({ syntax: this.props.settings.kvEditorDefaultLanguage });
if (!this.state.dataLoaded) {
await this.loadData();
}
}
getStringKVData(data: Record): string {
- return dumpData(Object.fromEntries(sortedObjectMap(data)), defaultIndent, this.state.syntax);
+ return dumpData(
+ Object.fromEntries(sortedObjectMap(data)),
+ this.props.settings.kvEditorIndent,
+ this.state.syntax,
+ );
}
syntaxSelectRef = createRef();
@@ -141,8 +139,6 @@ export class KVEditor extends Component {
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";
}
@@ -157,16 +153,21 @@ export class KVEditor extends Component {
this.setState({ syntax: this.syntaxSelectRef.current.value });
}}
>
-
-
-
-
+ {SupportedEditorLanguages.map((lang) => {
+ return (
+
+ );
+ })}
this.onCodeUpdate(code)}
/>
diff --git a/src/ui/pages/Secrets/KeyValue/KeyValueList.tsx b/src/ui/pages/Secrets/KeyValue/KeyValueList.tsx
index 0f5116d..8cdadde 100644
--- a/src/ui/pages/Secrets/KeyValue/KeyValueList.tsx
+++ b/src/ui/pages/Secrets/KeyValue/KeyValueList.tsx
@@ -25,12 +25,7 @@ function SecretsList(baseMount: string, secretPath: string[], secrets: string[])
{
if (secret.endsWith("/")) {
- route(
- kvListURL(
- baseMount,
- [...secretPath, secret.replace("/", "")]
- ),
- );
+ route(kvListURL(baseMount, [...secretPath, secret.replace("/", "")]));
} else {
route(kvViewURL(baseMount, secretPath, secret));
}
diff --git a/src/ui/pages/Secrets/KeyValue/KeyValueNew.tsx b/src/ui/pages/Secrets/KeyValue/KeyValueNew.tsx
index dbd1858..23b8069 100644
--- a/src/ui/pages/Secrets/KeyValue/KeyValueNew.tsx
+++ b/src/ui/pages/Secrets/KeyValue/KeyValueNew.tsx
@@ -56,7 +56,7 @@ export class KeyValueNew extends Component {
const mountInfo = await this.props.api.getMount(baseMount);
if (mountInfo.options.version == "1") {
// Can't have a empty secret on KV V1
- keyData = { "placeholder_on_kv1": "placeholder_on_kv1" };
+ keyData = { placeholder_on_kv1: "placeholder_on_kv1" };
}
try {
diff --git a/src/ui/pages/Secrets/TOTP/TOTPList.tsx b/src/ui/pages/Secrets/TOTP/TOTPList.tsx
index ca2c7d8..1ea60c1 100644
--- a/src/ui/pages/Secrets/TOTP/TOTPList.tsx
+++ b/src/ui/pages/Secrets/TOTP/TOTPList.tsx
@@ -71,7 +71,7 @@ export class RefreshingTOTPGridItem extends Component {
try {
const totpKeys = await api.getTOTPKeys(baseMount);
- let totpKeyPermissions = await Promise.all(Array.from(totpKeys.map(async (key) => {
- const totpCaps = await api.getCapsPath(removeDoubleSlash(baseMount + "/code/" + key));
- return {key: key, caps: totpCaps};
- })));
+ const totpKeyPermissions = await Promise.all(
+ Array.from(
+ totpKeys.map(async (key) => {
+ const totpCaps = await api.getCapsPath(removeDoubleSlash(baseMount + "/code/" + key));
+ return { key: key, caps: totpCaps };
+ }),
+ ),
+ );
- totpItems = Array.from(totpKeyPermissions.map((keyData) => {
- // Filter out all non-readable totp keys.
- if (!keyData.caps.includes("read")) return;
- return {
- totpKey: keyData.key,
- canDelete: keyData.caps.includes("delete"),
- };
- }));
+ totpItems = Array.from(
+ totpKeyPermissions.map((keyData) => {
+ // Filter out all non-readable totp keys.
+ if (!keyData.caps.includes("read")) return;
+ return {
+ totpKey: keyData.key,
+ canDelete: keyData.caps.includes("delete"),
+ };
+ }),
+ );
} catch (e: unknown) {
const error = e as Error;
if (error != DoesNotExistError) {
@@ -166,11 +172,7 @@ export class TOTPList extends Component {
} else {
return this.state.totpItems.map((totpItem) => {
return (
-
+
);
});
}
diff --git a/src/ui/pages/SetLanguage.tsx b/src/ui/pages/SetLanguage.tsx
index a831249..773cfc4 100644
--- a/src/ui/pages/SetLanguage.tsx
+++ b/src/ui/pages/SetLanguage.tsx
@@ -9,10 +9,8 @@ import { Form } from "../elements/Form";
import { Margin } from "../elements/Margin";
import { MarginInline } from "../elements/MarginInline";
import { PageTitle } from "../elements/PageTitle";
-import i18next from "i18next";
import { route } from "preact-router";
-
-const languageIDs = Object.getOwnPropertyNames(translations);
+import i18next from "i18next";
export class SetLanguage extends Component {
constructor() {
@@ -25,8 +23,8 @@ export class SetLanguage extends Component {