0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

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"> <div class="gh-stack">
{{#each @themeSettings as |setting index|}} <form>
{{#if (eq setting.type "select")}} {{#each @themeSettings as |setting index|}}
<div class="gh-stack-item gh-setting-first"> {{#if (eq setting.type "select")}}
<div class="flex-grow-1"> <CustomThemeSettings::Select @setting={{setting}} @index={{index}} />
<div class="gh-setting-title gh-theme-setting-title"> {{/if}}
{{humanize setting.key}} {{/each}}
</div> </form>
<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}}
</div> </div>

View file

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

View file

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

View file

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