mirror of
https://github.com/TryGhost/Ghost-Admin.git
synced 2023-12-14 02:33:04 +01:00
Updated members routes/controllers with Octane idioms
no issue - ran [`ember-native-class-codemod`](https://github.com/ember-codemods/ember-native-class-codemod) on members-related files - updated files to remove need for `@classic` decorator where possible - switched to tracked properties - removed usage of `this.get/set/toggleProperty` etc - swapped usage of `{{action 'foo'}}` for `{{this.foo}}`
This commit is contained in:
parent
9250d7939b
commit
e80fa137db
14 changed files with 289 additions and 242 deletions
|
@ -16,6 +16,10 @@ module.exports = {
|
|||
'plugin:ghost/ember'
|
||||
],
|
||||
rules: {
|
||||
// octane 🏎
|
||||
'ghost/ember/classic-decorator-hooks': 'error',
|
||||
'ghost/ember/classic-decorator-no-classic-methods': 'error',
|
||||
|
||||
// disable linting of `this.get` until there's a reliable autofix
|
||||
'ghost/ember/use-ember-get-and-set': 'off',
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* global key */
|
||||
import Component from '@ember/component';
|
||||
import Ember from 'ember';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import fallbackIfUndefined from '../utils/computed-fallback-if-undefined';
|
||||
import {A, isArray} from '@ember/array';
|
||||
import {action, computed, get} from '@ember/object';
|
||||
|
@ -19,6 +20,7 @@ const {Handlebars} = Ember;
|
|||
const BACKSPACE = 8;
|
||||
const TAB = 9;
|
||||
|
||||
@classic
|
||||
@tagName('')
|
||||
class GhTokenInput extends Component {
|
||||
// public attrs
|
||||
|
|
|
@ -50,7 +50,7 @@ export default class Trigger extends EmberPowerSelectMultipleTrigger {
|
|||
if (typeof lastSelection === 'string') {
|
||||
this.args.select.actions.search(lastSelection);
|
||||
} else {
|
||||
let searchField = this.get('searchField');
|
||||
let searchField = this.searchField;
|
||||
assert('`{{power-select-multiple}}` requires a `searchField` when the options are not strings to remove options using backspace', searchField);
|
||||
this.args.select.actions.search(get(lastSelection, searchField));
|
||||
}
|
||||
|
|
|
@ -1,95 +1,111 @@
|
|||
import Controller from '@ember/controller';
|
||||
import EmberObject from '@ember/object';
|
||||
import Controller, {inject as controller} from '@ember/controller';
|
||||
import EmberObject, {action, defineProperty} from '@ember/object';
|
||||
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
||||
import moment from 'moment';
|
||||
import {alias} from '@ember/object/computed';
|
||||
import {computed, defineProperty} from '@ember/object';
|
||||
import {inject as controller} from '@ember/controller';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
const SCRATCH_PROPS = ['name', 'email', 'note'];
|
||||
|
||||
export default Controller.extend({
|
||||
members: controller(),
|
||||
session: service(),
|
||||
dropdown: service(),
|
||||
notifications: service(),
|
||||
router: service(),
|
||||
store: service(),
|
||||
export default class MemberController extends Controller {
|
||||
@controller members;
|
||||
@service session;
|
||||
@service dropdown;
|
||||
@service notifications;
|
||||
@service router;
|
||||
@service store;
|
||||
|
||||
showImpersonateMemberModal: false,
|
||||
@tracked isLoading = false;
|
||||
@tracked showDeleteMemberModal = false;
|
||||
@tracked showImpersonateMemberModal = false;
|
||||
@tracked showUnsavedChangesModal = false;
|
||||
|
||||
member: alias('model'),
|
||||
leaveScreenTransition = null;
|
||||
|
||||
scratchMember: computed('member', function () {
|
||||
// Computed properties -----------------------------------------------------
|
||||
|
||||
@alias('model') member;
|
||||
|
||||
get scratchMember() {
|
||||
let scratchMember = EmberObject.create({member: this.member});
|
||||
SCRATCH_PROPS.forEach(prop => defineProperty(scratchMember, prop, boundOneWay(`member.${prop}`)));
|
||||
return scratchMember;
|
||||
}),
|
||||
}
|
||||
|
||||
subscribedAt: computed('member.createdAtUTC', function () {
|
||||
get subscribedAt() {
|
||||
let memberSince = moment(this.member.createdAtUTC).from(moment());
|
||||
let createdDate = moment(this.member.createdAtUTC).format('MMM DD, YYYY');
|
||||
return `${createdDate} (${memberSince})`;
|
||||
}),
|
||||
}
|
||||
|
||||
actions: {
|
||||
setProperty(propKey, value) {
|
||||
this._saveMemberProperty(propKey, value);
|
||||
},
|
||||
// Actions -----------------------------------------------------------------
|
||||
|
||||
toggleDeleteMemberModal() {
|
||||
this.toggleProperty('showDeleteMemberModal');
|
||||
},
|
||||
@action
|
||||
setProperty(propKey, value) {
|
||||
this._saveMemberProperty(propKey, value);
|
||||
}
|
||||
|
||||
toggleImpersonateMemberModal() {
|
||||
this.toggleProperty('showImpersonateMemberModal');
|
||||
},
|
||||
@action
|
||||
toggleDeleteMemberModal() {
|
||||
this.showDeleteMemberModal = !this.showDeleteMemberModal;
|
||||
}
|
||||
|
||||
save() {
|
||||
return this.save.perform();
|
||||
},
|
||||
@action
|
||||
toggleImpersonateMemberModal() {
|
||||
this.showImpersonateMemberModal = !this.showImpersonateMemberModal;
|
||||
}
|
||||
|
||||
deleteMember() {
|
||||
return this.member.destroyRecord().then(() => {
|
||||
return this.transitionToRoute('members');
|
||||
}, (error) => {
|
||||
return this.notifications.showAPIError(error, {key: 'member.delete'});
|
||||
});
|
||||
},
|
||||
@action
|
||||
save() {
|
||||
return this.saveTask.perform();
|
||||
}
|
||||
|
||||
toggleUnsavedChangesModal(transition) {
|
||||
let leaveTransition = this.leaveScreenTransition;
|
||||
@action
|
||||
deleteMember() {
|
||||
return this.member.destroyRecord().then(() => {
|
||||
return this.transitionToRoute('members');
|
||||
}, (error) => {
|
||||
return this.notifications.showAPIError(error, {key: 'member.delete'});
|
||||
});
|
||||
}
|
||||
|
||||
if (!transition && this.showUnsavedChangesModal) {
|
||||
this.set('leaveScreenTransition', null);
|
||||
this.set('showUnsavedChangesModal', false);
|
||||
return;
|
||||
}
|
||||
@action
|
||||
toggleUnsavedChangesModal(transition) {
|
||||
let leaveTransition = this.leaveScreenTransition;
|
||||
|
||||
if (!leaveTransition || transition.targetName === leaveTransition.targetName) {
|
||||
this.set('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.set('showUnsavedChangesModal', true);
|
||||
}
|
||||
},
|
||||
|
||||
leaveScreen() {
|
||||
this.member.rollbackAttributes();
|
||||
return this.leaveScreenTransition.retry();
|
||||
if (!transition && this.showUnsavedChangesModal) {
|
||||
this.leaveScreenTransition = null;
|
||||
this.showUnsavedChangesModal = false;
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
save: task(function* () {
|
||||
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 -------------------------------------------------------------------
|
||||
|
||||
@task({drop: true})
|
||||
*saveTask() {
|
||||
let {member, scratchMember} = this;
|
||||
|
||||
// if Cmd+S is pressed before the field loses focus make sure we're
|
||||
|
@ -109,18 +125,20 @@ export default Controller.extend({
|
|||
this.notifications.showAPIError(error, {key: 'member.save'});
|
||||
}
|
||||
}
|
||||
}).drop(),
|
||||
}
|
||||
|
||||
fetchMember: task(function* (memberId) {
|
||||
this.set('isLoading', true);
|
||||
@task
|
||||
*fetchMemberTask(memberId) {
|
||||
this.isLoading = true;
|
||||
|
||||
let member = yield this.store.findRecord('member', memberId, {
|
||||
this.member = yield this.store.findRecord('member', memberId, {
|
||||
reload: true
|
||||
});
|
||||
|
||||
this.set('member', member);
|
||||
this.set('isLoading', false);
|
||||
}),
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
// Private -----------------------------------------------------------------
|
||||
|
||||
_saveMemberProperty(propKey, newValue) {
|
||||
let currentValue = this.member.get(propKey);
|
||||
|
@ -136,4 +154,4 @@ export default Controller.extend({
|
|||
|
||||
this.member.set(propKey, newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
import Controller from '@ember/controller';
|
||||
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
||||
import moment from 'moment';
|
||||
import {computed} from '@ember/object';
|
||||
import {get} from '@ember/object';
|
||||
import {A} from '@ember/array';
|
||||
import {action} from '@ember/object';
|
||||
import {pluralize} from 'ember-inflector';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
/* eslint-disable ghost/ember/alias-model-in-controller */
|
||||
export default Controller.extend({
|
||||
store: service(),
|
||||
export default class MembersController extends Controller {
|
||||
@service store;
|
||||
|
||||
queryParams: ['label'],
|
||||
queryParams = ['label'];
|
||||
|
||||
label: null,
|
||||
members: null,
|
||||
searchText: '',
|
||||
modalLabel: null,
|
||||
showLabelModal: false,
|
||||
@tracked searchText = '';
|
||||
@tracked label = null;
|
||||
@tracked members = null;
|
||||
@tracked modalLabel = null;
|
||||
@tracked showLabelModal = false;
|
||||
|
||||
_hasLoadedLabels: false,
|
||||
_availableLabels: null,
|
||||
@tracked _availableLabels = A([]);
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set('members', this.store.peekAll('member'));
|
||||
hasLoadedLabels = false;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.members = this.store.peekAll('member');
|
||||
this._availableLabels = this.store.peekAll('label');
|
||||
},
|
||||
}
|
||||
|
||||
showLoader: computed('filteredMembers.length', 'fetchMembers.isRunning', function () {
|
||||
return (!this.get('filteredMembers.length') && this.get('fetchMembers.isRunning'));
|
||||
}),
|
||||
// Computed properties -----------------------------------------------------
|
||||
|
||||
listHeader: computed('selectedLabel', 'searchText', function () {
|
||||
get showLoader() {
|
||||
return (!this.filteredMembers.length && this.fetchMembersTask.isRunning);
|
||||
}
|
||||
|
||||
get listHeader() {
|
||||
let {searchText, selectedLabel, filteredMembers} = this;
|
||||
if (searchText) {
|
||||
return 'Search result';
|
||||
}
|
||||
if (this.fetchMembers.lastSuccessful) {
|
||||
if (this.fetchMembersTask.lastSuccessful) {
|
||||
let count = pluralize(filteredMembers.length, 'member');
|
||||
if (selectedLabel && selectedLabel.slug) {
|
||||
if (filteredMembers.length > 1) {
|
||||
|
@ -49,44 +52,40 @@ export default Controller.extend({
|
|||
return count;
|
||||
}
|
||||
return 'Loading...';
|
||||
}),
|
||||
}
|
||||
|
||||
showingAll: computed('label', 'searchText', function () {
|
||||
let {searchText, label} = this;
|
||||
get showingAll() {
|
||||
return !this.searchText && !this.label;
|
||||
}
|
||||
|
||||
return !searchText && !label;
|
||||
}),
|
||||
|
||||
availableLabels: computed('_availableLabels.@each.isNew', function () {
|
||||
get availableLabels() {
|
||||
let labels = this._availableLabels
|
||||
.filter(label => !label.get('isNew'))
|
||||
.filter(label => label.get('id') !== null)
|
||||
.filter(label => !label.isNew)
|
||||
.filter(label => label.id !== null)
|
||||
.sort((labelA, labelB) => labelA.name.localeCompare(labelB.name, undefined, {ignorePunctuation: true}));
|
||||
let options = labels.toArray();
|
||||
|
||||
options.unshiftObject({name: 'All labels', slug: null});
|
||||
|
||||
return options;
|
||||
}),
|
||||
}
|
||||
|
||||
selectedLabel: computed('label', 'availableLabels', function () {
|
||||
let label = this.get('label');
|
||||
let labels = this.get('availableLabels');
|
||||
get selectedLabel() {
|
||||
let {label, availableLabels} = this;
|
||||
return availableLabels.findBy('slug', label);
|
||||
}
|
||||
|
||||
return labels.findBy('slug', label);
|
||||
}),
|
||||
|
||||
labelModalData: computed('modalLabel', 'availableLabels', function () {
|
||||
let label = this.get('modalLabel');
|
||||
let labels = this.get('availableLabels');
|
||||
get labelModalData() {
|
||||
let label = this.modalLabel;
|
||||
let labels = this.availableLabels;
|
||||
|
||||
return {
|
||||
label,
|
||||
labels
|
||||
};
|
||||
}),
|
||||
}
|
||||
|
||||
filteredMembers: computed('members.@each.{name,email}', 'searchText', 'label', function () {
|
||||
get filteredMembers() {
|
||||
let {members, searchText, label} = this;
|
||||
searchText = searchText.toLowerCase();
|
||||
|
||||
|
@ -106,59 +105,69 @@ export default Controller.extend({
|
|||
return _label.slug === label;
|
||||
});
|
||||
}).sort((a, b) => {
|
||||
return b.get('createdAtUTC').valueOf() - a.get('createdAtUTC').valueOf();
|
||||
return b.createdAtUTC.valueOf() - a.createdAtUTC.valueOf();
|
||||
});
|
||||
|
||||
return filtered;
|
||||
}),
|
||||
}
|
||||
|
||||
actions: {
|
||||
exportData() {
|
||||
let exportUrl = ghostPaths().url.api('members/csv');
|
||||
let downloadURL = `${exportUrl}?limit=all`;
|
||||
let iframe = document.getElementById('iframeDownload');
|
||||
// Actions -----------------------------------------------------------------
|
||||
|
||||
if (!iframe) {
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.id = 'iframeDownload';
|
||||
iframe.style.display = 'none';
|
||||
document.body.append(iframe);
|
||||
}
|
||||
iframe.setAttribute('src', downloadURL);
|
||||
},
|
||||
changeLabel(label, e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
this.set('label', get(label, 'slug'));
|
||||
},
|
||||
addLabel(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
const newLabel = this.store.createRecord('label');
|
||||
this.set('modalLabel', newLabel);
|
||||
this.toggleProperty('showLabelModal');
|
||||
},
|
||||
editLabel(label, e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
let labels = this.get('availableLabels');
|
||||
@action
|
||||
exportData() {
|
||||
let exportUrl = ghostPaths().url.api('members/csv');
|
||||
let downloadURL = `${exportUrl}?limit=all`;
|
||||
let iframe = document.getElementById('iframeDownload');
|
||||
|
||||
let modalLabel = labels.findBy('slug', label);
|
||||
this.set('modalLabel', modalLabel);
|
||||
this.toggleProperty('showLabelModal');
|
||||
},
|
||||
toggleLabelModal() {
|
||||
this.toggleProperty('showLabelModal');
|
||||
if (!iframe) {
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.id = 'iframeDownload';
|
||||
iframe.style.display = 'none';
|
||||
document.body.append(iframe);
|
||||
}
|
||||
},
|
||||
iframe.setAttribute('src', downloadURL);
|
||||
}
|
||||
|
||||
fetchMembers: task(function* () {
|
||||
@action
|
||||
changeLabel(label, e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
this.label = label.slug;
|
||||
}
|
||||
|
||||
@action
|
||||
addLabel(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
const newLabel = this.store.createRecord('label');
|
||||
this.modalLabel = newLabel;
|
||||
this.showLabelModal = !this.showLabelModal;
|
||||
}
|
||||
|
||||
@action
|
||||
editLabel(label, e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
let modalLabel = this.availableLabels.findBy('slug', label);
|
||||
this.modalLabel = modalLabel;
|
||||
this.showLabelModal = !this.showLabelModal;
|
||||
}
|
||||
|
||||
@action
|
||||
toggleLabelModal() {
|
||||
this.showLabelModal = !this.showLabelModal;
|
||||
}
|
||||
|
||||
// Tasks -------------------------------------------------------------------
|
||||
|
||||
@task
|
||||
*fetchMembersTask() {
|
||||
let newFetchDate = new Date();
|
||||
|
||||
if (this._hasFetchedAll) {
|
||||
|
@ -178,5 +187,5 @@ export default Controller.extend({
|
|||
}
|
||||
|
||||
this._lastFetchDate = newFetchDate;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as controller} from '@ember/controller';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
/* eslint-disable ghost/ember/alias-model-in-controller */
|
||||
export default Controller.extend({
|
||||
members: controller(),
|
||||
router: service(),
|
||||
export default class ImportController extends Controller {
|
||||
@controller members;
|
||||
@service router;
|
||||
|
||||
actions: {
|
||||
fetchNewMembers() {
|
||||
this.members.fetchMembers.perform();
|
||||
},
|
||||
|
||||
close() {
|
||||
this.router.transitionTo('members');
|
||||
}
|
||||
@action
|
||||
fetchNewMembers() {
|
||||
this.members.fetchMembersTask.perform();
|
||||
}
|
||||
});
|
||||
|
||||
@action
|
||||
close() {
|
||||
this.router.transitionTo('members');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import CurrentUserSettings from 'ghost-admin/mixins/current-user-settings';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
||||
router: service(),
|
||||
@classic
|
||||
export default class MembersRoute extends AuthenticatedRoute.extend(CurrentUserSettings) {
|
||||
@service router;
|
||||
|
||||
_requiresBackgroundRefresh: true,
|
||||
_requiresBackgroundRefresh = true;
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
super.init(...arguments);
|
||||
this.router.on('routeWillChange', (transition) => {
|
||||
this.showUnsavedChangesModal(transition);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor());
|
||||
},
|
||||
super.beforeModel(...arguments);
|
||||
return this.session.user.then(this.transitionAuthor());
|
||||
}
|
||||
|
||||
model(params) {
|
||||
this._requiresBackgroundRefresh = false;
|
||||
|
@ -28,33 +30,30 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
|||
} else {
|
||||
return this.store.createRecord('member');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setupController(controller, member) {
|
||||
this._super(...arguments);
|
||||
super.setupController(...arguments);
|
||||
if (this._requiresBackgroundRefresh) {
|
||||
controller.fetchMember.perform(member.get('id'));
|
||||
controller.fetchMemberTask.perform(member.get('id'));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
|
||||
super.deactivate(...arguments);
|
||||
// clean up newly created records and revert unsaved changes to existing
|
||||
this.controller.member.rollbackAttributes();
|
||||
|
||||
this._requiresBackgroundRefresh = true;
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.controller.send('save');
|
||||
}
|
||||
},
|
||||
@action
|
||||
save() {
|
||||
this.controller.save();
|
||||
}
|
||||
|
||||
titleToken() {
|
||||
return this.controller.get('member.name');
|
||||
},
|
||||
return this.controller.member.name;
|
||||
}
|
||||
|
||||
showUnsavedChangesModal(transition) {
|
||||
if (transition.from && transition.from.name === this.routeName && transition.targetName) {
|
||||
|
@ -65,9 +64,9 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
|||
|
||||
if (!controller.member.isDeleted && isChanged) {
|
||||
transition.abort();
|
||||
controller.send('toggleUnsavedChangesModal', transition);
|
||||
controller.toggleUnsavedChangesModal(transition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import MemberRoute from '../member';
|
||||
|
||||
export default MemberRoute.extend({
|
||||
controllerName: 'member',
|
||||
templateName: 'member'
|
||||
});
|
||||
export default class NewMemberRoute extends MemberRoute {
|
||||
controllerName = 'member';
|
||||
templateName = 'member';
|
||||
}
|
||||
|
|
|
@ -1,45 +1,44 @@
|
|||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default AuthenticatedRoute.extend({
|
||||
config: service(),
|
||||
export default class MembersRoute extends AuthenticatedRoute {
|
||||
@service config;
|
||||
|
||||
queryParams: {
|
||||
queryParams = {
|
||||
label: {refreshModel: true}
|
||||
},
|
||||
};
|
||||
|
||||
// redirect to posts screen if:
|
||||
// - TODO: members is disabled?
|
||||
// - logged in user isn't owner/admin
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
||||
super.beforeModel(...arguments);
|
||||
return this.session.user.then((user) => {
|
||||
if (!user.isOwnerOrAdmin) {
|
||||
return this.transitionTo('home');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// trigger a background load of labels for filter dropdown
|
||||
setupController(controller) {
|
||||
this._super(...arguments);
|
||||
controller.fetchMembers.perform();
|
||||
if (!controller._hasLoadedLabels) {
|
||||
super.setupController(...arguments);
|
||||
controller.fetchMembersTask.perform();
|
||||
if (!controller.hasLoadedLabels) {
|
||||
this.store.query('label', {limit: 'all'}).then(() => {
|
||||
controller._hasLoadedLabels = true;
|
||||
controller.hasLoadedLabels = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
super.deactivate(...arguments);
|
||||
this.controller.modalLabel && this.controller.modalLabel.rollbackAttributes();
|
||||
},
|
||||
}
|
||||
|
||||
buildRouteInfoMetadata() {
|
||||
return {
|
||||
titleToken: 'Members'
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default Route.extend({
|
||||
});
|
||||
export default class MembersImportRoute extends Route {}
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
{{#unless this.member.isNew}}
|
||||
<button
|
||||
class="gh-btn gh-btn-white gh-btn-icon mr2"
|
||||
{{on "click" (action "toggleImpersonateMemberModal")}}>
|
||||
{{on "click" this.toggleImpersonateMemberModal}}>
|
||||
<span>Impersonate</span>
|
||||
</button>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<GhTaskButton @class="gh-btn gh-btn-blue gh-btn-icon" @type="button" @task={{this.save}} @autoReset={{true}} @data-test-button="save" />
|
||||
<GhTaskButton @class="gh-btn gh-btn-blue gh-btn-icon" @type="button" @task={{this.saveTask}} @autoReset={{true}} @data-test-button="save" />
|
||||
</section>
|
||||
</GhCanvasHeader>
|
||||
|
||||
|
@ -67,7 +67,7 @@
|
|||
<GhMemberSettingsForm
|
||||
@member={{this.member}}
|
||||
@scratchMember={{this.scratchMember}}
|
||||
@setProperty={{action "setProperty"}}
|
||||
@setProperty={{this.setProperty}}
|
||||
@isLoading={{this.isLoading}} />
|
||||
</form>
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
|||
<button
|
||||
type="button"
|
||||
class="gh-btn gh-btn-red gh-btn-icon mt3"
|
||||
{{on "click" (action "toggleDeleteMemberModal")}}
|
||||
{{on "click" this.toggleDeleteMemberModal}}
|
||||
data-test-button="delete-member"
|
||||
>
|
||||
<span>Delete member</span>
|
||||
|
@ -86,8 +86,8 @@
|
|||
{{#if this.showUnsavedChangesModal}}
|
||||
<GhFullscreenModal
|
||||
@modal="leave-settings"
|
||||
@confirm={{action "leaveScreen"}}
|
||||
@close={{action "toggleUnsavedChangesModal"}}
|
||||
@confirm={{this.leaveScreen}}
|
||||
@close={{this.toggleUnsavedChangesModal}}
|
||||
@modifier="action wide" />
|
||||
{{/if}}
|
||||
|
||||
|
@ -95,8 +95,8 @@
|
|||
<GhFullscreenModal
|
||||
@modal="delete-member"
|
||||
@model={{this.member}}
|
||||
@confirm={{action "deleteMember"}}
|
||||
@close={{action "toggleDeleteMemberModal"}}
|
||||
@confirm={{this.deleteMember}}
|
||||
@close={{this.toggleDeleteMemberModal}}
|
||||
@modifier="action wide" />
|
||||
{{/if}}
|
||||
|
||||
|
@ -104,6 +104,6 @@
|
|||
<GhFullscreenModal
|
||||
@modal="impersonate-member"
|
||||
@model={{this.member}}
|
||||
@close={{action "toggleImpersonateMemberModal"}}
|
||||
@close={{this.toggleImpersonateMemberModal}}
|
||||
@modifier="action wide" />
|
||||
{{/if}}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
<GhMembersContentfilter
|
||||
@selectedLabel={{this.selectedLabel}}
|
||||
@availableLabels={{this.availableLabels}}
|
||||
@onLabelChange={{action "changeLabel"}}
|
||||
@onLabelAdd={{action "addLabel"}}
|
||||
@onLabelEdit={{action "editLabel"}}
|
||||
@onLabelChange={{this.changeLabel}}
|
||||
@onLabelAdd={{this.addLabel}}
|
||||
@onLabelEdit={{this.editLabel}}
|
||||
/>
|
||||
<div class="relative gh-members-header-search">
|
||||
{{svg-jar "search" class="gh-input-search-icon"}}
|
||||
|
@ -34,9 +34,9 @@
|
|||
</LinkTo>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" {{action 'exportData'}} class="mr2">
|
||||
<button class="mr2" {{on "click" this.exportData}}>
|
||||
<span>Export all members</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</GhDropdown>
|
||||
</span>
|
||||
|
@ -93,7 +93,7 @@
|
|||
<GhFullscreenModal
|
||||
@modal="members-label-form"
|
||||
@model={{this.labelModalData}}
|
||||
@close={{action "toggleLabelModal"}}
|
||||
@close={{this.toggleLabelModal}}
|
||||
@modifier="action wide"
|
||||
/>
|
||||
{{/if}}
|
|
@ -52,6 +52,7 @@
|
|||
"ember-ajax": "5.0.0",
|
||||
"ember-assign-helper": "0.2.0",
|
||||
"ember-auto-import": "1.5.3",
|
||||
"ember-classic-decorator": "1.0.8",
|
||||
"ember-cli": "3.18.0",
|
||||
"ember-cli-app-version": "3.2.0",
|
||||
"ember-cli-babel": "7.20.0",
|
||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -837,7 +837,7 @@
|
|||
globals "^11.1.0"
|
||||
lodash "^4.17.13"
|
||||
|
||||
"@babel/types@^7.1.6", "@babel/types@^7.3.2", "@babel/types@^7.3.4", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6":
|
||||
"@babel/types@^7.1.6", "@babel/types@^7.3.2", "@babel/types@^7.3.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6":
|
||||
version "7.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7"
|
||||
integrity sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==
|
||||
|
@ -2269,6 +2269,14 @@ babel-plugin-ember-modules-api-polyfill@^2.13.0:
|
|||
dependencies:
|
||||
ember-rfc176-data "^0.3.13"
|
||||
|
||||
babel-plugin-filter-imports@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-3.0.0.tgz#a849683837ad29960da17492fb32789ab6b09a11"
|
||||
integrity sha512-p/chjzVTgCxUqyLM0q/pfWVZS7IJTwGQMwNg0LOvuQpKiTftQgZDtkGB8XvETnUw19rRcL7bJCTopSwibTN2tA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.4.0"
|
||||
lodash "^4.17.11"
|
||||
|
||||
babel-plugin-filter-imports@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-4.0.0.tgz#068f8da15236a96a9602c36dc6f4a6eeca70a4f4"
|
||||
|
@ -5195,6 +5203,14 @@ ember-basic-dropdown@^3.0.1:
|
|||
ember-maybe-in-element "^0.4.0"
|
||||
ember-truth-helpers "2.1.0"
|
||||
|
||||
ember-classic-decorator@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/ember-classic-decorator/-/ember-classic-decorator-1.0.8.tgz#e290e5b0b1a31a569587a85a9c5c7a2f1242cabb"
|
||||
integrity sha512-IsCDJ7rLsrFjYtgi9UXUmjzUQJaaJzmy/gKwGGtZ6kZwT5yhzSbScRi0P6Cb0guJPtlMMCE0sAQpJRbXmBb/gA==
|
||||
dependencies:
|
||||
babel-plugin-filter-imports "^3.0.0"
|
||||
ember-cli-babel "^7.11.1"
|
||||
|
||||
ember-cli-app-version@3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e"
|
||||
|
|
Loading…
Reference in a new issue