Add the ability to filter the results in the modtools modal
This commit is contained in:
parent
b215c59bd0
commit
00cac6d250
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -14180,7 +14180,7 @@
|
|||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -14190,7 +14190,7 @@
|
|||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -14232,7 +14232,7 @@
|
|||
},
|
||||
"load-json-file": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -14251,7 +14251,7 @@
|
|||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -18737,7 +18737,7 @@
|
|||
},
|
||||
"pinkie-promise": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
||||
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -20228,7 +20228,7 @@
|
|||
},
|
||||
"load-json-file": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -20241,7 +20241,7 @@
|
|||
},
|
||||
"os-locale": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
||||
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#converse-modals {
|
||||
.modal {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
|
||||
.modal-body {
|
||||
overflow-y: auto;
|
||||
max-height: 75vh;
|
||||
|
|
164
spec/modtools.js
164
spec/modtools.js
|
@ -3,6 +3,7 @@
|
|||
} (this, function (jasmine, mock, test_utils) {
|
||||
const _ = converse.env._;
|
||||
const $iq = converse.env.$iq;
|
||||
const $pres = converse.env.$pres;
|
||||
const sizzle = converse.env.sizzle;
|
||||
const Strophe = converse.env.Strophe;
|
||||
const u = converse.env.utils;
|
||||
|
@ -137,6 +138,169 @@
|
|||
done();
|
||||
}));
|
||||
|
||||
it("allows you to filter affiliation search results",
|
||||
mock.initConverse(
|
||||
['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [
|
||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'member'},
|
||||
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'member'},
|
||||
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'member'},
|
||||
{'jid': 'juliet@capulet.lit', 'nick': 'juliet', 'affiliation': 'member'},
|
||||
];
|
||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = '/modtools';
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
view.onKeyDown(enter);
|
||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||
|
||||
const modal = view.modtools_modal;
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
// Clear so that we don't match older stanzas
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
const select = modal.el.querySelector('.select-affiliation');
|
||||
expect(select.value).toBe('owner');
|
||||
select.value = 'member';
|
||||
const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
||||
button.click();
|
||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||
expect(user_els.length).toBe(6);
|
||||
|
||||
const filter = modal.el.querySelector('[name="filter"]');
|
||||
expect(filter).not.toBe(null);
|
||||
|
||||
filter.value = 'romeo';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||
|
||||
filter.value = 'r';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 3));
|
||||
|
||||
filter.value = 'gower';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||
done();
|
||||
}));
|
||||
|
||||
it("allows you to filter role search results",
|
||||
mock.initConverse(
|
||||
['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `nomorenicks@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/newb`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `newb@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/some1`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `some1@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `oldhag@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/crone`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `crone@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/tux`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `tux@montague.lit`,
|
||||
'role': 'participant'
|
||||
})
|
||||
));
|
||||
await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = '/modtools';
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
view.onKeyDown(enter);
|
||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||
|
||||
const modal = view.modtools_modal;
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
||||
const tab = modal.el.querySelector('#roles-tab');
|
||||
tab.click();
|
||||
|
||||
// Clear so that we don't match older stanzas
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
|
||||
const select = modal.el.querySelector('.select-role');
|
||||
expect(select.value).toBe('moderator');
|
||||
select.value = 'participant';
|
||||
|
||||
const button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
|
||||
button.click();
|
||||
await u.waitUntil(() => !modal.loading_users_with_role);
|
||||
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||
expect(user_els.length).toBe(6);
|
||||
|
||||
const filter = modal.el.querySelector('[name="filter"]');
|
||||
expect(filter).not.toBe(null);
|
||||
|
||||
filter.value = 'tux';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||
|
||||
filter.value = 'r';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 2));
|
||||
|
||||
filter.value = 'crone';
|
||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||
done();
|
||||
}));
|
||||
|
||||
it("shows an error message if a particular affiliation list may not be retrieved",
|
||||
mock.initConverse(
|
||||
['rosterGroupsFetched'], {},
|
||||
|
|
|
@ -230,6 +230,9 @@ converse.plugins.add('converse-muc-views', {
|
|||
this.chatroomview = attrs.chatroomview;
|
||||
BootstrapModal.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.affiliations_filter = '';
|
||||
this.roles_filter = '';
|
||||
|
||||
this.listenTo(this.model, 'change:role', () => {
|
||||
this.users_with_role = this.getUsersWithRole();
|
||||
this.render();
|
||||
|
@ -252,15 +255,19 @@ converse.plugins.add('converse-muc-views', {
|
|||
toHTML () {
|
||||
const occupant = this.chatroomview.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||
return tpl_moderator_tools_modal(Object.assign(this.model.toJSON(), {
|
||||
'affiliations_filter': this.affiliations_filter,
|
||||
'assignAffiliation': ev => this.assignAffiliation(ev),
|
||||
'assignRole': ev => this.assignRole(ev),
|
||||
'assignable_affiliations': this.getAssignableAffiliations(occupant),
|
||||
'assignable_roles': this.getAssignableRoles(occupant),
|
||||
'filterAffiliationResults': ev => this.filterAffiliationResults(ev),
|
||||
'filterRoleResults': ev => this.filterRoleResults(ev),
|
||||
'loading_users_with_affiliation': this.loading_users_with_affiliation,
|
||||
'queryAffiliation': ev => this.queryAffiliation(ev),
|
||||
'queryRole': ev => this.queryRole(ev),
|
||||
'queryable_affiliations': AFFILIATIONS.filter(a => !_converse.modtools_disable_query.includes(a)),
|
||||
'queryable_roles': ROLES.filter(a => !_converse.modtools_disable_query.includes(a)),
|
||||
'assignable_affiliations': this.getAssignableAffiliations(occupant),
|
||||
'assignable_roles': this.getAssignableRoles(occupant),
|
||||
'roles_filter': this.roles_filter,
|
||||
'switchTab': ev => this.switchTab(ev),
|
||||
'toggleForm': ev => this.toggleForm(ev),
|
||||
'users_with_affiliation': this.users_with_affiliation,
|
||||
|
@ -342,6 +349,16 @@ converse.plugins.add('converse-muc-views', {
|
|||
});
|
||||
},
|
||||
|
||||
filterRoleResults (ev) {
|
||||
this.roles_filter = ev.target.value;
|
||||
this.render();
|
||||
},
|
||||
|
||||
filterAffiliationResults (ev) {
|
||||
this.affiliations_filter = ev.target.value;
|
||||
this.render();
|
||||
},
|
||||
|
||||
queryRole (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
|
|
@ -13,6 +13,7 @@ const i18n_new_role = __('New Role');
|
|||
const i18n_no_users_with_aff = __('No users with that affiliation found.')
|
||||
const i18n_no_users_with_role = __('No users with that role found.');
|
||||
const i18n_reason = __('Reason');
|
||||
const i18n_filter = __('Type here to filter the search results');
|
||||
const i18n_role = __('Role');
|
||||
const i18n_show_users = __('Show users');
|
||||
|
||||
|
@ -163,7 +164,6 @@ const tpl_navigation = (o) => html`
|
|||
|
||||
|
||||
export default (o) => {
|
||||
|
||||
const show_both_tabs = o.queryable_roles.length && o.queryable_affiliations.length;
|
||||
return html`
|
||||
<div class="modal-dialog" role="document">
|
||||
|
@ -177,7 +177,6 @@ export default (o) => {
|
|||
|
||||
${ show_both_tabs ? tpl_navigation(o) : '' }
|
||||
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane tab-pane--columns ${ o.queryable_affiliations.length ? 'active' : ''}" id="affiliations-tabpanel" role="tabpanel" aria-labelledby="affiliations-tab">
|
||||
<form class="converse-form query-affiliation" @submit=${o.queryAffiliation}>
|
||||
|
@ -197,17 +196,25 @@ export default (o) => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col pt-2"><p class="helptext pb-3">${getAffiliationHelpText(o.affiliation)}</p></div>
|
||||
<div class="col mt-3">
|
||||
${ (Array.isArray(o.users_with_affiliation) && o.users_with_affiliation.length > 5) ?
|
||||
html`<input class="form-control" .value="${o.affiliations_filter}" @keyup=${o.filterAffiliationResults} type="text" name="filter" placeholder="${i18n_filter}"/>` : '' }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${ getAffiliationHelpText(o.affiliation) ?
|
||||
html`<div class="row"><div class="col pt-2"><p class="helptext pb-3">${getAffiliationHelpText(o.affiliation)}</p></div></div>` : '' }
|
||||
</div>
|
||||
</form>
|
||||
<div class="scrollable-container">
|
||||
<ul class="list-group list-group--users">
|
||||
${ (o.loading_users_with_affiliation) ? html`<li class="list-group-item"> ${spinner()} </li>` : '' }
|
||||
${ (Array.isArray(o.users_with_affiliation) && o.users_with_affiliation.length === 0) ? html`<li class="list-group-item">${i18n_no_users_with_aff}</li>` : '' }
|
||||
${ (Array.isArray(o.users_with_affiliation) && o.users_with_affiliation.length === 0) ?
|
||||
html`<li class="list-group-item">${i18n_no_users_with_aff}</li>` : '' }
|
||||
|
||||
${ (o.users_with_affiliation instanceof Error) ?
|
||||
html`<li class="list-group-item">${o.users_with_affiliation.message}</li>` :
|
||||
(o.users_with_affiliation || []).map(item => affiliation_list_item(Object.assign({item}, o))) }
|
||||
(o.users_with_affiliation || []).map(item => (item.nick.match(o.affiliations_filter) ? affiliation_list_item(Object.assign({item}, o)) : '')) }
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -228,15 +235,20 @@ export default (o) => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col pt-2"><p class="helptext pb-3">${getRoleHelpText(o.role)}</p></div>
|
||||
<div class="col mt-3">
|
||||
${ (Array.isArray(o.users_with_role) && o.users_with_role.length > 5) ?
|
||||
html`<input class="form-control" .value="${o.roles_filter}" @keyup=${o.filterRoleResults} type="text" name="filter" placeholder="${i18n_filter}"/>` : '' }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${ getRoleHelpText(o.role) ? html`<div class="row"><div class="col pt-2"><p class="helptext pb-3">${getRoleHelpText(o.role)}</p></div></div>` : ''}
|
||||
</div>
|
||||
</form>
|
||||
<div class="scrollable-container">
|
||||
<ul class="list-group list-group--users">
|
||||
${ o.loading_users_with_role ? html`<li class="list-group-item"> ${spinner()} </li>` : '' }
|
||||
${ (o.users_with_role && o.users_with_role.length === 0) ? html`<li class="list-group-item">${i18n_no_users_with_role}</li>` : '' }
|
||||
${ (o.users_with_role || []).map(item => role_list_item(Object.assign({item}, o))) }
|
||||
${ (o.users_with_role || []).map(item => (item.nick.match(o.roles_filter) ? role_list_item(Object.assign({item}, o)) : '')) }
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue
Block a user