From 9ebc9561d92e5632c68f131ec616d3172659e335 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Tue, 4 May 2021 17:25:57 +0100 Subject: [PATCH] ui: Fix text search for upstream instances (#10151) * ui: Fix text search for upstream instances * Clean up predicates for other model types * Add some docs around DataCollection and searching * Enable UI Engineering Docs for our preview sites * Use debug CSS in dev and staging --- .changelog/10151.txt | 3 + .../app/components/data-collection/README.mdx | 79 ++++++++++++++----- .../app/search/predicates/health-check.js | 16 ++-- .../consul-ui/app/search/predicates/nspace.js | 8 +- .../consul-ui/app/search/predicates/role.js | 6 +- .../app/search/predicates/service-instance.js | 2 +- .../consul-ui/app/search/predicates/token.js | 10 +-- .../search/predicates/upstream-instance.js | 11 +-- ui/packages/consul-ui/app/styles/debug.scss | 13 +++ ui/packages/consul-ui/config/environment.js | 4 + ui/packages/consul-ui/ember-cli-build.js | 57 ++++++++----- ui/packages/consul-ui/lib/startup/index.js | 3 +- .../lib/startup/templates/head.html.js | 2 +- 13 files changed, 141 insertions(+), 73 deletions(-) create mode 100644 .changelog/10151.txt diff --git a/.changelog/10151.txt b/.changelog/10151.txt new file mode 100644 index 0000000000..f75f843957 --- /dev/null +++ b/.changelog/10151.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Fix text searching through upstream instances. +``` diff --git a/ui/packages/consul-ui/app/components/data-collection/README.mdx b/ui/packages/consul-ui/app/components/data-collection/README.mdx index 626dc23e29..0be25b1669 100644 --- a/ui/packages/consul-ui/app/components/data-collection/README.mdx +++ b/ui/packages/consul-ui/app/components/data-collection/README.mdx @@ -1,25 +1,62 @@ ---- -class: ember ---- # DataCollection -```hbs - - {{collection.items.length}} - - Has Results - - - Is Empty - - +The DataCollection component is the component we use for searching, filtering and sorting. It does not dictate any rendering of your data, but it does provide two different states/contextual components for rendering: when there are some results, when there are no results and also (by not using the contextual components) when the amount of results does not matter to what you want to render (say a count of number of results). + +The component should be configured with the `@type` attribute, the component will use this to lookup 'specifications' for searching, sorting and filtering in the respective `app/search/predicates`, `app/sort/comparators` and `app/filter/predicates` folders. These specifications define _what_ is searched when you search a list of objects (for example searching Name could mean searching `model.Name` whereas searching Role could mean searching through an array of `item.RoleDefaults`). + +The component can also be further configured by specifications for _how_ to search, for example we currently only use `Exact` searching (pretty much an `indexOf` search), but we also have `fuzzy` and `regexp` searching methods available (but disabled until needed). These search 'methods' will use the above specifications again to define _what_ to search. Searching methods (the _how_) are in `utils/search/{exact,fuzzy,regexp}.js` and any new ones should implement at least a single `search` method. + +Lastly, a `SearchService` in `services/search.js` configures what is available for _what_ to search and _how_ to search, so if you need to add new models or search methods, that is where to look. + +```hbs preview-template +
+
Provide a widget to search with
+ +
+ +
+
Get some data to search on
+ + +
+
and show the complete set of data
+ {{#each source.data as |item|}} + {{item.Name}}, + {{/each}} +
+ +
+ +
+
Use the component
+ + + Has {{collection.items.length}} results:
+ + {{#each collection.items as |item|}} + {{item.Name}}, + {{/each}} + + + Is Empty + +
+ +
+ +
+
``` ### Arguments @@ -30,6 +67,8 @@ as |collection|> | `search` | `String` | '' | A search term to use for searching | | `sort` | `String` | '' | A sort term to use for sorting on ('Name:asc') | | `filter` | `Object` | | An object whose properties are the properties/values to filter on | +| `type` | `String` | '' | The name of the specification describing what to search, filter, sort | +| `searchable` | `String` | `exact` | The name of the method to use for searching | ### Yields diff --git a/ui/packages/consul-ui/app/search/predicates/health-check.js b/ui/packages/consul-ui/app/search/predicates/health-check.js index e644b52cb4..61cb54bd09 100644 --- a/ui/packages/consul-ui/app/search/predicates/health-check.js +++ b/ui/packages/consul-ui/app/search/predicates/health-check.js @@ -2,12 +2,12 @@ const asArray = function(arr) { return Array.isArray(arr) ? arr : arr.toArray(); }; export default { - Name: (item, value) => item.Name, - Node: (item, value) => item.Node, - Service: (item, value) => item.ServiceName, - CheckID: (item, value) => item.CheckID || '', - ID: (item, value) => item.Service.ID || '', - Notes: (item, value) => item.Notes, - Output: (item, value) => item.Output, - ServiceTags: (item, value) => asArray(item.ServiceTags || []), + Name: item => item.Name, + Node: item => item.Node, + Service: item => item.ServiceName, + CheckID: item => item.CheckID || '', + ID: item => item.Service.ID || '', + Notes: item => item.Notes, + Output: item => item.Output, + ServiceTags: item => asArray(item.ServiceTags || []), }; diff --git a/ui/packages/consul-ui/app/search/predicates/nspace.js b/ui/packages/consul-ui/app/search/predicates/nspace.js index 945b8d0a31..ada8ea8aa1 100644 --- a/ui/packages/consul-ui/app/search/predicates/nspace.js +++ b/ui/packages/consul-ui/app/search/predicates/nspace.js @@ -1,11 +1,11 @@ export default { - Name: (item, value) => item.Name, - Description: (item, value) => item.Description, - Role: (item, value) => { + Name: item => item.Name, + Description: item => item.Description, + Role: item => { const acls = item.ACLs || {}; return (acls.RoleDefaults || []).map(item => item.Name); }, - Policy: (item, value) => { + Policy: item => { const acls = item.ACLs || {}; return (acls.PolicyDefaults || []).map(item => item.Name); }, diff --git a/ui/packages/consul-ui/app/search/predicates/role.js b/ui/packages/consul-ui/app/search/predicates/role.js index 1cb534b76d..397f2f61e0 100644 --- a/ui/packages/consul-ui/app/search/predicates/role.js +++ b/ui/packages/consul-ui/app/search/predicates/role.js @@ -1,7 +1,7 @@ export default { - Name: (item, value) => item.Name, - Description: (item, value) => item.Description, - Policy: (item, value) => { + Name: item => item.Name, + Description: item => item.Description, + Policy: item => { return (item.Policies || []) .map(item => item.Name) .concat((item.ServiceIdentities || []).map(item => item.ServiceName)) diff --git a/ui/packages/consul-ui/app/search/predicates/service-instance.js b/ui/packages/consul-ui/app/search/predicates/service-instance.js index e1d6b63d57..1792f6372d 100644 --- a/ui/packages/consul-ui/app/search/predicates/service-instance.js +++ b/ui/packages/consul-ui/app/search/predicates/service-instance.js @@ -1,7 +1,7 @@ export default { Name: item => item.Name, Tags: item => item.Service.Tags || [], - ID: (item, value) => item.Service.ID || '', + ID: item => item.Service.ID || '', Address: item => item.Address || '', Port: item => (item.Service.Port || '').toString(), ['Service.Meta']: item => diff --git a/ui/packages/consul-ui/app/search/predicates/token.js b/ui/packages/consul-ui/app/search/predicates/token.js index 33a77df51a..87dc7a75ec 100644 --- a/ui/packages/consul-ui/app/search/predicates/token.js +++ b/ui/packages/consul-ui/app/search/predicates/token.js @@ -1,9 +1,9 @@ export default { - Name: (item, value) => item.Name, - Description: (item, value) => item.Description, - AccessorID: (item, value) => item.AccessorID, - Role: (item, value) => (item.Roles || []).map(item => item.Name), - Policy: (item, value) => { + Name: item => item.Name, + Description: item => item.Description, + AccessorID: item => item.AccessorID, + Role: item => (item.Roles || []).map(item => item.Name), + Policy: item => { return (item.Policies || []) .map(item => item.Name) .concat((item.ServiceIdentities || []).map(item => item.ServiceName)) diff --git a/ui/packages/consul-ui/app/search/predicates/upstream-instance.js b/ui/packages/consul-ui/app/search/predicates/upstream-instance.js index 26b133d53e..8af1dd5e2f 100644 --- a/ui/packages/consul-ui/app/search/predicates/upstream-instance.js +++ b/ui/packages/consul-ui/app/search/predicates/upstream-instance.js @@ -1,10 +1,5 @@ export default { - DestinationName: (item, value) => - item.DestinationName.toLowerCase().indexOf(value.toLowerCase()) !== -1, - LocalBindAddress: (item, value) => - item.LocalBindAddress.toLowerCase().indexOf(value.toLowerCase()) !== -1, - LocalBindPort: (item, value) => - item.LocalBindPort.toString() - .toLowerCase() - .indexOf(value.toLowerCase()) !== -1, + DestinationName: (item, value) => item.DestinationName, + LocalBindAddress: (item, value) => item.LocalBindAddress, + LocalBindPort: (item, value) => item.LocalBindPort.toString(), }; diff --git a/ui/packages/consul-ui/app/styles/debug.scss b/ui/packages/consul-ui/app/styles/debug.scss index 8f797eda4a..62be103de5 100644 --- a/ui/packages/consul-ui/app/styles/debug.scss +++ b/ui/packages/consul-ui/app/styles/debug.scss @@ -59,6 +59,19 @@ ul { margin-bottom: 0; } + figure { + margin-bottom: .5rem; + } + figcaption { + margin-bottom: .5rem; + color: var(--gray-400); + font-style: italic; + } + figure > [type=text] { + border: 1px solid var(--gray-999); + width: 100%; + padding: .5rem; + } } // &__snippets__tabs__button { // display: none; diff --git a/ui/packages/consul-ui/config/environment.js b/ui/packages/consul-ui/config/environment.js index b6fdeb6951..faf050a455 100644 --- a/ui/packages/consul-ui/config/environment.js +++ b/ui/packages/consul-ui/config/environment.js @@ -1,3 +1,7 @@ +// All of the configuration here is shared between buildtime and runtime and +// is therefore added to ember's tag in the actual app, if the +// configuration is for buildtime only you should probably just use +// ember-cli-build to prevent values being outputted in the meta tag 'use strict'; const path = require('path'); const utils = require('./utils'); diff --git a/ui/packages/consul-ui/ember-cli-build.js b/ui/packages/consul-ui/ember-cli-build.js index 35572820cb..638087bdf7 100644 --- a/ui/packages/consul-ui/ember-cli-build.js +++ b/ui/packages/consul-ui/ember-cli-build.js @@ -1,42 +1,58 @@ 'use strict'; const Funnel = require('broccoli-funnel'); const EmberApp = require('ember-cli/lib/broccoli/ember-app'); + module.exports = function(defaults) { + // available environments + // ['production', 'development', 'staging', 'test']; + const env = EmberApp.env(); const prodlike = ['production', 'staging']; - const isProd = env === 'production'; - const isProdLike = prodlike.indexOf(env) > -1; - const sourcemaps = !isProd; + const trees = {}; const addons = {}; const outputPaths = {}; - if (isProdLike) { - // exclude any component/pageobject.js files from production-like environments - trees.app = new Funnel('app', { - exclude: [ - 'components/**/pageobject.js', - 'components/**/*.test-support.js', - 'components/**/*.test.js', - // exclude our debug initializer, route and template - 'instance-initializers/debug.js', - 'templates/debug.hbs', - 'components/debug/**/*.*' - ], - }); - // exclude any debug like addons from production-like environments + let excludeFiles = []; + + const sourcemaps = !['production'].includes(env); + + // setup up different build configuration depending on environment + if(!['test'].includes(env)) { + // exclude any component/pageobject.js files from anything but test + excludeFiles = excludeFiles.concat([ + 'components/**/pageobject.js', + 'components/**/*.test-support.js', + 'components/**/*.test.js', + ]) + } + + if(['test', 'production'].includes(env)) { + // exclude our debug initializer, route and template + excludeFiles = excludeFiles.concat([ + 'instance-initializers/debug.js', + 'templates/debug.hbs', + 'components/debug/**/*.*' + ]) + // exclude any debug like addons from production or test environments addons.blacklist = [ // exclude docfy '@docfy/ember' ]; } else { - // add debug css is we are not in prodlike environments + // add debug css is we are not in test or production environments outputPaths.app = { css: { 'debug': '/assets/debug.css' } } } - let app = new EmberApp( + // + + trees.app = new Funnel('app', { + exclude: excludeFiles + }); + + const app = new EmberApp( Object.assign({}, defaults, { productionEnvironments: prodlike, }), @@ -138,6 +154,5 @@ module.exports = function(defaults) { app.import('vendor/init.js', { outputFile: 'assets/init.js', }); - let tree = app.toTree(); - return tree; + return app.toTree(); }; diff --git a/ui/packages/consul-ui/lib/startup/index.js b/ui/packages/consul-ui/lib/startup/index.js index 5dbbc74a09..41dcd89906 100644 --- a/ui/packages/consul-ui/lib/startup/index.js +++ b/ui/packages/consul-ui/lib/startup/index.js @@ -42,8 +42,7 @@ module.exports = { treeFor: function(name) { const tree = this._super.treeFor.apply(this, arguments); if (name === 'app') { - const prodlike = ['production', 'staging']; - if (prodlike.includes(process.env.EMBER_ENV)) { + if (['production', 'test'].includes(process.env.EMBER_ENV)) { return mergeTrees([tree, writeFile('components/debug/navigation/index.hbs', '')]); } } diff --git a/ui/packages/consul-ui/lib/startup/templates/head.html.js b/ui/packages/consul-ui/lib/startup/templates/head.html.js index 6bc28f79b3..6a71ea99a8 100644 --- a/ui/packages/consul-ui/lib/startup/templates/head.html.js +++ b/ui/packages/consul-ui/lib/startup/templates/head.html.js @@ -8,7 +8,7 @@ module.exports = ({ appName, environment, rootURL, config }) => ` ${ environment === 'test' ? `` : ``