From 8a43d76c8c035bdf601cfff1b532a871c7812072 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 000000000..f75f84395 --- /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 626dc23e2..0be25b166 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 e644b52cb..61cb54bd0 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 945b8d0a3..ada8ea8aa 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 1cb534b76..397f2f61e 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 e1d6b63d5..1792f6372 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 33a77df51..87dc7a75e 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 26b133d53..8af1dd5e2 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 2c42130f3..8b04b0322 100644 --- a/ui/packages/consul-ui/app/styles/debug.scss +++ b/ui/packages/consul-ui/app/styles/debug.scss @@ -66,6 +66,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 b6fdeb695..faf050a45 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 35572820c..638087bdf 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 5dbbc74a0..41dcd8990 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 fa3c56b0c..1d8d38ea0 100644 --- a/ui/packages/consul-ui/lib/startup/templates/head.html.js +++ b/ui/packages/consul-ui/lib/startup/templates/head.html.js @@ -9,7 +9,7 @@ module.exports = ({ appName, environment, rootURL, config }) => ` ${ environment === 'test' ? `` : ``