mirror of https://github.com/hashicorp/consul
UI: Move legacy ACLs to use the new searchables/changeable-sets (#4933)
parent
c532e53d9a
commit
104e6bac71
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
);
|
||||
});
|
||||
}
|
|
@ -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>}}
|
||||
|
|
|
@ -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}}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue