Wired up saving of custom theme settings

refs https://github.com/TryGhost/Team/issues/1070

- split select form component into it's own component so it's cleaner when we get to additional setting types
  - added change handler that updates the setting record's value when a new option is selected
- added `.isDirty` to the custom-theme-settings service so we can warn of unsaved changes and revert any changed values when needed
- added save of custom theme settings to the customize design modal's save routine
- added missing `notifications` service import to customize design controller
This commit is contained in:
Kevin Ansfield 2021-09-28 16:12:01 +01:00
parent 1e8e0485e3
commit d10e102de4
6 changed files with 58 additions and 24 deletions

View File

@ -0,0 +1,16 @@
<div class="gh-stack-item {{if (eq @index 0) "gh-setting-first"}}">
<div class="flex-grow-1">
<label class="gh-setting-title gh-theme-setting-title" for={{this.selectId}}>
{{humanize @setting.key}}
</label>
<select class="ember-select" name={{this.selectName}} id={{this.selectId}} {{on "change" this.setSelection}}>
{{#each @setting.options as |settingOption|}}
<option value={{settingOption}} selected={{eq settingOption @setting.value}}>
{{settingOption}}
{{#if (eq settingOption setting.default)}}(default){{/if}}
</option>
{{/each}}
</select>
</div>
</div>

View File

@ -0,0 +1,15 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {camelize} from '@ember/string';
import {guidFor} from '@ember/object/internals';
export default class CustomThemeSettingsSelectComponent extends Component {
selectId = `select-${guidFor(this)}`;
selectName = camelize(this.args.setting.key);
@action
setSelection(changeEvent) {
const value = changeEvent.target.value;
this.args.setting.set('value', value);
}
}

View File

@ -1,22 +1,9 @@
<div class="gh-stack">
{{#each @themeSettings as |setting index|}}
{{#if (eq setting.type "select")}}
<div class="gh-stack-item gh-setting-first">
<div class="flex-grow-1">
<div class="gh-setting-title gh-theme-setting-title">
{{humanize setting.key}}
</div>
<select class="ember-select">
{{#each setting.options as |settingOption|}}
<option value={{option}} selected={{eq settingOption setting.value}}>
{{settingOption}}
{{#if (eq settingOption setting.default)}}(default){{/if}}
</option>
{{/each}}
</select>
</div>
</div>
{{/if}}
{{/each}}
<form>
{{#each @themeSettings as |setting index|}}
{{#if (eq setting.type "select")}}
<CustomThemeSettings::Select @setting={{setting}} @index={{index}} />
{{/if}}
{{/each}}
</form>
</div>

View File

@ -3,8 +3,10 @@ import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency-decorators';
export default class SettingsDesignCustomizeController extends Controller {
@service settings;
@service customThemeSettings;
@service notifications;
@service router;
@service settings;
@task
*saveTask() {
@ -12,8 +14,15 @@ export default class SettingsDesignCustomizeController extends Controller {
if (this.settings.get('errors').length !== 0) {
return;
}
yield this.settings.save();
yield Promise.all(
this.settings.save(),
this.customThemeSettings.save()
);
this.router.transitionTo('settings.design');
// ensure task button switches to success state
return true;
} catch (error) {
if (error) {

View File

@ -4,6 +4,7 @@ import {bind} from '@ember/runloop';
import {inject as service} from '@ember/service';
export default class SettingsDesignCustomizeRoute extends AuthenticatedRoute {
@service customThemeSettings;
@service feature;
@service modals;
@service settings;
@ -35,7 +36,7 @@ export default class SettingsDesignCustomizeRoute extends AuthenticatedRoute {
@action
async willTransition(transition) {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.get('hasDirtyAttributes') || this.customThemeSettings.isDirty) {
transition.abort();
const shouldLeave = await this.confirmUnsavedChanges();
@ -73,7 +74,7 @@ export default class SettingsDesignCustomizeRoute extends AuthenticatedRoute {
}
confirmUnsavedChanges() {
if (!this.settings.get('hasDirtyAttributes')) {
if (!this.settings.get('hasDirtyAttributes') && !this.customThemeSettings.isDirty) {
return Promise.resolve(true);
}
@ -83,6 +84,7 @@ export default class SettingsDesignCustomizeRoute extends AuthenticatedRoute {
}).then((discardChanges) => {
if (discardChanges === true) {
this.settings.rollbackAttributes();
this.customThemeSettings.rollback();
}
return discardChanges;
}).finally(() => {

View File

@ -9,6 +9,11 @@ export default class CustomThemeSettingsServices extends Service {
@tracked settings = [];
get isDirty() {
const dirtySetting = this.settings.find(setting => setting.hasDirtyAttributes);
return !!dirtySetting;
}
load() {
return this.loadTask.perform();
}