0
Fork 0
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:
Kevin Ansfield 2020-07-23 14:56:49 +01:00
parent 42b3e3a412
commit 3b78973a21
4 changed files with 9 additions and 149 deletions

View file

@ -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>

View file

@ -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();

View file

@ -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"

View file

@ -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');
});
});