ui: Search/sort improvements (#9183)
This commit is contained in:
parent
b8d6e195ed
commit
8a954f0639
|
@ -1,4 +1,7 @@
|
|||
<form class="consul-intention-search-bar filter-bar">
|
||||
<form
|
||||
class="consul-intention-search-bar filter-bar"
|
||||
...attributes
|
||||
>
|
||||
<FreetextFilter
|
||||
@onsearch={{action onsearch}}
|
||||
@value={{search}}
|
||||
|
@ -19,6 +22,7 @@
|
|||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option class="value-allow" @value="allow" @selected={{contains 'allow' filter.accesses}}>Allow</Option>
|
||||
<Option class="value-deny" @value="deny" @selected={{contains 'deny' filter.accesses}}>Deny</Option>
|
||||
<Option class="value-" @value="app-aware" @selected={{contains 'app-aware' filter.accesses}}>App aware</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
|
|
@ -1,57 +1,59 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} @linkable={{action "isLinkable"}} class="consul-nspace-list" as |item|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if item.DeletedAt}}
|
||||
<p>
|
||||
Deleting {{item.Name}}...
|
||||
</p>
|
||||
{{else}}
|
||||
<a data-test-nspace={{item.Name}} href={{href-to 'dc.nspaces.edit' item.Name}}>{{item.Name}}</a>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd data-test-description>
|
||||
{{item.Description}}
|
||||
</dd>
|
||||
</dl>
|
||||
{{#if (env 'CONSUL_ACLS_ENABLED')}}
|
||||
<Consul::Token::Ruleset::List @item={{item}} />
|
||||
<ListCollection @items={{items}} @linkable={{action "isLinkable"}} class="consul-nspace-list" as |item|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if item.DeletedAt}}
|
||||
<p>
|
||||
Deleting {{item.Name}}...
|
||||
</p>
|
||||
{{else}}
|
||||
<a data-test-nspace={{item.Name}} href={{href-to 'dc.nspaces.edit' item.Name}}>{{item.Name}}</a>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions" as |Actions|>
|
||||
{{#if (not item.DeletedAt)}}
|
||||
<Actions as |Action|>
|
||||
<Action data-test-edit-action @href={{href-to 'dc.nspaces.edit' item.Name}}>
|
||||
<BlockSlot @name="label">
|
||||
Edit
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
{{#if (not-eq item.Name 'default') }}
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="confirmation" as |Confirmation|>
|
||||
<Confirmation class="warning">
|
||||
<BlockSlot @name="header">
|
||||
Confirm delete
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<p>
|
||||
Are you sure you want to delete this namespace?
|
||||
</p>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="confirm" as |Confirm|>
|
||||
<Confirm>Delete</Confirm>
|
||||
</BlockSlot>
|
||||
</Confirmation>
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
{{/if}}
|
||||
</Actions>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd data-test-description>
|
||||
{{item.Description}}
|
||||
</dd>
|
||||
</dl>
|
||||
{{#if (env 'CONSUL_ACLS_ENABLED')}}
|
||||
<Consul::Token::Ruleset::List @item={{item}} />
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions" as |Actions|>
|
||||
{{#if (not item.DeletedAt)}}
|
||||
<Actions as |Action|>
|
||||
<Action data-test-edit-action @href={{href-to 'dc.nspaces.edit' item.Name}}>
|
||||
<BlockSlot @name="label">
|
||||
Edit
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
{{#if (not-eq item.Name 'default') }}
|
||||
<Action data-test-delete-action @onclick={{action ondelete item}} class="dangerous">
|
||||
<BlockSlot @name="label">
|
||||
Delete
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="confirmation" as |Confirmation|>
|
||||
<Confirmation class="warning">
|
||||
<BlockSlot @name="header">
|
||||
Confirm delete
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<p>
|
||||
Are you sure you want to delete this namespace?
|
||||
</p>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="confirm" as |Confirm|>
|
||||
<Confirm>Delete</Confirm>
|
||||
</BlockSlot>
|
||||
</Confirmation>
|
||||
</BlockSlot>
|
||||
</Action>
|
||||
{{/if}}
|
||||
</Actions>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{else}}
|
||||
{{yield to="empty"}}
|
||||
{{/if}}
|
|
@ -28,7 +28,7 @@
|
|||
<PopoverSelect
|
||||
class="select-type"
|
||||
@position="left"
|
||||
@onchange={{action onfilter.type}}
|
||||
@onchange={{action onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -38,8 +38,8 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.types}}>Global Management</Option>
|
||||
<Option @value="standard" @selected={{contains 'standard' filter.types}}>Standard</Option>
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.kinds}}>Global Management</Option>
|
||||
<Option @value="standard" @selected={{contains 'standard' filter.kinds}}>Standard</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</PopoverSelect>
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.type}}
|
||||
@onchange={{action onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -37,15 +37,15 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="service" @selected={{contains 'service' filter.types}}>Service</Option>
|
||||
<Option @value="service" @selected={{contains 'service' filter.kinds}}>Service</Option>
|
||||
<Optgroup @label="Gateway">
|
||||
<Option @value="ingress-gateway" @selected={{contains 'ingress-gateway' filter.types}}>Ingress Gateway</Option>
|
||||
<Option @value="terminating-gateway" @selected={{contains 'terminating-gateway' filter.types}}>Terminating Gateway</Option>
|
||||
<Option @value="mesh-gateway" @selected={{contains 'mesh-gateway' filter.types}}>Mesh Gateway</Option>
|
||||
<Option @value="ingress-gateway" @selected={{contains 'ingress-gateway' filter.kinds}}>Ingress Gateway</Option>
|
||||
<Option @value="terminating-gateway" @selected={{contains 'terminating-gateway' filter.kinds}}>Terminating Gateway</Option>
|
||||
<Option @value="mesh-gateway" @selected={{contains 'mesh-gateway' filter.kinds}}>Mesh Gateway</Option>
|
||||
</Optgroup>
|
||||
<Optgroup @label="Mesh">
|
||||
<Option @value="in-mesh" @selected={{contains 'in-mesh' filter.types}}>In service mesh</Option>
|
||||
<Option @value="not-in-mesh" @selected={{contains 'not-in-mesh' filter.types}}>Not in service mesh</Option>
|
||||
<Option @value="in-mesh" @selected={{contains 'in-mesh' filter.kinds}}>In service mesh</Option>
|
||||
<Option @value="not-in-mesh" @selected={{contains 'not-in-mesh' filter.kinds}}>Not in service mesh</Option>
|
||||
</Optgroup>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="filters">
|
||||
<PopoverSelect
|
||||
@position="left"
|
||||
@onchange={{action onfilter.type}}
|
||||
@onchange={{action onfilter.kind}}
|
||||
@multiple={{true}}
|
||||
as |components|>
|
||||
<BlockSlot @name="selected">
|
||||
|
@ -17,9 +17,9 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="options">
|
||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.types}}>Global Management</Option>
|
||||
<Option @value="global" @selected={{contains 'global' filter.types}}>Global</Option>
|
||||
<Option @value="local" @selected={{contains 'local' filter.types}}>Local</Option>
|
||||
<Option @value="global-management" @selected={{contains 'global-management' filter.kinds}}>Global Management</Option>
|
||||
<Option @value="global" @selected={{contains 'global' filter.kinds}}>Global</Option>
|
||||
<Option @value="local" @selected={{contains 'local' filter.kinds}}>Local</Option>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverSelect>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
dc: 'dc',
|
||||
type: 'type',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Controller from '@ember/controller';
|
||||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -6,9 +6,10 @@ export default class IndexController extends Controller {
|
|||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
type: 'type',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import Controller from '@ember/controller';
|
|||
export default class IndexController extends Controller {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
export default () => ({ accesses = [] }) => item => {
|
||||
if (accesses.length > 0) {
|
||||
if (accesses.includes(item.Action)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
accesses: {
|
||||
allow: (item, value) => item.Action === value,
|
||||
deny: (item, value) => item.Action === value,
|
||||
'app-aware': (item, value) => typeof item.Action === 'undefined',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
export default () => ({ statuses = [] }) => {
|
||||
return item => {
|
||||
if (statuses.length > 0 && !statuses.includes(item.Status)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
statuses: {
|
||||
passing: (item, value) => item.Status === value,
|
||||
warning: (item, value) => item.Status === value,
|
||||
critical: (item, value) => item.Status === value,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,28 +1,15 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
export default () => ({ dcs = [], types = [] }) => {
|
||||
const typeIncludes = ['global-management', 'standard'].reduce((prev, item) => {
|
||||
prev[item] = types.includes(item);
|
||||
return prev;
|
||||
}, {});
|
||||
const selectedDcs = new Set(dcs);
|
||||
return item => {
|
||||
let type = true;
|
||||
let dc = true;
|
||||
if (types.length > 0) {
|
||||
type = false;
|
||||
if (typeIncludes['global-management'] && item.isGlobalManagement) {
|
||||
type = true;
|
||||
}
|
||||
if (typeIncludes['standard'] && !item.isGlobalManagement) {
|
||||
type = true;
|
||||
}
|
||||
}
|
||||
if (dcs.length > 0) {
|
||||
// if datacenters is undefined it means the policy is applicable to all datacenters
|
||||
dc =
|
||||
typeof item.Datacenters === 'undefined' ||
|
||||
setHelpers.intersectionSize(selectedDcs, new Set(item.Datacenters)) > 0;
|
||||
}
|
||||
return type && dc;
|
||||
};
|
||||
};
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
kinds: {
|
||||
'global-management': (item, value) => item.isGlobalManagement,
|
||||
standard: (item, value) => !item.isGlobalManagement,
|
||||
},
|
||||
dcs: (item, values) => {
|
||||
return (
|
||||
typeof item.Datacenters === 'undefined' ||
|
||||
setHelpers.intersectionSize(values, new Set(item.Datacenters)) > 0
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
export default () => ({ sources = [], statuses = [] }) => {
|
||||
const uniqueSources = new Set(sources);
|
||||
return item => {
|
||||
if (statuses.length > 0) {
|
||||
if (statuses.includes(item.Status)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (sources.length > 0) {
|
||||
if (setHelpers.intersectionSize(uniqueSources, new Set(item.ExternalSources || [])) !== 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
statuses: {
|
||||
passing: (item, value) => item.Status === value,
|
||||
warning: (item, value) => item.Status === value,
|
||||
critical: (item, value) => item.Status === value,
|
||||
},
|
||||
sources: (item, values) => {
|
||||
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,71 +1,25 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
export default () => ({ instances = [], sources = [], statuses = [], types = [] }) => {
|
||||
const uniqueSources = new Set(sources);
|
||||
const typeIncludes = [
|
||||
'ingress-gateway',
|
||||
'terminating-gateway',
|
||||
'mesh-gateway',
|
||||
'service',
|
||||
'in-mesh',
|
||||
'not-in-mesh',
|
||||
].reduce((prev, item) => {
|
||||
prev[item] = types.includes(item);
|
||||
return prev;
|
||||
}, {});
|
||||
const instanceIncludes = ['registered', 'not-registered'].reduce((prev, item) => {
|
||||
prev[item] = instances.includes(item);
|
||||
return prev;
|
||||
}, {});
|
||||
return item => {
|
||||
if (statuses.length > 0) {
|
||||
if (statuses.includes(item.MeshStatus)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (instances.length > 0) {
|
||||
if (item.InstanceCount > 0) {
|
||||
if (instanceIncludes['registered']) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (instanceIncludes['not-registered']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (types.length > 0) {
|
||||
if (typeIncludes['ingress-gateway'] && item.Kind === 'ingress-gateway') {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['terminating-gateway'] && item.Kind === 'terminating-gateway') {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['mesh-gateway'] && item.Kind === 'mesh-gateway') {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['service'] && typeof item.Kind === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['in-mesh']) {
|
||||
if (item.InMesh) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (typeIncludes['not-in-mesh']) {
|
||||
if (!item.InMesh) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (sources.length > 0) {
|
||||
if (setHelpers.intersectionSize(uniqueSources, new Set(item.ExternalSources || [])) !== 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
kinds: {
|
||||
'ingress-gateway': (item, value) => item.Kind === value,
|
||||
'terminating-gateway': (item, value) => item.Kind === value,
|
||||
'mesh-gateway': (item, value) => item.Kind === value,
|
||||
service: (item, value) => !item.Kind,
|
||||
'in-mesh': (item, value) => item.InMesh,
|
||||
'not-in-mesh': (item, value) => !item.InMesh,
|
||||
},
|
||||
statuses: {
|
||||
passing: (item, value) => item.MeshStatus === value,
|
||||
warning: (item, value) => item.MeshStatus === value,
|
||||
critical: (item, value) => item.MeshStatus === value,
|
||||
},
|
||||
instances: {
|
||||
registered: (item, value) => item.InstanceCount > 0,
|
||||
'not-registered': (item, value) => item.InstanceCount === 0,
|
||||
},
|
||||
sources: (item, values) => {
|
||||
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
export default () => ({ types = [] }) => {
|
||||
const typeIncludes = ['global-management', 'global', 'local'].reduce((prev, item) => {
|
||||
prev[item] = types.includes(item);
|
||||
return prev;
|
||||
}, {});
|
||||
return item => {
|
||||
if (types.length > 0) {
|
||||
if (typeIncludes['global-management'] && item.isGlobalManagement) {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['global'] && !item.Local) {
|
||||
return true;
|
||||
}
|
||||
if (typeIncludes['local'] && item.Local) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
import setHelpers from 'mnemonist/set';
|
||||
import { andOr } from 'consul-ui/utils/filter';
|
||||
|
||||
export default andOr({
|
||||
kinds: {
|
||||
'global-management': (item, value) => item.isGlobalManagement,
|
||||
global: (item, value) => !item.Local,
|
||||
local: (item, value) => item.Local,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -5,11 +5,12 @@ import { hash } from 'rsvp';
|
|||
import WithPolicyActions from 'consul-ui/mixins/policy/with-actions';
|
||||
|
||||
export default class IndexRoute extends Route.extend(WithPolicyActions) {
|
||||
@service('repository/policy')
|
||||
repo;
|
||||
@service('repository/policy') repo;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
dc: 'dc',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -5,8 +5,7 @@ import { hash } from 'rsvp';
|
|||
import WithRoleActions from 'consul-ui/mixins/role/with-actions';
|
||||
|
||||
export default class IndexRoute extends Route.extend(WithRoleActions) {
|
||||
@service('repository/role')
|
||||
repo;
|
||||
@service('repository/role') repo;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
|
|
|
@ -3,15 +3,14 @@ import Route from 'consul-ui/routing/route';
|
|||
import { hash } from 'rsvp';
|
||||
import { get } from '@ember/object';
|
||||
import WithTokenActions from 'consul-ui/mixins/token/with-actions';
|
||||
export default class IndexRoute extends Route.extend(WithTokenActions) {
|
||||
@service('repository/token')
|
||||
repo;
|
||||
|
||||
@service('settings')
|
||||
settings;
|
||||
export default class IndexRoute extends Route.extend(WithTokenActions) {
|
||||
@service('repository/token') repo;
|
||||
@service('settings') settings;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -3,6 +3,7 @@ import Route from 'consul-ui/routing/route';
|
|||
export default class IndexRoute extends Route {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -5,16 +5,16 @@ import { get, action } from '@ember/object';
|
|||
import isFolder from 'consul-ui/utils/isFolder';
|
||||
|
||||
export default class IndexRoute extends Route {
|
||||
@service('repository/kv') repo;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
};
|
||||
|
||||
@service('repository/kv')
|
||||
repo;
|
||||
|
||||
beforeModel() {
|
||||
// we are index or folder, so if the key doesn't have a trailing slash
|
||||
// add one to force a fake findBySlug
|
||||
|
|
|
@ -3,11 +3,11 @@ import Route from 'consul-ui/routing/route';
|
|||
import { hash } from 'rsvp';
|
||||
|
||||
export default class IndexRoute extends Route {
|
||||
@service('data-source/service')
|
||||
data;
|
||||
@service('data-source/service') data;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -4,11 +4,8 @@ import { hash } from 'rsvp';
|
|||
|
||||
import WithNspaceActions from 'consul-ui/mixins/nspace/with-actions';
|
||||
export default class IndexRoute extends Route.extend(WithNspaceActions) {
|
||||
@service('data-source/service')
|
||||
data;
|
||||
|
||||
@service('repository/nspace')
|
||||
repo;
|
||||
@service('data-source/service') data;
|
||||
@service('repository/nspace') repo;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
|
|
|
@ -3,18 +3,17 @@ import Route from 'consul-ui/routing/route';
|
|||
import { hash } from 'rsvp';
|
||||
|
||||
export default class IndexRoute extends Route {
|
||||
@service('data-source/service')
|
||||
data;
|
||||
@service('data-source/service') data;
|
||||
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
kind: 'kind',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
},
|
||||
// temporary support of old style status
|
||||
status: {
|
||||
as: 'status',
|
||||
},
|
||||
};
|
||||
|
||||
model(params) {
|
||||
|
|
|
@ -2,6 +2,9 @@ import Route from 'consul-ui/routing/route';
|
|||
|
||||
export default class InstancesRoute extends Route {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
status: 'status',
|
||||
source: 'source',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -2,6 +2,8 @@ import Route from 'consul-ui/routing/route';
|
|||
|
||||
export default class IndexRoute extends Route {
|
||||
queryParams = {
|
||||
sortBy: 'sort',
|
||||
access: 'access',
|
||||
search: {
|
||||
as: 'filter',
|
||||
replace: true,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{{title 'Access Controls'}}
|
||||
{{/if}}
|
||||
{{#let (hash
|
||||
types=(if type (split type ',') undefined)
|
||||
kinds=(if kind (split kind ',') undefined)
|
||||
dcs=(if dc (split dc ',') undefined)
|
||||
) as |filters|}}
|
||||
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||
|
@ -45,7 +45,7 @@
|
|||
@filter={{filters}}
|
||||
@onfilter={{hash
|
||||
dc=(action (mut dc) value="target.selectedItems")
|
||||
type=(action (mut type) value="target.selectedItems")
|
||||
kind=(action (mut kind) value="target.selectedItems")
|
||||
}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{#let (hash
|
||||
types=(if type (split type ',') undefined)
|
||||
kinds=(if kind (split kind ',') undefined)
|
||||
) as |filters|}}
|
||||
{{#let (or sortBy "CreateTime:desc") as |sort|}}
|
||||
<AppView
|
||||
|
@ -44,7 +44,7 @@
|
|||
|
||||
@filter={{filters}}
|
||||
@onfilter={{hash
|
||||
type=(action (mut type) value="target.selectedItems")
|
||||
kind=(action (mut kind) value="target.selectedItems")
|
||||
}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
|
|
@ -32,39 +32,41 @@
|
|||
<BlockSlot @name="content">
|
||||
{{#let (sort-by (comparator 'nspace' sort) items) as |sorted|}}
|
||||
<ChangeableSet @dispatcher={{searchable 'nspace' sorted}} @terms={{search}}>
|
||||
<BlockSlot @name="set" as |filtered|>
|
||||
<BlockSlot @name="content" as |filtered|>
|
||||
<Consul::Nspace::List
|
||||
@items={{filtered}}
|
||||
@ondelete={{queue (action send 'delete')}}
|
||||
>
|
||||
<EmptyState @allowLogin={{true}}>
|
||||
<BlockSlot @name="header">
|
||||
<h2>
|
||||
{{#if (gt items.length 0)}}
|
||||
No namespaces found
|
||||
{{else}}
|
||||
Welcome to Namespaces
|
||||
{{/if}}
|
||||
</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<p>
|
||||
{{#if (gt items.length 0)}}
|
||||
No namespaces where found matching that search, or you may not have access to view the namespaces you are searching for.
|
||||
{{else}}
|
||||
There don't seem to be any namespaces, or you may not have access to view namespaces yet.
|
||||
{{/if}}
|
||||
</p>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<li class="docs-link">
|
||||
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/namespace" rel="noopener noreferrer" target="_blank">Documentation on namespaces</a>
|
||||
</li>
|
||||
<li class="learn-link">
|
||||
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/namespaces/secure-namespaces" rel="noopener noreferrer" target="_blank">Read the guide</a>
|
||||
</li>
|
||||
</BlockSlot>
|
||||
</EmptyState>
|
||||
<:empty>
|
||||
<EmptyState @allowLogin={{true}}>
|
||||
<BlockSlot @name="header">
|
||||
<h2>
|
||||
{{#if (gt items.length 0)}}
|
||||
No namespaces found
|
||||
{{else}}
|
||||
Welcome to Namespaces
|
||||
{{/if}}
|
||||
</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<p>
|
||||
{{#if (gt items.length 0)}}
|
||||
No namespaces where found matching that search, or you may not have access to view the namespaces you are searching for.
|
||||
{{else}}
|
||||
There don't seem to be any namespaces, or you may not have access to view namespaces yet.
|
||||
{{/if}}
|
||||
</p>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<li class="docs-link">
|
||||
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/namespace" rel="noopener noreferrer" target="_blank">Documentation on namespaces</a>
|
||||
</li>
|
||||
<li class="learn-link">
|
||||
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/namespaces/secure-namespaces" rel="noopener noreferrer" target="_blank">Read the guide</a>
|
||||
</li>
|
||||
</BlockSlot>
|
||||
</EmptyState>
|
||||
</:empty>
|
||||
</Consul::Nspace::List>
|
||||
</BlockSlot>
|
||||
</ChangeableSet>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<EventSource @src={{items}} />
|
||||
{{#let (hash
|
||||
statuses=(if status (split status ',') undefined)
|
||||
types=(if type (split type ',') undefined)
|
||||
kinds=(if kind (split kind ',') undefined)
|
||||
sources=(if source (split source ',') undefined)
|
||||
) as |filters|}}
|
||||
{{#let (or sortBy "Name:asc") as |sort|}}
|
||||
|
@ -32,7 +32,7 @@
|
|||
@filter={{filters}}
|
||||
@onfilter={{hash
|
||||
status=(action (mut status) value="target.selectedItems")
|
||||
type=(action (mut type) value="target.selectedItems")
|
||||
kind=(action (mut kind) value="target.selectedItems")
|
||||
source=(action (mut source) value="target.selectedItems")
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import setHelpers from 'mnemonist/set';
|
||||
|
||||
const createPossibles = function(predicates) {
|
||||
// create arrays of allowed values
|
||||
return Object.entries(predicates).reduce((prev, [key, value]) => {
|
||||
if (typeof value !== 'function') {
|
||||
prev[key] = new Set(Object.keys(value));
|
||||
} else {
|
||||
prev[key] = null;
|
||||
}
|
||||
return prev;
|
||||
}, {});
|
||||
};
|
||||
const sanitize = function(values, possibles) {
|
||||
return Object.keys(possibles).reduce((prev, key) => {
|
||||
// only set the value if the value has a length of > 0
|
||||
const value = typeof values[key] === 'undefined' ? [] : values[key];
|
||||
if (value.length > 0) {
|
||||
if (possibles[key] !== null) {
|
||||
// only include possible values
|
||||
prev[key] = [...setHelpers.intersection(possibles[key], new Set(value))];
|
||||
} else {
|
||||
// only unique values
|
||||
prev[key] = [...new Set(value)];
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
}, {});
|
||||
};
|
||||
const execute = function(item, values, predicates) {
|
||||
// every/and the top level values
|
||||
return Object.entries(values).every(([key, values]) => {
|
||||
let predicate = predicates[key];
|
||||
if (typeof predicate === 'function') {
|
||||
return predicate(item, values);
|
||||
} else {
|
||||
// if the top level values can have multiple values some/or them
|
||||
return values.some(val => predicate[val](item, val));
|
||||
}
|
||||
});
|
||||
};
|
||||
// exports a function that requires a hash of predicates passed in
|
||||
export const andOr = predicates => {
|
||||
// figure out all possible values from the hash of predicates
|
||||
const possibles = createPossibles(predicates);
|
||||
return () => values => {
|
||||
// this is what is called post injection
|
||||
// the actual user values are passed in here so 'sanitize' them which is
|
||||
// basically checking against the possibles
|
||||
values = sanitize(values, possibles);
|
||||
// this is your actual filter predicate
|
||||
return item => {
|
||||
return execute(item, values, predicates);
|
||||
};
|
||||
};
|
||||
};
|
|
@ -97,7 +97,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = [items[0]];
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['ingress-gateway'],
|
||||
kinds: ['ingress-gateway'],
|
||||
})
|
||||
);
|
||||
assert.deepEqual(actual, expected);
|
||||
|
@ -105,7 +105,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = [items[1]];
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['mesh-gateway'],
|
||||
kinds: ['mesh-gateway'],
|
||||
})
|
||||
);
|
||||
assert.deepEqual(actual, expected);
|
||||
|
@ -113,7 +113,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = items;
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['ingress-gateway', 'mesh-gateway', 'service'],
|
||||
kinds: ['ingress-gateway', 'mesh-gateway', 'service'],
|
||||
})
|
||||
);
|
||||
assert.deepEqual(actual, expected);
|
||||
|
@ -141,7 +141,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = [items[0]];
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['ingress-gateway'],
|
||||
kinds: ['ingress-gateway'],
|
||||
statuses: ['passing'],
|
||||
instances: ['registered'],
|
||||
})
|
||||
|
@ -151,7 +151,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = [items[1]];
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['mesh-gateway'],
|
||||
kinds: ['mesh-gateway'],
|
||||
statuses: ['warning'],
|
||||
instances: ['registered'],
|
||||
})
|
||||
|
@ -161,7 +161,7 @@ module('Unit | Filter | Predicates | service', function() {
|
|||
expected = items;
|
||||
actual = items.filter(
|
||||
predicate({
|
||||
types: ['ingress-gateway', 'mesh-gateway', 'service'],
|
||||
kinds: ['ingress-gateway', 'mesh-gateway', 'service'],
|
||||
statuses: ['passing', 'warning', 'critical'],
|
||||
instances: ['registered', 'not-registered'],
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue