From bb95738321ff6dc94aa0de37889a8cc4fe7d9cd9 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Mon, 25 Jan 2021 18:13:54 +0000 Subject: [PATCH] ui: Search/filtering 'Filtered by:' search status (#9442) Adds a 'status' for the filtering/searching in the UI, without this its not super clear that you are filtering a recordset due to the menu selections being hidden once closed. You can also use the pills in this status view to delete individual filters. --- .changelog/9442.txt | 4 + ui/packages/consul-ui/.template-lintrc.js | 2 + .../consul-ui/app/components/action/index.hbs | 2 +- .../components/confirmation-alert/index.hbs | 1 + .../consul/acl/search-bar/index.hbs | 180 +++++++---- .../consul/health-check/search-bar/index.hbs | 290 ++++++++++------- .../consul/intention/search-bar/index.hbs | 210 +++++++----- .../components/consul/kv/search-bar/index.hbs | 190 +++++++---- .../consul/node/search-bar/index.hbs | 197 +++++++----- .../consul/nspace/search-bar/index.hbs | 137 +++++--- .../consul/policy/search-bar/index.hbs | 222 +++++++------ .../consul/role/search-bar/index.hbs | 148 +++++---- .../service-instance/search-bar/index.hbs | 233 ++++++++------ .../consul/service/search-bar/index.hbs | 301 +++++++++++------- .../consul/token/search-bar/index.hbs | 182 +++++++---- .../upstream-instance/search-bar/index.hbs | 135 +++++--- .../consul/upstream/search-bar/index.hbs | 188 ++++++----- .../app/components/data-collection/index.js | 19 +- .../app/components/popover-select/index.hbs | 2 +- .../app/components/popover-select/index.js | 51 +-- .../popover-select/optgroup/index.hbs | 4 +- .../popover-select/optgroup/index.js | 5 - .../popover-select/option/index.hbs | 12 +- .../components/popover-select/option/index.js | 34 +- .../app/components/search-bar/README.mdx | 61 ---- .../app/components/search-bar/index.hbs | 99 ++++-- .../app/components/search-bar/index.js | 38 ++- .../app/components/search-bar/index.scss | 60 ++++ .../app/components/search-bar/pageobject.js | 7 - .../search-bar/remove-filter/index.hbs | 7 + .../app/components/search-bar/utils.js | 38 +++ .../consul-ui/app/filter/predicates/acl.js | 2 +- .../app/filter/predicates/health-check.js | 6 +- .../app/filter/predicates/intention.js | 2 +- .../consul-ui/app/filter/predicates/kv.js | 2 +- .../consul-ui/app/filter/predicates/node.js | 2 +- .../consul-ui/app/filter/predicates/policy.js | 4 +- .../app/filter/predicates/service-instance.js | 5 +- .../app/filter/predicates/service.js | 9 +- .../consul-ui/app/filter/predicates/token.js | 2 +- ui/packages/consul-ui/app/models/role.js | 4 +- ui/packages/consul-ui/app/models/service.js | 10 + .../consul-ui/app/routes/dc/acls/index.js | 35 +- .../app/routes/dc/acls/policies/index.js | 5 +- .../app/routes/dc/acls/roles/index.js | 1 + .../app/routes/dc/acls/tokens/index.js | 20 +- .../app/routes/dc/intentions/index.js | 3 +- .../consul-ui/app/routes/dc/nodes/index.js | 14 +- .../consul-ui/app/routes/dc/nspaces/index.js | 10 +- .../consul-ui/app/routes/dc/services/index.js | 1 + .../dc/services/instance/healthchecks.js | 1 - .../dc/services/show/intentions/index.js | 3 +- .../app/routes/dc/services/show/services.js | 7 +- .../consul-ui/app/styles/components.scss | 1 + ui/packages/consul-ui/app/styles/layout.scss | 2 +- .../consul-ui/app/styles/typography.scss | 2 +- .../consul-ui/app/templates/dc/acls/index.hbs | 164 +++++----- .../app/templates/dc/acls/policies/index.hbs | 208 ++++++------ .../app/templates/dc/acls/roles/index.hbs | 34 +- .../app/templates/dc/acls/tokens/index.hbs | 218 +++++++------ .../app/templates/dc/intentions/index.hbs | 191 +++++------ .../consul-ui/app/templates/dc/kv/index.hbs | 28 +- .../app/templates/dc/nodes/index.hbs | 39 ++- .../templates/dc/nodes/show/healthchecks.hbs | 58 ++-- .../app/templates/dc/nodes/show/services.hbs | 47 +-- .../app/templates/dc/nspaces/index.hbs | 36 ++- .../app/templates/dc/services/index.hbs | 40 ++- .../dc/services/instance/healthchecks.hbs | 54 ++-- .../dc/services/instance/upstreams.hbs | 39 ++- .../templates/dc/services/show/instances.hbs | 46 ++- .../dc/services/show/intentions/index.hbs | 131 ++++---- .../templates/dc/services/show/services.hbs | 47 +-- .../templates/dc/services/show/upstreams.hbs | 47 +-- .../app/utils/intl/missing-message.js | 9 + .../integration/components/search-bar-test.js | 24 -- ui/packages/consul-ui/tests/pages.js | 23 +- .../consul-ui/tests/pages/dc/acls/index.js | 3 +- .../consul-ui/tests/pages/dc/services/show.js | 12 +- .../components/search-bar/filters-test.js | 154 +++++++++ .../unit/filter/predicates/intention-test.js | 6 +- .../unit/filter/predicates/service-test.js | 36 +-- ui/packages/consul-ui/translations/en-us.yaml | 157 +++++++++ 82 files changed, 3117 insertions(+), 1946 deletions(-) create mode 100644 .changelog/9442.txt delete mode 100644 ui/packages/consul-ui/app/components/popover-select/optgroup/index.js delete mode 100644 ui/packages/consul-ui/app/components/search-bar/README.mdx create mode 100644 ui/packages/consul-ui/app/components/search-bar/index.scss delete mode 100644 ui/packages/consul-ui/app/components/search-bar/pageobject.js create mode 100644 ui/packages/consul-ui/app/components/search-bar/remove-filter/index.hbs create mode 100644 ui/packages/consul-ui/app/components/search-bar/utils.js create mode 100644 ui/packages/consul-ui/app/utils/intl/missing-message.js delete mode 100644 ui/packages/consul-ui/tests/integration/components/search-bar-test.js create mode 100644 ui/packages/consul-ui/tests/unit/components/search-bar/filters-test.js diff --git a/.changelog/9442.txt b/.changelog/9442.txt new file mode 100644 index 0000000000..afdd67d20c --- /dev/null +++ b/.changelog/9442.txt @@ -0,0 +1,4 @@ +```release-note:feature +ui: Add additional search/filter status pills for viewing and removing current +filters in listing views +``` diff --git a/ui/packages/consul-ui/.template-lintrc.js b/ui/packages/consul-ui/.template-lintrc.js index c654b15cab..8f185a67d4 100644 --- a/ui/packages/consul-ui/.template-lintrc.js +++ b/ui/packages/consul-ui/.template-lintrc.js @@ -31,6 +31,8 @@ module.exports = { 'no-unnecessary-component-helper': false, 'link-href-attributes': false, + // we need to be able to say tabindex={{@tabindex}} + 'no-positive-tabindex': false, 'no-bare-strings': false, }, diff --git a/ui/packages/consul-ui/app/components/action/index.hbs b/ui/packages/consul-ui/app/components/action/index.hbs index 75484eb11a..34667ae4c5 100644 --- a/ui/packages/consul-ui/app/components/action/index.hbs +++ b/ui/packages/consul-ui/app/components/action/index.hbs @@ -19,9 +19,9 @@ {{~/if~}} {{~else~}} {{~/if}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/confirmation-alert/index.hbs b/ui/packages/consul-ui/app/components/confirmation-alert/index.hbs index 803ccd23cf..6df6162068 100644 --- a/ui/packages/consul-ui/app/components/confirmation-alert/index.hbs +++ b/ui/packages/consul-ui/app/components/confirmation-alert/index.hbs @@ -14,6 +14,7 @@ diff --git a/ui/packages/consul-ui/app/components/consul/acl/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/acl/search-bar/index.hbs index c5beb16ad4..978dc749bb 100644 --- a/ui/packages/consul-ui/app/components/consul/acl/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/acl/search-bar/index.hbs @@ -1,59 +1,127 @@ - + + + <:search as |search|> + +{{#if @filter.searchproperty}} + + + + {{t "common.search.searchproperty"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + {{#each @filter.searchproperty.default as |prop|}} + + {{/each}} + {{/let}} + + + {{/if}} + + + <:filter as |search|> + + + + {{t "components.consul.acl.search-bar.kind.name"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + {{#each (array "management" "client") as |state|}} + + {{/each}} + {{/let}} + + + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Name:asc" (t "common.sort.alpha.asc")) + (array "Name:desc" (t "common.sort.alpha.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/health-check/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/health-check/search-bar/index.hbs index abf5909334..78392f665e 100644 --- a/ui/packages/consul-ui/app/components/consul/health-check/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/health-check/search-bar/index.hbs @@ -1,140 +1,190 @@ - \ No newline at end of file + + + + \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/consul/intention/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/intention/search-bar/index.hbs index 5b65c1b975..0ffc6a0e04 100644 --- a/ui/packages/consul-ui/app/components/consul/intention/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/intention/search-bar/index.hbs @@ -1,102 +1,140 @@ - \ No newline at end of file + {{/let}} + + + + \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/consul/kv/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/kv/search-bar/index.hbs index 0652216a11..9636e9bc5a 100644 --- a/ui/packages/consul-ui/app/components/consul/kv/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/kv/search-bar/index.hbs @@ -1,68 +1,128 @@ - \ No newline at end of file + + + <:search as |search|> + +{{#if @filter.searchproperty}} + + + + {{t "common.search.searchproperty"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + {{#each @filter.searchproperty.default as |prop|}} + + {{/each}} + {{/let}} + + + {{/if}} + + + <:filter as |search|> + + + + {{t "components.consul.kv.search-bar.kind.name"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + {{#each (array "folder" "key") as |item|}} + + {{/each}} + {{/let}} + + + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Key:asc" (t "common.sort.alpha.asc")) + (array "Key:desc" (t "common.sort.alpha.desc")) + (array "Kind:asc" (t "components.consul.kv.search-bar.sort.kind.asc")) + (array "Kind:desc" (t "components.consul.kv.search-bar.sort.kind.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + + + + + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/node/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/node/search-bar/index.hbs index c87fec9e48..703d1be05c 100644 --- a/ui/packages/consul-ui/app/components/consul/node/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/node/search-bar/index.hbs @@ -1,90 +1,131 @@ - \ No newline at end of file + + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Node:asc" (t "common.sort.alpha.asc")) + (array "Node:desc" (t "common.sort.alpha.desc")) + (array "Status:asc" (t "common.sort.status.asc")) + (array "Status:desc" (t "common.sort.status.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + + + + + {{/let}} + + + + \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/consul/nspace/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/nspace/search-bar/index.hbs index ab47be81b4..1742d99f21 100644 --- a/ui/packages/consul-ui/app/components/consul/nspace/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/nspace/search-bar/index.hbs @@ -1,63 +1,98 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/consul/policy/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/policy/search-bar/index.hbs index 5572c00dc9..538be653c3 100644 --- a/ui/packages/consul-ui/app/components/consul/policy/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/policy/search-bar/index.hbs @@ -1,101 +1,145 @@ - + + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Name:asc" (t "common.sort.alpha.asc")) + (array "Name:desc" (t "common.sort.alpha.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/role/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/role/search-bar/index.hbs index 0aae4f1979..d4b5dc237a 100644 --- a/ui/packages/consul-ui/app/components/consul/role/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/role/search-bar/index.hbs @@ -1,68 +1,104 @@ - + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/service-instance/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/service-instance/search-bar/index.hbs index 71fb5c27e7..aa83582dad 100644 --- a/ui/packages/consul-ui/app/components/consul/service-instance/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/service-instance/search-bar/index.hbs @@ -1,111 +1,156 @@ - + + + + diff --git a/ui/packages/consul-ui/app/components/consul/service/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/service/search-bar/index.hbs index 007bd3e9da..4c487e9f35 100644 --- a/ui/packages/consul-ui/app/components/consul/service/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/service/search-bar/index.hbs @@ -1,135 +1,190 @@ - + + + + + {{t "components.consul.service.search-bar.kind"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + {{#each (array "ingress-gateway" "terminating-gateway" "mesh-gateway") as |kind|}} + + {{/each}} + + + {{#each (array "in-mesh" "not-in-mesh") as |state|}} + + {{/each}} + + {{/let}} + + + {{#if (gt @sources.length 0)}} + + + + {{t "common.search.source"}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + {{#each @sources as |source|}} + + {{/each}} + {{/let}} + + + {{/if}} + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Name:asc" (t "common.sort.alpha.asc")) + (array "Name:desc" (t "common.sort.alpha.desc")) + (array "Status:asc" (t "common.sort.status.asc")) + (array "Status:desc" (t "common.sort.status.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + + + + + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/token/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/token/search-bar/index.hbs index e5cdacd1c6..f7d13be101 100644 --- a/ui/packages/consul-ui/app/components/consul/token/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/token/search-bar/index.hbs @@ -1,83 +1,125 @@ - + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/consul/upstream-instance/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/upstream-instance/search-bar/index.hbs index 2111718bb5..cc3fb877f7 100644 --- a/ui/packages/consul-ui/app/components/consul/upstream-instance/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/upstream-instance/search-bar/index.hbs @@ -1,63 +1,96 @@ - + + + diff --git a/ui/packages/consul-ui/app/components/consul/upstream/search-bar/index.hbs b/ui/packages/consul-ui/app/components/consul/upstream/search-bar/index.hbs index 9cdc7242a3..e8e00687a7 100644 --- a/ui/packages/consul-ui/app/components/consul/upstream/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/upstream/search-bar/index.hbs @@ -1,86 +1,126 @@ - + + + <:sort as |search|> + + + + {{#let (from-entries (array + (array "Name:asc" (t "common.sort.alpha.asc")) + (array "Name:desc" (t "common.sort.alpha.desc")) + (array "Status:asc" (t "common.sort.status.asc")) + (array "Status:desc" (t "common.sort.status.desc")) + )) + as |selectable| + }} + {{get selectable @sort.value}} + {{/let}} + + + + {{#let components.Optgroup components.Option as |Optgroup Option|}} + + + + + + + + + {{/let}} + + + + diff --git a/ui/packages/consul-ui/app/components/data-collection/index.js b/ui/packages/consul-ui/app/components/data-collection/index.js index bf9e905af9..49780a957e 100644 --- a/ui/packages/consul-ui/app/components/data-collection/index.js +++ b/ui/packages/consul-ui/app/components/data-collection/index.js @@ -1,6 +1,6 @@ import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; -import { computed, action } from '@ember/object'; +import { computed, get, action } from '@ember/object'; import { alias } from '@ember/object/computed'; import { tracked } from '@glimmer/tracking'; import { sort } from '@ember/object/computed'; @@ -32,18 +32,19 @@ export default class DataCollectionComponent extends Component { return this.term || this.args.search || ''; } - @computed('type', 'searchMethod', 'filtered', 'searchProperties') + @computed('type', 'searchMethod', 'filtered', 'args.filters') get searchable() { + const searchproperties = + get(this, 'args.filters.searchproperty.value') || get(this, 'args.filters.searchproperty'); const Searchable = typeof this.searchMethod === 'string' ? this.searchableMap[this.searchMethod] : this.args.searchable; + return new Searchable(this.filtered, { finders: Object.fromEntries( Object.entries(this.searchService.predicate(this.type)).filter(([key, value]) => { - return typeof this.searchProperties === 'undefined' - ? true - : this.searchProperties.includes(key); + return typeof searchproperties === 'undefined' ? true : searchproperties.includes(key); }) ), }); @@ -89,7 +90,13 @@ export default class DataCollectionComponent extends Component { if (typeof predicate === 'undefined') { return this.content.slice(); } - return this.content.filter(predicate(this.args.filters)); + const filters = Object.entries(this.args.filters) + .filter(([key, value]) => Boolean(value)) + .map(([key, value]) => { + const val = typeof value !== 'string' ? value.value : value; + return [key, val]; + }); + return this.content.filter(predicate(Object.fromEntries(filters))); } @computed('args.{items.[],items.content.[]}') diff --git a/ui/packages/consul-ui/app/components/popover-select/index.hbs b/ui/packages/consul-ui/app/components/popover-select/index.hbs index a3ceb2cde7..527505654e 100644 --- a/ui/packages/consul-ui/app/components/popover-select/index.hbs +++ b/ui/packages/consul-ui/app/components/popover-select/index.hbs @@ -9,7 +9,7 @@ (component 'popover-select/optgroup' components=components) (component 'popover-select/option' select=this components=components - onclick=(queue + onclick=(pipe (action "click") (if multiple (noop) menu.toggle) ) diff --git a/ui/packages/consul-ui/app/components/popover-select/index.js b/ui/packages/consul-ui/app/components/popover-select/index.js index 4062c054e3..cd8bc330e1 100644 --- a/ui/packages/consul-ui/app/components/popover-select/index.js +++ b/ui/packages/consul-ui/app/components/popover-select/index.js @@ -6,47 +6,50 @@ export default Component.extend(Slotted, { tagName: '', dom: service('dom'), multiple: false, - subtractive: false, + required: false, 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); - } - } + this._options.add(option); }, removeOption: function(option) { - this._options.delete(option.value); + this._options.delete(option); }, 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); + click: function(option, e) { + // required={{true}} ? + if (!this.multiple) { + if (option.selected && this.required) { + return e; + } + [...this._options] + .filter(item => item !== option) + .forEach(item => { + item.selected = false; + }); + } else { + if (option.selected && this.required) { + const other = [...this._options].find(item => item !== option && item.selected); + if (!other) { + return e; + } } - options = this._options; } + option.selected = !option.selected; this.onchange( this.dom.setEventTargetProperties(e, { - selected: target => value, + selected: target => option.args.value, selectedItems: target => { - return [...options].join(','); + return [...this._options] + .filter(item => item.selected) + .map(item => item.args.value) + .join(','); }, }) ); - }, - change: function(option, e) { - this.onchange(this.dom.setEventTargetProperty(e, 'selected', selected => option)); + return e; }, }, }); diff --git a/ui/packages/consul-ui/app/components/popover-select/optgroup/index.hbs b/ui/packages/consul-ui/app/components/popover-select/optgroup/index.hbs index 2847a4ce4d..c26431e2c1 100644 --- a/ui/packages/consul-ui/app/components/popover-select/optgroup/index.hbs +++ b/ui/packages/consul-ui/app/components/popover-select/optgroup/index.hbs @@ -1,7 +1,7 @@ -{{#let components.MenuSeparator as |MenuSeparator|}} +{{#let @components.MenuSeparator as |MenuSeparator|}} - {{label}} + {{@label}} {{yield}} diff --git a/ui/packages/consul-ui/app/components/popover-select/optgroup/index.js b/ui/packages/consul-ui/app/components/popover-select/optgroup/index.js deleted file mode 100644 index 4798652642..0000000000 --- a/ui/packages/consul-ui/app/components/popover-select/optgroup/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ - tagName: '', -}); diff --git a/ui/packages/consul-ui/app/components/popover-select/option/index.hbs b/ui/packages/consul-ui/app/components/popover-select/option/index.hbs index 86119b1e92..8c7274494b 100644 --- a/ui/packages/consul-ui/app/components/popover-select/option/index.hbs +++ b/ui/packages/consul-ui/app/components/popover-select/option/index.hbs @@ -1,9 +1,13 @@ -{{#let components.MenuItem as |MenuItem|}} +{{#let @components.MenuItem as |MenuItem|}} {{yield}} diff --git a/ui/packages/consul-ui/app/components/popover-select/option/index.js b/ui/packages/consul-ui/app/components/popover-select/option/index.js index 910dcd5179..dea8a82c09 100644 --- a/ui/packages/consul-ui/app/components/popover-select/option/index.js +++ b/ui/packages/consul-ui/app/components/popover-select/option/index.js @@ -1,20 +1,16 @@ -import Component from '@ember/component'; -import { inject as service } from '@ember/service'; +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; -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); - }, - }, -}); +export default class Option extends Component { + @tracked selected; + + @action + connect() { + this.args.select.addOption(this); + } + @action + disconnect() { + this.args.select.removeOption(this); + } +} diff --git a/ui/packages/consul-ui/app/components/search-bar/README.mdx b/ui/packages/consul-ui/app/components/search-bar/README.mdx deleted file mode 100644 index 9abd12924b..0000000000 --- a/ui/packages/consul-ui/app/components/search-bar/README.mdx +++ /dev/null @@ -1,61 +0,0 @@ -## SearchBar - -```handlebars - -``` - -### Arguments - -| Argument | Type | Default | Description | -| --- | --- | --- | --- | -| `value` | `String` | | The string `value` of the freetext search bar | -| `onsearch` | `Function` | | The action to fire when the freetext search bar changes. Emits a native event with a `target.value` property containing the text typed into the search bar | -| `options` | `Array` | | An array of Key/Values pairs to use for options for either a filter interface or a sort interface | -| `selected` | `Object` | | An object containing a Key/Value pair of the currently selected option | -| `onchange` | `Function` | | The action to fire when the filter/sort changes. Emits an Event-like object, when filtering this has a `target.value` property containg the key of the selected filter, when sorting this has a `target.selected` property containing the selected Key/Value pair | -| `secondary` | `string` | | String identifier to signify what type of secondary filter to show. Currently only value here is 'sort' | - -`SearchBar` is used for a variety of searching behaviours, freetext searching, filtering and sorting. It is also slot based to enable you to completely overwrite the secondary search if need be. - -### Examples - -```handlebars -{{! Freetext only search bar}} - -``` - -```handlebars -{{! Freetext and filter search bar}} - -``` - -```handlebars -{{! Freetext and sort search bar}} - -``` - -### See - -- [Component Source Code](./index.js) -- [Template Source Code](./index.hbs) - ---- diff --git a/ui/packages/consul-ui/app/components/search-bar/index.hbs b/ui/packages/consul-ui/app/components/search-bar/index.hbs index b1f01a2859..f42e9cca7f 100644 --- a/ui/packages/consul-ui/app/components/search-bar/index.hbs +++ b/ui/packages/consul-ui/app/components/search-bar/index.hbs @@ -1,31 +1,68 @@ -{{yield}} -
- {{#yield-slot name="primary"}} -
- {{yield}} -
- {{else}} - - {{/yield-slot}} - {{#yield-slot name="secondary"}} -
- {{yield}} -
- {{else}} - {{#if options}} - {{#if (eq secondary 'sort')}} - {{else}} - - {{/if}} - {{/if}} - {{/yield-slot}} - + diff --git a/ui/packages/consul-ui/app/components/search-bar/index.js b/ui/packages/consul-ui/app/components/search-bar/index.js index a7be4db131..7fefbe8ef9 100644 --- a/ui/packages/consul-ui/app/components/search-bar/index.js +++ b/ui/packages/consul-ui/app/components/search-bar/index.js @@ -1,6 +1,34 @@ -import Component from '@ember/component'; -import Slotted from 'block-slots'; +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { diff, filters } from './utils'; -export default Component.extend(Slotted, { - tagName: '', -}); +export default class SearchBar extends Component { + // only show the filter status bar if we have searchproperty filters or + // normal types of filters, and we are currently filtering by either of those + get isFiltered() { + const searchproperty = this.args.filter.searchproperty || { default: [], value: [] }; + return ( + diff(searchproperty.default, searchproperty.value).length > 0 || + Object.entries(this.args.filter).some(([key, value]) => { + return key !== 'searchproperty' && typeof value.value !== 'undefined'; + }) + ); + } + + // convert the object based filters to an array of iterable filters ready for + // rendering + get filters() { + return filters(this.args.filter); + } + + @action + removeAllFilters() { + Object.values(this.args.filter).forEach((value, i) => { + // put in a little queue to ensure query params are unset properly + // ideally this would be done outside of the component + // TODO: Look to see if this can be moved to serializeQueryParam + // so we we aren't polluting components with queryParam related things + setTimeout(() => value.change(value.default || []), 1 * i); + }); + } +} diff --git a/ui/packages/consul-ui/app/components/search-bar/index.scss b/ui/packages/consul-ui/app/components/search-bar/index.scss new file mode 100644 index 0000000000..d0b14a955a --- /dev/null +++ b/ui/packages/consul-ui/app/components/search-bar/index.scss @@ -0,0 +1,60 @@ +.search-bar { + &-status { + & { + border-bottom: $decor-border-100; + border-bottom-color: $gray-200; + } + .remove-all button { + @extend %anchor; + } + li:not(.remove-all) { + & { + @extend %pill-200; + border: $decor-border-100; + border-color: $gray-200; + color: $gray-600; + } + button { + cursor: pointer; + } + button::before { + @extend %with-cancel-plain-mask, %as-pseudo; + color: $gray-600; + margin-top: 1px; + margin-right: 0.2rem; + } + } + & { + padding: .5rem 0; + padding-left: .5rem; + } + dt::after { + content: ':'; + padding-right: 0.3rem; + } + & > dl > dt { + float: left; + } + dt { + white-space: nowrap; + } + li { + display: inline-flex; + } + li:not(:last-child) { + margin-right: 0.3rem; + margin-bottom: 0.3rem; + } + li:not(.remove-all) { + & { + padding: 0 0.2rem; + } + dl { + display: flex; + } + button { + padding: 0; + } + } + } +} diff --git a/ui/packages/consul-ui/app/components/search-bar/pageobject.js b/ui/packages/consul-ui/app/components/search-bar/pageobject.js deleted file mode 100644 index 3630864630..0000000000 --- a/ui/packages/consul-ui/app/components/search-bar/pageobject.js +++ /dev/null @@ -1,7 +0,0 @@ -export default (search, secondary = () => {}) => scope => { - return { - scope: scope, - ...search(), - ...secondary(), - }; -}; diff --git a/ui/packages/consul-ui/app/components/search-bar/remove-filter/index.hbs b/ui/packages/consul-ui/app/components/search-bar/remove-filter/index.hbs new file mode 100644 index 0000000000..78e9975d52 --- /dev/null +++ b/ui/packages/consul-ui/app/components/search-bar/remove-filter/index.hbs @@ -0,0 +1,7 @@ +
  • + + {{yield}} +
  • diff --git a/ui/packages/consul-ui/app/components/search-bar/utils.js b/ui/packages/consul-ui/app/components/search-bar/utils.js new file mode 100644 index 0000000000..d56a6580c6 --- /dev/null +++ b/ui/packages/consul-ui/app/components/search-bar/utils.js @@ -0,0 +1,38 @@ +export const diff = (a, b) => { + return a.filter(item => !b.includes(item)); +}; +/** + * filters accepts the args.filter @attribute which is shaped like + * {filterName: {default: ['Node', 'Address'], value: ['Address']}, ...} + * It will turn this into an array of 'filters' shaped like + * [{key: 'filterName', value: 'Address', selected: ["Node"]}] + * importantly 'selected' isn't what is currently 'selected' it is what selected + * will be once you remove this filter + * There is more explanation in the unit tests for this function so thats worthwhile + * checking if you are in amongst this + */ +export const filters = filters => { + return Object.entries(filters) + .filter(([key, value]) => { + if (key === 'searchproperty') { + return diff(value.default, value.value).length > 0; + } + return (value.value || []).length > 0; + }) + .reduce((prev, [key, value]) => { + return prev.concat( + value.value.map(item => { + const obj = { + key: key, + value: item, + }; + if (key !== 'searchproperty') { + obj.selected = diff(value.value, [item]); + } else { + obj.selected = value.value.length === 1 ? value.default : diff(value.value, [item]); + } + return obj; + }) + ); + }, []); +}; diff --git a/ui/packages/consul-ui/app/filter/predicates/acl.js b/ui/packages/consul-ui/app/filter/predicates/acl.js index 126d210e21..dfc15b58c9 100644 --- a/ui/packages/consul-ui/app/filter/predicates/acl.js +++ b/ui/packages/consul-ui/app/filter/predicates/acl.js @@ -1,5 +1,5 @@ export default { - kinds: { + kind: { management: (item, value) => item.Type === value, client: (item, value) => item.Type === value, }, diff --git a/ui/packages/consul-ui/app/filter/predicates/health-check.js b/ui/packages/consul-ui/app/filter/predicates/health-check.js index ae7b329495..49d60f4591 100644 --- a/ui/packages/consul-ui/app/filter/predicates/health-check.js +++ b/ui/packages/consul-ui/app/filter/predicates/health-check.js @@ -1,14 +1,14 @@ export default { - statuses: { + status: { passing: (item, value) => item.Status === value, warning: (item, value) => item.Status === value, critical: (item, value) => item.Status === value, }, - kinds: { + kind: { service: (item, value) => item.Kind === value, node: (item, value) => item.Kind === value, }, - checks: { + check: { serf: (item, value) => item.Type === '', script: (item, value) => item.Type === value, http: (item, value) => item.Type === value, diff --git a/ui/packages/consul-ui/app/filter/predicates/intention.js b/ui/packages/consul-ui/app/filter/predicates/intention.js index 3f884de0fc..30646b8dd8 100644 --- a/ui/packages/consul-ui/app/filter/predicates/intention.js +++ b/ui/packages/consul-ui/app/filter/predicates/intention.js @@ -1,5 +1,5 @@ export default { - accesses: { + access: { allow: (item, value) => item.Action === value, deny: (item, value) => item.Action === value, 'app-aware': (item, value) => typeof item.Action === 'undefined', diff --git a/ui/packages/consul-ui/app/filter/predicates/kv.js b/ui/packages/consul-ui/app/filter/predicates/kv.js index 19cf277f14..8df7da9f75 100644 --- a/ui/packages/consul-ui/app/filter/predicates/kv.js +++ b/ui/packages/consul-ui/app/filter/predicates/kv.js @@ -1,5 +1,5 @@ export default { - kinds: { + kind: { folder: (item, value) => item.isFolder, key: (item, value) => !item.isFolder, }, diff --git a/ui/packages/consul-ui/app/filter/predicates/node.js b/ui/packages/consul-ui/app/filter/predicates/node.js index 14de992556..dc8e641c01 100644 --- a/ui/packages/consul-ui/app/filter/predicates/node.js +++ b/ui/packages/consul-ui/app/filter/predicates/node.js @@ -1,5 +1,5 @@ export default { - statuses: { + status: { passing: (item, value) => item.Status === value, warning: (item, value) => item.Status === value, critical: (item, value) => item.Status === value, diff --git a/ui/packages/consul-ui/app/filter/predicates/policy.js b/ui/packages/consul-ui/app/filter/predicates/policy.js index d3a6ca4eef..c5308357a8 100644 --- a/ui/packages/consul-ui/app/filter/predicates/policy.js +++ b/ui/packages/consul-ui/app/filter/predicates/policy.js @@ -1,11 +1,11 @@ import setHelpers from 'mnemonist/set'; export default { - kinds: { + kind: { 'global-management': (item, value) => item.isGlobalManagement, standard: (item, value) => !item.isGlobalManagement, }, - dcs: (item, values) => { + datacenter: (item, values) => { return ( typeof item.Datacenters === 'undefined' || setHelpers.intersectionSize(values, new Set(item.Datacenters)) > 0 diff --git a/ui/packages/consul-ui/app/filter/predicates/service-instance.js b/ui/packages/consul-ui/app/filter/predicates/service-instance.js index ee0b46498c..76111c5760 100644 --- a/ui/packages/consul-ui/app/filter/predicates/service-instance.js +++ b/ui/packages/consul-ui/app/filter/predicates/service-instance.js @@ -1,12 +1,13 @@ import setHelpers from 'mnemonist/set'; export default { - statuses: { + status: { passing: (item, value) => item.Status === value, warning: (item, value) => item.Status === value, critical: (item, value) => item.Status === value, + empty: (item, value) => item.MeshChecks.length === 0, }, - sources: (item, values) => { + source: (item, values) => { return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0; }, }; diff --git a/ui/packages/consul-ui/app/filter/predicates/service.js b/ui/packages/consul-ui/app/filter/predicates/service.js index d90ea28467..f9a7d4a1fc 100644 --- a/ui/packages/consul-ui/app/filter/predicates/service.js +++ b/ui/packages/consul-ui/app/filter/predicates/service.js @@ -1,7 +1,7 @@ import setHelpers from 'mnemonist/set'; export default { - kinds: { + kind: { 'ingress-gateway': (item, value) => item.Kind === value, 'terminating-gateway': (item, value) => item.Kind === value, 'mesh-gateway': (item, value) => item.Kind === value, @@ -9,16 +9,17 @@ export default { 'in-mesh': (item, value) => item.InMesh, 'not-in-mesh': (item, value) => !item.InMesh, }, - statuses: { + status: { passing: (item, value) => item.MeshStatus === value, warning: (item, value) => item.MeshStatus === value, critical: (item, value) => item.MeshStatus === value, + empty: (item, value) => item.MeshChecksTotal === 0, }, - instances: { + instance: { registered: (item, value) => item.InstanceCount > 0, 'not-registered': (item, value) => item.InstanceCount === 0, }, - sources: (item, values) => { + source: (item, values) => { return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0; }, }; diff --git a/ui/packages/consul-ui/app/filter/predicates/token.js b/ui/packages/consul-ui/app/filter/predicates/token.js index 3efcea84a5..31dd06ea52 100644 --- a/ui/packages/consul-ui/app/filter/predicates/token.js +++ b/ui/packages/consul-ui/app/filter/predicates/token.js @@ -1,5 +1,5 @@ export default { - kinds: { + kind: { 'global-management': (item, value) => item.isGlobalManagement, global: (item, value) => !item.Local, local: (item, value) => item.Local, diff --git a/ui/packages/consul-ui/app/models/role.js b/ui/packages/consul-ui/app/models/role.js index 18bcc28414..1a58194d2c 100644 --- a/ui/packages/consul-ui/app/models/role.js +++ b/ui/packages/consul-ui/app/models/role.js @@ -17,7 +17,9 @@ export default class Role extends Model { @attr('number') SyncTime; @attr('number') CreateIndex; @attr('number') ModifyIndex; - // frontend only for ordering where CreateIndex can't be used + // frontend only for ordering where CreateIndex can't be used i.e. for when + // we need to order items that aren't yet saved to the backend, for example + // in the role-selector @attr('number') CreateTime; // TODO: Figure out whether we need this or not @attr() Datacenters; // string[] diff --git a/ui/packages/consul-ui/app/models/service.js b/ui/packages/consul-ui/app/models/service.js index dc1f3a8d0f..ddebe4f58a 100644 --- a/ui/packages/consul-ui/app/models/service.js +++ b/ui/packages/consul-ui/app/models/service.js @@ -48,6 +48,16 @@ export default class Service extends Model { @attr() meta; // {} + @computed('ChecksPassing', 'ChecksWarning', 'ChecksCritical') + get ChecksTotal() { + return this.ChecksPassing + this.ChecksWarning + this.ChecksCritical; + } + + @computed('MeshChecksPassing', 'MeshChecksWarning', 'MeshChecksCritical') + get MeshChecksTotal() { + return this.MeshChecksPassing + this.MeshChecksWarning + this.MeshChecksCritical; + } + /* Mesh properties involve both the service and the associated proxy */ @computed('ConnectedWithProxy', 'ConnectedWithGateway') get MeshEnabled() { diff --git a/ui/packages/consul-ui/app/routes/dc/acls/index.js b/ui/packages/consul-ui/app/routes/dc/acls/index.js index 6c621b127d..c5761cc435 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/index.js @@ -1,13 +1,11 @@ import { inject as service } from '@ember/service'; import Route from 'consul-ui/routing/route'; -import { hash } from 'rsvp'; 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('settings') settings; queryParams = { @@ -19,24 +17,25 @@ export default class IndexRoute extends Route.extend(WithAclActions) { }, }; - beforeModel(transition) { - return this.settings.findBySlug('token').then(token => { - // If you don't have a token set or you have a - // token set with AccessorID set to not null (new ACL mode) - // then rewrite to the new acls - if (!token || get(token, 'AccessorID') !== null) { - // If you return here, you get a TransitionAborted error in the tests only - // everything works fine either way checking things manually - this.replaceWith('dc.acls.tokens'); - } - }); + async beforeModel(transition) { + const token = await this.settings.findBySlug('token'); + // If you don't have a token set or you have a + // token set with AccessorID set to not null (new ACL mode) + // then rewrite to the new acls + if (!token || get(token, 'AccessorID') !== null) { + // If you return here, you get a TransitionAborted error in the tests only + // everything works fine either way checking things manually + this.replaceWith('dc.acls.tokens'); + } } - model(params) { - return hash({ - items: this.repo.findAllByDatacenter(this.modelFor('dc').dc.Name), - token: this.settings.findBySlug('token'), - }); + async model(params) { + const _items = this.repo.findAllByDatacenter(this.modelFor('dc').dc.Name); + const _token = this.settings.findBySlug('token'); + return { + items: await _items, + token: await _token, + }; } setupController(controller, model) { diff --git a/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js b/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js index b24ac000b1..394f4c6f2a 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/policies/index.js @@ -9,7 +9,9 @@ export default class IndexRoute extends Route.extend(WithPolicyActions) { queryParams = { sortBy: 'sort', - dc: 'dc', + datacenter: { + as: 'dc', + }, kind: 'kind', searchproperty: { as: 'searchproperty', @@ -29,6 +31,7 @@ export default class IndexRoute extends Route.extend(WithPolicyActions) { this.modelFor('nspace').nspace.substr(1) ), }), + searchProperties: this.queryParams.searchproperty.empty[0], }); } diff --git a/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js b/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js index f2f594461e..46c14f4938 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/roles/index.js @@ -27,6 +27,7 @@ export default class IndexRoute extends Route.extend(WithRoleActions) { this.modelFor('nspace').nspace.substr(1) ), }), + searchProperties: this.queryParams.searchproperty.empty[0], }); } diff --git a/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js b/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js index 06deafc927..bfc26b5f92 100644 --- a/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js +++ b/ui/packages/consul-ui/app/routes/dc/acls/tokens/index.js @@ -21,16 +21,15 @@ export default class IndexRoute extends Route.extend(WithTokenActions) { }, }; - beforeModel(transition) { - return this.settings.findBySlug('token').then(token => { - // If you have a token set with AccessorID set to null (legacy mode) - // then rewrite to the old acls - if (token && get(token, 'AccessorID') === null) { - // If you return here, you get a TransitionAborted error in the tests only - // everything works fine either way checking things manually - this.replaceWith('dc.acls'); - } - }); + async beforeModel(transition) { + const token = await this.settings.findBySlug('token'); + // If you have a token set with AccessorID set to null (legacy mode) + // then rewrite to the old acls + if (token && get(token, 'AccessorID') === null) { + // If you return here, you get a TransitionAborted error in the tests only + // everything works fine either way checking things manually + this.replaceWith('dc.acls'); + } } model(params) { @@ -43,6 +42,7 @@ export default class IndexRoute extends Route.extend(WithTokenActions) { }), nspace: this.modelFor('nspace').nspace.substr(1), token: this.settings.findBySlug('token'), + searchProperties: this.queryParams.searchproperty.empty[0], }); } diff --git a/ui/packages/consul-ui/app/routes/dc/intentions/index.js b/ui/packages/consul-ui/app/routes/dc/intentions/index.js index 65479ab4b7..4195ad9fb0 100644 --- a/ui/packages/consul-ui/app/routes/dc/intentions/index.js +++ b/ui/packages/consul-ui/app/routes/dc/intentions/index.js @@ -14,10 +14,11 @@ export default class IndexRoute extends Route { }, }; - model(params) { + async model(params) { return { dc: this.modelFor('dc').dc.Name, nspace: this.modelFor('nspace').nspace.substr(1), + searchProperties: this.queryParams.searchproperty.empty[0], }; } diff --git a/ui/packages/consul-ui/app/routes/dc/nodes/index.js b/ui/packages/consul-ui/app/routes/dc/nodes/index.js index fea305f737..aa0b1d764b 100644 --- a/ui/packages/consul-ui/app/routes/dc/nodes/index.js +++ b/ui/packages/consul-ui/app/routes/dc/nodes/index.js @@ -1,6 +1,5 @@ import { inject as service } from '@ember/service'; import Route from 'consul-ui/routing/route'; -import { hash } from 'rsvp'; export default class IndexRoute extends Route { @service('data-source/service') data; @@ -18,13 +17,16 @@ export default class IndexRoute extends Route { }, }; - model(params) { + async model(params) { const dc = this.modelFor('dc').dc.Name; const nspace = this.modelFor('nspace').nspace.substr(1); - return hash({ - items: this.data.source(uri => uri`/${nspace}/${dc}/nodes`), - leader: this.data.source(uri => uri`/${nspace}/${dc}/leader`), - }); + const items = this.data.source(uri => uri`/${nspace}/${dc}/nodes`); + const leader = this.data.source(uri => uri`/${nspace}/${dc}/leader`); + return { + items: await items, + leader: await leader, + searchProperties: this.queryParams.searchproperty.empty[0], + }; } setupController(controller, model) { diff --git a/ui/packages/consul-ui/app/routes/dc/nspaces/index.js b/ui/packages/consul-ui/app/routes/dc/nspaces/index.js index d1e339a963..811616cf2d 100644 --- a/ui/packages/consul-ui/app/routes/dc/nspaces/index.js +++ b/ui/packages/consul-ui/app/routes/dc/nspaces/index.js @@ -1,6 +1,5 @@ import { inject as service } from '@ember/service'; import Route from 'consul-ui/routing/route'; -import { hash } from 'rsvp'; import WithNspaceActions from 'consul-ui/mixins/nspace/with-actions'; export default class IndexRoute extends Route.extend(WithNspaceActions) { @@ -19,10 +18,11 @@ export default class IndexRoute extends Route.extend(WithNspaceActions) { }, }; - model(params) { - return hash({ - items: this.data.source(uri => uri`/*/*/namespaces`), - }); + async model(params) { + return { + items: await this.data.source(uri => uri`/*/*/namespaces`), + searchProperties: this.queryParams.searchproperty.empty[0], + }; } setupController(controller, model) { diff --git a/ui/packages/consul-ui/app/routes/dc/services/index.js b/ui/packages/consul-ui/app/routes/dc/services/index.js index 3cbb1cce34..879621028d 100644 --- a/ui/packages/consul-ui/app/routes/dc/services/index.js +++ b/ui/packages/consul-ui/app/routes/dc/services/index.js @@ -27,6 +27,7 @@ export default class IndexRoute extends Route { dc, nspace, items, + searchProperties: this.queryParams.searchproperty.empty[0], }; } diff --git a/ui/packages/consul-ui/app/routes/dc/services/instance/healthchecks.js b/ui/packages/consul-ui/app/routes/dc/services/instance/healthchecks.js index cf650e9b14..8fcf2a7a07 100644 --- a/ui/packages/consul-ui/app/routes/dc/services/instance/healthchecks.js +++ b/ui/packages/consul-ui/app/routes/dc/services/instance/healthchecks.js @@ -4,7 +4,6 @@ export default class HealthchecksRoute extends Route { queryParams = { sortBy: 'sort', status: 'status', - kind: 'kind', check: 'check', searchproperty: { as: 'searchproperty', diff --git a/ui/packages/consul-ui/app/routes/dc/services/show/intentions/index.js b/ui/packages/consul-ui/app/routes/dc/services/show/intentions/index.js index 5184a777ca..0468f02954 100644 --- a/ui/packages/consul-ui/app/routes/dc/services/show/intentions/index.js +++ b/ui/packages/consul-ui/app/routes/dc/services/show/intentions/index.js @@ -14,11 +14,12 @@ export default class IndexRoute extends Route { }, }; - model(params) { + async model(params) { return { dc: this.modelFor('dc').dc.Name, nspace: this.modelFor('nspace').nspace.substr(1) || 'default', slug: this.paramsFor('dc.services.show').name, + searchProperties: this.queryParams.searchproperty.empty[0], }; } diff --git a/ui/packages/consul-ui/app/routes/dc/services/show/services.js b/ui/packages/consul-ui/app/routes/dc/services/show/services.js index 22f1ecf9ea..dd2abff12f 100644 --- a/ui/packages/consul-ui/app/routes/dc/services/show/services.js +++ b/ui/packages/consul-ui/app/routes/dc/services/show/services.js @@ -25,13 +25,12 @@ export default class ServicesRoute extends Route { .slice(0, -1) .join('.'); const name = this.modelFor(parent).slug; - const gatewayServices = await this.data.source( - uri => uri`/${nspace}/${dc}/gateways/for-service/${name}` - ); + const items = await this.data.source(uri => uri`/${nspace}/${dc}/gateways/for-service/${name}`); return { dc, nspace, - gatewayServices, + items, + searchProperties: this.queryParams.searchproperty.empty[0], }; } diff --git a/ui/packages/consul-ui/app/styles/components.scss b/ui/packages/consul-ui/app/styles/components.scss index b1bafe475c..6e7983ecee 100644 --- a/ui/packages/consul-ui/app/styles/components.scss +++ b/ui/packages/consul-ui/app/styles/components.scss @@ -53,6 +53,7 @@ @import 'consul-ui/components/freetext-filter'; @import 'consul-ui/components/informed-action'; @import 'consul-ui/components/tab-nav'; +@import 'consul-ui/components/search-bar'; @import 'consul-ui/components/consul/tomography/graph'; @import 'consul-ui/components/consul/discovery-chain'; diff --git a/ui/packages/consul-ui/app/styles/layout.scss b/ui/packages/consul-ui/app/styles/layout.scss index 786e100f8c..b8963f0850 100644 --- a/ui/packages/consul-ui/app/styles/layout.scss +++ b/ui/packages/consul-ui/app/styles/layout.scss @@ -18,7 +18,7 @@ html[data-route$='edit'] .app-view > header + div > *:first-child { /* if it is a filter bar and the thing after the filter bar is a p then it also */ /* needs a top margun :S */ %app-view-content .tab-section > *:first-child:not(.filter-bar):not(table), -%app-view-content .tab-section > .filter-bar + p, +%app-view-content .tab-section > .search-bar + p, %app-view-content .tab-section .consul-health-check-list { margin-top: 1.25em; } diff --git a/ui/packages/consul-ui/app/styles/typography.scss b/ui/packages/consul-ui/app/styles/typography.scss index a4196e48ab..8948d39fea 100644 --- a/ui/packages/consul-ui/app/styles/typography.scss +++ b/ui/packages/consul-ui/app/styles/typography.scss @@ -17,7 +17,7 @@ h3 { %radio-card header, fieldset > header, %main-nav-horizontal-action, -%app-view-content div > dl > dt, +%definition-table dt, %table caption, %tbody-th, %form-element > span { diff --git a/ui/packages/consul-ui/app/templates/dc/acls/index.hbs b/ui/packages/consul-ui/app/templates/dc/acls/index.hbs index 71051c7fef..7bf7b3da5e 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/index.hbs @@ -1,83 +1,93 @@ {{page-title 'ACLs'}} -{{#let (hash - kinds=(if kind (split kind ',') undefined) -) as |filters|}} - {{#let (or sortBy "Name:asc") as |sort|}} - - - - - -

    - ACL Tokens {{format-number items.length}} total -

    - -
    - - Create - - - {{#if (gt items.length 0) }} - + + - {{/if}} - - - - - + +

    + ACL Tokens {{format-number items.length}} total +

    + +
    + + Create + + + {{#if (gt items.length 0) }} + + {{/if}} + + + + + + + + + + +

    + {{#if (gt items.length 0)}} + No ACLs found + {{else}} + Welcome to ACLs + {{/if}} +

    +
    + +

    + {{#if (gt items.length 0)}} + No ACLs where found matching that search, or you may not have access to view the ACLs you are searching for. + {{else}} + There don't seem to be any ACLs yet, or you may not have access to view ACLs yet. + {{/if}} +

    +
    +
    +
    +
    +
    +
    - @ondelete={{route-action 'delete'}} - @onuse={{route-action 'use'}} - @onclone={{route-action 'clone'}} - > - - - - - -

    - {{#if (gt items.length 0)}} - No ACLs found - {{else}} - Welcome to ACLs - {{/if}} -

    -
    - -

    - {{#if (gt items.length 0)}} - No ACLs where found matching that search, or you may not have access to view the ACLs you are searching for. - {{else}} - There don't seem to be any ACLs yet, or you may not have access to view ACLs yet. - {{/if}} -

    -
    -
    -
    - -
    - - {{/let}} {{/let}} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/policies/index.hbs b/ui/packages/consul-ui/app/templates/dc/acls/policies/index.hbs index 63a8dc2138..afbad19188 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/policies/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/policies/index.hbs @@ -3,104 +3,118 @@ {{else}} {{page-title 'Access Controls'}} {{/if}} -{{#let (hash - kinds=(if kind (split kind ',') undefined) - dcs=(if dc (split dc ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Description') +{{#let + + (hash + value=(or sortBy "Name:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + kind=(hash + value=(if kind (split kind ',') undefined) + change=(action (mut kind) value="target.selectedItems") + ) + datacenter=(hash + value=(if datacenter (split datacenter ',') undefined) + change=(action (mut datacenter) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Name:asc") as |sort|}} - - - - - -

    - Access Controls -

    -
    - - {{#if isAuthorized }} - {{partial 'dc/acls/nav'}} - {{/if}} - - - Create - - - {{#if (gt items.length 0) }} - + + + + +

    + Access Controls +

    +
    + + {{#if isAuthorized }} + {{partial 'dc/acls/nav'}} + {{/if}} + + + Create + + + {{#if (gt items.length 0) }} + + {{/if}} + + + + + + + + + +

    + {{#if (gt items.length 0)}} + No policies found + {{else}} + Welcome to Policies + {{/if}} +

    +
    + +

    + {{#if (gt items.length 0)}} + No policies where found matching that search, or you may not have access to view the policies you are searching for. + {{else}} + There don't seem to be any policies, or you may not have access to view policies yet. + {{/if}} +

    +
    + + + + +
    +
    +
    +
    +
    - @filter={{filters}} - @onfilter={{hash - searchproperty=(action (mut searchproperty) value="target.selectedItems") - dc=(action (mut dc) value="target.selectedItems") - kind=(action (mut kind) value="target.selectedItems") - }} - /> - {{/if}} - - - - - - - - - -

    - {{#if (gt items.length 0)}} - No policies found - {{else}} - Welcome to Policies - {{/if}} -

    -
    - -

    - {{#if (gt items.length 0)}} - No policies where found matching that search, or you may not have access to view the policies you are searching for. - {{else}} - There don't seem to be any policies, or you may not have access to view policies yet. - {{/if}} -

    -
    - - - - -
    -
    -
    -
    - - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/acls/roles/index.hbs b/ui/packages/consul-ui/app/templates/dc/acls/roles/index.hbs index 265755ea5c..5cc11ccb5f 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/roles/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/roles/index.hbs @@ -4,13 +4,28 @@ {{page-title 'Access Controls'}} {{/if}} -{{#let (hash - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Description' 'Policy') +{{#let + + (hash + value=(or sortBy "Name:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Name:asc") as |sort|}} + + items + +as |sort filters items|}} + {{/if}} - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/acls/tokens/index.hbs b/ui/packages/consul-ui/app/templates/dc/acls/tokens/index.hbs index 19582e6312..849ba3cc19 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/tokens/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/tokens/index.hbs @@ -4,110 +4,122 @@ {{page-title 'Access Controls'}} {{/if}} -{{#let (hash - kinds=(if kind (split kind ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Description' 'Policy' 'Role') +{{#let + + (hash + value=(or sortBy "CreateTime:desc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + kind=(hash + value=(if kind (split kind ',') undefined) + change=(action (mut kind) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "CreateTime:desc") as |sort|}} - - - - - -

    - Access Controls -

    -
    - - {{#if isAuthorized }} - {{partial 'dc/acls/nav'}} - {{/if}} - - - Create - - - {{#if (gt items.length 0)}} - + + + + +

    + Access Controls +

    +
    + + {{#if isAuthorized }} + {{partial 'dc/acls/nav'}} + {{/if}} + + + Create + + + {{#if (gt items.length 0)}} + - {{/if}} - - - {{#if (token/is-legacy items)}} - - -

    Update

    -
    - -

    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 documentation.

    -
    -
    - {{/if}} - - - - - - - -

    - {{#if (gt items.length 0)}} - No tokens found - {{else}} - Welcome to ACL Tokens - {{/if}} -

    -
    - -

    - {{#if (gt items.length 0)}} - No tokens where found matching that search, or you may not have access to view the tokens you are searching for. - {{else}} - There don't seem to be any tokens, or you may not have access to view tokens yet. - {{/if}} -

    -
    -
    -
    -
    -
    -
    - {{/let}} + @filter={{filters}} + /> + {{/if}} + + + {{#if (token/is-legacy items)}} + + +

    Update

    +
    + +

    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 documentation.

    +
    +
    + {{/if}} + + + + + + + +

    + {{#if (gt items.length 0)}} + No tokens found + {{else}} + Welcome to ACL Tokens + {{/if}} +

    +
    + +

    + {{#if (gt items.length 0)}} + No tokens where found matching that search, or you may not have access to view the tokens you are searching for. + {{else}} + There don't seem to be any tokens, or you may not have access to view tokens yet. + {{/if}} +

    +
    +
    +
    +
    +
    + {{/let}} diff --git a/ui/packages/consul-ui/app/templates/dc/intentions/index.hbs b/ui/packages/consul-ui/app/templates/dc/intentions/index.hbs index 429ca59b00..5341b3c645 100644 --- a/ui/packages/consul-ui/app/templates/dc/intentions/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/intentions/index.hbs @@ -6,104 +6,115 @@ -{{#let api.data as |items|}} - {{#let (hash - accesses=(if access (split access ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'SourceName' 'DestinationName') +{{#let + + (hash + value=(or sortBy "Action:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + access=(hash + value=(if access (split access ',') undefined) + change=(action (mut access) value="target.selectedItems") ) - ) as |filters|}} - {{#let (or sortBy "Action:asc") as |sort|}} - - -

    - Intentions {{format-number items.length}} total -

    - -
    - - Create - - + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) + ) - {{#if (gt items.length 0) }} - - {{/if}} + + +

    + Intentions {{format-number items.length}} total +

    + +
    + + Create + + - +{{#if (gt items.length 0) }} + +{{/if}} + +
    + + - - - - - - - - - - - - -

    - {{#if (gt items.length 0)}} - No intentions found - {{else}} - Welcome to Intentions - {{/if}} -

    -
    - -

    - {{#if (gt items.length 0)}} - No intentions where found matching that search, or you may not have access to view the intentions you are searching for. - {{else}} - There don't seem to be any intentions, or you may not have access to view intentions yet. - {{/if}} -

    -
    - - - - -
    -
    -
    -
    -
    + @sort={{sort.value}} + @filters={{filters}} + @search={{search}} + @items={{items}} + as |collection|> + + + + + + + + + +

    + {{#if (gt items.length 0)}} + No intentions found + {{else}} + Welcome to Intentions + {{/if}} +

    +
    + +

    + {{#if (gt items.length 0)}} + No intentions where found matching that search, or you may not have access to view the intentions you are searching for. + {{else}} + There don't seem to be any intentions, or you may not have access to view intentions yet. + {{/if}} +

    +
    + + + + +
    +
    +
    -
    - {{/let}} - {{/let}} + +
    + + {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/kv/index.hbs b/ui/packages/consul-ui/app/templates/dc/kv/index.hbs index 970361cd62..667137cfa3 100644 --- a/ui/packages/consul-ui/app/templates/dc/kv/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/kv/index.hbs @@ -1,8 +1,21 @@ {{page-title 'Key/Value'}} -{{#let (hash - kinds=(if kind (split kind ',') undefined) -) as |filters|}} - {{#let (or sortBy "Kind:asc") as |sort|}} +{{#let + + (hash + value=(or sortBy "Kind:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + kind=(hash + value=(if kind (split kind ',') undefined) + change=(action (mut kind) value="target.selectedItems") + ) + ) + + items + +as |sort filters items|}} {{#if (not-eq parent.Key '/') }} @@ -31,12 +44,8 @@ @onsearch={{action (mut search) value="target.value"}} @sort={{sort}} - @onsort={{action (mut sortBy) value="target.selected"}} @filter={{filters}} - @onfilter={{hash - kind=(action (mut kind) value="target.selectedItems") - }} /> {{/if}} @@ -57,7 +66,7 @@ - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/nodes/index.hbs b/ui/packages/consul-ui/app/templates/dc/nodes/index.hbs index a57a4435fe..172d1965f9 100644 --- a/ui/packages/consul-ui/app/templates/dc/nodes/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/nodes/index.hbs @@ -1,14 +1,31 @@ {{page-title 'Nodes'}} -{{#let (hash - statuses=(if status (split status ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Node' 'Address' 'Meta') +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + status=(hash + value=(if status (split status ',') undefined) + change=(action (mut status) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} -{{#let (or sortBy "Status:asc") as |sort|}} + + items + +as |sort filters items|}}

    @@ -23,20 +40,15 @@ @onsearch={{action (mut search) value="target.value"}} @sort={{sort}} - @onsort={{action (mut sortBy) value="target.selected"}} @filter={{filters}} - @onfilter={{hash - searchproperty=(action (mut searchproperty) value="target.selectedItems") - status=(action (mut status) value="target.selectedItems") - }} /> {{/if}} - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/nodes/show/healthchecks.hbs b/ui/packages/consul-ui/app/templates/dc/nodes/show/healthchecks.hbs index 0cb9d223dc..6f3cd0e353 100644 --- a/ui/packages/consul-ui/app/templates/dc/nodes/show/healthchecks.hbs +++ b/ui/packages/consul-ui/app/templates/dc/nodes/show/healthchecks.hbs @@ -1,40 +1,55 @@ -{{#let (hash - statuses=(if status (split status ',') undefined) - kinds=(if kind (split kind ',') undefined) - checks=(if check (split check ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - searchProperties +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + status=(hash + value=(if status (split status ',') undefined) + change=(action (mut status) value="target.selectedItems") + ) + kind=(hash + value=(if kind (split kind ',') undefined) + change=(action (mut kind) value="target.selectedItems") + ) + check=(hash + value=(if check (split check ',') undefined) + change=(action (mut check) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Status:asc") as |sort|}} + + item.Checks + +as |sort filters items|}}
    - {{#if (gt item.Checks.length 0) }} + {{#if (gt items.length 0) }} {{/if}}

    - This node has no health checks{{#if (gt item.Checks.length 0)}} matching that search{{/if}}. + This node has no health checks{{#if (gt items.length 0)}} matching that search{{/if}}.

    - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/nodes/show/services.hbs b/ui/packages/consul-ui/app/templates/dc/nodes/show/services.hbs index 491a13c14f..1d1000fa68 100644 --- a/ui/packages/consul-ui/app/templates/dc/nodes/show/services.hbs +++ b/ui/packages/consul-ui/app/templates/dc/nodes/show/services.hbs @@ -1,13 +1,32 @@ -{{#let (hash - statuses=(if status (split status ',') undefined) - sources=(if source (split source ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - searchProperties +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + status=(hash + value=(if status (split status ',') undefined) + change=(action (mut status) value="target.selectedItems") + ) + source=(hash + value=(if source (split source ',') undefined) + change=(action (mut source) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Status:asc") as |sort|}} - {{#let (reject-by 'Service.Kind' 'connect-proxy' item.Services) as |items|}} + + (reject-by 'Service.Kind' 'connect-proxy' item.Services) + +as |sort filters items|}}
    {{#if (gt items.length 0) }} @@ -18,20 +37,14 @@ @searchproperties={{searchProperties}} @sort={{sort}} - @onsort={{action (mut sortBy) value="target.selected"}} @filter={{filters}} - @onfilter={{hash - searchproperty=(action (mut searchproperty) value="target.selectedItems") - status=(action (mut status) value="target.selectedItems") - source=(action (mut source) value="target.selectedItems") - }} /> {{/if}} {{! filter out any sidecar proxies }}
    - {{/let}} - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/nspaces/index.hbs b/ui/packages/consul-ui/app/templates/dc/nspaces/index.hbs index b3397375cf..a3a9eadd57 100644 --- a/ui/packages/consul-ui/app/templates/dc/nspaces/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/nspaces/index.hbs @@ -1,12 +1,27 @@ {{page-title 'Namespaces'}} -{{#let (hash - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Description' 'Policy' 'Role') + +{{#let + + (hash + value=(or sortBy "Name:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Name:asc") as |sort|}} - + + items + +as |sort filters items|}} + {{/if}} - {{/let}} {{/let}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/services/index.hbs b/ui/packages/consul-ui/app/templates/dc/services/index.hbs index 2b65e33e78..8925395670 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/index.hbs @@ -4,15 +4,31 @@ {{#let - (or sortBy "Status:asc") + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) (hash - statuses=(if status (split status ',') undefined) - kinds=(if kind (split kind ',') undefined) - sources=(if source (split source ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Tags') + status=(hash + value=(if status (split status ',') undefined) + change=(action (mut status) value="target.selectedItems") + ) + kind=(hash + value=(if kind (split kind ',') undefined) + change=(action (mut kind) value="target.selectedItems") + ) + source=(hash + value=(if source (split source ',') undefined) + change=(action (mut source) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties ) ) @@ -36,22 +52,16 @@ as |sort filters items|}} @onsearch={{action (mut search) value="target.value"}} @sort={{sort}} - @onsort={{action (mut sortBy) value="target.selected"}} @filter={{filters}} - @onfilter={{hash - searchproperty=(action (mut searchproperty) value="target.selectedItems") - status=(action (mut status) value="target.selectedItems") - kind=(action (mut kind) value="target.selectedItems") - source=(action (mut source) value="target.selectedItems") - }} + /> {{/if}} - {{#if (gt item.MeshChecks.length 0) }} + {{#if (gt items.length 0) }} {{/if}}

    - This instance has no health checks{{#if (gt item.MeshChecks.length 0)}} matching that search{{/if}}. + This instance has no health checks{{#if (gt items.length 0)}} matching that search{{/if}}.

    @@ -54,5 +65,4 @@
    - {{/let}} {{/let}} diff --git a/ui/packages/consul-ui/app/templates/dc/services/instance/upstreams.hbs b/ui/packages/consul-ui/app/templates/dc/services/instance/upstreams.hbs index 6ea8d7c32f..6cb5bd5e90 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/instance/upstreams.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/instance/upstreams.hbs @@ -1,12 +1,26 @@
    -{{#let (hash - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - searchProperties +{{#let + + (hash + value=(or sortBy "DestinationName:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "DestinationName:asc") as |sort|}} - {{#if (gt proxy.Service.Proxy.Upstreams.length 0)}} + + proxy.Service.Proxy.Upstreams + +as |sort filters items|}} + {{#if (gt items.length 0)}} {{/if}}

    - This service has no upstreams{{#if (gt proxy.Service.Proxy.Upstreams.length 0)}} matching that search{{/if}}. + This service has no upstreams{{#if (gt items.length 0)}} matching that search{{/if}}.

    - {{/let}} {{/let}}
    \ No newline at end of file diff --git a/ui/packages/consul-ui/app/templates/dc/services/show/instances.hbs b/ui/packages/consul-ui/app/templates/dc/services/show/instances.hbs index 39e2fb59ef..cb6c553ca5 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/show/instances.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/show/instances.hbs @@ -1,36 +1,49 @@
    -{{#let (hash - statuses=(if status (split status ',') undefined) - sources=(if source (split source ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - searchProperties +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + status=(hash + value=(if status (split status ',') undefined) + change=(action (mut status) value="target.selectedItems") + ) + source=(hash + value=(if source (split source ',') undefined) + change=(action (mut source) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Status:asc") as |sort|}} + + items + +as |sort filters items|}} {{#if (gt items.length 0) }} {{/if}} {{! Service > Service Instance view doesn't require filtering of proxies }} - {{/let}} {{/let}}
    diff --git a/ui/packages/consul-ui/app/templates/dc/services/show/intentions/index.hbs b/ui/packages/consul-ui/app/templates/dc/services/show/intentions/index.hbs index b8a7e22574..3a2135d842 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/show/intentions/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/show/intentions/index.hbs @@ -12,74 +12,83 @@ as |api|>
    -{{#let api.data as |items|}} - {{#let (hash - accesses=(if access (split access ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'SourceName' 'DestinationName') +{{#let + + (hash + value=(or sortBy "Action:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + access=(hash + value=(if access (split access ',') undefined) + change=(action (mut access) value="target.selectedItems") ) - ) as |filters|}} - {{#let (or sortBy "Action:asc") as |sort|}} -
    - - Create - + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) + ) + + api.data + +as |sort filters items|}} +
    + + Create + {{#if (gt items.length 0) }} - + @filter={{filters}} + /> {{/if}} - + + - - - - - - - - - - - - -

    - There are no intentions {{if (gt items.length 0) 'found '}} for this service. -

    -
    -
    -
    -
    -
    -
    -
    - {{/let}} - {{/let}} + @sort={{sort.value}} + @filters={{filters}} + @search={{search}} + @items={{items}} + as |collection|> + + + + + + + + + + +

    + There are no intentions {{if (gt items.length 0) 'found '}} for this service. +

    +
    +
    +
    + + + +
    {{/let}}
    diff --git a/ui/packages/consul-ui/app/templates/dc/services/show/services.hbs b/ui/packages/consul-ui/app/templates/dc/services/show/services.hbs index dec7ccb527..a080c23637 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/show/services.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/show/services.hbs @@ -1,27 +1,39 @@ - +
    -{{#let (hash - instances=(if instance (split instance ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Tags') +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + instance=(hash + value=(if instance (split instance ',') undefined) + change=(action (mut instance) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Name:asc") as |sort|}} -{{#if (gt gatewayServices.length 0)}} + + items + +as |sort filters items|}} +{{#if (gt items.length 0)}} {{/if}}

    @@ -30,10 +42,10 @@

    - There are no linked services{{#if (gt gatewayServices.length 0)}} matching that search{{/if}}. + There are no linked services{{#if (gt items.length 0)}} matching that search{{/if}}.

    - {{/let}} {{/let}}
    diff --git a/ui/packages/consul-ui/app/templates/dc/services/show/upstreams.hbs b/ui/packages/consul-ui/app/templates/dc/services/show/upstreams.hbs index bb67a00447..f6f54c8f04 100644 --- a/ui/packages/consul-ui/app/templates/dc/services/show/upstreams.hbs +++ b/ui/packages/consul-ui/app/templates/dc/services/show/upstreams.hbs @@ -1,27 +1,39 @@ - +
    -{{#let (hash - instances=(if instance (split instance ',') undefined) - searchproperties=(if (not-eq searchproperty undefined) - (split searchproperty ',') - (array 'Name' 'Tags') +{{#let + + (hash + value=(or sortBy "Status:asc") + change=(action (mut sortBy) value="target.selected") + ) + + (hash + instance=(hash + value=(if instance (split instance ',') undefined) + change=(action (mut instance) value="target.selectedItems") + ) + searchproperty=(hash + value=(if (not-eq searchproperty undefined) + (split searchproperty ',') + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) ) -) as |filters|}} - {{#let (or sortBy "Status:asc") as |sort|}} -{{#if (gt gatewayServices.length 0)}} + + items + +as |sort filters items|}} +{{#if (gt items.length 0)}} {{/if}}

    @@ -29,10 +41,10 @@

    - There are no upstreams{{#if (gt gatewayServices.length 0)}} matching that search{{/if}}. + There are no upstreams{{#if (gt items.length 0)}} matching that search{{/if}}.

    - {{/let}} {{/let}}
    diff --git a/ui/packages/consul-ui/app/utils/intl/missing-message.js b/ui/packages/consul-ui/app/utils/intl/missing-message.js new file mode 100644 index 0000000000..f156fb93c6 --- /dev/null +++ b/ui/packages/consul-ui/app/utils/intl/missing-message.js @@ -0,0 +1,9 @@ +// if we can't find the message, take the last part of the identifier and +// ucfirst it so it looks human +export default function missingMessage(key, locales) { + const last = key + .split('.') + .pop() + .replaceAll('-', ' '); + return `${last.substr(0, 1).toUpperCase()}${last.substr(1)}`; +} diff --git a/ui/packages/consul-ui/tests/integration/components/search-bar-test.js b/ui/packages/consul-ui/tests/integration/components/search-bar-test.js deleted file mode 100644 index 91b1780092..0000000000 --- a/ui/packages/consul-ui/tests/integration/components/search-bar-test.js +++ /dev/null @@ -1,24 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | search-bar', function(hooks) { - setupRenderingTest(hooks); - - test('it renders', async function(assert) { - // Set any properties with this.set('myProperty', 'value'); - this.set('search', function(e) {}); - - await render(hbs``); - - assert.equal(this.element.textContent.trim(), 'Search'); - - // Template block usage: - await render(hbs` - - `); - - assert.equal(this.element.textContent.trim(), 'Search'); - }); -}); diff --git a/ui/packages/consul-ui/tests/pages.js b/ui/packages/consul-ui/tests/pages.js index cef83a67b6..3512763071 100644 --- a/ui/packages/consul-ui/tests/pages.js +++ b/ui/packages/consul-ui/tests/pages.js @@ -6,7 +6,6 @@ import { collection, text, isPresent, - triggerable, } from 'ember-cli-page-object'; import { alias } from 'ember-cli-page-object/macros'; @@ -26,9 +25,7 @@ import pageFactory from 'consul-ui/components/hashicorp-consul/pageobject'; import radiogroup from 'consul-ui/components/radio-group/pageobject'; import tabgroup from 'consul-ui/components/tab-nav/pageobject'; import authFormFactory from 'consul-ui/components/auth-form/pageobject'; -import freetextFilterFactory from 'consul-ui/components/freetext-filter/pageobject'; -import searchBarFactory from 'consul-ui/components/search-bar/pageobject'; import emptyStateFactory from 'consul-ui/components/empty-state/pageobject'; import policyFormFactory from 'consul-ui/components/policy-form/pageobject'; @@ -82,11 +79,6 @@ const cancelable = createCancelable(clickable, is); // components const tokenList = tokenListFactory(clickable, attribute, collection, deletable); const authForm = authFormFactory(submitable, clickable, attribute); -const freetextFilter = freetextFilterFactory(triggerable); -const catalogToolbar = searchBarFactory(freetextFilter); -const aclFilter = searchBarFactory(freetextFilter, () => - radiogroup('type', ['', 'management', 'client']) -); const policyForm = policyFormFactory(submitable, cancelable, radiogroup, text); const policySelector = policySelectorFactory(clickable, deletable, collection, alias, policyForm); const roleForm = roleFormFactory(submitable, cancelable, policySelector); @@ -160,18 +152,7 @@ export default { radiogroup ) ), - service: create( - service( - visitable, - clickable, - attribute, - collection, - text, - consulIntentionList, - catalogToolbar, - tabgroup - ) - ), + service: create(service(visitable, clickable, attribute, collection, text, consulIntentionList, tabgroup)), instance: create( instance( visitable, @@ -199,7 +180,7 @@ export default { ), kvs: create(kvs(visitable, creatable, consulKvList)), kv: create(kv(visitable, attribute, submitable, deletable, cancelable, clickable)), - acls: create(acls(visitable, deletable, creatable, clickable, attribute, collection, aclFilter)), + acls: create(acls(visitable, deletable, creatable, clickable, attribute, collection)), acl: create(acl(visitable, submitable, deletable, cancelable, clickable)), policies: create(policies(visitable, creatable, consulPolicyList, popoverSelect)), policy: create(policy(visitable, submitable, deletable, cancelable, clickable, tokenList)), diff --git a/ui/packages/consul-ui/tests/pages/dc/acls/index.js b/ui/packages/consul-ui/tests/pages/dc/acls/index.js index a460f81dda..ec335ed87c 100644 --- a/ui/packages/consul-ui/tests/pages/dc/acls/index.js +++ b/ui/packages/consul-ui/tests/pages/dc/acls/index.js @@ -1,4 +1,4 @@ -export default function(visitable, deletable, creatable, clickable, attribute, collection, filter) { +export default function(visitable, deletable, creatable, clickable, attribute, collection) { return creatable({ visit: visitable('/:dc/acls'), acls: collection( @@ -11,6 +11,5 @@ export default function(visitable, deletable, creatable, clickable, attribute, c confirmUse: clickable('[data-test-confirm-use]'), }) ), - filter: filter('[data-test-acl-filter]'), }); } diff --git a/ui/packages/consul-ui/tests/pages/dc/services/show.js b/ui/packages/consul-ui/tests/pages/dc/services/show.js index 5f2d7b366e..7936ce8a43 100644 --- a/ui/packages/consul-ui/tests/pages/dc/services/show.js +++ b/ui/packages/consul-ui/tests/pages/dc/services/show.js @@ -1,13 +1,4 @@ -export default function( - visitable, - clickable, - attribute, - collection, - text, - intentions, - filter, - tabs -) { +export default function(visitable, clickable, attribute, collection, text, intentions, tabs) { const page = { visit: visitable('/:dc/services/:service'), externalSource: attribute('data-test-external-source', '[data-test-external-source]', { @@ -28,7 +19,6 @@ export default function( 'routing', 'tags', ]), - filter: filter(), // TODO: These need to somehow move to subpages instances: collection('.consul-service-instance-list > ul > li:not(:first-child)', { address: text('[data-test-address]'), diff --git a/ui/packages/consul-ui/tests/unit/components/search-bar/filters-test.js b/ui/packages/consul-ui/tests/unit/components/search-bar/filters-test.js new file mode 100644 index 0000000000..08c444c657 --- /dev/null +++ b/ui/packages/consul-ui/tests/unit/components/search-bar/filters-test.js @@ -0,0 +1,154 @@ +import { filters } from 'consul-ui/components/search-bar/utils'; +import { module, test } from 'qunit'; + +module('Unit | Component | search-bar/filters', function() { + test('it correctly reshapes the filter data', function(assert) { + [ + // basic filter, returns a single filter button when clicked + // resets selected/queryparam to empty + { + filters: { + status: { + value: ['passing'], + }, + }, + expected: [ + { + key: 'status', + value: 'passing', + selected: [], + }, + ], + }, + // basic filters, returns multiple filter button when clicked + // sets selected/queryparam to the left over single filter + { + filters: { + status: { + value: ['passing', 'warning'], + }, + }, + expected: [ + { + key: 'status', + value: 'passing', + selected: ['warning'], + }, + { + key: 'status', + value: 'warning', + selected: ['passing'], + }, + ], + }, + // basic filters, returns multiple filter button when clicked + // sets selected/queryparam to the left over multiple filters + { + filters: { + status: { + value: ['passing', 'warning', 'critical'], + }, + }, + expected: [ + { + key: 'status', + value: 'passing', + selected: ['warning', 'critical'], + }, + { + key: 'status', + value: 'warning', + selected: ['passing', 'critical'], + }, + { + key: 'status', + value: 'critical', + selected: ['passing', 'warning'], + }, + ], + }, + // basic filters, returns multiple filter button when clicked + // sets selected/queryparam to the left over multiple filters + // also search property multiple filter, sets the selected/queryparam to + // the left of single searchproperty filter + { + filters: { + status: { + value: ['passing', 'warning', 'critical'], + }, + searchproperties: { + default: ['Node', 'Address', 'Meta'], + value: ['Node', 'Address'], + }, + }, + expected: [ + { + key: 'status', + value: 'passing', + selected: ['warning', 'critical'], + }, + { + key: 'status', + value: 'warning', + selected: ['passing', 'critical'], + }, + { + key: 'status', + value: 'critical', + selected: ['passing', 'warning'], + }, + { + key: 'searchproperties', + value: 'Node', + selected: ['Address'], + }, + { + key: 'searchproperties', + value: 'Address', + selected: ['Node'], + }, + ], + }, + // basic filters, returns multiple filter button when clicked + // sets selected/queryparam to the left over multiple filters + // also search property single filter, resets the selected/queryparam to + // empty + { + filters: { + status: { + value: ['passing', 'warning', 'critical'], + }, + searchproperties: { + default: ['Node', 'Address', 'Meta'], + value: ['Node'], + }, + }, + expected: [ + { + key: 'status', + value: 'passing', + selected: ['warning', 'critical'], + }, + { + key: 'status', + value: 'warning', + selected: ['passing', 'critical'], + }, + { + key: 'status', + value: 'critical', + selected: ['passing', 'warning'], + }, + { + key: 'searchproperties', + value: 'Node', + selected: [], + }, + ], + }, + ].forEach(item => { + const actual = filters(item.filters); + assert.deepEqual(actual, item.expected); + }); + }); +}); diff --git a/ui/packages/consul-ui/tests/unit/filter/predicates/intention-test.js b/ui/packages/consul-ui/tests/unit/filter/predicates/intention-test.js index 26d67ff263..eaae3c9a25 100644 --- a/ui/packages/consul-ui/tests/unit/filter/predicates/intention-test.js +++ b/ui/packages/consul-ui/tests/unit/filter/predicates/intention-test.js @@ -20,7 +20,7 @@ module('Unit | Filter | Predicates | intention', function() { expected = [items[0]]; actual = items.filter( predicate({ - accesses: ['allow'], + access: ['allow'], }) ); assert.deepEqual(actual, expected); @@ -28,7 +28,7 @@ module('Unit | Filter | Predicates | intention', function() { expected = [items[1]]; actual = items.filter( predicate({ - accesses: ['deny'], + access: ['deny'], }) ); assert.deepEqual(actual, expected); @@ -36,7 +36,7 @@ module('Unit | Filter | Predicates | intention', function() { expected = items; actual = items.filter( predicate({ - accesses: ['allow', 'deny'], + access: ['allow', 'deny'], }) ); assert.deepEqual(actual, expected); diff --git a/ui/packages/consul-ui/tests/unit/filter/predicates/service-test.js b/ui/packages/consul-ui/tests/unit/filter/predicates/service-test.js index 004da99480..01f3e600ce 100644 --- a/ui/packages/consul-ui/tests/unit/filter/predicates/service-test.js +++ b/ui/packages/consul-ui/tests/unit/filter/predicates/service-test.js @@ -20,7 +20,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[0]]; actual = items.filter( predicate({ - instances: ['registered'], + instance: ['registered'], }) ); assert.deepEqual(actual, expected); @@ -28,7 +28,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[1]]; actual = items.filter( predicate({ - instances: ['not-registered'], + instance: ['not-registered'], }) ); assert.deepEqual(actual, expected); @@ -36,7 +36,7 @@ module('Unit | Filter | Predicates | service', function() { expected = items; actual = items.filter( predicate({ - instances: ['registered', 'not-registered'], + instance: ['registered', 'not-registered'], }) ); assert.deepEqual(actual, expected); @@ -60,7 +60,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[0]]; actual = items.filter( predicate({ - statuses: ['passing'], + status: ['passing'], }) ); assert.deepEqual(actual, expected); @@ -68,7 +68,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[1]]; actual = items.filter( predicate({ - statuses: ['warning'], + status: ['warning'], }) ); assert.deepEqual(actual, expected); @@ -76,7 +76,7 @@ module('Unit | Filter | Predicates | service', function() { expected = items; actual = items.filter( predicate({ - statuses: ['passing', 'warning', 'critical'], + status: ['passing', 'warning', 'critical'], }) ); assert.deepEqual(actual, expected); @@ -98,7 +98,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[0]]; actual = items.filter( predicate({ - kinds: ['ingress-gateway'], + kind: ['ingress-gateway'], }) ); assert.deepEqual(actual, expected); @@ -106,7 +106,7 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[1]]; actual = items.filter( predicate({ - kinds: ['mesh-gateway'], + kind: ['mesh-gateway'], }) ); assert.deepEqual(actual, expected); @@ -114,7 +114,7 @@ module('Unit | Filter | Predicates | service', function() { expected = items; actual = items.filter( predicate({ - kinds: ['ingress-gateway', 'mesh-gateway', 'service'], + kind: ['ingress-gateway', 'mesh-gateway', 'service'], }) ); assert.deepEqual(actual, expected); @@ -142,9 +142,9 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[0]]; actual = items.filter( predicate({ - kinds: ['ingress-gateway'], - statuses: ['passing'], - instances: ['registered'], + kind: ['ingress-gateway'], + status: ['passing'], + instance: ['registered'], }) ); assert.deepEqual(actual, expected); @@ -152,9 +152,9 @@ module('Unit | Filter | Predicates | service', function() { expected = [items[1]]; actual = items.filter( predicate({ - kinds: ['mesh-gateway'], - statuses: ['warning'], - instances: ['registered'], + kind: ['mesh-gateway'], + status: ['warning'], + instance: ['registered'], }) ); assert.deepEqual(actual, expected); @@ -162,9 +162,9 @@ module('Unit | Filter | Predicates | service', function() { expected = items; actual = items.filter( predicate({ - kinds: ['ingress-gateway', 'mesh-gateway', 'service'], - statuses: ['passing', 'warning', 'critical'], - instances: ['registered', 'not-registered'], + kind: ['ingress-gateway', 'mesh-gateway', 'service'], + status: ['passing', 'warning', 'critical'], + instance: ['registered', 'not-registered'], }) ); assert.deepEqual(actual, expected); diff --git a/ui/packages/consul-ui/translations/en-us.yaml b/ui/packages/consul-ui/translations/en-us.yaml index 84e4adae4b..f80096fd0d 100644 --- a/ui/packages/consul-ui/translations/en-us.yaml +++ b/ui/packages/consul-ui/translations/en-us.yaml @@ -1 +1,158 @@ common: + brand: + consul: Consul + terraform: Terraform + nomad: Nomad + vault: Vault + aws: AWS + kubernetes: Kubernetes + ui: + remove: Remove {item} + filtered-by: Filtered by {item} + name: Name + creation: Creation + consul: + name: Name + passing: Passing + warning: Warning + critical: Critical + registered: Registered + not-registered: Not Registered + empty: No checks + tags: Tags + service: Service + gateway: Gateway + mesh: Mesh + ingress-gateway: Ingress Gateway + terminating-gateway: Terminating Gateway + mesh-gateway: Mesh Gateway + status: Health Status + service-name: Service Name + node-name: Node Name + accessorid: AccessorID + datacenter: Datacenter + localbindaddress: Local Bind Address + localbindport: Local Bind Port + destinationname: Destination Name + sourcename: Source Name + search: + search: Search + searchproperty: Search Across + source: Source + critical: Failing + in-mesh: In service mesh + not-in-mesh: Not in service mesh + sort: + alpha: + asc: A to Z + desc: Z to A + numeric: + asc: Ascending + desc: Descending + age: + asc: Oldest to Newest + desc: Newest to Oldest + status: + asc: Unhealthy to Healthy + desc: Healthy to Unhealthy + +components: + consul: + service: + search-bar: + kind: Service Type + in-mesh: In service mesh + not-in-mesh: Not in service mesh + upstream: + search-bar: + instance: + name: Type + service-instance: + search-bar: + sort: + name: + name: Service Name + health-check: + search-bar: + kind: + name: Kind + options: + service: Service Check + node: Node Check + check: + name: Type + options: + alias: alias + docker: docker + grpc: grpc + http: http + script: script + serf: serf + tcp: tcp + ttl: ttl + sort: + name: + name: Check Name + kind: + name: Check Type + asc: Service to Node + desc: Node to Service + acl: + search-bar: + kind: + name: Type + options: + management: Management + client: Client + token: + search-bar: + kind: + name: Type + options: + global-management: Global Management + global: Global Scope + local: Local Scope + policy: + search-bar: + kind: + name: Type + options: + global-management: Global Management + standard: Standard + kv: + search-bar: + kind: + name: Type + options: + folder: Folder + key: Key + sort: + kind: + asc: Folders to Keys + desc: Keys to Folders + intention: + search-bar: + access: + name: Permission + options: + allow: Allow + deny: Deny + app-aware: App aware + sort: + access: + name: Permission + asc: Allow to Deny + desc: Deny to Allow + source-name: + name: Source + asc: "Source: A to Z" + desc: "Source: Z to A" + destination-name: + name: Destination + asc: "Destination: A to Z" + desc: "Destination: Z to A" + precedence: + name: Precedence + asc: Ascending + desc: Descending +