2024-02-16 01:31:49 -05:00
|
|
|
import Component from "@glimmer/component";
|
2024-02-26 17:07:32 -05:00
|
|
|
import { cached, tracked } from "@glimmer/tracking";
|
2024-02-16 01:31:49 -05:00
|
|
|
import { fn } from "@ember/helper";
|
|
|
|
import { on } from "@ember/modifier";
|
|
|
|
import { action } from "@ember/object";
|
2024-03-12 18:52:46 -04:00
|
|
|
import { LinkTo } from "@ember/routing";
|
|
|
|
import { service } from "@ember/service";
|
2024-03-17 22:03:30 -04:00
|
|
|
import { gt } from "truth-helpers";
|
2024-02-20 05:43:18 -05:00
|
|
|
import DButton from "discourse/components/d-button";
|
2024-03-12 18:52:46 -04:00
|
|
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
2024-03-17 22:03:30 -04:00
|
|
|
import dIcon from "discourse-common/helpers/d-icon";
|
2024-03-12 18:52:46 -04:00
|
|
|
import i18n from "discourse-common/helpers/i18n";
|
|
|
|
import { cloneJSON } from "discourse-common/lib/object";
|
2024-02-20 05:43:18 -05:00
|
|
|
import I18n from "discourse-i18n";
|
2024-02-26 17:07:32 -05:00
|
|
|
import FieldInput from "./field";
|
2024-02-16 01:31:49 -05:00
|
|
|
|
|
|
|
class Node {
|
2024-02-26 17:07:32 -05:00
|
|
|
@tracked text;
|
|
|
|
object;
|
|
|
|
schema;
|
|
|
|
index;
|
2024-02-16 01:31:49 -05:00
|
|
|
active = false;
|
2024-03-14 19:47:42 -04:00
|
|
|
parentTree;
|
2024-02-16 01:31:49 -05:00
|
|
|
trees = [];
|
|
|
|
|
2024-03-14 19:47:42 -04:00
|
|
|
constructor({ text, index, object, schema, parentTree }) {
|
2024-02-16 01:31:49 -05:00
|
|
|
this.text = text;
|
|
|
|
this.index = index;
|
2024-02-26 17:07:32 -05:00
|
|
|
this.object = object;
|
|
|
|
this.schema = schema;
|
2024-03-14 19:47:42 -04:00
|
|
|
this.parentTree = parentTree;
|
2024-02-16 01:31:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Tree {
|
|
|
|
propertyName = null;
|
|
|
|
nodes = [];
|
|
|
|
}
|
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
export default class SchemaThemeSettingEditor extends Component {
|
2024-03-12 18:52:46 -04:00
|
|
|
@service router;
|
2024-02-16 01:31:49 -05:00
|
|
|
@tracked activeIndex = 0;
|
2024-02-20 05:43:18 -05:00
|
|
|
@tracked backButtonText;
|
2024-03-12 18:52:46 -04:00
|
|
|
@tracked saveButtonDisabled = false;
|
|
|
|
|
|
|
|
data = cloneJSON(this.args.setting.value);
|
2024-02-16 01:31:49 -05:00
|
|
|
history = [];
|
2024-03-12 18:52:46 -04:00
|
|
|
schema = this.args.setting.objects_schema;
|
2024-02-16 01:31:49 -05:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
@cached
|
2024-02-16 01:31:49 -05:00
|
|
|
get tree() {
|
2024-03-12 18:52:46 -04:00
|
|
|
let schema = this.schema;
|
|
|
|
let data = this.data;
|
2024-03-14 19:47:42 -04:00
|
|
|
let tree = new Tree();
|
2024-02-16 01:31:49 -05:00
|
|
|
|
|
|
|
for (const point of this.history) {
|
2024-03-14 19:47:42 -04:00
|
|
|
tree.propertyName = point.propertyName;
|
2024-02-20 05:43:18 -05:00
|
|
|
data = data[point.node.index][point.propertyName];
|
|
|
|
schema = schema.properties[point.propertyName].schema;
|
2024-02-16 01:31:49 -05:00
|
|
|
}
|
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
data.forEach((object, index) => {
|
|
|
|
const node = new Node({
|
|
|
|
index,
|
|
|
|
schema,
|
|
|
|
object,
|
2024-03-14 19:47:42 -04:00
|
|
|
text: object[schema.identifier] || `${schema.name} ${index + 1}`,
|
|
|
|
parentTree: tree,
|
2024-02-26 17:07:32 -05:00
|
|
|
});
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
if (index === this.activeIndex) {
|
|
|
|
node.active = true;
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
const childObjectsProperties = this.findChildObjectsProperties(
|
|
|
|
schema.properties
|
|
|
|
);
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
for (const childObjectsProperty of childObjectsProperties) {
|
|
|
|
const subtree = new Tree();
|
|
|
|
subtree.propertyName = childObjectsProperty.name;
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-03-17 22:03:30 -04:00
|
|
|
data[index][childObjectsProperty.name]?.forEach(
|
2024-02-16 01:31:49 -05:00
|
|
|
(childObj, childIndex) => {
|
|
|
|
subtree.nodes.push(
|
|
|
|
new Node({
|
2024-03-14 19:47:42 -04:00
|
|
|
text:
|
|
|
|
childObj[childObjectsProperty.schema.identifier] ||
|
|
|
|
`${childObjectsProperty.schema.name} ${childIndex + 1}`,
|
2024-02-16 01:31:49 -05:00
|
|
|
index: childIndex,
|
2024-02-26 17:07:32 -05:00
|
|
|
object: childObj,
|
|
|
|
schema: childObjectsProperty.schema,
|
2024-03-14 19:47:42 -04:00
|
|
|
parentTree: subtree,
|
2024-02-16 01:31:49 -05:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
node.trees.push(subtree);
|
|
|
|
}
|
|
|
|
}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
tree.nodes.push(node);
|
|
|
|
});
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
@cached
|
|
|
|
get activeNode() {
|
|
|
|
return this.tree.nodes.find((node, index) => {
|
|
|
|
return index === this.activeIndex;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
get fields() {
|
|
|
|
const node = this.activeNode;
|
|
|
|
const list = [];
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
for (const [name, spec] of Object.entries(node.schema.properties)) {
|
|
|
|
if (spec.type === "objects") {
|
|
|
|
continue;
|
|
|
|
}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
list.push({
|
|
|
|
name,
|
2024-02-29 03:11:32 -05:00
|
|
|
spec,
|
2024-02-26 17:07:32 -05:00
|
|
|
value: node.object[name],
|
2024-03-14 19:47:42 -04:00
|
|
|
description: this.fieldDescription(name),
|
2024-02-26 17:07:32 -05:00
|
|
|
});
|
|
|
|
}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
findChildObjectsProperties(properties) {
|
|
|
|
const list = [];
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
for (const [name, spec] of Object.entries(properties)) {
|
|
|
|
if (spec.type === "objects") {
|
|
|
|
list.push({
|
|
|
|
name,
|
2024-02-26 17:07:32 -05:00
|
|
|
schema: spec.schema,
|
2024-02-16 01:31:49 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-03-12 18:52:46 -04:00
|
|
|
@action
|
|
|
|
saveChanges() {
|
|
|
|
this.saveButtonDisabled = true;
|
|
|
|
|
|
|
|
this.args.setting
|
|
|
|
.updateSetting(this.args.themeId, this.data)
|
|
|
|
.then((result) => {
|
|
|
|
this.args.setting.set("value", result[this.args.setting.setting]);
|
|
|
|
|
|
|
|
this.router.transitionTo(
|
|
|
|
"adminCustomizeThemes.show",
|
|
|
|
this.args.themeId
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.catch(popupAjaxError)
|
|
|
|
.finally(() => (this.saveButtonDisabled = false));
|
|
|
|
}
|
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
@action
|
|
|
|
onClick(node) {
|
|
|
|
this.activeIndex = node.index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2024-02-20 05:43:18 -05:00
|
|
|
onChildClick(node, tree, parentNode) {
|
|
|
|
this.history.push({
|
|
|
|
propertyName: tree.propertyName,
|
|
|
|
node: parentNode,
|
|
|
|
});
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-20 05:43:18 -05:00
|
|
|
this.backButtonText = I18n.t("admin.customize.theme.schema.back_button", {
|
|
|
|
name: parentNode.text,
|
|
|
|
});
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
this.activeIndex = node.index;
|
|
|
|
}
|
|
|
|
|
2024-02-20 05:43:18 -05:00
|
|
|
@action
|
|
|
|
backButtonClick() {
|
|
|
|
const historyPoint = this.history.pop();
|
|
|
|
this.activeIndex = historyPoint.node.index;
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-20 05:43:18 -05:00
|
|
|
if (this.history.length > 0) {
|
|
|
|
this.backButtonText = I18n.t("admin.customize.theme.schema.back_button", {
|
|
|
|
name: this.history[this.history.length - 1].node.text,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.backButtonText = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
@action
|
|
|
|
inputFieldChanged(field, newVal) {
|
|
|
|
if (field.name === this.activeNode.schema.identifier) {
|
|
|
|
this.activeNode.text = newVal;
|
|
|
|
}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-02-26 17:07:32 -05:00
|
|
|
this.activeNode.object[field.name] = newVal;
|
|
|
|
}
|
|
|
|
|
2024-03-14 19:47:42 -04:00
|
|
|
fieldDescription(fieldName) {
|
|
|
|
const descriptions = this.args.setting.objects_schema_property_descriptions;
|
|
|
|
|
|
|
|
if (!descriptions) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let key;
|
|
|
|
|
|
|
|
if (this.activeNode.parentTree.propertyName) {
|
|
|
|
key = `${this.activeNode.parentTree.propertyName}.${fieldName}`;
|
|
|
|
} else {
|
|
|
|
key = `${fieldName}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return descriptions[key];
|
|
|
|
}
|
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
<template>
|
2024-03-17 22:03:30 -04:00
|
|
|
<div class="schema-theme-setting-editor">
|
|
|
|
<div class="schema-theme-setting-editor__navigation">
|
|
|
|
<ul class="schema-theme-setting-editor__tree">
|
|
|
|
{{#if this.backButtonText}}
|
|
|
|
<li
|
|
|
|
role="link"
|
|
|
|
class="schema-theme-setting-editor__tree-node--back-btn"
|
|
|
|
{{on "click" this.backButtonClick}}
|
|
|
|
>
|
|
|
|
<div class="schema-theme-setting-editor__tree-node-text">
|
|
|
|
{{dIcon "chevron-left"}}
|
|
|
|
{{this.backButtonText}}
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
{{/if}}
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-03-17 22:03:30 -04:00
|
|
|
{{#each this.tree.nodes as |node|}}
|
2024-02-16 01:31:49 -05:00
|
|
|
<li
|
|
|
|
role="link"
|
2024-03-17 22:03:30 -04:00
|
|
|
class="schema-theme-setting-editor__tree-node --parent
|
|
|
|
{{if node.active ' --active'}}"
|
2024-02-16 01:31:49 -05:00
|
|
|
{{on "click" (fn this.onClick node)}}
|
|
|
|
>
|
2024-03-17 22:03:30 -04:00
|
|
|
<div class="schema-theme-setting-editor__tree-node-text">
|
|
|
|
{{node.text}}
|
|
|
|
|
|
|
|
{{#if (gt node.trees.length 0)}}
|
|
|
|
{{dIcon (if node.active "chevron-down" "chevron-right")}}
|
|
|
|
{{/if}}
|
|
|
|
</div>
|
2024-02-16 01:31:49 -05:00
|
|
|
</li>
|
2024-03-17 22:03:30 -04:00
|
|
|
|
2024-02-16 01:31:49 -05:00
|
|
|
{{#each node.trees as |nestedTree|}}
|
2024-03-17 22:03:30 -04:00
|
|
|
{{#if (gt nestedTree.nodes.length 0)}}
|
|
|
|
<li
|
|
|
|
class="schema-theme-setting-editor__tree-node --child --heading"
|
|
|
|
data-test-parent-index={{node.index}}
|
|
|
|
>
|
|
|
|
<div class="schema-theme-setting-editor__tree-node-text">
|
|
|
|
{{nestedTree.propertyName}}
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
{{/if}}
|
|
|
|
|
|
|
|
{{#each nestedTree.nodes as |childNode|}}
|
|
|
|
<li
|
|
|
|
role="link"
|
|
|
|
class="schema-theme-setting-editor__tree-node --child"
|
|
|
|
{{on
|
|
|
|
"click"
|
|
|
|
(fn this.onChildClick childNode nestedTree node)
|
|
|
|
}}
|
|
|
|
data-test-parent-index={{node.index}}
|
|
|
|
>
|
|
|
|
<div class="schema-theme-setting-editor__tree-node-text">
|
|
|
|
{{childNode.text}}
|
|
|
|
{{dIcon "chevron-right"}}
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
{{/each}}
|
2024-02-16 01:31:49 -05:00
|
|
|
{{/each}}
|
2024-03-17 22:03:30 -04:00
|
|
|
{{/each}}
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="schema-theme-setting-editor__fields">
|
|
|
|
{{#each this.fields as |field|}}
|
|
|
|
<FieldInput
|
|
|
|
@name={{field.name}}
|
|
|
|
@value={{field.value}}
|
|
|
|
@spec={{field.spec}}
|
|
|
|
@onValueChange={{fn this.inputFieldChanged field}}
|
|
|
|
@description={{field.description}}
|
|
|
|
/>
|
2024-02-16 01:31:49 -05:00
|
|
|
{{/each}}
|
2024-03-17 22:03:30 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="schema-theme-setting-editor__footer">
|
|
|
|
<DButton
|
|
|
|
@disabled={{this.saveButtonDisabled}}
|
|
|
|
@action={{this.saveChanges}}
|
|
|
|
@label="save"
|
|
|
|
class="btn-primary"
|
2024-02-26 17:07:32 -05:00
|
|
|
/>
|
2024-03-12 18:52:46 -04:00
|
|
|
|
2024-03-17 22:03:30 -04:00
|
|
|
<LinkTo
|
|
|
|
@route="adminCustomizeThemes.show"
|
|
|
|
@model={{@themeId}}
|
|
|
|
class="btn-transparent"
|
|
|
|
>
|
|
|
|
{{i18n "cancel"}}
|
|
|
|
</LinkTo>
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-02-16 01:31:49 -05:00
|
|
|
</template>
|
|
|
|
}
|