mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Switched member unsaved changes modal to new modal pattern
refs https://github.com/TryGhost/Team/issues/1734 refs https://github.com/TryGhost/Team/issues/559 refs https://github.com/TryGhost/Ghost/issues/14101 - switches to newer modal patterns ready for later Ember upgrades
This commit is contained in:
parent
e17d24358e
commit
543c44415d
3 changed files with 44 additions and 60 deletions
|
@ -20,12 +20,9 @@ export default class MemberController extends Controller {
|
||||||
@tracked isLoading = false;
|
@tracked isLoading = false;
|
||||||
@tracked showDeleteMemberModal = false;
|
@tracked showDeleteMemberModal = false;
|
||||||
@tracked showImpersonateMemberModal = false;
|
@tracked showImpersonateMemberModal = false;
|
||||||
@tracked showUnsavedChangesModal = false;
|
|
||||||
@tracked modalLabel = null;
|
@tracked modalLabel = null;
|
||||||
@tracked showLabelModal = false;
|
@tracked showLabelModal = false;
|
||||||
|
|
||||||
leaveScreenTransition = null;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this._availableLabels = this.store.peekAll('label');
|
this._availableLabels = this.store.peekAll('label');
|
||||||
|
@ -135,37 +132,6 @@ export default class MemberController extends Controller {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
toggleUnsavedChangesModal(transition) {
|
|
||||||
let leaveTransition = this.leaveScreenTransition;
|
|
||||||
|
|
||||||
if (!transition && this.showUnsavedChangesModal) {
|
|
||||||
this.leaveScreenTransition = null;
|
|
||||||
this.showUnsavedChangesModal = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!leaveTransition || transition.targetName === leaveTransition.targetName) {
|
|
||||||
this.leaveScreenTransition = transition;
|
|
||||||
|
|
||||||
// if a save is running, wait for it to finish then transition
|
|
||||||
if (this.save.isRunning) {
|
|
||||||
return this.save.last.then(() => {
|
|
||||||
transition.retry();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// we genuinely have unsaved data, show the modal
|
|
||||||
this.showUnsavedChangesModal = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
leaveScreen() {
|
|
||||||
this.member.rollbackAttributes();
|
|
||||||
return this.leaveScreenTransition.retry();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tasks -------------------------------------------------------------------
|
// Tasks -------------------------------------------------------------------
|
||||||
|
|
||||||
@task({drop: true})
|
@task({drop: true})
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import AdminRoute from 'ghost-admin/routes/admin';
|
import AdminRoute from 'ghost-admin/routes/admin';
|
||||||
|
import ConfirmUnsavedChangesModal from '../components/modals/confirm-unsaved-changes';
|
||||||
import {action} from '@ember/object';
|
import {action} from '@ember/object';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
|
|
||||||
export default class MembersRoute extends AdminRoute {
|
export default class MembersRoute extends AdminRoute {
|
||||||
@service feature;
|
@service feature;
|
||||||
|
@service modals;
|
||||||
@service router;
|
@service router;
|
||||||
|
|
||||||
_requiresBackgroundRefresh = true;
|
_requiresBackgroundRefresh = true;
|
||||||
|
@ -11,7 +13,6 @@ export default class MembersRoute extends AdminRoute {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this.router.on('routeWillChange', (transition) => {
|
this.router.on('routeWillChange', (transition) => {
|
||||||
this.showUnsavedChangesModal(transition);
|
|
||||||
this.closeImpersonateModal(transition);
|
this.closeImpersonateModal(transition);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -36,10 +37,10 @@ export default class MembersRoute extends AdminRoute {
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
super.deactivate(...arguments);
|
|
||||||
// clean up newly created records and revert unsaved changes to existing
|
|
||||||
this.controller.member.rollbackAttributes();
|
|
||||||
this._requiresBackgroundRefresh = true;
|
this._requiresBackgroundRefresh = true;
|
||||||
|
|
||||||
|
this.confirmModal = null;
|
||||||
|
this.hasConfirmed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -47,27 +48,48 @@ export default class MembersRoute extends AdminRoute {
|
||||||
this.controller.save();
|
this.controller.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
titleToken() {
|
@action
|
||||||
return this.controller.member.name;
|
async willTransition(transition) {
|
||||||
}
|
if (this.hasConfirmed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
showUnsavedChangesModal(transition) {
|
transition.abort();
|
||||||
if (transition.from && transition.from.name === this.routeName && transition.targetName) {
|
|
||||||
let {controller} = this;
|
|
||||||
|
|
||||||
// member.changedAttributes is always true for new members but number of changed attrs is reliable
|
// wait for any existing confirm modal to be closed before allowing transition
|
||||||
let isChanged = Object.keys(controller.member.changedAttributes()).length > 0;
|
if (this.confirmModal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!controller.member.isDeleted && isChanged) {
|
if (this.controller.saveTask?.isRunning) {
|
||||||
transition.abort();
|
await this.controller.saveTask.last;
|
||||||
controller.toggleUnsavedChangesModal(transition);
|
}
|
||||||
return;
|
|
||||||
}
|
const shouldLeave = await this.confirmUnsavedChanges();
|
||||||
|
|
||||||
|
if (shouldLeave) {
|
||||||
|
this.controller.model.rollbackAttributes();
|
||||||
|
this.hasConfirmed = true;
|
||||||
|
return transition.retry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async confirmUnsavedChanges() {
|
||||||
|
if (this.controller.model?.hasDirtyAttributes) {
|
||||||
|
this.confirmModal = this.modals
|
||||||
|
.open(ConfirmUnsavedChangesModal)
|
||||||
|
.finally(() => {
|
||||||
|
this.confirmModal = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.confirmModal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
closeImpersonateModal(transition) {
|
closeImpersonateModal(transition) {
|
||||||
// If user navigates away with forward or back button, ensure returning to page
|
// If user navigates away with forward or back button, ensure returning to page
|
||||||
// hides modal
|
// hides modal
|
||||||
if (transition.from && transition.from.name === this.routeName && transition.targetName) {
|
if (transition.from && transition.from.name === this.routeName && transition.targetName) {
|
||||||
let {controller} = this;
|
let {controller} = this;
|
||||||
|
@ -75,4 +97,8 @@ export default class MembersRoute extends AdminRoute {
|
||||||
controller.closeImpersonateMemberModal(transition);
|
controller.closeImpersonateMemberModal(transition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
titleToken() {
|
||||||
|
return this.controller.member.name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,14 +68,6 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{#if this.showUnsavedChangesModal}}
|
|
||||||
<GhFullscreenModal
|
|
||||||
@modal="leave-settings"
|
|
||||||
@confirm={{this.leaveScreen}}
|
|
||||||
@close={{this.toggleUnsavedChangesModal}}
|
|
||||||
@modifier="action wide" />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.showDeleteMemberModal}}
|
{{#if this.showDeleteMemberModal}}
|
||||||
<GhFullscreenModal
|
<GhFullscreenModal
|
||||||
@modal="delete-member"
|
@modal="delete-member"
|
||||||
|
|
Loading…
Add table
Reference in a new issue