ui: Add 'Search Across' for finer grained searching (#9282)
This commit is contained in:
parent
91d5d6c586
commit
7d8ea08da7
|
@ -0,0 +1,122 @@
|
|||
<div
|
||||
class="consul-acl-list"
|
||||
...attributes
|
||||
>
|
||||
<TabularCollection
|
||||
@items={{@items}}
|
||||
as |item index|
|
||||
>
|
||||
<BlockSlot @name="header">
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="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>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions" as |index change checked|>
|
||||
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}} @submenus={{array "logout" "use" "delete"}}>
|
||||
<BlockSlot @name="trigger">
|
||||
More
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu" as |confirm send keypressClick|>
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (eq item.ID token.SecretID) }}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Stop using</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm logout
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" onclick={{action send 'logout' item}}>Logout</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{else}}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm use
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to use this ACL token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button
|
||||
{{on 'click' (fn @onuse item)}}
|
||||
data-test-confirm-use
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
Use
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li role="none">
|
||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action @onclone item}}>Duplicate</button>
|
||||
</li>
|
||||
{{# if (not-eq item.ID 'anonymous') }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'delete'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm Delete
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to delete this token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action @ondelete item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</BlockSlot>
|
||||
</TabularCollection>
|
||||
</div>
|
|
@ -0,0 +1,59 @@
|
|||
<form
|
||||
class="consul-acl-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action @onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Type
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="management" @selected={{contains 'management' @filter.kinds}}>Management</Option>
|
||||
<Option @value="client" @selected={{contains 'service' @filter.kinds}}>Client</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</div>
|
||||
<div class="sort">
|
||||
<PopoverSelect
|
||||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action @onsort}}
|
||||
@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|}}
|
||||
<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>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</div>
|
||||
</form>
|
|
@ -3,15 +3,8 @@
|
|||
...attributes
|
||||
{{did-update this.updateCRDManagement @items}}
|
||||
>
|
||||
<DataWriter
|
||||
@sink={{concat '/' @dc '/' @nspace '/intention/'}}
|
||||
@type="intention"
|
||||
@ondelete={{action @ondelete}}
|
||||
as |writer|>
|
||||
<BlockSlot @name="content">
|
||||
|
||||
{{#let (hash
|
||||
Table=(component 'consul/intention/list/table' delete=writer.delete items=this.items)
|
||||
{{yield (hash
|
||||
Table=(component 'consul/intention/list/table' delete=@delete items=this.items)
|
||||
CheckNotice=(if this.checkedItem
|
||||
(component 'consul/intention/list/check' item=this.checkedItem)
|
||||
''
|
||||
|
@ -20,15 +13,5 @@
|
|||
(component 'consul/intention/notice/custom-resource')
|
||||
''
|
||||
)
|
||||
) as |api|}}
|
||||
|
||||
{{#if (gt this.items.length 0)}}
|
||||
{{yield api to="idle"}}
|
||||
{{else}}
|
||||
{{yield api to="empty"}}
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
|
||||
</BlockSlot>
|
||||
</DataWriter>
|
||||
)}}
|
||||
</div>
|
|
@ -5,13 +5,8 @@ import { tracked } from '@glimmer/tracking';
|
|||
import { sort } from '@ember/object/computed';
|
||||
|
||||
export default class ConsulIntentionList extends Component {
|
||||
@service('filter') filter;
|
||||
@service('sort') sort;
|
||||
@service('search') search;
|
||||
@service('repository/intention') repo;
|
||||
|
||||
@sort('searched', 'comparator') sorted;
|
||||
|
||||
@tracked isManagedByCRDs;
|
||||
|
||||
constructor(owner, args) {
|
||||
|
@ -19,25 +14,11 @@ export default class ConsulIntentionList extends Component {
|
|||
this.updateCRDManagement(args.items);
|
||||
}
|
||||
get items() {
|
||||
return this.sorted;
|
||||
}
|
||||
get filtered() {
|
||||
const predicate = this.filter.predicate('intention');
|
||||
return this.args.items.filter(predicate(this.args.filters));
|
||||
}
|
||||
get searched() {
|
||||
if (typeof this.args.search === 'undefined') {
|
||||
return this.filtered;
|
||||
}
|
||||
const predicate = this.search.predicate('intention');
|
||||
return this.filtered.filter(predicate(this.args.search));
|
||||
}
|
||||
get comparator() {
|
||||
return [this.args.sort];
|
||||
return this.args.items || [];
|
||||
}
|
||||
get checkedItem() {
|
||||
if (this.searched.length === 1) {
|
||||
return this.searched[0].SourceName === this.args.search ? this.searched[0] : null;
|
||||
if (this.items.length === 1 && this.args.check) {
|
||||
return this.items[0].SourceName === this.args.check ? this.items[0] : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -2,27 +2,48 @@
|
|||
class="consul-intention-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
<div class="filters">
|
||||
>
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.access}}
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Intent
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-allow" @value="allow" @selected={{contains 'allow' filter.accesses}}>Allow</Option>
|
||||
<Option class="value-deny" @value="deny" @selected={{contains 'deny' filter.accesses}}>Deny</Option>
|
||||
<Option class="value-" @value="app-aware" @selected={{contains 'app-aware' filter.accesses}}>App aware</Option>
|
||||
<Option @value="SourceName" @selected={{contains 'SourceName' @filter.searchproperties}}>Source Name</Option>
|
||||
<Option @value="DestinationName" @selected={{contains 'DestinationName' @filter.searchproperties}}>Destination Name</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action @onfilter.access}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Permission
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-allow" @value="allow" @selected={{contains 'allow' @filter.accesses}}>Allow</Option>
|
||||
<Option class="value-deny" @value="deny" @selected={{contains 'deny' @filter.accesses}}>Deny</Option>
|
||||
<Option class="value-" @value="app-aware" @selected={{contains 'app-aware' @filter.accesses}}>App aware</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
@ -32,7 +53,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -49,27 +70,27 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,9 +1,12 @@
|
|||
.consul-intention-search-bar {
|
||||
.value-allow button::before {
|
||||
@extend %with-arrow-right-color-mask, %as-pseudo;
|
||||
@extend %with-arrow-right-mask, %as-pseudo;
|
||||
color: $green-500;
|
||||
}
|
||||
.value-deny button::before {
|
||||
@extend %with-deny-color-icon, %as-pseudo;
|
||||
}
|
||||
.value- button::before {
|
||||
@extend %with-layers-mask, %as-pseudo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
<DataWriter
|
||||
@sink={{concat '/' dc '/' nspace '/kv/'}}
|
||||
@type="kv"
|
||||
@label="key"
|
||||
@ondelete={{action ondelete}}
|
||||
as |writer|>
|
||||
<BlockSlot @name="content">
|
||||
{{#if (gt items.length 0)}}
|
||||
<TabularCollection class="consul-kv-list" @items={{items}} as |item index|>
|
||||
<TabularCollection
|
||||
class="consul-kv-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
<th>Name</th>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="row">
|
||||
<td data-test-kv={{item.Key}} class={{if item.isFolder 'folder' 'file'}}>
|
||||
<a href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{right-trim (left-trim item.Key parent.Key) '/'}}</a>
|
||||
<a href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{right-trim (left-trim item.Key @parent.Key) '/'}}</a>
|
||||
</td>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions" as |index change checked|>
|
||||
|
@ -38,7 +34,14 @@
|
|||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{queue (action change) (action writer.delete item)}}>Delete</button>
|
||||
<button
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
class="type-delete"
|
||||
onclick={{queue (action change) (action @delete item)}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
|
@ -51,8 +54,3 @@
|
|||
</PopoverMenu>
|
||||
</BlockSlot>
|
||||
</TabularCollection>
|
||||
{{else}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</DataWriter>
|
|
@ -1,6 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
ondelete: function() {},
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
<form
|
||||
class="consul-kv-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
class="type-kind"
|
||||
@position="left"
|
||||
@onchange={{action @onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Type
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="folder" @selected={{contains 'folder' @filter.kinds}}>Folder</Option>
|
||||
<Option @value="key" @selected={{contains 'key' @filter.kinds}}>Key</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</div>
|
||||
<div class="sort">
|
||||
<PopoverSelect
|
||||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
{{#let (from-entries (array
|
||||
(array "Key:asc" "A to Z")
|
||||
(array "Key:desc" "Z to A")
|
||||
(array "Kind:asc" "Folders to Keys")
|
||||
(array "Kind:desc" "Keys to Folders")
|
||||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable @sort}}
|
||||
{{/let}}
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Optgroup @label="Name">
|
||||
<Option @value="Key:asc" @selected={{eq "Key:asc" @sort}}>A to Z</Option>
|
||||
<Option @value="Key:desc" @selected={{eq "Key:desc" @sort}}>Z to A</Option>
|
||||
</Optgroup>
|
||||
<Optgroup @label="Type">
|
||||
<Option @value="Kind:asc" @selected={{eq "Kind:asc" @sort}}>Folders to Keys</Option>
|
||||
<Option @value="Kind:desc" @selected={{eq "Kind:desc" @sort}}>Keys to Folders</Option>
|
||||
</Optgroup>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</div>
|
||||
</form>
|
|
@ -1,5 +1,7 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-node-list" as |item index|>
|
||||
<ListCollection
|
||||
class="consul-node-list"
|
||||
@items={{@items}}
|
||||
as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
<dl class={{item.Status}}>
|
||||
<dt>
|
||||
|
@ -24,8 +26,8 @@
|
|||
</a>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
{{#if (eq item.Address leader.Address)}}
|
||||
<span class="leader" data-test-leader={{leader.Address}}>Leader</span>
|
||||
{{#if (eq item.Address @leader.Address)}}
|
||||
<span class="leader" data-test-leader={{@leader.Address}}>Leader</span>
|
||||
{{/if}}
|
||||
{{#if (gt item.Services.length 0)}}
|
||||
<span>
|
||||
|
@ -46,4 +48,3 @@
|
|||
</dl>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,14 +1,39 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-node-list filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Node" @selected={{contains 'Node' @filter.searchproperties}}>Node Name</Option>
|
||||
<Option @value="Address" @selected={{contains 'Address' @filter.searchproperties}}>Address</Option>
|
||||
<Option @value="Meta" @selected={{contains 'Meta' @filter.searchproperties}}>Node Meta</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
class="type-status"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.status}}
|
||||
@onchange={{action @onfilter.status}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -18,10 +43,10 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' filter.statuses}}>No checks</Option>
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' @filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' @filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' @filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' @filter.statuses}}>No checks</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
@ -31,7 +56,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -44,19 +69,19 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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="Node:asc" @selected={{eq "Node:asc" sort}}>A to Z</Option>
|
||||
<Option @value="Node:desc" @selected={{eq "Node:desc" sort}}>Z to A</Option>
|
||||
<Option @value="Node:asc" @selected={{eq "Node:asc" @sort}}>A to Z</Option>
|
||||
<Option @value="Node:desc" @selected={{eq "Node:desc" @sort}}>Z to A</Option>
|
||||
</Optgroup>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,5 +1,9 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} @linkable={{action "isLinkable"}} class="consul-nspace-list" as |item|>
|
||||
<ListCollection
|
||||
class="consul-nspace-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
@linkable={{action this.isLinkable}}
|
||||
as |item|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if item.DeletedAt}}
|
||||
<p>
|
||||
|
@ -29,7 +33,7 @@
|
|||
</BlockSlot>
|
||||
</Action>
|
||||
{{#if (not-eq item.Name 'default') }}
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
<Action data-test-delete-action @onclick={{action @ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
|
@ -54,6 +58,3 @@
|
|||
{{/if}}
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{else}}
|
||||
{{yield to="empty"}}
|
||||
{{/if}}
|
|
@ -1,10 +1,8 @@
|
|||
import Component from '@ember/component';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
actions: {
|
||||
isLinkable: function(item) {
|
||||
export default class ConsulNspaceList extends Component {
|
||||
isLinkable(item) {
|
||||
return !item.DeletedAt;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,41 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-nspace-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Description" @selected={{contains 'Description' @filter.searchproperties}}>Description</Option>
|
||||
<Option @value="Policy" @selected={{contains 'Policy' @filter.searchproperties}}>Policy</Option>
|
||||
<Option @value="Role" @selected={{contains 'Role' @filter.searchproperties}}>Role</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="sort">
|
||||
<PopoverSelect
|
||||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -20,15 +46,15 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,5 +1,7 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-policy-list" as |item|>
|
||||
<ListCollection
|
||||
class="consul-policy-list"
|
||||
@items={{@items}}
|
||||
as |item|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (eq (policy/typeof item) 'policy-management')}}
|
||||
<dl class="policy-management">
|
||||
|
@ -40,7 +42,7 @@
|
|||
</BlockSlot>
|
||||
</Action>
|
||||
{{#if (not-eq (policy/typeof item) 'policy-management')}}
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
<Action data-test-delete-action @onclick={{action @ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
|
@ -64,4 +66,3 @@
|
|||
</Actions>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,14 +1,38 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-policy-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Description" @selected={{contains 'Description' @filter.searchproperties}}>Description</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
class="select-dcs"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.dc}}
|
||||
@onchange={{action @onfilter.dc}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -19,16 +43,16 @@
|
|||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
{{#each dcs as |dc|}}
|
||||
<Option @value={{dc.Name}} @selected={{contains dc.Name filter.dcs}}>{{dc.Name}}</Option>
|
||||
<Option @value={{@dc.Name}} @selected={{contains dc.Name @filter.dcs}}>{{dc.Name}}</Option>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
<DataSource @src="/*/*/datacenters" @loading="lazy" @onchange={{action (mut dcs) value="data"}} />
|
||||
<DataSource @src="/*/*/datacenters" @loading="lazy" @onchange={{action (mut this.dcs) value="data"}} />
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
<PopoverSelect
|
||||
class="select-type"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.kind}}
|
||||
@onchange={{action @onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -38,8 +62,8 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.kinds}}>Global Management</Option>
|
||||
<Option @value="standard" @selected={{contains 'standard' filter.kinds}}>Standard</Option>
|
||||
<Option @value="global-management" @selected={{contains 'global-management' @filter.kinds}}>Global Management</Option>
|
||||
<Option @value="standard" @selected={{contains 'standard' @filter.kinds}}>Standard</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
@ -49,7 +73,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -60,15 +84,15 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Component from '@ember/component';
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
export default Component.extend({});
|
||||
export default class ConsulPolicySearchBarComponent extends Component {}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-role-list" as |item|>
|
||||
<ListCollection
|
||||
class="consul-role-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
as |item|>
|
||||
<BlockSlot @name="header">
|
||||
<a data-test-role={{item.Name}} href={{href-to 'dc.acls.roles.edit' item.ID}}>{{item.Name}}</a>
|
||||
</BlockSlot>
|
||||
|
@ -19,7 +22,7 @@
|
|||
Edit
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
<Action data-test-delete-action @onclick={{action @ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
|
@ -42,4 +45,3 @@
|
|||
</Actions>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,15 +1,40 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-role-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Description" @selected={{contains 'Description' @filter.searchproperties}}>Description</Option>
|
||||
<Option @value="Policy" @selected={{contains 'Policy' @filter.searchproperties}}>Policy</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="sort">
|
||||
<PopoverSelect
|
||||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -22,19 +47,19 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,20 +1,23 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-service-instance-list" as |item index|>
|
||||
<ListCollection
|
||||
class="consul-service-instance-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (eq routeName "dc.services.show")}}
|
||||
<a data-test-service-name href={{href-to routeName item.Service}}>
|
||||
{{#if (eq @routeName "dc.services.show")}}
|
||||
<a data-test-service-name href={{href-to @routeName item.Service}}>
|
||||
{{item.ID}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a data-test-service-name href={{href-to routeName item.Service.Service item.Node.Node (or item.Service.ID item.Service.Service)}}>
|
||||
<a data-test-service-name href={{href-to @routeName item.Service.Service item.Node.Node (or item.Service.ID item.Service.Service)}}>
|
||||
{{item.Service.ID}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
{{#if checks}}
|
||||
{{#if @checks}}
|
||||
<Consul::ExternalSource @item={{item}} />
|
||||
<Consul::InstanceChecks @type="service" @items={{get checks item.Service}} />
|
||||
<Consul::InstanceChecks @type="service" @items={{get @checks item.Service}} />
|
||||
{{else}}
|
||||
<Consul::ExternalSource @item={{item.Service}} />
|
||||
<Consul::InstanceChecks @type="service" @items={{filter-by 'ServiceID' '' item.Checks}} />
|
||||
|
@ -60,7 +63,7 @@
|
|||
</dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{#if (and checks item.Port)}}
|
||||
{{#if (and @checks item.Port)}}
|
||||
<dl class="port">
|
||||
<dt>
|
||||
Port
|
||||
|
@ -81,4 +84,3 @@
|
|||
{{/if}}
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,14 +1,43 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-service-instance-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Tags" @selected={{contains 'Tags' @filter.searchproperties}}>Tags</Option>
|
||||
<Option @value="ID" @selected={{contains 'ID' @filter.searchproperties}}>Service ID</Option>
|
||||
<Option @value="Address" @selected={{contains 'Address' @filter.searchproperties}}>Address</Option>
|
||||
<Option @value="Port" @selected={{contains 'Port' @filter.searchproperties}}>Port</Option>
|
||||
<Option @value="Service.Meta" @selected={{contains 'Service.Meta' @filter.searchproperties}}>Service Meta</Option>
|
||||
<Option @value="Node.Meta" @selected={{contains 'Node.Meta' @filter.searchproperties}}>Node Meta</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
class="type-status"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.status}}
|
||||
@onchange={{action @onfilter.status}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -18,18 +47,18 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' filter.statuses}}>No checks</Option>
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' @filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' @filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' @filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' @filter.statuses}}>No checks</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
{{#if (gt sources.length 0)}}
|
||||
{{#if (gt @sources.length 0)}}
|
||||
<PopoverSelect
|
||||
class="type-source"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.source}}
|
||||
@onchange={{action @onfilter.source}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -39,8 +68,8 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
{{#each sources as |source|}}
|
||||
<Option class={{source}} @value={{source}} @selected={{contains source filter.sources}}>{{source}}</Option>
|
||||
{{#each @sources as |source|}}
|
||||
<Option class={{source}} @value={{source}} @selected={{contains source @filter.sources}}>{{source}}</Option>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
|
@ -52,7 +81,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -65,19 +94,19 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,5 +1,10 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} @linkable={{action "isLinkable"}} class="consul-service-list" as |item index|>
|
||||
<ListCollection
|
||||
class="consul-service-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
@linkable={{action this.isLinkable}}
|
||||
as |item index|
|
||||
>
|
||||
<BlockSlot @name="header">
|
||||
<dl class={{item.MeshStatus}}>
|
||||
<dt>
|
||||
|
@ -85,4 +90,3 @@
|
|||
<TagList @item={{item}} />
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,11 +1,9 @@
|
|||
import Component from '@ember/component';
|
||||
import { get } from '@ember/object';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
actions: {
|
||||
isLinkable: function(item) {
|
||||
return get(item, 'InstanceCount') > 0;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default class ConsulServiceList extends Component {
|
||||
@action
|
||||
isLinkable(item) {
|
||||
return item.InstanceCount > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,38 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-service-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Tags" @selected={{contains 'Tags' @filter.searchproperties}}>Tags</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
class="type-status"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.status}}
|
||||
@onchange={{action @onfilter.status}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -18,16 +42,16 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' filter.statuses}}>No checks</Option>
|
||||
<Option class="value-passing" @value="passing" @selected={{contains 'passing' @filter.statuses}}>Passing</Option>
|
||||
<Option class="value-warning" @value="warning" @selected={{contains 'warning' @filter.statuses}}>Warning</Option>
|
||||
<Option class="value-critical" @value="critical" @selected={{contains 'critical' @filter.statuses}}>Failing</Option>
|
||||
<Option class="value-empty" @value="empty" @selected={{contains 'empty' @filter.statuses}}>No checks</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.kind}}
|
||||
@onchange={{action @onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -37,24 +61,24 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="service" @selected={{contains 'service' filter.kinds}}>Service</Option>
|
||||
<Option @value="service" @selected={{contains 'service' @filter.kinds}}>Service</Option>
|
||||
<Optgroup @label="Gateway">
|
||||
<Option @value="ingress-gateway" @selected={{contains 'ingress-gateway' filter.kinds}}>Ingress Gateway</Option>
|
||||
<Option @value="terminating-gateway" @selected={{contains 'terminating-gateway' filter.kinds}}>Terminating Gateway</Option>
|
||||
<Option @value="mesh-gateway" @selected={{contains 'mesh-gateway' filter.kinds}}>Mesh Gateway</Option>
|
||||
<Option @value="ingress-gateway" @selected={{contains 'ingress-gateway' @filter.kinds}}>Ingress Gateway</Option>
|
||||
<Option @value="terminating-gateway" @selected={{contains 'terminating-gateway' @filter.kinds}}>Terminating Gateway</Option>
|
||||
<Option @value="mesh-gateway" @selected={{contains 'mesh-gateway' @filter.kinds}}>Mesh Gateway</Option>
|
||||
</Optgroup>
|
||||
<Optgroup @label="Mesh">
|
||||
<Option @value="in-mesh" @selected={{contains 'in-mesh' filter.kinds}}>In service mesh</Option>
|
||||
<Option @value="not-in-mesh" @selected={{contains 'not-in-mesh' filter.kinds}}>Not in service mesh</Option>
|
||||
<Option @value="in-mesh" @selected={{contains 'in-mesh' @filter.kinds}}>In service mesh</Option>
|
||||
<Option @value="not-in-mesh" @selected={{contains 'not-in-mesh' @filter.kinds}}>Not in service mesh</Option>
|
||||
</Optgroup>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
{{#if (gt sources.length 0)}}
|
||||
{{#if (gt @sources.length 0)}}
|
||||
<PopoverSelect
|
||||
class="type-source"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.source}}
|
||||
@onchange={{action @onfilter.source}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -64,8 +88,8 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
{{#each sources as |source|}}
|
||||
<Option class={{source}} @value={{source}} @selected={{contains source filter.sources}}>{{source}}</Option>
|
||||
{{#each @sources as |source|}}
|
||||
<Option class={{source}} @value={{source}} @selected={{contains source @filter.sources}}>{{source}}</Option>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
|
@ -77,7 +101,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -90,19 +114,19 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,7 +1,9 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-token-list" as |item|>
|
||||
<ListCollection
|
||||
class="consul-token-list"
|
||||
@items={{@items}}
|
||||
as |item|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (eq item.AccessorID token.AccessorID)}}
|
||||
{{#if (eq item.AccessorID @token.AccessorID)}}
|
||||
<dl rel="me">
|
||||
<dd>
|
||||
<Tooltip @position="top-start">
|
||||
|
@ -35,14 +37,14 @@
|
|||
</BlockSlot>
|
||||
</Action>
|
||||
{{#if (not (token/is-legacy item))}}
|
||||
<Action data-test-clone-action @onclick={{action onclone item}}>
|
||||
<Action data-test-clone-action @onclick={{action @onclone item}}>
|
||||
<BlockSlot @name="label">
|
||||
Duplicate
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
{{/if}}
|
||||
{{#if (eq item.AccessorID token.AccessorID)}}
|
||||
<Action data-test-logout-action class="dangerous" @onclick={{action onlogout item}}>
|
||||
<Action data-test-logout-action class="dangerous" @onclick={{action @onlogout item}}>
|
||||
<BlockSlot @name="label">
|
||||
Logout
|
||||
</BlockSlot>
|
||||
|
@ -63,7 +65,7 @@
|
|||
</BlockSlot>
|
||||
</Action>
|
||||
{{else}}
|
||||
<Action data-test-use-action @onclick={{action onuse item}}>
|
||||
<Action data-test-use-action @onclick={{action @onuse item}}>
|
||||
<BlockSlot @name="label">
|
||||
Use
|
||||
</BlockSlot>
|
||||
|
@ -84,8 +86,8 @@
|
|||
</BlockSlot>
|
||||
</Action>
|
||||
{{/if}}
|
||||
{{#if (not (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)))}}
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
{{#if (not (or (token/is-anonymous item) (eq item.AccessorID @token.AccessorID)))}}
|
||||
<Action data-test-delete-action @onclick={{action @ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
|
@ -109,4 +111,3 @@
|
|||
</Actions>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,13 +1,39 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-token-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="AccessorID" @selected={{contains 'AccessorID' @filter.searchproperties}}>AccessorID</Option>
|
||||
<Option @value="Description" @selected={{contains 'Description' @filter.searchproperties}}>Description</Option>
|
||||
<Option @value="Policy" @selected={{contains 'Policy' @filter.searchproperties}}>Policy</Option>
|
||||
<Option @value="Role" @selected={{contains 'Role' @filter.searchproperties}}>Role</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.kind}}
|
||||
@onchange={{action @onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -17,9 +43,9 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.kinds}}>Global Management</Option>
|
||||
<Option @value="global" @selected={{contains 'global' filter.kinds}}>Global</Option>
|
||||
<Option @value="local" @selected={{contains 'local' filter.kinds}}>Local</Option>
|
||||
<Option @value="global-management" @selected={{contains 'global-management' @filter.kinds}}>Global Management</Option>
|
||||
<Option @value="global" @selected={{contains 'global' @filter.kinds}}>Global Scope</Option>
|
||||
<Option @value="local" @selected={{contains 'local' @filter.kinds}}>Local Scope</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
@ -29,7 +55,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -40,15 +66,15 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({});
|
|
@ -1,4 +1,9 @@
|
|||
<ListCollection @items={{items}} @linkable={{action "isLinkable"}} class="consul-upstream-list" as |item index|>
|
||||
<ListCollection
|
||||
class="consul-upstream-list"
|
||||
...attributes
|
||||
@items={{@items}}
|
||||
@linkable={{action this.isLinkable}}
|
||||
as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (gt item.InstanceCount 0)}}
|
||||
<dl class={{item.MeshStatus}}>
|
||||
|
@ -19,8 +24,9 @@
|
|||
</Tooltip>
|
||||
</dd>
|
||||
</dl>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace nspace))}}
|
||||
<a data-test-service-name href={{href-to 'nspace.dc.services.show' (concat '~' item.Namespace) dc item.Name }}>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace @nspace))}}
|
||||
{{item.Namespace}}
|
||||
<a data-test-service-name href={{href-to 'nspace.dc.services.show' (concat '~' item.Namespace) @dc item.Name }}>
|
||||
{{item.Name}}
|
||||
</a>
|
||||
{{else}}
|
||||
|
@ -35,7 +41,7 @@
|
|||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace nspace))}}
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace @nspace))}}
|
||||
<dl class="nspace">
|
||||
<dt>
|
||||
<Tooltip>
|
||||
|
@ -47,18 +53,19 @@
|
|||
</dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{#if (gt item.GatewayConfig.Addresses.length 0)}}
|
||||
{{#each item.GatewayConfig.Addresses as |address|}}
|
||||
<dl>
|
||||
<dt>
|
||||
<span>Address</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<CopyButton
|
||||
@value={{address}}
|
||||
@name="Address"
|
||||
/>
|
||||
</dt>
|
||||
<dd>{{address}}</dd>
|
||||
{{address}}
|
||||
</dd>
|
||||
</dl>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import Component from '@ember/component';
|
||||
import { get } from '@ember/object';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
actions: {
|
||||
isLinkable: function(item) {
|
||||
return get(item, 'InstanceCount') > 0;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default class ConsulServiceList extends Component {
|
||||
@action
|
||||
isLinkable(item) {
|
||||
return item.InstanceCount > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,37 @@
|
|||
<form class="filter-bar">
|
||||
<form
|
||||
class="consul-upstream-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<div class="search">
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
@onsearch={{action @onsearch}}
|
||||
@value={{@search}}
|
||||
@placeholder="Search"
|
||||
/>
|
||||
>
|
||||
<PopoverSelect
|
||||
class="type-search-properties"
|
||||
@position="right"
|
||||
@onchange={{action @onfilter.searchproperty}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{contains 'Name' @filter.searchproperties}}>Name</Option>
|
||||
<Option @value="Tags" @selected={{contains 'Tags' @filter.searchproperties}}>Tags</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.instance}}
|
||||
@onchange={{action @onfilter.instance}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -17,8 +41,8 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="registered" @selected={{contains 'registered' filter.instances}}>Registered</Option>
|
||||
<Option @value="not-registered" @selected={{contains 'not-registered' filter.instances}}>Not Registered</Option>
|
||||
<Option @value="registered" @selected={{contains 'registered' @filter.instances}}>Registered</Option>
|
||||
<Option @value="not-registered" @selected={{contains 'not-registered' @filter.instances}}>Not Registered</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
@ -28,7 +52,7 @@
|
|||
class="type-sort"
|
||||
data-test-sort-control
|
||||
@position="right"
|
||||
@onchange={{action onsort}}
|
||||
@onchange={{action @onsort}}
|
||||
@multiple={{false}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -41,19 +65,19 @@
|
|||
))
|
||||
as |selectable|
|
||||
}}
|
||||
{{get selectable sort}}
|
||||
{{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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
{{yield (hash
|
||||
items=this.items
|
||||
Collection=(if (gt this.items.length 0) (component 'anonymous') '')
|
||||
Empty=(if (eq this.items.length 0) (component 'anonymous') '')
|
||||
)}}
|
|
@ -0,0 +1,56 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { sort } from '@ember/object/computed';
|
||||
import { defineProperty } from '@ember/object';
|
||||
|
||||
export default class DataCollectionComponent extends Component {
|
||||
@service('filter') filter;
|
||||
@service('sort') sort;
|
||||
@service('search') search;
|
||||
|
||||
get type() {
|
||||
return this.args.type;
|
||||
}
|
||||
|
||||
get items() {
|
||||
// the ember sort computed accepts either:
|
||||
// 1. The name of a property (as a string) returning an array properties to sort by
|
||||
// 2. A function to use for sorting
|
||||
let comparator = 'comparator';
|
||||
if (typeof this.comparator === 'function') {
|
||||
comparator = this.comparator;
|
||||
}
|
||||
defineProperty(this, 'sorted', sort('searched', comparator));
|
||||
return this.sorted;
|
||||
}
|
||||
|
||||
get searched() {
|
||||
if (typeof this.args.search === 'undefined') {
|
||||
return this.filtered;
|
||||
}
|
||||
const predicate = this.search.predicate(this.type);
|
||||
const options = {};
|
||||
if (typeof this.args.filters.searchproperties !== 'undefined') {
|
||||
options.properties = this.args.filters.searchproperties;
|
||||
}
|
||||
return this.filtered.filter(predicate(this.args.search, options));
|
||||
}
|
||||
|
||||
get filtered() {
|
||||
if (typeof this.args.filters === 'undefined') {
|
||||
return this.args.items;
|
||||
}
|
||||
const predicate = this.filter.predicate(this.type);
|
||||
if (typeof predicate === 'undefined') {
|
||||
return this.args.items;
|
||||
}
|
||||
return this.args.items.filter(predicate(this.args.filters));
|
||||
}
|
||||
|
||||
get comparator() {
|
||||
if (typeof this.args.sort === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
return this.sort.comparator(this.type)(this.args.sort);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
||||
%filter-bar-reversed {
|
||||
color: inherit;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
.filter-bar {
|
||||
&,
|
||||
> div {
|
||||
display: flex;
|
||||
}
|
||||
& {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.sort {
|
||||
margin-left: auto;
|
||||
}
|
||||
.popover-select {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
.popover-menu > [type='checkbox'] + label button {
|
||||
padding-left: 1.5rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
|
||||
}
|
||||
.popover-menu [role='menuitem'] {
|
||||
justify-content: normal !important;
|
||||
}
|
||||
}
|
||||
@media #{$--lt-horizontal-filters} {
|
||||
.filter-bar {
|
||||
&,
|
||||
& > div {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.search {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
width: 100%;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media #{$--lt-horizontal-selects} {
|
||||
.filter-bar {
|
||||
.filters, .sort {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
.filter-bar {
|
||||
& {
|
||||
background-color: $gray-010;
|
||||
border-bottom: $decor-border-100;
|
||||
border-color: $gray-200;
|
||||
}
|
||||
.filters, .sort {
|
||||
.popover-menu > [type='checkbox']:checked + label button {
|
||||
color: $blue-500;
|
||||
background-color: $gray-100;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
<Meta title="Components/FreetextFilter" />
|
||||
|
||||
# FreetextFilter
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Basic"
|
||||
argTypes={{
|
||||
}}
|
||||
>{(args) => ({
|
||||
template: hbs`<FreetextFilter />`,
|
||||
context: args
|
||||
})}
|
||||
</Story>
|
||||
<Story
|
||||
name="Search Across"
|
||||
argTypes={{
|
||||
}}
|
||||
>{(args) => ({
|
||||
template: hbs`<FreetextFilter>
|
||||
<PopoverSelect
|
||||
@position="right"
|
||||
@multiple={{true}}
|
||||
as |popover|>
|
||||
<BlockSlot @name="selected">
|
||||
<span>
|
||||
Search across
|
||||
</span>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let popover.Optgroup popover.Option as |Optgroup Option|}}
|
||||
<Option @value="Name" @selected={{true}}>Name</Option>
|
||||
<Option @value="Tags">Tags</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
</FreetextFilter>`,
|
||||
context: args
|
||||
})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
|
@ -1,6 +1,19 @@
|
|||
<fieldset class="freetext-filter">
|
||||
<fieldset
|
||||
class="freetext-filter"
|
||||
...attributes
|
||||
>
|
||||
<label class="type-search">
|
||||
<span>Search</span>
|
||||
<input type="search" onsearch={{action "change"}} oninput={{action "change"}} onkeydown={{action "keydown"}} name="s" value={{value}} placeholder={{placeholder}} autofocus="autofocus" />
|
||||
<span class="freetext-filter_label">Search</span>
|
||||
<input
|
||||
class="freetext-filter_input"
|
||||
type="search"
|
||||
onsearch={{action this.change}}
|
||||
oninput={{action this.change}}
|
||||
onkeydown={{action this.keydown}}
|
||||
name="s" value={{@value}}
|
||||
placeholder={{this.placeholder}}
|
||||
autofocus="autofocus"
|
||||
/>
|
||||
</label>
|
||||
{{yield}}
|
||||
</fieldset>
|
|
@ -1,19 +1,25 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
const ENTER = 13;
|
||||
export default Component.extend({
|
||||
dom: service('dom'),
|
||||
tagName: '',
|
||||
actions: {
|
||||
change: function(e) {
|
||||
this.onsearch(
|
||||
this.dom.setEventTargetProperty(e, 'value', value => (value === '' ? undefined : value))
|
||||
);
|
||||
},
|
||||
keydown: function(e) {
|
||||
export default class FreetextFilter extends Component {
|
||||
get placeholder() {
|
||||
return this.args.placeholder || 'Search';
|
||||
}
|
||||
|
||||
get onsearch() {
|
||||
return this.args.onsearch || (() => {});
|
||||
}
|
||||
|
||||
@action
|
||||
change(e) {
|
||||
this.onsearch(e);
|
||||
}
|
||||
|
||||
@action
|
||||
keydown(e) {
|
||||
if (e.keyCode === ENTER) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
.freetext-filter {
|
||||
--height: 2.2rem;
|
||||
& {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: var(--height);
|
||||
}
|
||||
&_input,
|
||||
& > label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
&_input,
|
||||
&_label {
|
||||
height: 100%;
|
||||
}
|
||||
&_input {
|
||||
padding: 8px 10px;
|
||||
padding-left: var(--height);
|
||||
min-width: 12.7rem;
|
||||
width: 100%;
|
||||
}
|
||||
&_label {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: var(--height);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
.freetext-filter {
|
||||
& {
|
||||
border: $decor-border-100;
|
||||
border-radius: $decor-radius-100;
|
||||
|
||||
background-color: $white;
|
||||
border-color: $gray-200;
|
||||
color: $gray-400;
|
||||
}
|
||||
&:hover,
|
||||
&:hover * {
|
||||
border-color: $gray-400;
|
||||
}
|
||||
& *,
|
||||
&_input::placeholder {
|
||||
cursor: inherit;
|
||||
color: inherit;
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
&_input {
|
||||
-webkit-appearance: none;
|
||||
border: none;
|
||||
}
|
||||
&_label::after {
|
||||
@extend %as-pseudo;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
&_label::after {
|
||||
@extend %with-search-mask;
|
||||
}
|
||||
.popover-menu {
|
||||
background-color: $gray-050;
|
||||
color: $gray-800;
|
||||
}
|
||||
.popover-menu {
|
||||
border-left: 1px solid;
|
||||
border-color: inherit;
|
||||
}
|
||||
.popover-menu > [type='checkbox']:checked + label button {
|
||||
background-color: $gray-200;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,12 @@
|
|||
<div class="more-popover-menu">
|
||||
<PopoverMenu @expanded={{expanded}} @onchange={{action onchange}} @keyboardAccess={{false}} as |components api|>
|
||||
<div
|
||||
class="more-popover-menu"
|
||||
...attributes
|
||||
>
|
||||
<PopoverMenu
|
||||
@expanded={{expanded}}
|
||||
@onchange={{action onchange}}
|
||||
@keyboardAccess={{false}}
|
||||
as |components api|>
|
||||
<BlockSlot @name="trigger">
|
||||
More
|
||||
</BlockSlot>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{{yield}}
|
||||
<div class="popover-menu" ...attributes>
|
||||
<div
|
||||
class="popover-menu"
|
||||
...attributes
|
||||
>
|
||||
<AriaMenu @keyboardAccess={{keyboardAccess}} as |change keypress keypressClick aria|>
|
||||
|
||||
{{#let (hash
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div role="menu">
|
||||
<YieldSlot @name="confirmation" @params={{
|
||||
block-params (component 'confirmation-alert'
|
||||
onclick=(queue (action onclick) (action menu.clickTrigger))
|
||||
onclick=(queue (action menu.clickTrigger) (action onclick))
|
||||
name=(concat menu.confirm guid)
|
||||
)
|
||||
}}>{{yield}}</YieldSlot>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<PopoverMenu @position={{or position "left"}} class="popover-select" ...attributes as |components menu|>
|
||||
<PopoverMenu
|
||||
class="popover-select"
|
||||
...attributes
|
||||
@position={{or position "left"}}
|
||||
as |components menu|
|
||||
>
|
||||
{{yield}}
|
||||
{{#let
|
||||
(component 'popover-select/optgroup' components=components)
|
||||
|
|
|
@ -40,10 +40,7 @@ export default Component.extend(Slotted, {
|
|||
this.dom.setEventTargetProperties(e, {
|
||||
selected: target => value,
|
||||
selectedItems: target => {
|
||||
const opts = [...options];
|
||||
if (opts.length > 0) {
|
||||
return opts.join(',');
|
||||
}
|
||||
return [...options].join(',');
|
||||
},
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
<input
|
||||
...attributes
|
||||
{{ref this "input"}}
|
||||
{{did-insert (set this 'input')}}
|
||||
type="checkbox"
|
||||
checked={{if checked 'checked' undefined}}
|
||||
id={{concat 'toggle-button-' guid}}
|
||||
onchange={{action 'change'}}
|
||||
/>
|
||||
<label {{ref this "label"}} for={{concat 'toggle-button-' guid}}>
|
||||
<label
|
||||
{{did-insert (set this 'label')}}
|
||||
for={{concat 'toggle-button-' guid}}
|
||||
>
|
||||
{{yield (hash
|
||||
click=(action 'click')
|
||||
)}}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import { action } from '@ember/object';
|
||||
import Controller from '@ember/controller';
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
filterBy: {
|
||||
as: 'type',
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
@action
|
||||
sendClone(item) {
|
||||
this.send('clone', item);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
dc: 'dc',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
search: {
|
||||
as: 'filter',
|
||||
},
|
||||
};
|
||||
}
|
|
@ -2,17 +2,6 @@ import { computed } from '@ember/object';
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
@computed('items.[]')
|
||||
get services() {
|
||||
return this.items.filter(function(item) {
|
||||
|
|
|
@ -2,16 +2,6 @@ import { computed } from '@ember/object';
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class InstancesController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
@computed('items')
|
||||
get externalSources() {
|
||||
const sources = this.items.reduce(function(prev, item) {
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class ServicesController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
instance: 'instance',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class UpstreamsController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
instance: 'instance',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
kinds: {
|
||||
management: (item, value) => item.Type === value,
|
||||
client: (item, value) => item.Type === value,
|
||||
},
|
||||
};
|
|
@ -1,9 +1,7 @@
|
|||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
accesses: {
|
||||
allow: (item, value) => item.Action === value,
|
||||
deny: (item, value) => item.Action === value,
|
||||
'app-aware': (item, value) => typeof item.Action === 'undefined',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
kinds: {
|
||||
folder: (item, value) => item.isFolder,
|
||||
key: (item, value) => !item.isFolder,
|
||||
},
|
||||
};
|
|
@ -1,10 +1,7 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
statuses: {
|
||||
passing: (item, value) => item.Status === value,
|
||||
warning: (item, value) => item.Status === value,
|
||||
critical: (item, value) => item.Status === value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
kinds: {
|
||||
'global-management': (item, value) => item.isGlobalManagement,
|
||||
standard: (item, value) => !item.isGlobalManagement,
|
||||
|
@ -12,4 +9,4 @@ export default andOr({
|
|||
setHelpers.intersectionSize(values, new Set(item.Datacenters)) > 0
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
statuses: {
|
||||
passing: (item, value) => item.Status === value,
|
||||
warning: (item, value) => item.Status === value,
|
||||
|
@ -10,4 +9,4 @@ export default andOr({
|
|||
sources: (item, values) => {
|
||||
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
kinds: {
|
||||
'ingress-gateway': (item, value) => item.Kind === value,
|
||||
'terminating-gateway': (item, value) => item.Kind === value,
|
||||
|
@ -22,4 +21,4 @@ export default andOr({
|
|||
sources: (item, values) => {
|
||||
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
export default {
|
||||
kinds: {
|
||||
'global-management': (item, value) => item.isGlobalManagement,
|
||||
global: (item, value) => !item.Local,
|
||||
local: (item, value) => item.Local,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -25,6 +25,11 @@ export default class Kv extends Model {
|
|||
@attr('number') ModifyIndex;
|
||||
@attr('string') Session;
|
||||
|
||||
@computed('isFolder')
|
||||
get Kind() {
|
||||
return this.isFolder ? 'folder' : 'key';
|
||||
}
|
||||
|
||||
@computed('Key')
|
||||
get isFolder() {
|
||||
return isFolder(this.Key || '');
|
||||
|
|
|
@ -20,6 +20,8 @@ export default class ServiceInstance extends Model {
|
|||
@attr() meta;
|
||||
|
||||
@or('Service.ID', 'Service.Service') Name;
|
||||
@or('Service.Address', 'Node.Service') Address;
|
||||
|
||||
@alias('Service.Tags') Tags;
|
||||
@alias('Service.Meta') Meta;
|
||||
@alias('Service.Namespace') Namespace;
|
||||
|
|
|
@ -6,13 +6,13 @@ import { get } from '@ember/object';
|
|||
import WithAclActions from 'consul-ui/mixins/acl/with-actions';
|
||||
|
||||
export default class IndexRoute extends Route.extend(WithAclActions) {
|
||||
@service('repository/acl')
|
||||
repo;
|
||||
@service('repository/acl') repo;
|
||||
|
||||
@service('settings')
|
||||
settings;
|
||||
@service('settings') settings;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -11,6 +11,10 @@ export default class IndexRoute extends Route.extend(WithPolicyActions) {
|
|||
sortBy: 'sort',
|
||||
dc: 'dc',
|
||||
kind: 'kind',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Description']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -9,6 +9,10 @@ export default class IndexRoute extends Route.extend(WithRoleActions) {
|
|||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Description', 'Policy']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -11,6 +11,10 @@ export default class IndexRoute extends Route.extend(WithTokenActions) {
|
|||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['AccessorID', 'Description', 'Role', 'Policy']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -4,6 +4,10 @@ export default class IndexRoute extends Route {
|
|||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['SourceName', 'DestinationName']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -9,6 +9,7 @@ export default class IndexRoute extends Route {
|
|||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -8,6 +8,10 @@ export default class IndexRoute extends Route {
|
|||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Node', 'Address', 'Meta']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -9,6 +9,10 @@ export default class IndexRoute extends Route.extend(WithNspaceActions) {
|
|||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Description', 'Role', 'Policy']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -10,6 +10,10 @@ export default class IndexRoute extends Route {
|
|||
status: 'status',
|
||||
source: 'source',
|
||||
kind: 'kind',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Tags']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
@ -17,26 +21,11 @@ export default class IndexRoute extends Route {
|
|||
};
|
||||
|
||||
model(params) {
|
||||
let terms = params.s || '';
|
||||
// we check for the old style `status` variable here
|
||||
// and convert it to the new style filter=status:critical
|
||||
let status = params.status;
|
||||
if (status) {
|
||||
status = `status:${status}`;
|
||||
if (terms.indexOf(status) === -1) {
|
||||
terms = terms
|
||||
.split('\n')
|
||||
.concat(status)
|
||||
.join('\n')
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
const nspace = this.modelFor('nspace').nspace.substr(1);
|
||||
const dc = this.modelFor('dc').dc.Name;
|
||||
return hash({
|
||||
nspace: nspace,
|
||||
dc: dc,
|
||||
terms: terms !== '' ? terms.split('\n') : [],
|
||||
items: this.data.source(uri => uri`/${nspace}/${dc}/services`),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ export default class InstancesRoute extends Route {
|
|||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Tags', 'ID', 'Address', 'Port', 'Service.Meta', 'Node.Meta']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -4,6 +4,10 @@ export default class IndexRoute extends Route {
|
|||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['SourceName', 'DestinationName']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -3,8 +3,20 @@ import Route from 'consul-ui/routing/route';
|
|||
import { hash } from 'rsvp';
|
||||
|
||||
export default class ServicesRoute extends Route {
|
||||
@service('data-source/service')
|
||||
data;
|
||||
@service('data-source/service') data;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
instance: 'instance',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Tags']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
model() {
|
||||
const dc = this.modelFor('dc').dc.Name;
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
import Route from './services';
|
||||
|
||||
export default class UpstreamsRoute extends Route {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
instance: 'instance',
|
||||
searchproperty: {
|
||||
as: 'searchproperty',
|
||||
empty: [['Name', 'Tags']],
|
||||
},
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
templateName = 'dc/services/show/upstreams';
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { setProperties } from '@ember/object';
|
||||
import { get, setProperties } from '@ember/object';
|
||||
|
||||
// paramsFor
|
||||
import { routes } from 'consul-ui/router';
|
||||
|
@ -7,6 +7,37 @@ import wildcard from 'consul-ui/utils/routing/wildcard';
|
|||
const isWildcard = wildcard(routes);
|
||||
|
||||
export default class BaseRoute extends Route {
|
||||
/**
|
||||
* By default any empty string query parameters should remove the query
|
||||
* parameter from the URL. This is the most common behavior if you don't
|
||||
* require this behavior overwrite this method in the specific Route for the
|
||||
* specific queryParam key.
|
||||
* If the behaviour should be different add an empty: [] parameter to the
|
||||
* queryParameter configuration to configure what is deemed 'empty'
|
||||
*/
|
||||
serializeQueryParam(value, key, type) {
|
||||
if(typeof value !== 'undefined') {
|
||||
const empty = get(this, `queryParams.${key}.empty`);
|
||||
if(typeof empty === 'undefined') {
|
||||
// by default any queryParams when an empty string mean undefined,
|
||||
// therefore remove the queryParam from the URL
|
||||
if(value === '') {
|
||||
value = undefined;
|
||||
}
|
||||
} else {
|
||||
const possible = empty[0];
|
||||
let actual = value;
|
||||
if(Array.isArray(actual)) {
|
||||
actual = actual.split(',');
|
||||
}
|
||||
const diff = possible.filter(item => !actual.includes(item))
|
||||
if(diff.length === 0) {
|
||||
value = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Set the routeName for the controller so that it is available in the template
|
||||
* for the route/controller.. This is mainly used to give a route name to the
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
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,10 +0,0 @@
|
|||
import { get } from '@ember/object';
|
||||
import rightTrim from 'consul-ui/utils/right-trim';
|
||||
export default function(filterable) {
|
||||
return filterable(function(item, { s = '' }) {
|
||||
const key = rightTrim(get(item, 'Key'), '/')
|
||||
.split('/')
|
||||
.pop();
|
||||
return key.toLowerCase().indexOf(s.toLowerCase()) !== -1;
|
||||
});
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { get } from '@ember/object';
|
||||
export default function(filterable) {
|
||||
return filterable(function(item, { s = '' }) {
|
||||
const sLower = s.toLowerCase();
|
||||
return (
|
||||
get(item, 'Node')
|
||||
.toLowerCase()
|
||||
.indexOf(sLower) !== -1 ||
|
||||
get(item, 'Address')
|
||||
.toLowerCase()
|
||||
.indexOf(sLower) !== -1
|
||||
);
|
||||
});
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
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, 'Description')
|
||||
.toLowerCase()
|
||||
.indexOf(sLower) !== -1 ||
|
||||
(get(item, 'ACLs.PolicyDefaults') || []).some(function(item) {
|
||||
return item.Name.toLowerCase().indexOf(sLower) !== -1;
|
||||
}) ||
|
||||
(get(item, 'ACLs.RoleDefaults') || []).some(function(item) {
|
||||
return item.Name.toLowerCase().indexOf(sLower) !== -1;
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue