Ghost/ghost/admin/app/services/custom-theme-settings.js
Kevin Ansfield 505ae7493e Optimized loading of custom theme setting in design screens
no issue

We want to automatically show brand settings expanded in the design menu when the active theme has no custom theme settings, in order to do that without causing visual noise/jank we need to ensure that we have all the data we need up-front before the design menu is rendered.

- optimized `customThemeSettings` loading behaviour
  - `.load()` will now only perform a fetch if settings have not previously been loaded so it can be called without causing unnecessary waits
  - `.reload()` will force a clear+refetch of the settings - called by `themeManagement.activate()` after successfully changing a theme
- moved fetching of theme settings from the design menu constructor to the `settings.design` route's `model()` hook
  - means the app will wait for loading to finish before showing any of the design settings screen so we can guarantee the data we need is available
- moved update of preview html from the design menu constructor to the design settings route as it's a more appropriate place to find screen setup/loading behaviour
2021-10-22 10:49:13 +01:00

125 lines
3.2 KiB
JavaScript

import Service from '@ember/service';
import {isEmpty} from '@ember/utils';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency-decorators';
import {tracked} from '@glimmer/tracking';
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] = 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._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());
}
_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;
}
}