mirror of https://github.com/status-im/consul.git
ui: Add Optgroups and selectedItems to multiple select dropdown and use (#8476)
* ui: Switch selects to use more HTML-like approach for optgroups * Add KV comparator * Use new option/optgroup approach for sort/select * Fix up tests for new order of menu items
This commit is contained in:
parent
7f711bb68f
commit
a686de0414
|
@ -27,7 +27,12 @@
|
||||||
</a>
|
</a>
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<button role="menuitem" tabindex="-1" type="button" onclick={{action this.onclick}}>
|
<button
|
||||||
|
type="button"
|
||||||
|
role="menuitem"
|
||||||
|
aria-selected={{if selected 'true'}}
|
||||||
|
tabindex="-1"
|
||||||
|
onclick={{action (or this.onclick (noop))}}>
|
||||||
<YieldSlot @name="label">
|
<YieldSlot @name="label">
|
||||||
{{yield}}
|
{{yield}}
|
||||||
</YieldSlot>
|
</YieldSlot>
|
||||||
|
|
|
@ -1,28 +1,31 @@
|
||||||
<div class="popover-select" ...attributes>
|
<PopoverMenu @position={{or position "left"}} class="popover-select" ...attributes as |components menu|>
|
||||||
<PopoverMenu as |components menu|>
|
{{yield}}
|
||||||
|
{{#let
|
||||||
|
(component 'popover-select/optgroup' components=components)
|
||||||
|
(component 'popover-select/option'
|
||||||
|
select=this components=components
|
||||||
|
onclick=(queue
|
||||||
|
(action "click")
|
||||||
|
(if multiple (noop) menu.toggle)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
as |Optgroup Option|
|
||||||
|
}}
|
||||||
<BlockSlot @name="trigger">
|
<BlockSlot @name="trigger">
|
||||||
<span>
|
<YieldSlot @name="selected">
|
||||||
{{selected.value}}
|
{{yield (hash
|
||||||
</span>
|
Optgroup=Optgroup
|
||||||
|
Option=Option
|
||||||
|
)}}
|
||||||
|
</YieldSlot>
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="menu">
|
<BlockSlot @name="menu">
|
||||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
<YieldSlot @name="options">
|
||||||
<MenuSeparator>
|
{{yield (hash
|
||||||
<BlockSlot @name="label">
|
Optgroup=Optgroup
|
||||||
{{title}}
|
Option=Option
|
||||||
</BlockSlot>
|
)}}
|
||||||
</MenuSeparator>
|
</YieldSlot>
|
||||||
{{#each options as |option|}}
|
|
||||||
<MenuItem
|
|
||||||
class={{if (eq selected.key option.key) 'is-active'}}
|
|
||||||
@onclick={{action (queue (action 'change' option) (if multiple (noop) menu.toggle))}}
|
|
||||||
>
|
|
||||||
<BlockSlot @name="label">
|
|
||||||
{{option.value}}
|
|
||||||
</BlockSlot>
|
|
||||||
</MenuItem>
|
|
||||||
{{/each}}
|
|
||||||
{{/let}}
|
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
|
{{/let}}
|
||||||
</PopoverMenu>
|
</PopoverMenu>
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,12 +1,53 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
import Slotted from 'block-slots';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend(Slotted, {
|
||||||
tagName: '',
|
tagName: '',
|
||||||
dom: service('dom'),
|
dom: service('dom'),
|
||||||
multiple: false,
|
multiple: false,
|
||||||
|
subtractive: true,
|
||||||
onchange: function() {},
|
onchange: function() {},
|
||||||
|
addOption: function(option) {
|
||||||
|
if (typeof this._options === 'undefined') {
|
||||||
|
this._options = new Set();
|
||||||
|
}
|
||||||
|
if (this.subtractive) {
|
||||||
|
if (!option.selected) {
|
||||||
|
this._options.add(option.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (option.selected) {
|
||||||
|
this._options.add(option.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeOption: function(option) {
|
||||||
|
this._options.delete(option.value);
|
||||||
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
click: function(e, value) {
|
||||||
|
let options = [value];
|
||||||
|
if (this.multiple) {
|
||||||
|
if (this._options.has(value)) {
|
||||||
|
this._options.delete(value);
|
||||||
|
} else {
|
||||||
|
this._options.add(value);
|
||||||
|
}
|
||||||
|
options = this._options;
|
||||||
|
}
|
||||||
|
this.onchange(
|
||||||
|
this.dom.setEventTargetProperties(e, {
|
||||||
|
selected: target => value,
|
||||||
|
selectedItems: target => {
|
||||||
|
const opts = [...options];
|
||||||
|
if (opts.length > 0) {
|
||||||
|
return opts.join(',');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
change: function(option, e) {
|
change: function(option, e) {
|
||||||
this.onchange(this.dom.setEventTargetProperty(e, 'selected', selected => option));
|
this.onchange(this.dom.setEventTargetProperty(e, 'selected', selected => option));
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{{#let components.MenuSeparator as |MenuSeparator|}}
|
||||||
|
<MenuSeparator>
|
||||||
|
<BlockSlot @name="label">
|
||||||
|
{{label}}
|
||||||
|
</BlockSlot>
|
||||||
|
</MenuSeparator>
|
||||||
|
{{yield}}
|
||||||
|
{{/let}}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
tagName: '',
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
{{#let components.MenuItem as |MenuItem|}}
|
||||||
|
<MenuItem
|
||||||
|
class={{if selected 'is-active'}}
|
||||||
|
@onclick={{action 'click'}}
|
||||||
|
@selected={{selected}}
|
||||||
|
>
|
||||||
|
<BlockSlot @name="label">
|
||||||
|
{{yield}}
|
||||||
|
</BlockSlot>
|
||||||
|
</MenuItem>
|
||||||
|
{{/let}}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import Component from '@ember/component';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
tagName: '',
|
||||||
|
dom: service('dom'),
|
||||||
|
didInsertElement: function() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.select.addOption(this);
|
||||||
|
},
|
||||||
|
willDestroyElement: function() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.select.removeOption(this);
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
click: function(e) {
|
||||||
|
this.onclick(e, this.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,24 +1,23 @@
|
||||||
{{yield}}
|
{{yield}}
|
||||||
<form class={{concat 'filter-bar' (if (eq secondary 'sort') ' with-sort')}} ...attributes>
|
<form class={{concat 'filter-bar' (if (eq secondary 'sort') ' with-sort')}} ...attributes>
|
||||||
<FreetextFilter
|
{{#yield-slot name="primary"}}
|
||||||
@onsearch={{action onsearch}}
|
<fieldset>
|
||||||
@value={{value}}
|
{{yield}}
|
||||||
@placeholder={{or placeholder 'Search'}}
|
</fieldset>
|
||||||
/>
|
{{else}}
|
||||||
|
<FreetextFilter
|
||||||
|
@onsearch={{action onsearch}}
|
||||||
|
@value={{value}}
|
||||||
|
@placeholder={{or placeholder 'Search'}}
|
||||||
|
/>
|
||||||
|
{{/yield-slot}}
|
||||||
{{#yield-slot name="secondary"}}
|
{{#yield-slot name="secondary"}}
|
||||||
{{yield}}
|
<fieldset>
|
||||||
|
{{yield}}
|
||||||
|
</fieldset>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if options}}
|
{{#if options}}
|
||||||
{{#if (eq secondary 'sort')}}
|
{{#if (eq secondary 'sort')}}
|
||||||
<fieldset>
|
|
||||||
<PopoverSelect
|
|
||||||
data-popover-select
|
|
||||||
@selected={{selected}}
|
|
||||||
@options={{options}}
|
|
||||||
@onchange={{action onchange}}
|
|
||||||
@title="Sort By"
|
|
||||||
/>
|
|
||||||
</fieldset>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
@keyboardAccess={{true}}
|
@keyboardAccess={{true}}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { alias } from '@ember/object/computed';
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
items: alias('item.Nodes'),
|
items: alias('item.Nodes'),
|
||||||
queryParams: {
|
queryParams: {
|
||||||
|
sortBy: 'sort',
|
||||||
search: {
|
search: {
|
||||||
as: 'filter',
|
as: 'filter',
|
||||||
replace: true,
|
replace: true,
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import Controller from '@ember/controller';
|
import Controller from '@ember/controller';
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
queryParams: {
|
queryParams: {
|
||||||
filterBy: {
|
sortBy: 'sort',
|
||||||
as: 'action',
|
|
||||||
},
|
|
||||||
search: {
|
search: {
|
||||||
as: 'filter',
|
as: 'filter',
|
||||||
replace: true,
|
replace: true,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import service from 'consul-ui/sort/comparators/service';
|
import service from 'consul-ui/sort/comparators/service';
|
||||||
|
import kv from 'consul-ui/sort/comparators/kv';
|
||||||
import check from 'consul-ui/sort/comparators/check';
|
import check from 'consul-ui/sort/comparators/check';
|
||||||
import intention from 'consul-ui/sort/comparators/intention';
|
import intention from 'consul-ui/sort/comparators/intention';
|
||||||
import token from 'consul-ui/sort/comparators/token';
|
import token from 'consul-ui/sort/comparators/token';
|
||||||
|
@ -11,6 +12,7 @@ export function initialize(container) {
|
||||||
const Sort = container.resolveRegistration('service:sort');
|
const Sort = container.resolveRegistration('service:sort');
|
||||||
const comparators = {
|
const comparators = {
|
||||||
service: service(),
|
service: service(),
|
||||||
|
kv: kv(),
|
||||||
check: check(),
|
check: check(),
|
||||||
intention: intention(),
|
intention: intention(),
|
||||||
token: token(),
|
token: token(),
|
||||||
|
|
|
@ -69,6 +69,24 @@ export default Service.extend({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setEventTargetProperties: function(e, propObj) {
|
||||||
|
const target = e.target;
|
||||||
|
return new Proxy(e, {
|
||||||
|
get: function(obj, prop, receiver) {
|
||||||
|
if (prop === 'target') {
|
||||||
|
return new Proxy(target, {
|
||||||
|
get: function(obj, prop, receiver) {
|
||||||
|
if (typeof propObj[prop] !== 'undefined') {
|
||||||
|
return propObj[prop](e.target);
|
||||||
|
}
|
||||||
|
return target[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Reflect.get(...arguments);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
listeners: createListeners,
|
listeners: createListeners,
|
||||||
root: function() {
|
root: function() {
|
||||||
return this.doc.documentElement;
|
return this.doc.documentElement;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default () => key => {
|
||||||
|
return key;
|
||||||
|
};
|
|
@ -5,7 +5,7 @@
|
||||||
border-bottom: $decor-border-200;
|
border-bottom: $decor-border-200;
|
||||||
}
|
}
|
||||||
%app-view-content h2,
|
%app-view-content h2,
|
||||||
%app-view-content fieldset {
|
%app-view-content form:not(.filter-bar) fieldset {
|
||||||
border-bottom: $decor-border-200;
|
border-bottom: $decor-border-200;
|
||||||
}
|
}
|
||||||
%app-view-content fieldset h2 {
|
%app-view-content fieldset h2 {
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
}
|
}
|
||||||
%app-view-title,
|
%app-view-title,
|
||||||
%app-view-content h2,
|
%app-view-content h2,
|
||||||
%app-view-content fieldset {
|
%app-view-content form:not(.filter-bar) fieldset {
|
||||||
border-color: $gray-200;
|
border-color: $gray-200;
|
||||||
}
|
}
|
||||||
// We know that any sibling navs might have a top border
|
// We know that any sibling navs might have a top border
|
||||||
|
|
|
@ -5,7 +5,6 @@ a.type-create {
|
||||||
// TODO: Once we move action-groups to use aria menu we can get rid of
|
// TODO: Once we move action-groups to use aria menu we can get rid of
|
||||||
// some of this and just use not(aria-haspopup)
|
// some of this and just use not(aria-haspopup)
|
||||||
button[type='reset'],
|
button[type='reset'],
|
||||||
%app-view-content form button[type='button']:not([aria-haspopup='menu']),
|
|
||||||
header .actions button[type='button']:not(.copy-btn),
|
header .actions button[type='button']:not(.copy-btn),
|
||||||
button.type-cancel,
|
button.type-cancel,
|
||||||
html.template-error div > a {
|
html.template-error div > a {
|
||||||
|
|
|
@ -4,14 +4,7 @@
|
||||||
{{title 'Access Controls'}}
|
{{title 'Access Controls'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#let (selectable-key-values
|
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||||
(array "Name:asc" "A to Z")
|
|
||||||
(array "Name:desc" "Z to A")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
|
|
||||||
<AppView
|
<AppView
|
||||||
@class="policy list"
|
@class="policy list"
|
||||||
@loading={{isLoading}}
|
@loading={{isLoading}}
|
||||||
|
@ -45,15 +38,41 @@
|
||||||
<SearchBar
|
<SearchBar
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@secondary="sort"
|
class="with-sort"
|
||||||
@selected={{sort.selected}}
|
>
|
||||||
@options={{sort.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Name:asc" "A to Z")
|
||||||
|
(array "Name:desc" "Z to A")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Name">
|
||||||
|
<Option @value="Name:asc" @selected={{eq "Name:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="Name:desc" @selected={{eq "Name:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#let (sort-by (comparator 'policy' sort.selected.key) items) as |sorted|}}
|
{{#let (sort-by (comparator 'policy' sort) items) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'policy' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'policy' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="set" as |filtered|>
|
<BlockSlot @name="set" as |filtered|>
|
||||||
<ConsulPolicyList
|
<ConsulPolicyList
|
||||||
|
|
|
@ -4,16 +4,7 @@
|
||||||
{{title 'Access Controls'}}
|
{{title 'Access Controls'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#let (selectable-key-values
|
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||||
(array "Name:asc" "A to Z")
|
|
||||||
(array "Name:desc" "Z to A")
|
|
||||||
(array "CreateIndex:asc" "Newest to oldest")
|
|
||||||
(array "CreateIndex:desc" "Oldest to newest")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
|
|
||||||
<AppView
|
<AppView
|
||||||
@class="role list"
|
@class="role list"
|
||||||
@loading={{isLoading}}
|
@loading={{isLoading}}
|
||||||
|
@ -47,15 +38,47 @@
|
||||||
<SearchBar
|
<SearchBar
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@secondary="sort"
|
class="with-sort"
|
||||||
@selected={{sort.selected}}
|
>
|
||||||
@options={{sort.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Name:asc" "A to Z")
|
||||||
|
(array "Name:desc" "Z to A")
|
||||||
|
(array "CreateIndex:desc" "Newest to oldest")
|
||||||
|
(array "CreateIndex:asc" "Oldest to newest")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Name">
|
||||||
|
<Option @value="Name:asc" @selected={{eq "Name:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="Name:desc" @selected={{eq "Name:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Creation">
|
||||||
|
<Option @value="CreateIndex:desc" @selected={{eq "CreateIndex:desc" sort}}>Newest to oldest</Option>
|
||||||
|
<Option @value="CreateIndex:asc" @selected={{eq "CreateIndex:asc" sort}}>Oldest to newest</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#let (sort-by (comparator 'role' sort.selected.key) items) as |sorted|}}
|
{{#let (sort-by (comparator 'role' sort) items) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'role' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'role' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="set" as |filtered|>
|
<BlockSlot @name="set" as |filtered|>
|
||||||
<ConsulRoleList
|
<ConsulRoleList
|
||||||
|
|
|
@ -4,13 +4,7 @@
|
||||||
{{title 'Access Controls'}}
|
{{title 'Access Controls'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#let (selectable-key-values
|
{{#let (or sortBy "CreateTime:desc") as |sort|}}
|
||||||
(array "CreateTime:desc" "Newest to oldest")
|
|
||||||
(array "CreateTime:asc" "Oldest to newest")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
<AppView
|
<AppView
|
||||||
@class="token list"
|
@class="token list"
|
||||||
@loading={{isLoading}}
|
@loading={{isLoading}}
|
||||||
|
@ -41,22 +35,47 @@
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="toolbar">
|
<BlockSlot @name="toolbar">
|
||||||
{{#if (gt items.length 0)}}
|
{{#if (gt items.length 0)}}
|
||||||
<SearchBar
|
<SearchBar
|
||||||
data-test-intention-filter="true"
|
@value={{search}}
|
||||||
@value={{search}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
class="with-sort"
|
||||||
@secondary="sort"
|
>
|
||||||
@selected={{sort.selected}}
|
<BlockSlot @name="secondary">
|
||||||
@options={{sort.items}}
|
<PopoverSelect
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
@position="right"
|
||||||
/>
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "CreateTime:desc" "Newest to oldest")
|
||||||
|
(array "CreateTime:asc" "Oldest to newest")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Creation">
|
||||||
|
<Option @value="CreateTime:desc" @selected={{eq "CreateTime:desc" sort}}>Newest to oldest</Option>
|
||||||
|
<Option @value="CreateTime:asc" @selected={{eq "CreateTime:asc" sort}}>Oldest to newest</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#if (token/is-legacy items)}}
|
{{#if (token/is-legacy items)}}
|
||||||
<p data-test-notification-update class="notice info"><strong>Update.</strong> We have upgraded our ACL System to allow the creation of reusable policies that can be applied to tokens. Read more about the changes and how to upgrade legacy tokens in our <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl-migrate-tokens.html" target="_blank" rel="noopener noreferrer">documentation</a>.</p>
|
<p data-test-notification-update class="notice info"><strong>Update.</strong> We have upgraded our ACL System to allow the creation of reusable policies that can be applied to tokens. Read more about the changes and how to upgrade legacy tokens in our <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl-migrate-tokens.html" target="_blank" rel="noopener noreferrer">documentation</a>.</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#let (sort-by (comparator 'token' sort.selected.key) items) as |sorted|}}
|
{{#let (sort-by (comparator 'token' sort) items) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'token' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'token' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="set" as |filtered|>
|
<BlockSlot @name="set" as |filtered|>
|
||||||
<ConsulTokenList
|
<ConsulTokenList
|
||||||
|
|
|
@ -6,21 +6,7 @@
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
|
|
||||||
<BlockSlot @name="loaded">
|
<BlockSlot @name="loaded">
|
||||||
|
{{#let (or sortBy "Action:asc") as |sort|}}
|
||||||
{{#let (selectable-key-values
|
|
||||||
(array "Action:asc" "Allow to Deny")
|
|
||||||
(array "Action:desc" "Deny to Allow")
|
|
||||||
(array "SourceName:asc" "Source: A to Z")
|
|
||||||
(array "SourceName:desc" "Source: Z to A")
|
|
||||||
(array "DestinationName:asc" "Destination: A to Z")
|
|
||||||
(array "DestinationName:desc" "Destination: Z to A")
|
|
||||||
(array "Precedence:asc" "Precedence: Asc")
|
|
||||||
(array "Precedence:desc" "Precedence: Desc")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
|
|
||||||
<AppView @class="intention list">
|
<AppView @class="intention list">
|
||||||
<BlockSlot @name="header">
|
<BlockSlot @name="header">
|
||||||
<h1>
|
<h1>
|
||||||
|
@ -34,18 +20,61 @@
|
||||||
<BlockSlot @name="toolbar">
|
<BlockSlot @name="toolbar">
|
||||||
{{#if (gt api.data.length 0) }}
|
{{#if (gt api.data.length 0) }}
|
||||||
<SearchBar
|
<SearchBar
|
||||||
data-test-intention-filter="true"
|
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@secondary="sort"
|
class="with-sort"
|
||||||
@selected={{sort.selected}}
|
>
|
||||||
@options={{sort.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Action:asc" "Allow to Deny")
|
||||||
|
(array "Action:desc" "Deny to Allow")
|
||||||
|
(array "SourceName:asc" "Source: A to Z")
|
||||||
|
(array "SourceName:desc" "Source: Z to A")
|
||||||
|
(array "DestinationName:asc" "Destination: A to Z")
|
||||||
|
(array "DestinationName:desc" "Destination: Z to A")
|
||||||
|
(array "Precedence:asc" "Precedence: Ascending")
|
||||||
|
(array "Precedence:desc" "Precedence: Descending")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Permission">
|
||||||
|
<Option @value="Action:asc" @selected={{eq "Action:asc" sort}}>Allow to Deny</Option>
|
||||||
|
<Option @value="Action:desc" @selected={{eq "Action:desc" sort}}>Deny to Allow</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Source">
|
||||||
|
<Option @value="SourceName:asc" @selected={{eq "SourceName:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="SourceName:desc" @selected={{eq "SourceName:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Destination">
|
||||||
|
<Option @value="DestinationName:asc" @selected={{eq "DestinationName:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="DestinationName:desc" @selected={{eq "DestinationName:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Precedence">
|
||||||
|
<Option @value="Precedence:asc" @selected={{eq "Precedence:asc" sort}}>Ascending</Option>
|
||||||
|
<Option @value="Precedence:desc" @selected={{eq "Precedence:desc" sort}}>Descending</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#let (sort-by (comparator 'intention' sort.selected.key) api.data) as |sorted|}}
|
{{#let (sort-by (comparator 'intention' sort) api.data) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="content" as |filtered|>
|
<BlockSlot @name="content" as |filtered|>
|
||||||
<ConsulIntentionList
|
<ConsulIntentionList
|
||||||
|
|
|
@ -1,79 +1,118 @@
|
||||||
{{title 'Key/Value'}}
|
{{title 'Key/Value'}}
|
||||||
<AppView @class="kv list">
|
{{#let (or sortBy "isFolder:asc") as |sort|}}
|
||||||
<BlockSlot @name="breadcrumbs">
|
<AppView @class="kv list">
|
||||||
<ol>
|
<BlockSlot @name="breadcrumbs">
|
||||||
{{#if (not-eq parent.Key '/') }}
|
<ol>
|
||||||
<li><a href={{href-to 'dc.kv'}}>Key / Values</a></li>
|
{{#if (not-eq parent.Key '/') }}
|
||||||
{{/if}}
|
<li><a href={{href-to 'dc.kv'}}>Key / Values</a></li>
|
||||||
{{#each (slice 0 -2 (split parent.Key '/')) as |breadcrumb index|}}
|
{{/if}}
|
||||||
<li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li>
|
{{#each (slice 0 -2 (split parent.Key '/')) as |breadcrumb index|}}
|
||||||
{{/each}}
|
<li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li>
|
||||||
</ol>
|
{{/each}}
|
||||||
</BlockSlot>
|
</ol>
|
||||||
<BlockSlot @name="header">
|
</BlockSlot>
|
||||||
<h1>
|
<BlockSlot @name="header">
|
||||||
{{#if (eq parent.Key '/')}}
|
<h1>
|
||||||
Key / Value
|
{{#if (eq parent.Key '/')}}
|
||||||
{{else}}
|
Key / Value
|
||||||
{{take 1 (drop 1 (reverse (split parent.Key '/')))}}
|
{{else}}
|
||||||
{{/if}}
|
{{take 1 (drop 1 (reverse (split parent.Key '/')))}}
|
||||||
</h1>
|
{{/if}}
|
||||||
<label for="toolbar-toggle"></label>
|
</h1>
|
||||||
</BlockSlot>
|
<label for="toolbar-toggle"></label>
|
||||||
<BlockSlot @name="toolbar">
|
</BlockSlot>
|
||||||
{{#if (gt items.length 0) }}
|
<BlockSlot @name="toolbar">
|
||||||
<SearchBar
|
{{#if (gt items.length 0) }}
|
||||||
@placeholder="Search by name"
|
<SearchBar
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
/>
|
class="with-sort"
|
||||||
{{/if}}
|
>
|
||||||
</BlockSlot>
|
<BlockSlot @name="secondary">
|
||||||
<BlockSlot @name="actions">
|
<PopoverSelect
|
||||||
{{#if (not-eq parent.Key '/') }}
|
@position="right"
|
||||||
<a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
{{else}}
|
@multiple={{false}}
|
||||||
<a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
|
as |components|>
|
||||||
{{/if}}
|
<BlockSlot @name="selected">
|
||||||
</BlockSlot>
|
<span>
|
||||||
<BlockSlot @name="content">
|
{{#let (from-entries (array
|
||||||
<ChangeableSet @dispatcher={{searchable 'kv' items}} @terms={{search}}>
|
(array "Key:asc" "A to Z")
|
||||||
<BlockSlot @name="content" as |filtered|>
|
(array "Key:desc" "Z to A")
|
||||||
<ConsulKvList
|
(array "isFolder:desc" "Folders to Keys")
|
||||||
@items={{sort-by "isFolder:desc" "Key:asc" filtered}}
|
(array "isFolder:asc" "Keys to Folders")
|
||||||
@parent={{parent}}
|
))
|
||||||
@ondelete={{refresh-route}}
|
as |selectable|
|
||||||
>
|
}}
|
||||||
<EmptyState @allowLogin={{true}}>
|
{{get selectable sort}}
|
||||||
<BlockSlot @name="header">
|
{{/let}}
|
||||||
<h2>
|
</span>
|
||||||
{{#if (gt items.length 0)}}
|
|
||||||
No K/V pairs found
|
|
||||||
{{else}}
|
|
||||||
Welcome to Key/Value
|
|
||||||
{{/if}}
|
|
||||||
</h2>
|
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="body">
|
<BlockSlot @name="options">
|
||||||
<p>
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
{{#if (gt items.length 0)}}
|
<Optgroup @label="Name">
|
||||||
No K/V pairs where found matching that search, or you may not have access to view the K/V pairs you are searching for.
|
<Option @value="Key:asc" @selected={{eq "Key:asc" sort}}>A to Z</Option>
|
||||||
{{else}}
|
<Option @value="Key:desc" @selected={{eq "Key:desc" sort}}>Z to A</Option>
|
||||||
You don't have any K/V pairs, or you may not have access to view K/V pairs yet.
|
</Optgroup>
|
||||||
{{/if}}
|
<Optgroup @label="Type">
|
||||||
</p>
|
<Option @value="isFolder:desc" @selected={{eq "isFolder:desc" sort}}>Folders to Keys</Option>
|
||||||
|
<Option @value="isFolder:asc" @selected={{eq "isFolder:asc" sort}}>Keys to Folders</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="actions">
|
</PopoverSelect>
|
||||||
<li class="docs-link">
|
</BlockSlot>
|
||||||
<a href="{{env 'CONSUL_DOCS_URL'}}/agent/kv" rel="noopener noreferrer" target="_blank">Documentation on K/V</a>
|
</SearchBar>
|
||||||
</li>
|
{{/if}}
|
||||||
<li class="learn-link">
|
</BlockSlot>
|
||||||
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/kv" rel="noopener noreferrer" target="_blank">Read the guide</a>
|
<BlockSlot @name="actions">
|
||||||
</li>
|
{{#if (not-eq parent.Key '/') }}
|
||||||
</BlockSlot>
|
<a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
|
||||||
</EmptyState>
|
{{else}}
|
||||||
</ConsulKvList>
|
<a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
|
||||||
</BlockSlot>
|
{{/if}}
|
||||||
</ChangeableSet>
|
</BlockSlot>
|
||||||
</BlockSlot>
|
<BlockSlot @name="content">
|
||||||
</AppView>
|
{{#let (sort-by (comparator 'kv' sort) items) as |sorted|}}
|
||||||
|
<ChangeableSet @dispatcher={{searchable 'kv' sorted}} @terms={{search}}>
|
||||||
|
<BlockSlot @name="content" as |filtered|>
|
||||||
|
<ConsulKvList
|
||||||
|
@items={{filtered}}
|
||||||
|
@parent={{parent}}
|
||||||
|
@ondelete={{refresh-route}}
|
||||||
|
>
|
||||||
|
<EmptyState @allowLogin={{true}}>
|
||||||
|
<BlockSlot @name="header">
|
||||||
|
<h2>
|
||||||
|
{{#if (gt items.length 0)}}
|
||||||
|
No K/V pairs found
|
||||||
|
{{else}}
|
||||||
|
Welcome to Key/Value
|
||||||
|
{{/if}}
|
||||||
|
</h2>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="body">
|
||||||
|
<p>
|
||||||
|
{{#if (gt items.length 0)}}
|
||||||
|
No K/V pairs where found matching that search, or you may not have access to view the K/V pairs you are searching for.
|
||||||
|
{{else}}
|
||||||
|
You don't have any K/V pairs, or you may not have access to view K/V pairs yet.
|
||||||
|
{{/if}}
|
||||||
|
</p>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="actions">
|
||||||
|
<li class="docs-link">
|
||||||
|
<a href="{{env 'CONSUL_DOCS_URL'}}/agent/kv" rel="noopener noreferrer" target="_blank">Documentation on K/V</a>
|
||||||
|
</li>
|
||||||
|
<li class="learn-link">
|
||||||
|
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/kv" rel="noopener noreferrer" target="_blank">Read the guide</a>
|
||||||
|
</li>
|
||||||
|
</BlockSlot>
|
||||||
|
</EmptyState>
|
||||||
|
</ConsulKvList>
|
||||||
|
</BlockSlot>
|
||||||
|
</ChangeableSet>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</AppView>
|
||||||
|
{{/let}}
|
|
@ -1,11 +1,5 @@
|
||||||
{{title 'Namespaces'}}
|
{{title 'Namespaces'}}
|
||||||
{{#let (selectable-key-values
|
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||||
(array "Name:asc" "A to Z")
|
|
||||||
(array "Name:desc" "Z to A")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
<EventSource @src={{items}} />
|
<EventSource @src={{items}} />
|
||||||
<AppView @class="nspace list" @loading={{isLoading}}>
|
<AppView @class="nspace list" @loading={{isLoading}}>
|
||||||
<BlockSlot @name="notification" as |status type subject|>
|
<BlockSlot @name="notification" as |status type subject|>
|
||||||
|
@ -21,18 +15,44 @@
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="toolbar">
|
<BlockSlot @name="toolbar">
|
||||||
{{#if (gt items.length 0)}}
|
{{#if (gt items.length 0)}}
|
||||||
<SearchBar
|
<SearchBar
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@secondary="sort"
|
class="with-sort"
|
||||||
@selected={{sort.selected}}
|
>
|
||||||
@options={{sort.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Name:asc" "A to Z")
|
||||||
|
(array "Name:desc" "Z to A")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Name">
|
||||||
|
<Option @value="Name:asc" @selected={{eq "Name:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="Name:desc" @selected={{eq "Name:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#let (sort-by (comparator 'nspace' sort.selected.key) items) as |sorted|}}
|
{{#let (sort-by (comparator 'nspace' sort) items) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'nspace' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'nspace' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="set" as |filtered|>
|
<BlockSlot @name="set" as |filtered|>
|
||||||
<ConsulNspaceList
|
<ConsulNspaceList
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
{{title 'Services'}}
|
{{title 'Services'}}
|
||||||
<EventSource @src={{items}} />
|
<EventSource @src={{items}} />
|
||||||
{{#let (selectable-key-values
|
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||||
(array "Name:asc" "A to Z")
|
|
||||||
(array "Name:desc" "Z to A")
|
|
||||||
(array "Status:asc" "Unhealthy to Healthy")
|
|
||||||
(array "Status:desc" "Healthy to Unhealthy")
|
|
||||||
selected=sortBy
|
|
||||||
)
|
|
||||||
as |sort|
|
|
||||||
}}
|
|
||||||
<AppView @class="service list">
|
<AppView @class="service list">
|
||||||
<BlockSlot @name="notification" as |status type|>
|
<BlockSlot @name="notification" as |status type|>
|
||||||
{{partial 'dc/services/notifications'}}
|
{{partial 'dc/services/notifications'}}
|
||||||
|
@ -24,15 +16,47 @@
|
||||||
<SearchBar
|
<SearchBar
|
||||||
@value={{search}}
|
@value={{search}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@secondary="sort"
|
class="with-sort"
|
||||||
@selected={{sort.selected}}
|
>
|
||||||
@options={{sort.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut sortBy) value='target.selected.key'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Name:asc" "A to Z")
|
||||||
|
(array "Name:desc" "Z to A")
|
||||||
|
(array "Status:asc" "Unhealthy to Healthy")
|
||||||
|
(array "Status:desc" "Healthy to Unhealthy")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Health Status">
|
||||||
|
<Option @value="Status:asc" @selected={{eq "Status:asc" sort}}>Unhealthy to Healthy</Option>
|
||||||
|
<Option @value="Status:desc" @selected={{eq "Status:desc" sort}}>Healthy to Unhealthy</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Service Name">
|
||||||
|
<Option @value="Name:asc" @selected={{eq "Name:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="Name:desc" @selected={{eq "Name:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="content">
|
<BlockSlot @name="content">
|
||||||
{{#let (sort-by (comparator 'service' sort.selected.key) services) as |sorted|}}
|
{{#let (sort-by (comparator 'service' sort) services) as |sorted|}}
|
||||||
<ChangeableSet @dispatcher={{searchable 'service' sorted}} @terms={{search}}>
|
<ChangeableSet @dispatcher={{searchable 'service' sorted}} @terms={{search}}>
|
||||||
<BlockSlot @name="set" as |filtered|>
|
<BlockSlot @name="set" as |filtered|>
|
||||||
<ConsulServiceList @items={{filtered}} @proxies={{proxies}}/>
|
<ConsulServiceList @items={{filtered}} @proxies={{proxies}}/>
|
||||||
|
|
|
@ -3,38 +3,68 @@
|
||||||
<ErrorState @error={{api.error}} />
|
<ErrorState @error={{api.error}} />
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
<BlockSlot @name="loaded">
|
<BlockSlot @name="loaded">
|
||||||
{{#let (filter-by "Action" "deny" api.data) as |denied|}}
|
{{#let (or sortBy "Action:asc") as |sort|}}
|
||||||
{{#let (selectable-key-values
|
|
||||||
(array "" (concat "All (" api.data.length ")"))
|
|
||||||
(array "allow" (concat "Allow (" (sub api.data.length denied.length) ")"))
|
|
||||||
(array "deny" (concat "Deny (" denied.length ")"))
|
|
||||||
selected=filterBy
|
|
||||||
)
|
|
||||||
as |filter|
|
|
||||||
}}
|
|
||||||
<div id="intentions" class="tab-section">
|
<div id="intentions" class="tab-section">
|
||||||
<div role="tabpanel">
|
<div role="tabpanel">
|
||||||
<Portal @target="app-view-actions">
|
<Portal @target="app-view-actions">
|
||||||
<a data-test-create href={{href-to 'dc.services.show.intentions.create'}} class="type-create">Create</a>
|
<a data-test-create href={{href-to 'dc.services.show.intentions.create'}} class="type-create">Create</a>
|
||||||
</Portal>
|
</Portal>
|
||||||
{{#if (gt api.data.length 0) }}
|
{{#if (gt api.data.length 0) }}
|
||||||
<input type="checkbox" id="toolbar-toggle" />
|
<SearchBar
|
||||||
<SearchBar
|
@value={{search}}
|
||||||
@value={{search}}
|
@onsearch={{action (mut search) value="target.value"}}
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
class="with-sort"
|
||||||
@selected={{filter.selected}}
|
>
|
||||||
@options={{filter.items}}
|
<BlockSlot @name="secondary">
|
||||||
@onchange={{action (mut filterBy) value='target.value'}}
|
<PopoverSelect
|
||||||
/>
|
@position="right"
|
||||||
|
@onchange={{action (mut sortBy) value='target.selected'}}
|
||||||
|
@multiple={{false}}
|
||||||
|
as |components|>
|
||||||
|
<BlockSlot @name="selected">
|
||||||
|
<span>
|
||||||
|
{{#let (from-entries (array
|
||||||
|
(array "Action:asc" "Allow to Deny")
|
||||||
|
(array "Action:desc" "Deny to Allow")
|
||||||
|
(array "SourceName:asc" "Source: A to Z")
|
||||||
|
(array "SourceName:desc" "Source: Z to A")
|
||||||
|
(array "DestinationName:asc" "Destination: A to Z")
|
||||||
|
(array "DestinationName:desc" "Destination: Z to A")
|
||||||
|
(array "Precedence:asc" "Precedence: Ascending")
|
||||||
|
(array "Precedence:desc" "Precedence: Descending")
|
||||||
|
))
|
||||||
|
as |selectable|
|
||||||
|
}}
|
||||||
|
{{get selectable sort}}
|
||||||
|
{{/let}}
|
||||||
|
</span>
|
||||||
|
</BlockSlot>
|
||||||
|
<BlockSlot @name="options">
|
||||||
|
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||||
|
<Optgroup @label="Permission">
|
||||||
|
<Option @value="Action:asc" @selected={{eq "Action:asc" sort}}>Allow to Deny</Option>
|
||||||
|
<Option @value="Action:desc" @selected={{eq "Action:desc" sort}}>Deny to Allow</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Source">
|
||||||
|
<Option @value="SourceName:asc" @selected={{eq "SourceName:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="SourceName:desc" @selected={{eq "SourceName:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Destination">
|
||||||
|
<Option @value="DestinationName:asc" @selected={{eq "DestinationName:asc" sort}}>A to Z</Option>
|
||||||
|
<Option @value="DestinationName:desc" @selected={{eq "DestinationName:desc" sort}}>Z to A</Option>
|
||||||
|
</Optgroup>
|
||||||
|
<Optgroup @label="Precedence">
|
||||||
|
<Option @value="Precedence:asc" @selected={{eq "Precedence:asc" sort}}>Ascending</Option>
|
||||||
|
<Option @value="Precedence:desc" @selected={{eq "Precedence:desc" sort}}>Descending</Option>
|
||||||
|
</Optgroup>
|
||||||
|
{{/let}}
|
||||||
|
</BlockSlot>
|
||||||
|
</PopoverSelect>
|
||||||
|
</BlockSlot>
|
||||||
|
</SearchBar>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<ChangeableSet
|
{{#let (sort-by (comparator 'intention' sort) api.data) as |sorted|}}
|
||||||
@dispatcher={{
|
<ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}>
|
||||||
searchable
|
|
||||||
'intention'
|
|
||||||
(if (eq filter.selected.key "") api.data (filter-by "Action" filter.selected.key api.data))
|
|
||||||
}}
|
|
||||||
@terms={{search}}
|
|
||||||
>
|
|
||||||
<BlockSlot @name="content" as |filtered|>
|
<BlockSlot @name="content" as |filtered|>
|
||||||
<ConsulIntentionList
|
<ConsulIntentionList
|
||||||
@items={{filtered}}
|
@items={{filtered}}
|
||||||
|
@ -51,9 +81,9 @@
|
||||||
</ConsulIntentionList>
|
</ConsulIntentionList>
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
</ChangeableSet>
|
</ChangeableSet>
|
||||||
|
{{/let}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/let}}
|
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / roles / sorting
|
Feature: dc / acls / roles / sorting
|
||||||
Scenario: Sorting Roles
|
Scenario: Sorting Roles
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 4 role models from yaml
|
And 4 role models from yaml
|
||||||
---
|
---
|
||||||
- Name: "system-A"
|
- Name: "system-A"
|
||||||
CreateIndex: 3
|
CreateIndex: 3
|
||||||
- Name: "system-D"
|
- Name: "system-D"
|
||||||
CreateIndex: 2
|
CreateIndex: 2
|
||||||
- Name: "system-C"
|
- Name: "system-C"
|
||||||
CreateIndex: 1
|
CreateIndex: 1
|
||||||
- Name: "system-B"
|
- Name: "system-B"
|
||||||
CreateIndex: 4
|
CreateIndex: 4
|
||||||
---
|
---
|
||||||
When I visit the roles page for yaml
|
When I visit the roles page for yaml
|
||||||
---
|
---
|
||||||
dc: dc-1
|
dc: dc-1
|
||||||
---
|
---
|
||||||
Then the url should be /dc-1/acls/roles
|
Then the url should be /dc-1/acls/roles
|
||||||
Then I see 4 role models
|
Then I see 4 role models
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.1.button on the sort
|
When I click options.1.button on the sort
|
||||||
Then I see name on the roles vertically like yaml
|
Then I see name on the roles vertically like yaml
|
||||||
---
|
---
|
||||||
- "system-D"
|
- "system-D"
|
||||||
- "system-C"
|
- "system-C"
|
||||||
- "system-B"
|
- "system-B"
|
||||||
- "system-A"
|
- "system-A"
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.0.button on the sort
|
When I click options.0.button on the sort
|
||||||
Then I see name on the roles vertically like yaml
|
Then I see name on the roles vertically like yaml
|
||||||
---
|
---
|
||||||
- "system-A"
|
- "system-A"
|
||||||
- "system-B"
|
- "system-B"
|
||||||
- "system-C"
|
- "system-C"
|
||||||
- "system-D"
|
- "system-D"
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.2.button on the sort
|
When I click options.3.button on the sort
|
||||||
Then I see name on the roles vertically like yaml
|
Then I see name on the roles vertically like yaml
|
||||||
---
|
---
|
||||||
- "system-C"
|
- "system-C"
|
||||||
- "system-D"
|
- "system-D"
|
||||||
- "system-A"
|
- "system-A"
|
||||||
- "system-B"
|
- "system-B"
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.3.button on the sort
|
When I click options.2.button on the sort
|
||||||
Then I see name on the roles vertically like yaml
|
Then I see name on the roles vertically like yaml
|
||||||
---
|
---
|
||||||
- "system-B"
|
- "system-B"
|
||||||
- "system-A"
|
- "system-A"
|
||||||
- "system-D"
|
- "system-D"
|
||||||
- "system-C"
|
- "system-C"
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / services / intentions: Intentions per service
|
Feature: dc / services / show / intentions: Intentions per service
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "dc1"
|
Given 1 datacenter model with the value "dc1"
|
||||||
And 1 node models
|
And 1 node models
|
||||||
|
@ -26,6 +26,6 @@ Feature: dc / services / intentions: Intentions per service
|
||||||
And I click actions on the intentions
|
And I click actions on the intentions
|
||||||
And I click delete on the intentions
|
And I click delete on the intentions
|
||||||
And I click confirmDelete on the intentions
|
And I click confirmDelete on the intentions
|
||||||
Then a DELETE request was made to "/v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc1"
|
Then a DELETE request was made to "/v1/connect/intentions/755b72bd-f5ab-4c92-90cc-bed0e7d8e9f0?dc=dc1"
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
|
|
|
@ -40,7 +40,7 @@ Feature: dc / services / sorting
|
||||||
dc: dc-1
|
dc: dc-1
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.1.button on the sort
|
When I click options.3.button on the sort
|
||||||
Then I see name on the services vertically like yaml
|
Then I see name on the services vertically like yaml
|
||||||
---
|
---
|
||||||
- Service-F
|
- Service-F
|
||||||
|
@ -51,20 +51,20 @@ Feature: dc / services / sorting
|
||||||
- Service-A
|
- Service-A
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.0.button on the sort
|
|
||||||
Then I see name on the services vertically like yaml
|
|
||||||
---
|
|
||||||
- Service-A
|
|
||||||
- Service-B
|
|
||||||
- Service-C
|
|
||||||
- Service-D
|
|
||||||
- Service-E
|
|
||||||
- Service-F
|
|
||||||
---
|
|
||||||
When I click selected on the sort
|
|
||||||
When I click options.2.button on the sort
|
When I click options.2.button on the sort
|
||||||
Then I see name on the services vertically like yaml
|
Then I see name on the services vertically like yaml
|
||||||
---
|
---
|
||||||
|
- Service-A
|
||||||
|
- Service-B
|
||||||
|
- Service-C
|
||||||
|
- Service-D
|
||||||
|
- Service-E
|
||||||
|
- Service-F
|
||||||
|
---
|
||||||
|
When I click selected on the sort
|
||||||
|
When I click options.0.button on the sort
|
||||||
|
Then I see name on the services vertically like yaml
|
||||||
|
---
|
||||||
- Service-B
|
- Service-B
|
||||||
- Service-C
|
- Service-C
|
||||||
- Service-A
|
- Service-A
|
||||||
|
@ -73,7 +73,7 @@ Feature: dc / services / sorting
|
||||||
- Service-E
|
- Service-E
|
||||||
---
|
---
|
||||||
When I click selected on the sort
|
When I click selected on the sort
|
||||||
When I click options.3.button on the sort
|
When I click options.1.button on the sort
|
||||||
Then I see name on the services vertically like yaml
|
Then I see name on the services vertically like yaml
|
||||||
---
|
---
|
||||||
- Service-E
|
- Service-E
|
||||||
|
|
Loading…
Reference in New Issue