mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Ensure hidden settings return falsy when used with the @custom
helper (#17920)
no refs When a theme setting is hidden, it should return a falsy value when used
This commit is contained in:
parent
212eacf4b9
commit
46897bdb3a
7 changed files with 105 additions and 31 deletions
|
@ -72,7 +72,7 @@ export default class DesignMenuComponent extends Component {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
handleThemeSettingChange() {
|
handleThemeSettingChange() {
|
||||||
this.customThemeSettings.rebuildSettingGroups();
|
this.customThemeSettings.updateSettingsVisibility();
|
||||||
this.themeManagement.updatePreviewHtmlTask.perform();
|
this.themeManagement.updatePreviewHtmlTask.perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
<div class="gh-stack">
|
<div class="gh-stack">
|
||||||
<form>
|
<form>
|
||||||
{{#each @themeSettings as |setting index|}}
|
{{#each @themeSettings as |setting index|}}
|
||||||
{{#if (eq setting.type "select")}}
|
{{#if setting.visible}}
|
||||||
<CustomThemeSettings::Select @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
{{#if (eq setting.type "select")}}
|
||||||
{{/if}}
|
<CustomThemeSettings::Select @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
||||||
{{#if (eq setting.type "boolean")}}
|
{{/if}}
|
||||||
<CustomThemeSettings::Boolean @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
{{#if (eq setting.type "boolean")}}
|
||||||
{{/if}}
|
<CustomThemeSettings::Boolean @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
||||||
{{#if (eq setting.type "color")}}
|
{{/if}}
|
||||||
<CustomThemeSettings::Color @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
{{#if (eq setting.type "color")}}
|
||||||
{{/if}}
|
<CustomThemeSettings::Color @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
||||||
{{#if (eq setting.type "text")}}
|
{{/if}}
|
||||||
<CustomThemeSettings::Text @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
{{#if (eq setting.type "text")}}
|
||||||
{{/if}}
|
<CustomThemeSettings::Text @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
||||||
{{#if (eq setting.type "image")}}
|
{{/if}}
|
||||||
<CustomThemeSettings::Image @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
{{#if (eq setting.type "image")}}
|
||||||
|
<CustomThemeSettings::Image @setting={{setting}} @index={{index}} @onChange={{@onChange}} />
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -8,5 +8,6 @@ export default Model.extend({
|
||||||
default: attr('string'),
|
default: attr('string'),
|
||||||
value: attr(),
|
value: attr(),
|
||||||
group: attr('string'),
|
group: attr('string'),
|
||||||
visibility: attr('string')
|
visibility: attr('string'),
|
||||||
|
visible: attr('boolean', {defaultValue: true})
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,8 @@ import {run} from '@ember/runloop';
|
||||||
import {task} from 'ember-concurrency';
|
import {task} from 'ember-concurrency';
|
||||||
import {tracked} from '@glimmer/tracking';
|
import {tracked} from '@glimmer/tracking';
|
||||||
|
|
||||||
|
const HIDDEN_SETTING_VALUE = null;
|
||||||
|
|
||||||
export default class CustomThemeSettingsServices extends Service {
|
export default class CustomThemeSettingsServices extends Service {
|
||||||
@service store;
|
@service store;
|
||||||
|
|
||||||
|
@ -34,7 +36,7 @@ export default class CustomThemeSettingsServices extends Service {
|
||||||
const keyValue = {};
|
const keyValue = {};
|
||||||
|
|
||||||
this.settings.forEach((setting) => {
|
this.settings.forEach((setting) => {
|
||||||
keyValue[setting.key] = setting.value;
|
keyValue[setting.key] = this._isSettingVisible(setting) ? setting.value : HIDDEN_SETTING_VALUE;
|
||||||
});
|
});
|
||||||
|
|
||||||
return keyValue;
|
return keyValue;
|
||||||
|
@ -64,6 +66,8 @@ export default class CustomThemeSettingsServices extends Service {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.settingGroups = this._buildSettingGroups(settings);
|
this.settingGroups = this._buildSettingGroups(settings);
|
||||||
|
|
||||||
|
this.updateSettingsVisibility();
|
||||||
|
|
||||||
this._hasLoaded = true;
|
this._hasLoaded = true;
|
||||||
|
|
||||||
return this.settings;
|
return this.settings;
|
||||||
|
@ -93,8 +97,10 @@ export default class CustomThemeSettingsServices extends Service {
|
||||||
this.settings.forEach(setting => setting.rollbackAttributes());
|
this.settings.forEach(setting => setting.rollbackAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildSettingGroups() {
|
updateSettingsVisibility() {
|
||||||
this.settingGroups = this._buildSettingGroups(this.settings);
|
this.settings.forEach((setting) => {
|
||||||
|
setting.visible = this._isSettingVisible(setting);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildSettingGroups(settings) {
|
_buildSettingGroups(settings) {
|
||||||
|
@ -116,15 +122,7 @@ export default class CustomThemeSettingsServices extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.KNOWN_GROUPS.forEach((knownGroup) => {
|
this.KNOWN_GROUPS.forEach((knownGroup) => {
|
||||||
const groupSettings = settings
|
const groupSettings = settings.filter(setting => setting.group === knownGroup.key);
|
||||||
.filter(setting => setting.group === knownGroup.key)
|
|
||||||
.filter((setting) => {
|
|
||||||
if (setting.visibility) {
|
|
||||||
return nql(setting.visibility).queryJSON(this.keyValueObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (groupSettings.length) {
|
if (groupSettings.length) {
|
||||||
groups.push(Object.assign({}, knownGroup, {settings: groupSettings}));
|
groups.push(Object.assign({}, knownGroup, {settings: groupSettings}));
|
||||||
|
@ -133,4 +131,14 @@ export default class CustomThemeSettingsServices extends Service {
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isSettingVisible(setting) {
|
||||||
|
if (!setting.visibility) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsMap = this.settings.reduce((map, {key, value}) => ({...map, [key]: value}), {});
|
||||||
|
|
||||||
|
return nql(setting.visibility).queryJSON(settingsMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const BREAD = require('./CustomThemeSettingsBREADService');
|
const BREAD = require('./CustomThemeSettingsBREADService');
|
||||||
|
const nql = require('@tryghost/nql');
|
||||||
const tpl = require('@tryghost/tpl');
|
const tpl = require('@tryghost/tpl');
|
||||||
const {ValidationError} = require('@tryghost/errors');
|
const {ValidationError} = require('@tryghost/errors');
|
||||||
const debug = require('@tryghost/debug')('custom-theme-settings-service');
|
const debug = require('@tryghost/debug')('custom-theme-settings-service');
|
||||||
|
@ -10,6 +11,8 @@ const messages = {
|
||||||
invalidValueForSetting: 'Invalid value for \'{key}\'. The value must follow this format: {format}.'
|
invalidValueForSetting: 'Invalid value for \'{key}\'. The value must follow this format: {format}.'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const HIDDEN_SETTING_VALUE = null;
|
||||||
|
|
||||||
module.exports = class CustomThemeSettingsService {
|
module.exports = class CustomThemeSettingsService {
|
||||||
/**
|
/**
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
|
@ -150,11 +153,15 @@ module.exports = class CustomThemeSettingsService {
|
||||||
this._activeThemeSettings[setting.key].value = setting.value;
|
this._activeThemeSettings[setting.key].value = setting.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settingsObjects = this.listSettings();
|
||||||
|
|
||||||
// update the public cache
|
// update the public cache
|
||||||
this._valueCache.populate(this.listSettings());
|
this._valueCache.populate(
|
||||||
|
this._computeCachedSettings(settingsObjects)
|
||||||
|
);
|
||||||
|
|
||||||
// return full setting objects
|
// return full setting objects
|
||||||
return this.listSettings();
|
return settingsObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private -----------------------------------------------------------------
|
// Private -----------------------------------------------------------------
|
||||||
|
@ -233,7 +240,9 @@ module.exports = class CustomThemeSettingsService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._valueCache.populate(settings);
|
this._valueCache.populate(
|
||||||
|
this._computeCachedSettings(settings)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,4 +273,26 @@ module.exports = class CustomThemeSettingsService {
|
||||||
|
|
||||||
this._activeThemeSettings = activeThemeSettings;
|
this._activeThemeSettings = activeThemeSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the settings to cache, taking into account visibility rules
|
||||||
|
*
|
||||||
|
* @param {Object[]} settings - list of setting objects
|
||||||
|
* @returns {Object[]} - list of setting objects with visibility rules applied
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_computeCachedSettings(settings) {
|
||||||
|
const settingsMap = settings.reduce((map, {key, value}) => ({...map, [key]: value}), {});
|
||||||
|
|
||||||
|
return settings.map((setting) => {
|
||||||
|
return {
|
||||||
|
...setting,
|
||||||
|
// If a setting is not visible, set the value to HIDDEN_SETTING_VALUE so that it is not exposed in the cache
|
||||||
|
// (meaning it also won't be exposed in the theme when rendering)
|
||||||
|
value: setting.visibility && nql(setting.visibility).queryJSON(settingsMap) === false
|
||||||
|
? HIDDEN_SETTING_VALUE
|
||||||
|
: setting.value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tryghost/debug": "0.1.24",
|
"@tryghost/debug": "0.1.24",
|
||||||
"@tryghost/errors": "1.2.24",
|
"@tryghost/errors": "1.2.24",
|
||||||
|
"@tryghost/nql": "0.11.0",
|
||||||
"@tryghost/tpl": "0.1.24",
|
"@tryghost/tpl": "0.1.24",
|
||||||
"lodash": "4.17.21"
|
"lodash": "4.17.21"
|
||||||
}
|
}
|
||||||
|
|
|
@ -875,5 +875,36 @@ describe('Service', function () {
|
||||||
}]
|
}]
|
||||||
).should.be.resolved();
|
).should.be.resolved();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not expose hidden settings in the public cache', async function () {
|
||||||
|
const HIDDEN_SETTING_VALUE = null;
|
||||||
|
|
||||||
|
const settingName = 'foo';
|
||||||
|
const settingDefinition = {
|
||||||
|
type: 'select',
|
||||||
|
options: ['Foo', 'Bar', 'Baz'],
|
||||||
|
default: 'Foo',
|
||||||
|
visibility: 'some_other_setting:bar'
|
||||||
|
};
|
||||||
|
|
||||||
|
await service.activateTheme('test', {
|
||||||
|
name: 'test',
|
||||||
|
customSettings: {
|
||||||
|
[settingName]: settingDefinition
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await service.updateSettings(
|
||||||
|
[{
|
||||||
|
key: settingName,
|
||||||
|
value: 'Foo',
|
||||||
|
...settingDefinition
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
cache.getAll().should.deepEqual({
|
||||||
|
[settingName]: HIDDEN_SETTING_VALUE
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue