mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 15:25:35 +08:00
DEV: Open theme settings objects editor from admin customize theme page (#26006)
Why this change? The `/admin/customize/themes/:id/schema/name` route is a work in progress but we want to be able to start navigating to it from the `/admin/customize/themes/:id` route. What does this change do? 1. Move `adminCustomizeThemes.schema` to a child route of `adminCustomizeThemes.show`. This is because we need the model from the parent route and if it isn't a child route we end up having to load the theme model again from the server. 1. Add the `objects_schema` attribute to `ThemeSettingsSerializer` 1. Refactor `SiteSettingComponent` to be able to render a button so that we don't have to hardcode the button rendering into the `SiteSettings::String` component
This commit is contained in:
parent
81ede05005
commit
94b09f3331
|
@ -25,16 +25,25 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{component
|
{{#if this.settingEditButton}}
|
||||||
this.componentName
|
<DButton
|
||||||
setting=this.setting
|
@action={{this.settingEditButton.action}}
|
||||||
value=this.buffered.value
|
@icon={{this.settingEditButton.icon}}
|
||||||
validationMessage=this.validationMessage
|
@label={{this.settingEditButton.label}}
|
||||||
preview=this.preview
|
class="setting-value-edit-button"
|
||||||
isSecret=this.isSecret
|
/>
|
||||||
allowAny=this.allowAny
|
{{else}}
|
||||||
changeValueCallback=this.changeValueCallback
|
{{component
|
||||||
}}
|
this.componentName
|
||||||
|
setting=this.setting
|
||||||
|
value=this.buffered.value
|
||||||
|
validationMessage=this.validationMessage
|
||||||
|
preview=this.preview
|
||||||
|
isSecret=this.isSecret
|
||||||
|
allowAny=this.allowAny
|
||||||
|
changeValueCallback=this.changeValueCallback
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if this.dirty}}
|
{{#if this.dirty}}
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
{{#if this.setting.textarea}}
|
{{#if this.setting.textarea}}
|
||||||
<Textarea @value={{this.value}} class="input-setting-textarea" />
|
<Textarea @value={{this.value}} class="input-setting-textarea" />
|
||||||
{{else if this.setting.json_schema}}
|
|
||||||
<DButton
|
|
||||||
@action={{fn (mut this.showJsonEditorModal) true}}
|
|
||||||
@icon="pencil-alt"
|
|
||||||
@label="admin.site_settings.json_schema.edit"
|
|
||||||
/>
|
|
||||||
{{else if this.isSecret}}
|
{{else if this.isSecret}}
|
||||||
<Input @type="password" @value={{this.value}} class="input-setting-string" />
|
<Input @type="password" @value={{this.value}} class="input-setting-string" />
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -13,14 +7,4 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<SettingValidationMessage @message={{this.validationMessage}} />
|
<SettingValidationMessage @message={{this.validationMessage}} />
|
||||||
<div class="desc">{{html-safe this.setting.description}}</div>
|
<div class="desc">{{html-safe this.setting.description}}</div>
|
||||||
|
|
||||||
{{#if this.showJsonEditorModal}}
|
|
||||||
<Modal::JsonSchemaEditor
|
|
||||||
@updateValue={{fn (mut this.value)}}
|
|
||||||
@value={{this.value}}
|
|
||||||
@settingName={{this.setting.setting}}
|
|
||||||
@jsonSchema={{this.setting.json_schema}}
|
|
||||||
@closeModal={{fn (mut this.showJsonEditorModal) false}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
|
@ -1,98 +0,0 @@
|
||||||
import Controller from "@ember/controller";
|
|
||||||
|
|
||||||
export default class AdminCustomizeThemesSchemaController extends Controller {
|
|
||||||
data = [
|
|
||||||
{
|
|
||||||
name: "item 1",
|
|
||||||
width: 143,
|
|
||||||
is_valid: true,
|
|
||||||
enum_prop: 11,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: "child 1-1",
|
|
||||||
grandchildren: [
|
|
||||||
{
|
|
||||||
name: "grandchild 1-1-1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "child 1-2",
|
|
||||||
grandchildren: [
|
|
||||||
{
|
|
||||||
name: "grandchild 1-2-1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "item 2",
|
|
||||||
width: 803,
|
|
||||||
is_valid: false,
|
|
||||||
enum_prop: 22,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: "child 2-1",
|
|
||||||
grandchildren: [
|
|
||||||
{
|
|
||||||
name: "grandchild 2-1-1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "child 2-2",
|
|
||||||
grandchildren: [
|
|
||||||
{
|
|
||||||
name: "grandchild 2-2-1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
schema = {
|
|
||||||
name: "item",
|
|
||||||
identifier: "name",
|
|
||||||
properties: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: "integer",
|
|
||||||
},
|
|
||||||
is_valid: {
|
|
||||||
type: "boolean",
|
|
||||||
},
|
|
||||||
enum_prop: {
|
|
||||||
type: "enum",
|
|
||||||
choices: [11, 22],
|
|
||||||
},
|
|
||||||
children: {
|
|
||||||
type: "objects",
|
|
||||||
schema: {
|
|
||||||
name: "child",
|
|
||||||
identifier: "name",
|
|
||||||
properties: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
grandchildren: {
|
|
||||||
type: "objects",
|
|
||||||
schema: {
|
|
||||||
name: "grandchild",
|
|
||||||
identifier: "name",
|
|
||||||
properties: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@ import Mixin from "@ember/object/mixin";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
import { isNone } from "@ember/utils";
|
import { isNone } from "@ember/utils";
|
||||||
|
import JsonSchemaEditorModal from "discourse/components/modal/json-schema-editor";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { fmt, propertyNotEqual } from "discourse/lib/computed";
|
import { fmt, propertyNotEqual } from "discourse/lib/computed";
|
||||||
import { splitString } from "discourse/lib/utilities";
|
import { splitString } from "discourse/lib/utilities";
|
||||||
|
@ -78,6 +79,7 @@ const DEFAULT_USER_PREFERENCES = [
|
||||||
|
|
||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
modal: service(),
|
modal: service(),
|
||||||
|
router: service(),
|
||||||
site: service(),
|
site: service(),
|
||||||
attributeBindings: ["setting.setting:data-setting"],
|
attributeBindings: ["setting.setting:data-setting"],
|
||||||
classNameBindings: [":row", ":setting", "overridden", "typeClass"],
|
classNameBindings: [":row", ":setting", "overridden", "typeClass"],
|
||||||
|
@ -168,6 +170,39 @@ export default Mixin.create({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("setting")
|
||||||
|
settingEditButton(setting) {
|
||||||
|
if (setting.json_schema) {
|
||||||
|
return {
|
||||||
|
action: () => {
|
||||||
|
this.modal.show(JsonSchemaEditorModal, {
|
||||||
|
model: {
|
||||||
|
updateValue: (value) => {
|
||||||
|
this.buffered.set("value", value);
|
||||||
|
},
|
||||||
|
value: this.buffered.get("value"),
|
||||||
|
settingName: setting.setting,
|
||||||
|
jsonSchema: setting.json_schema,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
label: "admin.site_settings.json_schema.edit",
|
||||||
|
icon: "pencil-alt",
|
||||||
|
};
|
||||||
|
} else if (setting.objects_schema) {
|
||||||
|
return {
|
||||||
|
action: () => {
|
||||||
|
this.router.transitionTo(
|
||||||
|
"adminCustomizeThemes.show.schema",
|
||||||
|
setting.setting
|
||||||
|
);
|
||||||
|
},
|
||||||
|
label: "admin.customize.theme.edit_objects_theme_setting",
|
||||||
|
icon: "pencil-alt",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async update() {
|
async update() {
|
||||||
const key = this.buffered.get("setting");
|
const key = this.buffered.get("setting");
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import Route from "@ember/routing/route";
|
|
||||||
|
|
||||||
export default class AdminCustomizeThemesSchemaRoute extends Route {
|
|
||||||
setupController() {
|
|
||||||
super.setupController(...arguments);
|
|
||||||
this.controllerFor("adminCustomizeThemes").set("editingTheme", true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Route from "@ember/routing/route";
|
||||||
|
|
||||||
|
export default class AdminCustomizeThemesShowSchemaRoute extends Route {
|
||||||
|
model(params) {
|
||||||
|
const theme = this.modelFor("adminCustomizeThemesShow");
|
||||||
|
const setting = theme.settings.findBy("setting", params.setting_name);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: setting.value,
|
||||||
|
schema: setting.objects_schema,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setupController() {
|
||||||
|
super.setupController(...arguments);
|
||||||
|
this.controllerFor("adminCustomizeThemes").set("editingTheme", true);
|
||||||
|
|
||||||
|
this.controllerFor("adminCustomizeThemes.show").set(
|
||||||
|
"editingThemeSetting",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate() {
|
||||||
|
this.controllerFor("adminCustomizeThemes").set("editingTheme", false);
|
||||||
|
|
||||||
|
this.controllerFor("adminCustomizeThemes.show").set(
|
||||||
|
"editingThemeSetting",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,7 @@ export default class AdminCustomizeThemesShowRoute extends Route {
|
||||||
colorSchemeId: model.get("color_scheme_id"),
|
colorSchemeId: model.get("color_scheme_id"),
|
||||||
colorSchemes: parentController.get("model.extras.color_schemes"),
|
colorSchemes: parentController.get("model.extras.color_schemes"),
|
||||||
editingName: false,
|
editingName: false,
|
||||||
|
editingThemeSetting: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.handleHighlight(model);
|
this.handleHighlight(model);
|
||||||
|
|
|
@ -57,9 +57,10 @@ export default function () {
|
||||||
"adminCustomizeThemes",
|
"adminCustomizeThemes",
|
||||||
{ path: "themes", resetNamespace: true },
|
{ path: "themes", resetNamespace: true },
|
||||||
function () {
|
function () {
|
||||||
this.route("show", { path: "/:theme_id" });
|
this.route("show", { path: "/:theme_id" }, function () {
|
||||||
|
this.route("schema", { path: "schema/:setting_name" });
|
||||||
|
});
|
||||||
this.route("edit", { path: "/:theme_id/:target/:field_name/edit" });
|
this.route("edit", { path: "/:theme_id/:target/:field_name/edit" });
|
||||||
this.route("schema", { path: "/:theme_id/schema/:setting_name" });
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<SchemaThemeSetting::Editor @schema={{this.schema}} @data={{this.data}} />
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<SchemaThemeSetting::Editor
|
||||||
|
@schema={{this.model.schema}}
|
||||||
|
@data={{this.model.data}}
|
||||||
|
/>
|
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@
|
||||||
@closeModal={{@closeModal}}
|
@closeModal={{@closeModal}}
|
||||||
@title={{i18n
|
@title={{i18n
|
||||||
"admin.site_settings.json_schema.modal_title"
|
"admin.site_settings.json_schema.modal_title"
|
||||||
name=@settingName
|
name=@model.settingName
|
||||||
}}
|
}}
|
||||||
class="json-schema-editor-modal"
|
class="json-schema-editor-modal"
|
||||||
>
|
>
|
||||||
|
|
|
@ -8,12 +8,12 @@ import { afterRender } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default class JsonSchemaEditorModal extends Component {
|
export default class JsonSchemaEditorModal extends Component {
|
||||||
@tracked editor = null;
|
@tracked editor = null;
|
||||||
@tracked value = this.args.value;
|
@tracked value = this.args.model.value;
|
||||||
@tracked flash;
|
@tracked flash;
|
||||||
@tracked flashType;
|
@tracked flashType;
|
||||||
|
|
||||||
get settingName() {
|
get settingName() {
|
||||||
return this.args.settingName.replace(/\_/g, " ");
|
return this.args.model.settingName.replace(/\_/g, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -34,7 +34,7 @@ export default class JsonSchemaEditorModal extends Component {
|
||||||
|
|
||||||
if (!errors.length) {
|
if (!errors.length) {
|
||||||
this.value = JSON.stringify(this.editor.getValue());
|
this.value = JSON.stringify(this.editor.getValue());
|
||||||
this.args.updateValue(this.value);
|
this.args.model.updateValue(this.value);
|
||||||
this.args.closeModal();
|
this.args.closeModal();
|
||||||
} else {
|
} else {
|
||||||
this.flash = errors.mapBy("message").join("\n");
|
this.flash = errors.mapBy("message").join("\n");
|
||||||
|
@ -53,7 +53,7 @@ export default class JsonSchemaEditorModal extends Component {
|
||||||
JSONEditor.defaults.options.iconlib = "discourseIcons";
|
JSONEditor.defaults.options.iconlib = "discourseIcons";
|
||||||
|
|
||||||
this.editor = new JSONEditor(editor, {
|
this.editor = new JSONEditor(editor, {
|
||||||
schema: this.args.jsonSchema,
|
schema: this.args.model.jsonSchema,
|
||||||
disable_array_delete_all_rows: true,
|
disable_array_delete_all_rows: true,
|
||||||
disable_array_delete_last_row: true,
|
disable_array_delete_last_row: true,
|
||||||
disable_array_reorder: false,
|
disable_array_reorder: false,
|
||||||
|
|
|
@ -9,7 +9,8 @@ class ThemeSettingsSerializer < ApplicationSerializer
|
||||||
:valid_values,
|
:valid_values,
|
||||||
:list_type,
|
:list_type,
|
||||||
:textarea,
|
:textarea,
|
||||||
:json_schema
|
:json_schema,
|
||||||
|
:objects_schema
|
||||||
|
|
||||||
def setting
|
def setting
|
||||||
object.name
|
object.name
|
||||||
|
@ -65,6 +66,14 @@ class ThemeSettingsSerializer < ApplicationSerializer
|
||||||
object.type == ThemeSetting.types[:string]
|
object.type == ThemeSetting.types[:string]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def objects_schema
|
||||||
|
object.schema
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_objects_schema?
|
||||||
|
object.type == ThemeSetting.types[:objects]
|
||||||
|
end
|
||||||
|
|
||||||
def json_schema
|
def json_schema
|
||||||
object.json_schema
|
object.json_schema
|
||||||
end
|
end
|
||||||
|
|
|
@ -5485,6 +5485,7 @@ en:
|
||||||
has_overwritten_history: "Current theme version no longer exists because the Git history has been overwritten by a force push."
|
has_overwritten_history: "Current theme version no longer exists because the Git history has been overwritten by a force push."
|
||||||
add: "Add"
|
add: "Add"
|
||||||
theme_settings: "Theme Settings"
|
theme_settings: "Theme Settings"
|
||||||
|
edit_objects_theme_setting: "Objects Setting Editor"
|
||||||
overriden_settings_explanation: "Overridden settings are marked with a dot and have a highlighted color. To reset these settings to the default value, press the reset button next to them."
|
overriden_settings_explanation: "Overridden settings are marked with a dot and have a highlighted color. To reset these settings to the default value, press the reset button next to them."
|
||||||
no_settings: "This theme has no settings."
|
no_settings: "This theme has no settings."
|
||||||
theme_translations: "Theme Translations"
|
theme_translations: "Theme Translations"
|
||||||
|
|
|
@ -14,4 +14,8 @@ class ThemeSettingsManager::Objects < ThemeSettingsManager
|
||||||
theme.reload
|
theme.reload
|
||||||
record.json_value
|
record.json_value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def schema
|
||||||
|
@opts[:schema]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
22
spec/serializers/theme_settings_serializer_spec.rb
Normal file
22
spec/serializers/theme_settings_serializer_spec.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe ThemeSettingsSerializer do
|
||||||
|
fab!(:theme)
|
||||||
|
|
||||||
|
describe "#objects_schema" do
|
||||||
|
let(:objects_setting) do
|
||||||
|
yaml = File.read("#{Rails.root}/spec/fixtures/theme_settings/objects_settings.yaml")
|
||||||
|
theme.set_field(target: :settings, name: "yaml", value: yaml)
|
||||||
|
theme.save!
|
||||||
|
theme.settings[:objects_setting]
|
||||||
|
end
|
||||||
|
|
||||||
|
before { SiteSetting.experimental_objects_type_for_theme_settings = true }
|
||||||
|
|
||||||
|
it "should include the attribute when theme setting is typed objects" do
|
||||||
|
payload = ThemeSettingsSerializer.new(objects_setting).as_json
|
||||||
|
|
||||||
|
expect(payload[:theme_settings][:objects_schema][:name]).to eq("sections")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,12 +5,13 @@ describe "Admin Customize Themes", type: :system do
|
||||||
fab!(:theme)
|
fab!(:theme)
|
||||||
fab!(:admin)
|
fab!(:admin)
|
||||||
|
|
||||||
|
let(:admin_customize_themes_page) { PageObjects::Pages::AdminCustomizeThemes.new }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
|
||||||
describe "when visiting the page to customize themes" do
|
describe "when visiting the page to customize themes" do
|
||||||
fab!(:theme_2) { Fabricate(:theme) }
|
fab!(:theme_2) { Fabricate(:theme) }
|
||||||
fab!(:theme_3) { Fabricate(:theme) }
|
fab!(:theme_3) { Fabricate(:theme) }
|
||||||
let(:admin_customize_themes_page) { PageObjects::Pages::AdminCustomizeThemes.new }
|
|
||||||
let(:delete_themes_confirm_modal) { PageObjects::Modals::DeleteThemesConfirm.new }
|
let(:delete_themes_confirm_modal) { PageObjects::Modals::DeleteThemesConfirm.new }
|
||||||
|
|
||||||
it "should allow admin to bulk delete inactive themes" do
|
it "should allow admin to bulk delete inactive themes" do
|
||||||
|
@ -84,4 +85,32 @@ describe "Admin Customize Themes", type: :system do
|
||||||
expect(ace_content.text).to eq("console.log('test')")
|
expect(ace_content.text).to eq("console.log('test')")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "when editing a theme setting of objects type" do
|
||||||
|
let(:objects_setting) do
|
||||||
|
theme.set_field(
|
||||||
|
target: :settings,
|
||||||
|
name: "yaml",
|
||||||
|
value: File.read("#{Rails.root}/spec/fixtures/theme_settings/objects_settings.yaml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
theme.save!
|
||||||
|
theme.settings[:objects_setting]
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.experimental_objects_type_for_theme_settings = true
|
||||||
|
objects_setting
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow admin to edit the theme setting of objecst type" do
|
||||||
|
visit("/admin/customize/themes/#{theme.id}")
|
||||||
|
|
||||||
|
admin_customize_themes_page.click_edit_objects_theme_setting_button("objects_setting")
|
||||||
|
|
||||||
|
expect(page).to have_current_path(
|
||||||
|
"/admin/customize/themes/#{theme.id}/schema/objects_setting",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,6 +38,10 @@ module PageObjects
|
||||||
def click_delete_themes_button
|
def click_delete_themes_button
|
||||||
find(".btn-delete").click
|
find(".btn-delete").click
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def click_edit_objects_theme_setting_button(setting_name)
|
||||||
|
find(".theme-setting[data-setting=\"#{setting_name}\"] .setting-value-edit-button").click
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user