UI: Move legacy ACLs to use the new searchables/changeable-sets (#4933)

pull/5729/head
John Cowen 2018-11-19 14:49:16 +00:00 committed by John Cowen
parent c532e53d9a
commit 104e6bac71
7 changed files with 150 additions and 93 deletions

View File

@ -1,11 +1,12 @@
import Controller from '@ember/controller';
import { computed, get } from '@ember/object';
import WithFiltering from 'consul-ui/mixins/with-filtering';
import WithSearching from 'consul-ui/mixins/with-searching';
import ucfirst from 'consul-ui/utils/ucfirst';
const countType = function(items, type) {
return type === '' ? get(items, 'length') : items.filterBy('Type', type).length;
};
export default Controller.extend(WithFiltering, {
export default Controller.extend(WithSearching, WithFiltering, {
queryParams: {
type: {
as: 'type',
@ -15,6 +16,17 @@ export default Controller.extend(WithFiltering, {
replace: true,
},
},
init: function() {
this.searchParams = {
acl: 's',
};
this._super(...arguments);
},
searchable: computed('filtered', function() {
return get(this, 'searchables.acl')
.add(get(this, 'filtered'))
.search(get(this, this.searchParams.acl));
}),
typeFilters: computed('items', function() {
const items = get(this, 'items');
return ['', 'management', 'client'].map(function(item) {
@ -27,18 +39,8 @@ export default Controller.extend(WithFiltering, {
};
});
}),
// TODO: This should be using a searchable
filter: function(item, { s = '', type = '' }) {
const sLower = s.toLowerCase();
return (
(get(item, 'Name')
.toLowerCase()
.indexOf(sLower) !== -1 ||
get(item, 'ID')
.toLowerCase()
.indexOf(sLower) !== -1) &&
(type === '' || get(item, 'Type') === type)
);
filter: function(item, { type = '' }) {
return type === '' || get(item, 'Type') === type;
},
actions: {
sendClone: function(item) {

View File

@ -2,6 +2,7 @@ import intention from 'consul-ui/search/filters/intention';
import token from 'consul-ui/search/filters/token';
import policy from 'consul-ui/search/filters/policy';
import kv from 'consul-ui/search/filters/kv';
import acl from 'consul-ui/search/filters/acl';
import node from 'consul-ui/search/filters/node';
// service instance
import nodeService from 'consul-ui/search/filters/node/service';
@ -16,6 +17,7 @@ export function initialize(application) {
const searchables = {
intention: intention(filterable),
token: token(filterable),
acl: acl(filterable),
policy: policy(filterable),
kv: kv(filterable),
healthyNode: node(filterable),

View File

@ -0,0 +1,14 @@
import { get } from '@ember/object';
export default function(filterable) {
return filterable(function(item, { s = '' }) {
const sLower = s.toLowerCase();
return (
get(item, 'Name')
.toLowerCase()
.indexOf(sLower) !== -1 ||
get(item, 'ID')
.toLowerCase()
.indexOf(sLower) !== -1
);
});
}

View File

@ -1,4 +1,4 @@
{{!<form>}}
{{freetext-filter onchange=(action onchange) value=search placeholder="Search by name/token"}}
{{freetext-filter searchable=searchable value=search placeholder="Search by name/token"}}
{{radio-group name="type" value=type items=filters onchange=(action onchange)}}
{{!</form>}}

View File

@ -13,87 +13,90 @@
{{/block-slot}}
{{#block-slot 'toolbar'}}
{{#if (gt items.length 0) }}
{{acl-filter filters=typeFilters search=filters.s type=filters.type onchange=(action 'filter')}}
{{acl-filter searchable=searchable filters=typeFilters search=filters.s type=filters.type onchange=(action 'filter')}}
{{/if}}
{{/block-slot}}
{{#block-slot 'content'}}
{{#if (gt filtered.length 0)}}
{{#tabular-collection
items=(sort-by 'Name:asc' filtered) as |item index|
}}
{{#block-slot 'header'}}
<th>Name</th>
<th>Type</th>
{{/block-slot}}
{{#block-slot 'row'}}
<td data-test-acl="{{item.Name}}">
<a href={{href-to 'dc.acls.edit' item.ID}}>{{item.Name}}</a>
</td>
<td>
{{#if (eq item.Type 'management')}}
<strong>{{item.Type}}</strong>
{{else}}
<span>{{item.Type}}</span>
{{/if}}
</td>
{{/block-slot}}
{{#block-slot 'actions' as |index change checked|}}
{{#confirmation-dialog confirming=false index=index}}
{{#block-slot 'action' as |confirm|}}
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
<ul>
<li>
<a data-test-edit href={{href-to 'dc.acls.edit' item.ID}}>Edit</a>
</li>
{{#if (eq item.ID token.SecretID) }}
<li>
<a data-test-logout onclick={{queue (action confirm 'logout' item) (action change)}}>Stop using</a>
</li>
{{else}}
{{#changeable-set dispatcher=searchable}}
{{#block-slot 'set' as |filtered|}}
{{#tabular-collection
items=(sort-by 'Name:asc' filtered) as |item index|
}}
{{#block-slot 'header'}}
<th>Name</th>
<th>Type</th>
{{/block-slot}}
{{#block-slot 'row'}}
<td data-test-acl="{{item.Name}}">
<a href={{href-to 'dc.acls.edit' item.ID}}>{{item.Name}}</a>
</td>
<td>
{{#if (eq item.Type 'management')}}
<strong>{{item.Type}}</strong>
{{else}}
<span>{{item.Type}}</span>
{{/if}}
</td>
{{/block-slot}}
{{#block-slot 'actions' as |index change checked|}}
{{#confirmation-dialog confirming=false index=index}}
{{#block-slot 'action' as |confirm|}}
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
<ul>
<li>
<a data-test-edit href={{href-to 'dc.acls.edit' item.ID}}>Edit</a>
</li>
{{#if (eq item.ID token.SecretID) }}
<li>
<a data-test-logout onclick={{queue (action confirm 'logout' item) (action change)}}>Stop using</a>
</li>
{{else}}
<li>
<a data-test-use onclick={{queue (action confirm 'use' item) (action change)}}>Use</a>
</li>
{{/if}}
<li>
<a data-test-clone onclick={{action 'sendClone' item}}>Clone</a>
</li>
{{# if (not-eq item.ID 'anonymous') }}
<li>
<a data-test-delete onclick={{action confirm 'delete' item}}>Delete</a>
</li>
{{/if}}
</ul>
{{/action-group}}
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message name|}}
<p>
{{#if (eq name 'delete')}}
Are you sure you want to delete this ACL token?
{{else if (eq name 'logout')}}
Are you sure you want to stop using this ACL token? This will log you out.
{{ else if (eq name 'use')}}
Are you sure you want to use this ACL token?
{{/if}}
</p>
<button type="button" class="type-delete" {{action execute}}>
{{#if (eq name 'delete')}}
Confirm Delete
{{else if (eq name 'logout')}}
Confirm Logout
{{ else if (eq name 'use')}}
Confirm Use
{{/if}}
</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
{{/block-slot}}
{{/confirmation-dialog}}
{{/block-slot}}
{{/tabular-collection}}
{{else}}
<p>
There are no ACLs.
</p>
{{/if}}
<li>
<a data-test-use onclick={{queue (action confirm 'use' item) (action change)}}>Use</a>
</li>
{{/if}}
<li>
<a data-test-clone onclick={{action 'sendClone' item}}>Clone</a>
</li>
{{# if (not-eq item.ID 'anonymous') }}
<li>
<a data-test-delete onclick={{action confirm 'delete' item}}>Delete</a>
</li>
{{/if}}
</ul>
{{/action-group}}
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message name|}}
<p>
{{#if (eq name 'delete')}}
Are you sure you want to delete this ACL token?
{{else if (eq name 'logout')}}
Are you sure you want to stop using this ACL token? This will log you out.
{{ else if (eq name 'use')}}
Are you sure you want to use this ACL token?
{{/if}}
</p>
<button type="button" class="type-delete" {{action execute}}>
{{#if (eq name 'delete')}}
Confirm Delete
{{else if (eq name 'logout')}}
Confirm Logout
{{ else if (eq name 'use')}}
Confirm Use
{{/if}}
</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
{{/block-slot}}
{{/confirmation-dialog}}
{{/block-slot}}
{{/tabular-collection}}
{{/block-slot}}
{{#block-slot 'empty'}}
<p>
There are no ACLs.
</p>
{{/block-slot}}
{{/changeable-set}}
{{/block-slot}}
{{/app-view}}

View File

@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:dc/acls/index', 'Unit | Controller | dc/acls/index', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
needs: ['service:search', 'service:dom'],
});
// Replace this with your real tests.

View File

@ -0,0 +1,36 @@
import getFilter from 'consul-ui/search/filters/acl';
import { module, test } from 'qunit';
module('Unit | Search | Filter | acl');
const filter = getFilter(cb => cb);
test('items are found by properties', function(assert) {
[
{
ID: 'HIT-id',
Name: 'name',
},
{
ID: 'id',
Name: 'name-HIT',
},
].forEach(function(item) {
const actual = filter(item, {
s: 'hit',
});
assert.ok(actual);
});
});
test('items are not found', function(assert) {
[
{
ID: 'id',
Name: 'name',
},
].forEach(function(item) {
const actual = filter(item, {
s: 'hit',
});
assert.notOk(actual);
});
});