ui: Fuzzy and Regex searching (#9424)
Moves search things around to match an interface that can be switched in and out of fuzzy searching using fuse.js. We add both fuzzy searching and regex based searching to the codebase here, but it is not yet compiled in.
This commit is contained in:
parent
098ca1f567
commit
5dbfbf0049
|
@ -1,6 +1,7 @@
|
||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { computed, get, action } from '@ember/object';
|
import { computed, action } from '@ember/object';
|
||||||
|
import { alias } from '@ember/object/computed';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { sort } from '@ember/object/computed';
|
import { sort } from '@ember/object/computed';
|
||||||
import { defineProperty } from '@ember/object';
|
import { defineProperty } from '@ember/object';
|
||||||
|
@ -12,30 +13,48 @@ export default class DataCollectionComponent extends Component {
|
||||||
|
|
||||||
@tracked term = '';
|
@tracked term = '';
|
||||||
|
|
||||||
|
@alias('searchService.searchables') searchableMap;
|
||||||
|
|
||||||
get type() {
|
get type() {
|
||||||
return this.args.type;
|
return this.args.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get searchMethod() {
|
||||||
|
return this.args.searchable || 'exact';
|
||||||
|
}
|
||||||
|
|
||||||
|
get searchProperties() {
|
||||||
|
return this.args.filters.searchproperties;
|
||||||
|
}
|
||||||
|
|
||||||
@computed('term', 'args.search')
|
@computed('term', 'args.search')
|
||||||
get searchTerm() {
|
get searchTerm() {
|
||||||
return this.term || this.args.search || '';
|
return this.term || this.args.search || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@computed('type', 'searchMethod', 'filtered', 'searchProperties')
|
||||||
search(term) {
|
get searchable() {
|
||||||
this.term = term;
|
const Searchable =
|
||||||
return this.items;
|
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);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('args{items,.items.content}')
|
@computed('type', 'args.sort')
|
||||||
get content() {
|
get comparator() {
|
||||||
// TODO: Temporary little hack to ensure we detect DataSource proxy
|
if (typeof this.args.sort === 'undefined') {
|
||||||
// objects but not any other special Ember Proxy object like ember-data
|
return [];
|
||||||
// things. Remove this once we no longer need the Proxies
|
|
||||||
if (this.args.items.dispatchEvent === 'function') {
|
|
||||||
return this.args.items.content;
|
|
||||||
}
|
}
|
||||||
return this.args.items;
|
return this.sort.comparator(this.type)(this.args.sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('comparator', 'searched')
|
@computed('comparator', 'searched')
|
||||||
|
@ -51,36 +70,42 @@ export default class DataCollectionComponent extends Component {
|
||||||
return this.sorted;
|
return this.sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('type', 'filtered', 'args.filters.searchproperties', 'searchTerm')
|
@computed('searchTerm', 'searchable', 'filtered')
|
||||||
get searched() {
|
get searched() {
|
||||||
if (this.searchTerm === '') {
|
if (this.searchTerm === '') {
|
||||||
return this.filtered;
|
return this.filtered;
|
||||||
}
|
}
|
||||||
const predicate = this.searchService.predicate(this.type);
|
return this.searchable.search(this.searchTerm);
|
||||||
const options = {};
|
|
||||||
if (typeof get(this, 'args.filters.searchproperties') !== 'undefined') {
|
|
||||||
options.properties = this.args.filters.searchproperties;
|
|
||||||
}
|
|
||||||
return this.filtered.filter(predicate(this.searchTerm, options));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('type', 'content', 'args.filters')
|
@computed('type', 'content', 'args.filters')
|
||||||
get filtered() {
|
get filtered() {
|
||||||
|
// if we don't filter, return a copy of the content so we end up with what
|
||||||
|
// filter will return when filtering ED recordsets
|
||||||
if (typeof this.args.filters === 'undefined') {
|
if (typeof this.args.filters === 'undefined') {
|
||||||
return this.content;
|
return this.content.slice();
|
||||||
}
|
}
|
||||||
const predicate = this.filter.predicate(this.type);
|
const predicate = this.filter.predicate(this.type);
|
||||||
if (typeof predicate === 'undefined') {
|
if (typeof predicate === 'undefined') {
|
||||||
return this.content;
|
return this.content.slice();
|
||||||
}
|
}
|
||||||
return this.content.filter(predicate(this.args.filters));
|
return this.content.filter(predicate(this.args.filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('type', 'args.sort')
|
@computed('args.{items.[],items.content.[]}')
|
||||||
get comparator() {
|
get content() {
|
||||||
if (typeof this.args.sort === 'undefined') {
|
// TODO: Temporary little hack to ensure we detect DataSource proxy
|
||||||
return [];
|
// objects but not any other special Ember Proxy object like ember-data
|
||||||
|
// things. Remove this once we no longer need the Proxies
|
||||||
|
if (this.args.items.dispatchEvent === 'function') {
|
||||||
|
return this.args.items.content;
|
||||||
}
|
}
|
||||||
return this.sort.comparator(this.type)(this.args.sort);
|
return this.args.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
search(term) {
|
||||||
|
this.term = term;
|
||||||
|
return this.items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export default {
|
export default {
|
||||||
ID: (item, value) => item.ID.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
ID: item => item.ID,
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: item => item.Name,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,31 +2,12 @@ const asArray = function(arr) {
|
||||||
return Array.isArray(arr) ? arr : arr.toArray();
|
return Array.isArray(arr) ? arr : arr.toArray();
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => {
|
Name: (item, value) => item.Name,
|
||||||
return item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1;
|
Node: (item, value) => item.Node,
|
||||||
},
|
Service: (item, value) => item.ServiceName,
|
||||||
Node: (item, value) => {
|
CheckID: (item, value) => item.CheckID || '',
|
||||||
return item.Node.toLowerCase().indexOf(value.toLowerCase()) !== -1;
|
ID: (item, value) => item.Service.ID || '',
|
||||||
},
|
Notes: (item, value) => item.Notes,
|
||||||
Service: (item, value) => {
|
Output: (item, value) => item.Output,
|
||||||
const lower = value.toLowerCase();
|
ServiceTags: (item, value) => asArray(item.ServiceTags || []),
|
||||||
return (
|
|
||||||
item.ServiceName.toLowerCase().indexOf(lower) !== -1 ||
|
|
||||||
item.ServiceID.toLowerCase().indexOf(lower) !== -1
|
|
||||||
);
|
|
||||||
},
|
|
||||||
CheckID: (item, value) => (item.CheckID || '').toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
|
||||||
Notes: (item, value) =>
|
|
||||||
item.Notes.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(value.toLowerCase()) !== -1,
|
|
||||||
Output: (item, value) =>
|
|
||||||
item.Output.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(value.toLowerCase()) !== -1,
|
|
||||||
ServiceTags: (item, value) => {
|
|
||||||
return asArray(item.ServiceTags || []).some(
|
|
||||||
item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
const allLabel = 'All Services (*)'.toLowerCase();
|
const allLabel = 'All Services (*)';
|
||||||
export default {
|
export default {
|
||||||
SourceName: (item, value) =>
|
SourceName: item =>
|
||||||
item.SourceName.toLowerCase().indexOf(value.toLowerCase()) !== -1 ||
|
[item.SourceName, item.SourceName === '*' ? allLabel : undefined].filter(Boolean),
|
||||||
(item.SourceName === '*' && allLabel.indexOf(value.toLowerCase()) !== -1),
|
DestinationName: item =>
|
||||||
DestinationName: (item, value) =>
|
[item.DestinationName, item.DestinationName === '*' ? allLabel : undefined].filter(Boolean),
|
||||||
item.DestinationName.toLowerCase().indexOf(value.toLowerCase()) !== -1 ||
|
|
||||||
(item.DestinationName === '*' && allLabel.indexOf(value.toLowerCase()) !== -1),
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import rightTrim from 'consul-ui/utils/right-trim';
|
import rightTrim from 'consul-ui/utils/right-trim';
|
||||||
export default {
|
export default {
|
||||||
Key: (item, value) =>
|
Key: item =>
|
||||||
rightTrim(item.Key.toLowerCase())
|
rightTrim(item.Key.toLowerCase())
|
||||||
.split('/')
|
.split('/')
|
||||||
.filter(item => Boolean(item))
|
.filter(item => Boolean(item))
|
||||||
.pop()
|
.pop(),
|
||||||
.indexOf(value.toLowerCase()) !== -1,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
Node: (item, value) => item.Node.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Node: item => item.Node,
|
||||||
Address: (item, value) => item.Address.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Address: item => item.Address,
|
||||||
Meta: (item, value) =>
|
Meta: item => Object.entries(item.Meta || {}).reduce((prev, entry) => prev.concat(entry), []),
|
||||||
Object.entries(item.Meta || {}).some(entry =>
|
|
||||||
entry.some(item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1)
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: (item, value) => item.Name,
|
||||||
Description: (item, value) => item.Description.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Description: (item, value) => item.Description,
|
||||||
Role: (item, value) => {
|
Role: (item, value) => {
|
||||||
const acls = item.ACLs || {};
|
const acls = item.ACLs || {};
|
||||||
return (acls.RoleDefaults || []).some(
|
return (acls.RoleDefaults || []).map(item => item.Name);
|
||||||
item => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
Policy: (item, value) => {
|
Policy: (item, value) => {
|
||||||
const acls = item.ACLs || {};
|
const acls = item.ACLs || {};
|
||||||
return (acls.PolicyDefaults || []).some(
|
return (acls.PolicyDefaults || []).map(item => item.Name);
|
||||||
item => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: item => item.Name,
|
||||||
Description: (item, value) => item.Description.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Description: item => item.Description,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: (item, value) => item.Name,
|
||||||
Description: (item, value) => item.Description.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Description: (item, value) => item.Description,
|
||||||
Policy: (item, value) => {
|
Policy: (item, value) => {
|
||||||
return (
|
return (item.Policies || [])
|
||||||
(item.Policies || []).some(
|
.map(item => item.Name)
|
||||||
item => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
.concat((item.ServiceIdentities || []).map(item => item.ServiceName))
|
||||||
) ||
|
.concat((item.NodeIdentities || []).map(item => item.NodeName));
|
||||||
(item.ServiceIdentities || []).some(
|
|
||||||
item => item.ServiceName.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
) ||
|
|
||||||
(item.NodeIdentities || []).some(
|
|
||||||
item => item.NodeName.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +1,11 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => {
|
Name: item => item.Name,
|
||||||
return item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1;
|
Tags: item => item.Service.Tags || [],
|
||||||
},
|
ID: (item, value) => item.Service.ID || '',
|
||||||
Tags: (item, value) =>
|
Address: item => item.Address || '',
|
||||||
(item.Service.Tags || []).some(item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1),
|
Port: item => (item.Service.Port || '').toString(),
|
||||||
ID: (item, value) => (item.Service.ID || '').toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
['Service.Meta']: item =>
|
||||||
Address: (item, value) =>
|
Object.entries(item.Service.Meta || {}).reduce((prev, entry) => prev.concat(entry), []),
|
||||||
item.Address.toString()
|
['Node.Meta']: item =>
|
||||||
.toLowerCase()
|
Object.entries(item.Node.Meta || {}).reduce((prev, entry) => prev.concat(entry), []),
|
||||||
.indexOf(value.toLowerCase()) !== -1,
|
|
||||||
Port: (item, value) =>
|
|
||||||
item.Service.Port.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(value.toLowerCase()) !== -1,
|
|
||||||
['Service.Meta']: (item, value) =>
|
|
||||||
Object.entries(item.Meta || item.Service.Meta || {}).some(entry =>
|
|
||||||
entry.some(item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1)
|
|
||||||
),
|
|
||||||
['Node.Meta']: (item, value) =>
|
|
||||||
Object.entries(item.Node.Meta || {}).some(entry =>
|
|
||||||
entry.some(item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1)
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: item => item.Name,
|
||||||
Tags: (item, value) => (item.Tags || []).some(item => item.toLowerCase().indexOf(value.toLowerCase()) !== -1)
|
Tags: item => item.Tags || [],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
export default {
|
export default {
|
||||||
Name: (item, value) => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Name: (item, value) => item.Name,
|
||||||
Description: (item, value) => item.Description.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
Description: (item, value) => item.Description,
|
||||||
AccessorID: (item, value) => item.AccessorID.toLowerCase().indexOf(value.toLowerCase()) !== -1,
|
AccessorID: (item, value) => item.AccessorID,
|
||||||
Role: (item, value) =>
|
Role: (item, value) => (item.Roles || []).map(item => item.Name),
|
||||||
(item.Roles || []).some(item => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1),
|
|
||||||
Policy: (item, value) => {
|
Policy: (item, value) => {
|
||||||
return (
|
return (item.Policies || [])
|
||||||
(item.Policies || []).some(
|
.map(item => item.Name)
|
||||||
item => item.Name.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
.concat((item.ServiceIdentities || []).map(item => item.ServiceName))
|
||||||
) ||
|
.concat((item.NodeIdentities || []).map(item => item.NodeName));
|
||||||
(item.ServiceIdentities || []).some(
|
|
||||||
item => item.ServiceName.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
) ||
|
|
||||||
(item.NodeIdentities || []).some(
|
|
||||||
item => item.NodeName.toLowerCase().indexOf(value.toLowerCase()) !== -1
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Service from '@ember/service';
|
import Service from '@ember/service';
|
||||||
import setHelpers from 'mnemonist/set';
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
|
||||||
import intention from 'consul-ui/search/predicates/intention';
|
import intention from 'consul-ui/search/predicates/intention';
|
||||||
import upstreamInstance from 'consul-ui/search/predicates/upstream-instance';
|
import upstreamInstance from 'consul-ui/search/predicates/upstream-instance';
|
||||||
|
@ -14,36 +15,27 @@ import role from 'consul-ui/search/predicates/role';
|
||||||
import policy from 'consul-ui/search/predicates/policy';
|
import policy from 'consul-ui/search/predicates/policy';
|
||||||
import nspace from 'consul-ui/search/predicates/nspace';
|
import nspace from 'consul-ui/search/predicates/nspace';
|
||||||
|
|
||||||
export const search = spec => {
|
|
||||||
let possible = Object.keys(spec);
|
|
||||||
return (term, options = {}) => {
|
|
||||||
const actual = [
|
|
||||||
...setHelpers.intersection(new Set(possible), new Set(options.properties || possible)),
|
|
||||||
];
|
|
||||||
return item => {
|
|
||||||
return (
|
|
||||||
typeof actual.find(key => {
|
|
||||||
return spec[key](item, term);
|
|
||||||
}) !== 'undefined'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const predicates = {
|
const predicates = {
|
||||||
intention: search(intention),
|
intention: intention,
|
||||||
service: search(service),
|
service: service,
|
||||||
['service-instance']: search(serviceInstance),
|
['service-instance']: serviceInstance,
|
||||||
['upstream-instance']: search(upstreamInstance),
|
['upstream-instance']: upstreamInstance,
|
||||||
['health-check']: search(healthCheck),
|
['health-check']: healthCheck,
|
||||||
node: search(node),
|
node: node,
|
||||||
kv: search(kv),
|
kv: kv,
|
||||||
acl: search(acl),
|
acl: acl,
|
||||||
token: search(token),
|
token: token,
|
||||||
role: search(role),
|
role: role,
|
||||||
policy: search(policy),
|
policy: policy,
|
||||||
nspace: search(nspace),
|
nspace: nspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SearchService extends Service {
|
export default class SearchService extends Service {
|
||||||
|
searchables = {
|
||||||
|
exact: ExactSearch,
|
||||||
|
// regex: RegExpSearch,
|
||||||
|
// fuzzy: FuzzySearch,
|
||||||
|
};
|
||||||
predicate(name) {
|
predicate(name) {
|
||||||
return predicates[name];
|
return predicates[name];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import PredicateSearch from './predicate';
|
||||||
|
|
||||||
|
export default class ExactSearch extends PredicateSearch {
|
||||||
|
predicate(s) {
|
||||||
|
s = s.toLowerCase();
|
||||||
|
return (item = '') =>
|
||||||
|
item
|
||||||
|
.toString()
|
||||||
|
.toLowerCase()
|
||||||
|
.indexOf(s) !== -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import Fuse from 'fuse.js';
|
||||||
|
|
||||||
|
export default class FuzzySearch {
|
||||||
|
constructor(items, options) {
|
||||||
|
this.fuse = new Fuse(items, {
|
||||||
|
includeMatches: true,
|
||||||
|
|
||||||
|
shouldSort: false, // use our own sorting for the moment
|
||||||
|
threshold: 0.4,
|
||||||
|
keys: Object.keys(options.finders) || [],
|
||||||
|
getFn(item, key) {
|
||||||
|
return (options.finders[key[0]](item) || []).toString();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
search(s) {
|
||||||
|
return this.fuse.search(s).map(item => item.item);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
export default class PredicateSearch {
|
||||||
|
constructor(items, options) {
|
||||||
|
this.items = items;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
search(s) {
|
||||||
|
const predicate = this.predicate(s);
|
||||||
|
// Test the value of each key for each object against the regex
|
||||||
|
// All that match are returned.
|
||||||
|
return this.items.filter(item => {
|
||||||
|
return Object.entries(this.options.finders).some(([key, finder]) => {
|
||||||
|
const val = finder(item);
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
return val.some(predicate);
|
||||||
|
} else {
|
||||||
|
return predicate(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import PredicateSearch from './predicate';
|
||||||
|
|
||||||
|
export default class RegExpSearch extends PredicateSearch {
|
||||||
|
predicate(s) {
|
||||||
|
let regex;
|
||||||
|
try {
|
||||||
|
regex = new RegExp(s, 'i');
|
||||||
|
} catch (e) {
|
||||||
|
// Return a predicate that excludes everything; most likely due to an
|
||||||
|
// eager search of an incomplete regex
|
||||||
|
return () => false;
|
||||||
|
}
|
||||||
|
return item => regex.test(item);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +1,43 @@
|
||||||
import predicates from 'consul-ui/search/predicates/acl';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/acl';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | acl', function() {
|
module('Unit | Search | Predicate | acl', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
ID: 'HIT-id',
|
||||||
|
Name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 'id',
|
||||||
|
Name: 'name-HIT',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
ID: 'HIT-id',
|
finders: predicates,
|
||||||
Name: 'name',
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
|
||||||
ID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'id',
|
|
||||||
Name: 'name-HIT',
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 2);
|
assert.equal(actual.length, 2);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
ID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
ID: 'id',
|
finders: predicates,
|
||||||
Name: 'name',
|
}
|
||||||
},
|
).search('hit');
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,51 +1,48 @@
|
||||||
import predicates from 'consul-ui/search/predicates/intention';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/intention';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | intention', function() {
|
module('Unit | Search | Predicate | intention', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
SourceName: 'Hit',
|
||||||
|
DestinationName: 'destination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SourceName: 'source',
|
||||||
|
DestinationName: 'destination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SourceName: 'source',
|
||||||
|
DestinationName: 'hiT',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
SourceName: 'Hit',
|
finders: predicates,
|
||||||
DestinationName: 'destination',
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
|
||||||
SourceName: 'source',
|
|
||||||
DestinationName: 'destination',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SourceName: 'source',
|
|
||||||
DestinationName: 'hiT',
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 2);
|
assert.equal(actual.length, 2);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
SourceName: 'source',
|
||||||
|
DestinationName: 'destination',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
SourceName: 'source',
|
finders: predicates,
|
||||||
DestinationName: 'destination',
|
}
|
||||||
},
|
).search('hit');
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
test('items are found by *', function(assert) {
|
test('items are found by *', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
{
|
[
|
||||||
SourceName: '*',
|
|
||||||
DestinationName: 'destination',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SourceName: 'source',
|
|
||||||
DestinationName: '*',
|
|
||||||
},
|
|
||||||
].filter(search('*'));
|
|
||||||
assert.equal(actual.length, 2);
|
|
||||||
});
|
|
||||||
test("* items are found by searching anything in 'All Services (*)'", function(assert) {
|
|
||||||
['All Services (*)', 'SerVices', '(*)', '*', 'vIces', 'lL Ser'].forEach(term => {
|
|
||||||
const actual = [
|
|
||||||
{
|
{
|
||||||
SourceName: '*',
|
SourceName: '*',
|
||||||
DestinationName: 'destination',
|
DestinationName: 'destination',
|
||||||
|
@ -54,8 +51,31 @@ module('Unit | Search | Predicate | intention', function() {
|
||||||
SourceName: 'source',
|
SourceName: 'source',
|
||||||
DestinationName: '*',
|
DestinationName: '*',
|
||||||
},
|
},
|
||||||
].filter(search(term));
|
],
|
||||||
assert.equal(actual.length, 2);
|
{
|
||||||
|
finders: predicates,
|
||||||
|
}
|
||||||
|
).search('*');
|
||||||
|
assert.equal(actual.length, 2);
|
||||||
|
});
|
||||||
|
test("* items are found by searching anything in 'All Services (*)'", function(assert) {
|
||||||
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
SourceName: '*',
|
||||||
|
DestinationName: 'destination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SourceName: 'source',
|
||||||
|
DestinationName: '*',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
finders: predicates,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
['All Services (*)', 'SerVices', '(*)', '*', 'vIces', 'lL Ser'].forEach(term => {
|
||||||
|
assert.equal(actual.search(term).length, 2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,32 +1,42 @@
|
||||||
import predicates from 'consul-ui/search/predicates/kv';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/kv';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | kv', function() {
|
module('Unit | Search | Predicate | kv', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Key: 'HIT-here',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: 'folder-HIT/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: 'excluded',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: 'really/long/path/HIT-here',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Key: 'HIT-here',
|
finders: predicates,
|
||||||
},
|
}
|
||||||
{
|
).search('hit');
|
||||||
Key: 'folder-HIT/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: 'excluded',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: 'really/long/path/HIT-here',
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Key: 'key',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Key: 'key',
|
finders: predicates,
|
||||||
},
|
}
|
||||||
].filter(search('hit'));
|
).search('hit');
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,47 +1,67 @@
|
||||||
import predicates from 'consul-ui/search/predicates/node';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/node';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | node', function() {
|
module('Unit | Search | Predicate | node', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by name', function(assert) {
|
test('items are found by name', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Node: 'node-HIT',
|
||||||
|
Address: '10.0.0.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Node: 'node',
|
||||||
|
Address: '10.0.0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Node: 'node-HIT',
|
finders: predicates,
|
||||||
Address: '10.0.0.0',
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
|
||||||
Node: 'node',
|
|
||||||
Address: '10.0.0.0',
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 1);
|
assert.equal(actual.length, 1);
|
||||||
});
|
});
|
||||||
test('items are found by IP address', function(assert) {
|
test('items are found by IP address', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Node: 'node-HIT',
|
||||||
|
Address: '10.0.0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Node: 'node-HIT',
|
finders: predicates,
|
||||||
Address: '10.0.0.0',
|
}
|
||||||
},
|
).search('10');
|
||||||
].filter(search('10'));
|
|
||||||
assert.equal(actual.length, 1);
|
assert.equal(actual.length, 1);
|
||||||
});
|
});
|
||||||
test('items are not found by name', function(assert) {
|
test('items are not found by name', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Node: 'name',
|
||||||
|
Address: '10.0.0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Node: 'name',
|
finders: predicates,
|
||||||
Address: '10.0.0.0',
|
}
|
||||||
},
|
).search('hit');
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
test('items are not found by IP address', function(assert) {
|
test('items are not found by IP address', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Node: 'name',
|
||||||
|
Address: '10.0.0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Node: 'name',
|
finders: predicates,
|
||||||
Address: '10.0.0.0',
|
}
|
||||||
},
|
).search('9');
|
||||||
].filter(search('9'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,39 @@
|
||||||
import predicates from 'consul-ui/search/predicates/policy';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/policy';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | policy', function() {
|
module('Unit | Search | Predicate | policy', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name-HIT',
|
||||||
|
Description: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'desc-HIT-ription',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name-HIT',
|
finders: predicates,
|
||||||
Description: 'description',
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'desc-HIT-ription',
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 2);
|
assert.equal(actual.length, 2);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name',
|
finders: predicates,
|
||||||
Description: 'description',
|
}
|
||||||
},
|
).search('hit');
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,78 +1,93 @@
|
||||||
import predicates from 'consul-ui/search/predicates/role';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
|
import predicates from 'consul-ui/search/predicates/role';
|
||||||
|
|
||||||
module('Unit | Search | Predicate | role', function() {
|
module('Unit | Search | Predicate | role', function() {
|
||||||
const search = create(predicates);
|
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name-HIT',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'desc-HIT-ription',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [{ Name: 'policy' }, { Name: 'policy-HIT' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
ServiceIdentities: [
|
||||||
|
{ ServiceName: 'service-identity' },
|
||||||
|
{ ServiceName: 'service-identity-HIT' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name-HIT',
|
finders: predicates,
|
||||||
Description: 'description',
|
}
|
||||||
Policies: [],
|
).search('hit');
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'desc-HIT-ription',
|
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [{ Name: 'policy' }, { Name: 'policy-HIT' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
ServiceIdentities: [
|
|
||||||
{ ServiceName: 'service-identity' },
|
|
||||||
{ ServiceName: 'service-identity-HIT' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 4);
|
assert.equal(actual.length, 4);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [{ Name: 'policy' }, { Name: 'policy-second' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
ServiceIdenitities: [{ ServiceName: 'si' }, { ServiceName: 'si-second' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name',
|
finders: predicates,
|
||||||
Description: 'description',
|
}
|
||||||
Policies: [],
|
).search('hit');
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [{ Name: 'policy' }, { Name: 'policy-second' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
ServiceIdenitities: [{ ServiceName: 'si' }, { ServiceName: 'si-second' }],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
test('arraylike things can be empty', function(assert) {
|
test('arraylike things can be empty', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: null,
|
||||||
|
ServiceIdentities: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
ServiceIdentities: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name',
|
finders: predicates,
|
||||||
Description: 'description',
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: null,
|
|
||||||
ServiceIdentities: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [],
|
|
||||||
ServiceIdentities: [],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,54 +1,63 @@
|
||||||
import { search } from 'consul-ui/services/search';
|
|
||||||
import spec from 'consul-ui/search/predicates/service';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
module('Unit | Search | Filter | service', function() {
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
const predicate = search(spec);
|
import predicates from 'consul-ui/search/predicates/service';
|
||||||
|
|
||||||
|
module('Unit | Search | Predicate | service', function() {
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
[
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name-HIT',
|
||||||
|
Tags: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Tags: ['tag', 'tag-withHiT'],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name-HIT',
|
finders: predicates,
|
||||||
Tags: [],
|
}
|
||||||
},
|
).search('hit');
|
||||||
{
|
assert.equal(actual.length, 2);
|
||||||
Name: 'name',
|
|
||||||
Tags: ['tag', 'tag-withHiT'],
|
|
||||||
},
|
|
||||||
].forEach(function(item) {
|
|
||||||
const actual = predicate('hit')(item);
|
|
||||||
assert.ok(actual);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
[
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Tags: ['one', 'two'],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name',
|
finders: predicates,
|
||||||
},
|
}
|
||||||
{
|
).search('hit');
|
||||||
Name: 'name',
|
assert.equal(actual.length, 0);
|
||||||
Tags: ['one', 'two'],
|
|
||||||
},
|
|
||||||
].forEach(function(item) {
|
|
||||||
const actual = predicate('hit')(item);
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
test('tags can be empty', function(assert) {
|
test('tags can be empty', function(assert) {
|
||||||
[
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Tags: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'name',
|
||||||
|
Tags: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
Name: 'name',
|
finders: predicates,
|
||||||
},
|
}
|
||||||
{
|
).search('hit');
|
||||||
Name: 'name',
|
assert.equal(actual.length, 0);
|
||||||
Tags: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: 'name',
|
|
||||||
Tags: [],
|
|
||||||
},
|
|
||||||
].forEach(function(item) {
|
|
||||||
const actual = predicate('hit')(item);
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,126 +1,141 @@
|
||||||
import predicates from 'consul-ui/search/predicates/token';
|
|
||||||
import { search as create } from 'consul-ui/services/search';
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
module('Unit | Search | Filter | token', function() {
|
import ExactSearch from 'consul-ui/utils/search/exact';
|
||||||
const search = create(predicates);
|
import predicates from 'consul-ui/search/predicates/token';
|
||||||
|
|
||||||
|
module('Unit | Search | Predicate | token', function() {
|
||||||
test('items are found by properties', function(assert) {
|
test('items are found by properties', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'HIT-id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name-HIT',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'desc-HIT-ription',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [{ Name: 'policy' }, { Name: 'policy-HIT' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Roles: [{ Name: 'role' }, { Name: 'role-HIT' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
ServiceIdentities: [
|
||||||
|
{ ServiceName: 'service-identity' },
|
||||||
|
{ ServiceName: 'service-identity-HIT' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
NodeIdentities: [{ NodeName: 'node-identity' }, { NodeName: 'node-identity-HIT' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
AccessorID: 'id',
|
finders: predicates,
|
||||||
Name: 'name',
|
}
|
||||||
Description: 'description',
|
).search('hit');
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'HIT-id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name-HIT',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'desc-HIT-ription',
|
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [{ Name: 'policy' }, { Name: 'policy-HIT' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Roles: [{ Name: 'role' }, { Name: 'role-HIT' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
ServiceIdentities: [
|
|
||||||
{ ServiceName: 'service-identity' },
|
|
||||||
{ ServiceName: 'service-identity-HIT' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
NodeIdentities: [{ NodeName: 'node-identity' }, { NodeName: 'node-identity-HIT' }],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 7);
|
assert.equal(actual.length, 7);
|
||||||
});
|
});
|
||||||
test('items are not found', function(assert) {
|
test('items are not found', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [{ Name: 'policy' }, { Name: 'policy-second' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Roles: [{ Name: 'role' }, { Name: 'role-second' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
ServiceIdentities: [{ ServiceName: 'si' }, { ServiceName: 'si-second' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
NodeIdentities: [{ NodeName: 'si' }, { NodeName: 'si-second' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
AccessorID: 'id',
|
finders: predicates,
|
||||||
Name: 'name',
|
}
|
||||||
Description: 'description',
|
).search('hit');
|
||||||
Policies: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [{ Name: 'policy' }, { Name: 'policy-second' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Roles: [{ Name: 'role' }, { Name: 'role-second' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
ServiceIdentities: [{ ServiceName: 'si' }, { ServiceName: 'si-second' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
NodeIdentities: [{ NodeName: 'si' }, { NodeName: 'si-second' }],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
test('arraylike things can be empty', function(assert) {
|
test('arraylike things can be empty', function(assert) {
|
||||||
const actual = [
|
const actual = new ExactSearch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: null,
|
||||||
|
Roles: null,
|
||||||
|
ServiceIdentities: null,
|
||||||
|
NodeIdentities: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessorID: 'id',
|
||||||
|
Name: 'name',
|
||||||
|
Description: 'description',
|
||||||
|
Policies: [],
|
||||||
|
Roles: [],
|
||||||
|
ServiceIdentities: [],
|
||||||
|
NodeIdentities: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
{
|
{
|
||||||
AccessorID: 'id',
|
finders: predicates,
|
||||||
Name: 'name',
|
}
|
||||||
Description: 'description',
|
).search('hit');
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: null,
|
|
||||||
Roles: null,
|
|
||||||
ServiceIdentities: null,
|
|
||||||
NodeIdentities: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AccessorID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
Description: 'description',
|
|
||||||
Policies: [],
|
|
||||||
Roles: [],
|
|
||||||
ServiceIdentities: [],
|
|
||||||
NodeIdentities: [],
|
|
||||||
},
|
|
||||||
].filter(search('hit'));
|
|
||||||
assert.equal(actual.length, 0);
|
assert.equal(actual.length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue