mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Removed bulk member edit dev experiment
no issue - we're moving forward with a simplified bulk delete and the UI would conflict if both approaches are behind the dev experiments flag
This commit is contained in:
parent
42b3e3a412
commit
3b78973a21
4 changed files with 9 additions and 149 deletions
|
@ -1,10 +1,5 @@
|
|||
<li class="gh-list-row gh-members-list-item {{if @member.is_loading "loading"}}" ...attributes>
|
||||
{{#if @member.is_loading}}
|
||||
{{#if @isEditing}}
|
||||
<div class="gh-list-data gh-members-list-checkbox">
|
||||
<input type="checkbox" checked={{@isSelected}} disabled>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="gh-list-data gh-members-list-basic gh-list-loadingcell">
|
||||
<div class="gh-list-loading-title"></div>
|
||||
<div class="gh-list-loading-detail"></div>
|
||||
|
@ -13,13 +8,7 @@
|
|||
<div class="gh-list-data gh-members-list-subscribed-at gh-list-cellwidth-20"></div>
|
||||
<div class="gh-list-data gh-members-list-chevron gh-list-cellwidth-chevron"></div>
|
||||
{{else}}
|
||||
{{#if @isEditing}}
|
||||
<div class="gh-list-data gh-members-list-checkbox">
|
||||
<input type="checkbox" checked={{@isSelected}} disabled>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} @disabled={{@isEditing}} @disabledClass="default-cursor" title="Member details" class="gh-list-data gh-members-list-basic">
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-basic">
|
||||
<div class="flex items-center">
|
||||
<GhMemberAvatar @member={{@member}} @containerClass="w9 h9 mr3 flex-shrink-0" />
|
||||
<div>
|
||||
|
@ -31,7 +20,7 @@
|
|||
</div>
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} @disabled={{@isEditing}} @disabledClass="default-cursor" title="Member details" class="gh-list-data gh-members-list-geolocation gh-list-cellwidth-20 middarkgrey f8 {{if (not @member.name) "gh-members-geolocation-noname"}}">
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-geolocation gh-list-cellwidth-20 middarkgrey f8 {{if (not @member.name) "gh-members-geolocation-noname"}}">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (eq @member.geolocation.country_code "US")}}
|
||||
{{@member.geolocation.region}}, US
|
||||
|
@ -43,19 +32,17 @@
|
|||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} @disabled={{@isEditing}} @disabledClass="default-cursor" title="Member details" class="gh-list-data gh-members-list-subscribed-at gh-list-cellwidth-20 middarkgrey f8 {{if (not @member.name) "gh-members-subscribed-noname"}}">
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-subscribed-at gh-list-cellwidth-20 middarkgrey f8 {{if (not @member.name) "gh-members-subscribed-noname"}}">
|
||||
{{#if @member.createdAtUTC}}
|
||||
{{moment-format @member.createdAtUTC "D MMM YYYY"}}
|
||||
<span class="midlightgrey">({{moment-from-now @member.createdAtUTC}})</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} @disabled={{@isEditing}} @disabledClass="default-cursor" title="Member details" class="gh-list-data gh-list-cellwidth-chevron gh-members-list-chevron">
|
||||
{{#unless @isEditing}}
|
||||
<div class="flex items-center justify-end w-100 h-100">
|
||||
<span class="nr2">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
|
||||
</div>
|
||||
{{/unless}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-list-cellwidth-chevron gh-members-list-chevron">
|
||||
<div class="flex items-center justify-end w-100 h-100">
|
||||
<span class="nr2">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
|
@ -37,13 +37,11 @@ export default class MembersController extends Controller {
|
|||
];
|
||||
|
||||
@tracked members = A([]);
|
||||
@tracked allSelected = false;
|
||||
@tracked searchText = '';
|
||||
@tracked searchParam = '';
|
||||
@tracked paidParam = null;
|
||||
@tracked label = null;
|
||||
@tracked modalLabel = null;
|
||||
@tracked isEditing = false;
|
||||
@tracked showLabelModal = false;
|
||||
@tracked showDeleteMembersModal = false;
|
||||
|
||||
|
@ -117,20 +115,6 @@ export default class MembersController extends Controller {
|
|||
return this.paidParams.findBy('value', this.paidParam) || {value: '!unknown'};
|
||||
}
|
||||
|
||||
get selectedCount() {
|
||||
return this.allSelected ? this.members.length : 0;
|
||||
}
|
||||
|
||||
get selectAllLabel() {
|
||||
let {members} = this;
|
||||
|
||||
if (this.allSelected) {
|
||||
return `All items selected (${formatNumber(members.length)})`;
|
||||
} else {
|
||||
return `Select all (${formatNumber(members.length)})`;
|
||||
}
|
||||
}
|
||||
|
||||
// Actions -----------------------------------------------------------------
|
||||
|
||||
@action
|
||||
|
@ -141,23 +125,6 @@ export default class MembersController extends Controller {
|
|||
this.membersStats.fetch();
|
||||
}
|
||||
|
||||
@action
|
||||
toggleEditMode() {
|
||||
if (this.isEditing) {
|
||||
this.resetSelection();
|
||||
} else {
|
||||
this.isEditing = true;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
toggleSelectAll() {
|
||||
if (this.members.length === 0) {
|
||||
return this.allSelected = false;
|
||||
}
|
||||
this.allSelected = !this.allSelected;
|
||||
}
|
||||
|
||||
@action
|
||||
search(e) {
|
||||
this.searchTask.perform(e.target.value);
|
||||
|
@ -247,8 +214,6 @@ export default class MembersController extends Controller {
|
|||
// params is undefined when called as a "refresh" of the model
|
||||
let {label, paidParam, searchParam} = typeof params === 'undefined' ? this : params;
|
||||
|
||||
this.resetSelection();
|
||||
|
||||
if (!searchParam) {
|
||||
this.resetSearch();
|
||||
}
|
||||
|
@ -313,7 +278,6 @@ export default class MembersController extends Controller {
|
|||
|
||||
// reset and reload
|
||||
this.store.unloadAll('member');
|
||||
this.resetSelection();
|
||||
this.reload();
|
||||
|
||||
return response.meta.stats;
|
||||
|
@ -325,11 +289,6 @@ export default class MembersController extends Controller {
|
|||
this.searchText = '';
|
||||
}
|
||||
|
||||
resetSelection() {
|
||||
this.isEditing = false;
|
||||
this.allSelected = false;
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.membersStats.invalidate();
|
||||
this.membersStats.fetch();
|
||||
|
|
|
@ -57,49 +57,17 @@
|
|||
{{/if}}
|
||||
|
||||
<section class="content-list">
|
||||
{{!-- overlaid on header to keep table column sizing --}}
|
||||
{{#if this.isEditing}}
|
||||
<div class="members-list-header-overlay" data-test-edit-overlay>
|
||||
<div class="flex flex-row">
|
||||
<div>
|
||||
<input type="checkbox" id="select-all-members" name="select-all-members" {{on "input" this.toggleSelectAll}} data-test-checkbox="select-all">
|
||||
<label for="select-all-members" data-test-label="selection">{{this.selectAllLabel}}</label>
|
||||
</div>
|
||||
<button class="gh-btn" {{on "click" this.toggleDeleteMembersModal}} disabled={{not this.selectedCount}} data-test-button="delete">
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="gh-btn" {{on "click" this.toggleEditMode}} data-test-button="done">
|
||||
<span>Done</span>
|
||||
</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<ol class="members-list gh-list {{unless this.members "no-posts"}}">
|
||||
{{#if this.members}}
|
||||
<li class="gh-list-row header relative">
|
||||
{{#if this.isEditing}}
|
||||
{{!-- necessary because we add an extra column in the list items --}}
|
||||
<div class="gh-list-header gh-members-list-checkbox"></div>
|
||||
{{/if}}
|
||||
<div class="gh-list-header" data-test-list-header>{{this.listHeader}}</div>
|
||||
<div class="gh-list-header gh-members-list-geolocation gh-list-cellwidth-20 nowrap">Location</div>
|
||||
<div class="gh-list-header gh-members-list-subscribed-at gh-list-cellwidth-20 nowrap">Created</div>
|
||||
<div class="gh-list-header gh-members-list-chevron gh-list-cellwidth-chevron">
|
||||
{{!-- TODO: 🍆🖌 --}}
|
||||
{{#if this.config.enableDeveloperExperiments}}
|
||||
<button class="gh-btn" style="position: absolute; top: 2px; right: 3px" {{on "click" this.toggleEditMode}} data-test-button="edit">
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="gh-list-header gh-members-list-chevron gh-list-cellwidth-chevron"></div>
|
||||
</li>
|
||||
<VerticalCollection @items={{this.members}} @key="id" @containerSelector=".gh-main" @estimateHeight={{69}} @staticHeight={{true}} @bufferSize={{20}} as |member|>
|
||||
<GhMembersListItem
|
||||
@member={{member}}
|
||||
@isEditing={{this.isEditing}}
|
||||
@isSelected={{this.allSelected}}
|
||||
@data-test-member={{member.id}}
|
||||
/>
|
||||
</VerticalCollection>
|
||||
|
@ -131,7 +99,7 @@
|
|||
{{#if this.showDeleteMembersModal}}
|
||||
<GhFullscreenModal
|
||||
@modal="delete-members"
|
||||
@model={{hash memberCount=this.selectedCount}}
|
||||
@model={{hash memberCount=this.members.length}}
|
||||
@confirm={{this.deleteMembers}}
|
||||
@close={{this.toggleDeleteMembersModal}}
|
||||
@modifier="action wide"
|
||||
|
|
|
@ -161,58 +161,4 @@ describe('Acceptance: Members', function () {
|
|||
.to.equal('example@domain.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulk editing', function () {
|
||||
beforeEach(async function () {
|
||||
this.server.loadFixtures('configs');
|
||||
|
||||
let role = this.server.create('role', {name: 'Owner'});
|
||||
this.server.create('user', {roles: [role]});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('can bulk delete all members', async function () {
|
||||
this.server.createList('member', 100);
|
||||
|
||||
await visit('/members');
|
||||
|
||||
expect(find('[data-test-list-header]'), 'initial list header text').to.contain.text('100 members');
|
||||
expect(find('[data-test-edit-overlay]'), 'initial header edit overlay').to.not.exist;
|
||||
|
||||
await click('[data-test-button="edit"]');
|
||||
|
||||
expect(find('[data-test-edit-overlay]'), 'edit mode overlay').to.exist;
|
||||
expect(find('[data-test-label="selection"'), 'initial selection label').to.contain.text('Select all (100)');
|
||||
expect(find('[data-test-button="delete"]'), 'initial delete button').to.have.attribute('disabled');
|
||||
|
||||
await click('[data-test-checkbox="select-all"]');
|
||||
|
||||
expect(find('[data-test-label="selection"'), 'post-select-all selection label').to.contain.text('All items selected');
|
||||
expect(find('[data-test-button="delete"]'), 'post-select-all delete button').to.not.have.attribute('disabled');
|
||||
|
||||
await click('[data-test-button="delete"]');
|
||||
|
||||
expect(find('[data-test-modal="delete-members"]'), 'post-delete-click delete modal').to.exist;
|
||||
expect(find('[data-test-state="delete-unconfirmed"]'), 'post-delete-click unconfirmed state').to.exist;
|
||||
expect(find('[data-test-text="delete-count"]'), 'confirm delete count').to.contain.text('100 members');
|
||||
|
||||
await click('[data-test-button="confirm"]');
|
||||
|
||||
expect(find('[data-test-no-members]'), 'background no-members state').to.exist;
|
||||
expect(find('[data-test-state="delete-complete"]'), 'post-confirm complete state').to.exist;
|
||||
expect(find('[data-test-text="deleted-count"]'), 'post-confirm delete count').to.contain.text('100');
|
||||
expect(find('[data-test-bulk-delete-errors]'), 'post-confirm errors').to.not.exist;
|
||||
|
||||
await click('[data-test-button="close-modal"');
|
||||
|
||||
expect(find('[data-test-modal="delete-members"]'), 'post-close delete modal').to.not.exist;
|
||||
});
|
||||
|
||||
it('can handle bulk delete outright error');
|
||||
it('can handle partial delete success');
|
||||
it('can bulk delete all members with a filter');
|
||||
it('can bulk delete all members with a search');
|
||||
it('can bulk delete all paid/free members');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue