diff --git a/api.go b/api.go index 6507c6a..b1581d9 100644 --- a/api.go +++ b/api.go @@ -1097,15 +1097,12 @@ func (app *appContext) GetConfig(gc *gin.Context) { } } s := resp.Sections["ui"].Settings["language"] - s.Options = app.lang.langOptions - s.Value = app.lang.langOptions[app.lang.chosenIndex] - resp.Sections["ui"].Settings["language"] = s for sectName, section := range resp.Sections { for settingName, setting := range section.Settings { val := app.config.Section(sectName).Key(settingName) s := resp.Sections[sectName].Settings[settingName] switch setting.Type { - case "text", "email", "select": + case "text", "email", "select", "password": s.Value = val.MustString("") case "number": s.Value = val.MustInt(0) @@ -1115,6 +1112,9 @@ func (app *appContext) GetConfig(gc *gin.Context) { resp.Sections[sectName].Settings[settingName] = s } } + s.Options = app.lang.langOptions + s.Value = app.lang.langOptions[app.lang.chosenIndex] + resp.Sections["ui"].Settings["language"] = s gc.JSON(200, resp) } diff --git a/css/base.css b/css/base.css index f76e126..d997dd4 100644 --- a/css/base.css +++ b/css/base.css @@ -68,6 +68,10 @@ margin-left: 1rem; } +.ml-half { + margin-left: 0.5rem; +} + .mr-1 { margin-right: 1rem; } @@ -96,6 +100,10 @@ align-items: top; } +.flex { + display: flex; +} + .flex-expand { display: flex; justify-content: space-between; diff --git a/html/admin.html b/html/admin.html index 5c397b6..21a8040 100644 --- a/html/admin.html +++ b/html/admin.html @@ -101,17 +101,17 @@
${s.meta.description}
`; + this._section.innerHTML = ` + ${s.meta.name} +${s.meta.description}
+ `; this.update(s); - } update = (s: Section) => { for (let name of s.order) { @@ -378,24 +396,30 @@ class sectionPanel { } else { switch (setting.type) { case "text": - setting = new DOMText(setting, this._sectionName); + setting = new DOMText(setting, this._sectionName, name); break; case "password": - setting = new DOMPassword(setting, this._sectionName); + setting = new DOMPassword(setting, this._sectionName, name); break; case "email": - setting = new DOMEmail(setting, this._sectionName); + setting = new DOMEmail(setting, this._sectionName, name); break; case "number": - setting = new DOMNumber(setting, this._sectionName); + setting = new DOMNumber(setting, this._sectionName, name); break; case "bool": setting = new DOMBool(setting as SBool, this._sectionName, name); break; case "select": - setting = new DOMSelect(setting as SSelect, this._sectionName); + setting = new DOMSelect(setting as SSelect, this._sectionName, name); break; } + this.values[name] = ""+setting.value; + document.addEventListener(`settings-${this._sectionName}-${name}`, (event: CustomEvent) => { + const oldValue = this.values[name]; + this.values[name] = ""+event.detail; + document.dispatchEvent(new CustomEvent("settings-section-changed")); + }); this._section.appendChild(setting.asElement()); this._settings[name] = setting; } @@ -422,10 +446,15 @@ interface Settings { } export class settingsList { + private _saveButton = document.getElementById("settings-save") as HTMLSpanElement; + private _saveNoRestart = document.getElementById("settings-apply-no-restart") as HTMLSpanElement; + private _saveRestart = document.getElementById("settings-apply-restart") as HTMLSpanElement; + private _panel = document.getElementById("settings-panel") as HTMLDivElement; private _sidebar = document.getElementById("settings-sidebar") as HTMLDivElement; private _sections: { [name: string]: sectionPanel } private _buttons: { [name: string]: HTMLSpanElement } + private _needsRestart: boolean = false; addSection = (name: string, s: Section) => { const section = new sectionPanel(s, name); @@ -442,7 +471,6 @@ export class settingsList { private _showPanel = (name: string) => { for (let n in this._sections) { if (n == name) { - console.log("found", n); this._sections[name].visible = true; this._buttons[name].classList.add("selected"); } else { @@ -452,9 +480,53 @@ export class settingsList { } } + private _save = () => { + let config = {}; + for (let name in this._sections) { + config[name] = this._sections[name].values; + } + if (this._needsRestart) { + this._saveRestart.onclick = () => { + config["restart-program"] = true; + this._send(config, () => { + window.modals.settingsRestart.close(); + window.modals.settingsRefresh.show(); + }); + }; + this._saveNoRestart.onclick = () => { + config["restart-program"] = false; + this._send(config, window.modals.settingsRestart.close); + } + window.modals.settingsRestart.show(); + } else { + this._send(config); + } + // console.log(config); + } + + private _send = (config: Object, run?: () => void) => _post("/config", config, (req: XMLHttpRequest) => { + if (req.readyState == 4) { + if (req.status == 200 || req.status == 204) { + window.notifications.customPositive("settingsSaved", "Success:", "settings were saved."); + } else { + window.notifications.customError("settingsSaved", "Couldn't save settings."); + } + this.reload(); + if (run) { run(); } + } + }); + constructor() { this._sections = {}; this._buttons = {}; + document.addEventListener("settings-section-changed", () => this._saveButton.classList.remove("unfocused")); + this._saveButton.onclick = this._save; + document.addEventListener("settings-requires-restart", () => { this._needsRestart = true; }); + + if (window.ombiEnabled) { + let ombi = new ombiDefaults(); + this._sidebar.appendChild(ombi.button()); + } } reload = () => _get("/config", null, (req: XMLHttpRequest) => { @@ -471,8 +543,78 @@ export class settingsList { this.addSection(name, settings.sections[name]); } } + this._showPanel(settings.order[0]); + this._needsRestart = false; document.dispatchEvent(new CustomEvent("settings-loaded")); + this._saveButton.classList.add("unfocused"); } }) - } + +interface ombiUser { + id: string; + name: string; +} + +class ombiDefaults { + private _form: HTMLFormElement; + private _button: HTMLSpanElement; + private _select: HTMLSelectElement; + private _users: { [id: string]: string } = {}; + constructor() { + this._button = document.createElement("span") as HTMLSpanElement; + this._button.classList.add("button", "~neutral", "!low", "settings-section-button", "mb-half"); + this._button.innerHTML = `Ombi user defaults `; + this._button.onclick = this.load; + this._form = document.getElementById("form-ombi-defaults") as HTMLFormElement; + this._form.onsubmit = this.send; + this._select = this._form.querySelector("select") as HTMLSelectElement; + } + button = (): HTMLSpanElement => { return this._button; } + send = () => { + const button = this._form.querySelector("span.submit") as HTMLSpanElement; + toggleLoader(button); + let resp = {} as ombiUser; + resp.id = this._select.value; + resp.name = this._users[resp.id]; + _post("/ombi/defaults", resp, (req: XMLHttpRequest) => { + if (req.readyState == 4) { + toggleLoader(button); + if (req.status == 200 || req.status == 204) { + window.notifications.customPositive("ombiDefaults", "Success:", "stored ombi defaults."); + } else { + window.notifications.customError("ombiDefaults", "Failed to store ombi defaults."); + } + window.modals.ombiDefaults.close(); + } + }); + } + + load = () => { + toggleLoader(this._button); + _get("/ombi/users", null, (req: XMLHttpRequest) => { + if (req.readyState == 4) { + if (req.status == 200 && "users" in req.response) { + const users = req.response["users"] as ombiUser[]; + let innerHTML = ""; + for (let user of users) { + this._users[user.id] = user.name; + innerHTML += ``; + } + this._select.innerHTML = innerHTML; + toggleLoader(this._button); + window.modals.ombiDefaults.show(); + } else { + toggleLoader(this._button); + window.notifications.customError("ombiLoadError", "Failed to load ombi users.") + } + } + }); + } +} + + + + + +