497f3b40dd
refs https://github.com/TryGhost/Product/issues/3924 Settings were being marked as dirty when visibility was changed causing the confirm dialog to show when navigating away from the settings page. This change manually computes the dirtiness of the setting to ensure the visibility change is ignored
155 lines
4.2 KiB
JavaScript
155 lines
4.2 KiB
JavaScript
import Service, {inject as service} from '@ember/service';
|
|
import nql from '@tryghost/nql';
|
|
import {isEmpty} from '@ember/utils';
|
|
import {run} from '@ember/runloop';
|
|
import {task} from 'ember-concurrency';
|
|
import {tracked} from '@glimmer/tracking';
|
|
|
|
const HIDDEN_SETTING_VALUE = null;
|
|
|
|
export default class CustomThemeSettingsServices extends Service {
|
|
@service store;
|
|
|
|
@tracked settings = [];
|
|
@tracked settingGroups = [];
|
|
|
|
_hasLoaded = false;
|
|
|
|
KNOWN_GROUPS = [{
|
|
key: 'homepage',
|
|
name: 'Homepage',
|
|
icon: 'house',
|
|
previewType: 'homepage'
|
|
}, {
|
|
key: 'post',
|
|
name: 'Post',
|
|
icon: 'post',
|
|
previewType: 'post'
|
|
}];
|
|
|
|
get isDirty() {
|
|
const dirtySetting = this.settings.find(setting => setting.hasDirtyAttributes);
|
|
return !!dirtySetting;
|
|
}
|
|
|
|
get keyValueObject() {
|
|
const keyValue = {};
|
|
|
|
this.settings.forEach((setting) => {
|
|
keyValue[setting.key] = this._isSettingVisible(setting) ? setting.value : HIDDEN_SETTING_VALUE;
|
|
});
|
|
|
|
return keyValue;
|
|
}
|
|
|
|
load() {
|
|
return this.loadTask.perform();
|
|
}
|
|
|
|
reload() {
|
|
this._hasLoaded = false;
|
|
|
|
return this.loadTask.perform();
|
|
}
|
|
|
|
@task
|
|
*loadTask() {
|
|
if (this.hasLoaded) {
|
|
return this.settings;
|
|
}
|
|
|
|
// unload stored settings and re-load from API so they always match active theme
|
|
// run is required here, see https://github.com/emberjs/data/issues/5447#issuecomment-845672812
|
|
run(() => this.store.unloadAll('custom-theme-setting'));
|
|
|
|
const settings = yield this.store.findAll('custom-theme-setting');
|
|
this.settings = settings;
|
|
this.settingGroups = this._buildSettingGroups(settings);
|
|
|
|
this.updateSettingsVisibility();
|
|
|
|
this._hasLoaded = true;
|
|
|
|
return this.settings;
|
|
}
|
|
|
|
save() {
|
|
return this.saveTask.perform();
|
|
}
|
|
|
|
@task
|
|
*saveTask() {
|
|
if (isEmpty(this.settings)) {
|
|
return this.settings;
|
|
}
|
|
|
|
// save all records in a single request to `/custom_theme_settings`
|
|
const listRecord = this.store.createRecord('custom-theme-setting-list', {customThemeSettings: this.settings});
|
|
yield listRecord.save();
|
|
|
|
// don't keep references to lists and their children around
|
|
this.store.unloadRecord(listRecord);
|
|
|
|
return this.settings;
|
|
}
|
|
|
|
rollback() {
|
|
this.settings.forEach(setting => setting.rollbackAttributes());
|
|
}
|
|
|
|
updateSettingsVisibility() {
|
|
this.settings.forEach((setting) => {
|
|
setting.visible = this._isSettingVisible(setting);
|
|
|
|
// Updating the setting visibility will cause the setting to be marked as dirty so
|
|
// we need to compute whether the setting is actually dirty and set the flag manually
|
|
const changedProperties = Object.keys(setting.changedAttributes()).filter(key => key !== 'visible');
|
|
|
|
setting.hasDirtyAttributes = false;
|
|
|
|
if (changedProperties.length > 0) {
|
|
setting.hasDirtyAttributes = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
_buildSettingGroups(settings) {
|
|
if (!settings || !settings.length) {
|
|
return [];
|
|
}
|
|
|
|
const groupKeys = this.KNOWN_GROUPS.map(g => g.key);
|
|
const groups = [];
|
|
|
|
const siteWideSettings = settings.filter(setting => !groupKeys.includes(setting.group));
|
|
if (siteWideSettings.length) {
|
|
groups.push({
|
|
key: 'site-wide',
|
|
name: 'Site-wide',
|
|
icon: 'view-site',
|
|
settings: siteWideSettings
|
|
});
|
|
}
|
|
|
|
this.KNOWN_GROUPS.forEach((knownGroup) => {
|
|
const groupSettings = settings.filter(setting => setting.group === knownGroup.key);
|
|
|
|
if (groupSettings.length) {
|
|
groups.push(Object.assign({}, knownGroup, {settings: groupSettings}));
|
|
}
|
|
});
|
|
|
|
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);
|
|
}
|
|
}
|