From d0c43129237c945eb7764c5c9df3633da10ba6eb Mon Sep 17 00:00:00 2001 From: Kenia <19161242+kaxcode@users.noreply.github.com> Date: Wed, 8 Apr 2020 13:09:36 -0400 Subject: [PATCH] ui: Redesign Service List page (#7605) * Create GridCollection for nodes page with styling * Update ListCollection styling * Update TagList styling * Create CompositeRow styling component * Update ConsulServiceList component with styling * Create service health-checks helper * Add InstanceCount to the service model * Add tag-svg to codebase * Create and update tests for service-list page * Upgrade @hashicorp/consul-api-double to 2.14.0 --- .../components/consul-service-list/index.hbs | 45 ++++------- .../components/consul-service-list/index.js | 63 +-------------- .../app/components/grid-collection/index.hbs | 6 ++ ui-v2/app/components/grid-collection/index.js | 78 +++++++++++++++++++ ui-v2/app/components/list-collection/index.js | 38 +-------- ui-v2/app/controllers/dc/services/index.js | 21 ++++- ui-v2/app/helpers/service/health-checks.js | 16 ++++ ui-v2/app/models/service.js | 1 + .../app/styles/base/icons/base-variables.scss | 1 + .../styles/base/icons/icon-placeholders.scss | 10 +++ .../components/composite-row/index.scss | 13 ++++ .../components/composite-row/layout.scss | 22 ++++++ .../styles/components/composite-row/skin.scss | 18 +++++ .../components/consul-service-list.scss | 11 +++ .../components/consul-service-list/index.scss | 2 + .../consul-service-list/layout.scss | 21 +++++ .../components/consul-service-list/skin.scss | 43 ++++++++++ .../styles/components/grid-collection.scss | 39 ++++++++++ ui-v2/app/styles/components/index.scss | 3 + .../styles/components/list-collection.scss | 35 --------- ui-v2/app/styles/components/pill.scss | 3 +- .../styles/components/tag-list/layout.scss | 20 ++--- .../app/styles/components/tag-list/skin.scss | 3 + ui-v2/app/templates/dc/nodes/index.hbs | 4 +- ui-v2/app/templates/dc/services/index.hbs | 12 ++- ui-v2/package.json | 2 +- .../components/catalog-filter.feature | 14 +++- ui-v2/tests/acceptance/dc/error.feature | 10 ++- .../tests/acceptance/dc/list-blocking.feature | 1 - ui-v2/tests/acceptance/dc/list.feature | 1 - .../acceptance/dc/nspaces/manage.feature | 17 +++- .../acceptance/dc/services/dc-switch.feature | 16 +++- .../acceptance/dc/services/index.feature | 14 ++-- .../dc/services/list-blocking.feature | 26 +++++++ .../tests/acceptance/dc/services/list.feature | 20 +++++ .../steps/dc/services/list-blocking-steps.js | 10 +++ .../steps/dc/services/list-steps.js | 10 +++ ui-v2/tests/pages.js | 2 +- ui-v2/tests/pages/dc/services/index.js | 13 ++-- ui-v2/yarn.lock | 6 +- 40 files changed, 482 insertions(+), 208 deletions(-) create mode 100644 ui-v2/app/components/grid-collection/index.hbs create mode 100644 ui-v2/app/components/grid-collection/index.js create mode 100644 ui-v2/app/helpers/service/health-checks.js create mode 100644 ui-v2/app/styles/components/composite-row/index.scss create mode 100644 ui-v2/app/styles/components/composite-row/layout.scss create mode 100644 ui-v2/app/styles/components/composite-row/skin.scss create mode 100644 ui-v2/app/styles/components/consul-service-list.scss create mode 100644 ui-v2/app/styles/components/consul-service-list/index.scss create mode 100644 ui-v2/app/styles/components/consul-service-list/layout.scss create mode 100644 ui-v2/app/styles/components/consul-service-list/skin.scss create mode 100644 ui-v2/app/styles/components/grid-collection.scss create mode 100644 ui-v2/tests/acceptance/dc/services/list-blocking.feature create mode 100644 ui-v2/tests/acceptance/dc/services/list.feature create mode 100644 ui-v2/tests/acceptance/steps/dc/services/list-blocking-steps.js create mode 100644 ui-v2/tests/acceptance/steps/dc/services/list-steps.js diff --git a/ui-v2/app/components/consul-service-list/index.hbs b/ui-v2/app/components/consul-service-list/index.hbs index e5e4c695f..3781b18cb 100644 --- a/ui-v2/app/components/consul-service-list/index.hbs +++ b/ui-v2/app/components/consul-service-list/index.hbs @@ -1,34 +1,15 @@ +{{yield}} {{#if (gt items.length 0)}} - - - Service - - Health Checks - - The number of health checks for the service on all nodes - - - Tags - - - - - {{#let (service/external-source item) as |externalSource| }} - {{#if externalSource }} - - {{else}} - - {{/if}} - {{/let}} - {{item.Name}} - - - - - - - - - - + + + + + {{item.Name}} + + + + {{yield}} + + + {{/if}} \ No newline at end of file diff --git a/ui-v2/app/components/consul-service-list/index.js b/ui-v2/app/components/consul-service-list/index.js index 98d3278c4..a7be4db13 100644 --- a/ui-v2/app/components/consul-service-list/index.js +++ b/ui-v2/app/components/consul-service-list/index.js @@ -1,65 +1,6 @@ import Component from '@ember/component'; -import { get, computed } from '@ember/object'; -import { htmlSafe } from '@ember/string'; +import Slotted from 'block-slots'; -const max = function(arr, prop) { - return arr.reduce(function(prev, item) { - return Math.max(prev, get(item, prop)); - }, 0); -}; -const chunk = function(str, size) { - const num = Math.ceil(str.length / size); - const chunks = new Array(num); - for (let i = 0, o = 0; i < num; ++i, o += size) { - chunks[i] = str.substr(o, size); - } - return chunks; -}; -const width = function(num) { - const str = num.toString(); - const len = str.length; - const commas = chunk(str, 3).length - 1; - return commas * 4 + len * 10; -}; -const widthDeclaration = function(num) { - return htmlSafe(`width: ${num}px`); -}; -export default Component.extend({ +export default Component.extend(Slotted, { tagName: '', - onchange: function() {}, - maxWidth: computed('{maxPassing,maxWarning,maxCritical}', function() { - const PADDING = 32 * 3 + 13; - return ['maxPassing', 'maxWarning', 'maxCritical'].reduce((prev, item) => { - return prev + width(get(this, item)); - }, PADDING); - }), - totalWidth: computed('maxWidth', function() { - return widthDeclaration(get(this, 'maxWidth')); - }), - remainingWidth: computed('maxWidth', function() { - // maxWidth is the maximum width of the healthchecks column - // there are currently 2 other columns so divide it by 2 and - // take that off 50% (100% / number of fluid columns) - // also we added a Type column which we've currently fixed to 100px - // so again divide that by 2 and take it off each fluid column - return htmlSafe(`width: calc(50% - 50px - ${Math.round(get(this, 'maxWidth') / 2)}px)`); - }), - maxPassing: computed('items.[]', function() { - return max(get(this, 'items'), 'ChecksPassing'); - }), - maxWarning: computed('items.[]', function() { - return max(get(this, 'items'), 'ChecksWarning'); - }), - maxCritical: computed('items.[]', function() { - return max(get(this, 'items'), 'ChecksCritical'); - }), - passingWidth: computed('maxPassing', function() { - return widthDeclaration(width(get(this, 'maxPassing'))); - }), - warningWidth: computed('maxWarning', function() { - return widthDeclaration(width(get(this, 'maxWarning'))); - }), - criticalWidth: computed('maxCritical', function() { - return widthDeclaration(width(get(this, 'maxCritical'))); - }), }); diff --git a/ui-v2/app/components/grid-collection/index.hbs b/ui-v2/app/components/grid-collection/index.hbs new file mode 100644 index 000000000..f1863719f --- /dev/null +++ b/ui-v2/app/components/grid-collection/index.hbs @@ -0,0 +1,6 @@ + +
  • + {{~#each _cells as |cell|~}} +
  • {{yield cell.item cell.index }}
  • + {{~/each~}} +
    \ No newline at end of file diff --git a/ui-v2/app/components/grid-collection/index.js b/ui-v2/app/components/grid-collection/index.js new file mode 100644 index 000000000..c566fa7ce --- /dev/null +++ b/ui-v2/app/components/grid-collection/index.js @@ -0,0 +1,78 @@ +import { inject as service } from '@ember/service'; +import { computed, get, set } from '@ember/object'; +import Component from 'ember-collection/components/ember-collection'; +import PercentageColumns from 'ember-collection/layouts/percentage-columns'; +import style from 'ember-computed-style'; +import WithResizing from 'consul-ui/mixins/with-resizing'; + +export default Component.extend(WithResizing, { + dom: service('dom'), + tagName: 'div', + attributeBindings: ['style'], + height: 500, + cellHeight: 113, + style: style('getStyle'), + classNames: ['grid-collection'], + init: function() { + this._super(...arguments); + this.columns = [25, 25, 25, 25]; + }, + didReceiveAttrs: function() { + this._super(...arguments); + this._cellLayout = this['cell-layout'] = new PercentageColumns( + get(this, 'items.length'), + get(this, 'columns'), + get(this, 'cellHeight') + ); + }, + getStyle: computed('height', function() { + return { + height: get(this, 'height'), + }; + }), + resize: function(e) { + // TODO: This top part is very similar to resize in tabular-collection + // see if it make sense to DRY out + const dom = get(this, 'dom'); + const $appContent = dom.element('main > div'); + if ($appContent) { + const rect = this.element.getBoundingClientRect(); + const $footer = dom.element('footer[role="contentinfo"]'); + const space = rect.top + $footer.clientHeight; + const height = e.detail.height - space; + this.set('height', Math.max(0, height)); + this.updateItems(); + this.updateScrollPosition(); + } + const width = e.detail.width; + const len = get(this, 'columns.length'); + switch (true) { + case width > 1013: + if (len != 4) { + set(this, 'columns', [25, 25, 25, 25]); + } + break; + case width > 744: + if (len != 3) { + set(this, 'columns', [33, 33, 34]); + } + break; + case width > 487: + if (len != 2) { + set(this, 'columns', [50, 50]); + } + break; + case width < 488: + if (len != 1) { + set(this, 'columns', [100]); + } + } + if (len !== get(this, 'columns.length')) { + this._cellLayout = this['cell-layout'] = new PercentageColumns( + get(this, 'items.length'), + get(this, 'columns'), + get(this, 'cellHeight') + ); + } + }, +}); diff --git a/ui-v2/app/components/list-collection/index.js b/ui-v2/app/components/list-collection/index.js index 1a5229583..39181ec81 100644 --- a/ui-v2/app/components/list-collection/index.js +++ b/ui-v2/app/components/list-collection/index.js @@ -1,5 +1,5 @@ import { inject as service } from '@ember/service'; -import { computed, get, set } from '@ember/object'; +import { computed, get } from '@ember/object'; import Component from 'ember-collection/components/ember-collection'; import PercentageColumns from 'ember-collection/layouts/percentage-columns'; import style from 'ember-computed-style'; @@ -10,12 +10,11 @@ export default Component.extend(WithResizing, { tagName: 'div', attributeBindings: ['style'], height: 500, - cellHeight: 113, style: style('getStyle'), classNames: ['list-collection'], init: function() { this._super(...arguments); - this.columns = [25, 25, 25, 25]; + this.columns = [100]; }, didReceiveAttrs: function() { this._super(...arguments); @@ -36,43 +35,14 @@ export default Component.extend(WithResizing, { const dom = get(this, 'dom'); const $appContent = dom.element('main > div'); if ($appContent) { + const border = 1; const rect = this.element.getBoundingClientRect(); const $footer = dom.element('footer[role="contentinfo"]'); - const space = rect.top + $footer.clientHeight; + const space = rect.top + $footer.clientHeight + border; const height = e.detail.height - space; this.set('height', Math.max(0, height)); this.updateItems(); this.updateScrollPosition(); } - const width = e.detail.width; - const len = get(this, 'columns.length'); - switch (true) { - case width > 1013: - if (len != 4) { - set(this, 'columns', [25, 25, 25, 25]); - } - break; - case width > 744: - if (len != 3) { - set(this, 'columns', [33, 33, 34]); - } - break; - case width > 487: - if (len != 2) { - set(this, 'columns', [50, 50]); - } - break; - case width < 488: - if (len != 1) { - set(this, 'columns', [100]); - } - } - if (len !== get(this, 'columns.length')) { - this._cellLayout = this['cell-layout'] = new PercentageColumns( - get(this, 'items.length'), - get(this, 'columns'), - get(this, 'cellHeight') - ); - } }, }); diff --git a/ui-v2/app/controllers/dc/services/index.js b/ui-v2/app/controllers/dc/services/index.js index aa8eeafb7..6a27337e2 100644 --- a/ui-v2/app/controllers/dc/services/index.js +++ b/ui-v2/app/controllers/dc/services/index.js @@ -14,9 +14,26 @@ export default Controller.extend(WithEventSource, WithSearching, { }; this._super(...arguments); }, - searchable: computed('items.[]', function() { + searchable: computed('services.[]', function() { return get(this, 'searchables.service') - .add(this.items) + .add(this.services) .search(this.terms); }), + services: computed('items.[]', function() { + return this.items.filter(function(item) { + return item.Kind === 'consul'; + }); + }), + proxies: computed('items.[]', function() { + return this.items.filter(function(item) { + return item.Kind === 'connect-proxy'; + }); + }), + withProxies: computed('proxies', function() { + const proxies = {}; + this.proxies.forEach(item => { + proxies[item.Name.replace('-proxy', '')] = true; + }); + return proxies; + }), }); diff --git a/ui-v2/app/helpers/service/health-checks.js b/ui-v2/app/helpers/service/health-checks.js new file mode 100644 index 000000000..71259e61d --- /dev/null +++ b/ui-v2/app/helpers/service/health-checks.js @@ -0,0 +1,16 @@ +import { helper } from '@ember/component/helper'; + +export function healthChecks([item], hash) { + switch (true) { + case item.ChecksCritical !== 0: + return 'critical'; + case item.ChecksWarning !== 0: + return 'warning'; + case item.ChecksPassing !== 0: + return 'passing'; + default: + return 'empty'; + } +} + +export default helper(healthChecks); diff --git a/ui-v2/app/models/service.js b/ui-v2/app/models/service.js index e9548c574..49b04c2ac 100644 --- a/ui-v2/app/models/service.js +++ b/ui-v2/app/models/service.js @@ -13,6 +13,7 @@ export default Model.extend({ return []; }, }), + InstanceCount: attr('number'), Kind: attr('string'), ExternalSources: attr(), Meta: attr(), diff --git a/ui-v2/app/styles/base/icons/base-variables.scss b/ui-v2/app/styles/base/icons/base-variables.scss index 2bbf7b7c8..39ec2fb8a 100644 --- a/ui-v2/app/styles/base/icons/base-variables.scss +++ b/ui-v2/app/styles/base/icons/base-variables.scss @@ -153,6 +153,7 @@ $sub-right-svg: url('data:image/svg+xml;charset=UTF-8,'); $swap-horizontal-svg: url('data:image/svg+xml;charset=UTF-8,'); $swap-vertical-svg: url('data:image/svg+xml;charset=UTF-8,'); +$tag-svg: url('data:image/svg+xml;charset=UTF-8,'); $terraform-logo-color-svg: url('data:image/svg+xml;charset=UTF-8,'); $trash-svg: url('data:image/svg+xml;charset=UTF-8,'); $tune-svg: url('data:image/svg+xml;charset=UTF-8,'); diff --git a/ui-v2/app/styles/base/icons/icon-placeholders.scss b/ui-v2/app/styles/base/icons/icon-placeholders.scss index 6af6e1971..477a85de1 100644 --- a/ui-v2/app/styles/base/icons/icon-placeholders.scss +++ b/ui-v2/app/styles/base/icons/icon-placeholders.scss @@ -1538,6 +1538,16 @@ mask-image: $swap-vertical-svg; } +%with-tag-icon { + @extend %with-icon; + background-image: $tag-svg; +} +%with-tag-mask { + @extend %with-mask; + -webkit-mask-image: $tag-svg; + mask-image: $tag-svg; +} + %with-terraform-logo-color-icon { @extend %with-icon; background-image: $terraform-logo-color-svg; diff --git a/ui-v2/app/styles/components/composite-row/index.scss b/ui-v2/app/styles/components/composite-row/index.scss new file mode 100644 index 000000000..16a0c0af0 --- /dev/null +++ b/ui-v2/app/styles/components/composite-row/index.scss @@ -0,0 +1,13 @@ +@import './layout'; +@import './skin'; +%composite-row a:hover, +%composite-row a:focus, +%composite-row a:active { + @extend %composite-row-intent; +} +%composite-row > a > span { + @extend %composite-row-header; +} +%composite-row > a > ul { + @extend %composite-row-detail; +} diff --git a/ui-v2/app/styles/components/composite-row/layout.scss b/ui-v2/app/styles/components/composite-row/layout.scss new file mode 100644 index 000000000..760ef739a --- /dev/null +++ b/ui-v2/app/styles/components/composite-row/layout.scss @@ -0,0 +1,22 @@ +%composite-row a { + display: block; + box-sizing: border-box; + padding: 12px; + padding-right: 0; + border: 1px solid; + border-bottom: 0; +} +%composite-row-intent { + border: 1px solid; + position: relative; +} +%composite-row-detail { + display: flex; + flex-wrap: nowrap; +} +%composite-row-detail * { + white-space: nowrap; +} +%composite-row-detail > li:not(:first-child) { + margin-left: 12px; +} diff --git a/ui-v2/app/styles/components/composite-row/skin.scss b/ui-v2/app/styles/components/composite-row/skin.scss new file mode 100644 index 000000000..3759364a2 --- /dev/null +++ b/ui-v2/app/styles/components/composite-row/skin.scss @@ -0,0 +1,18 @@ +%composite-row { + list-style-type: none; +} +%composite-row a { + border-top-color: $gray-200; + border-right-color: transparent; + border-left-color: transparent; +} +%composite-row-intent { + border-color: $gray-200; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} +%composite-row-header { + color: $black; +} +%composite-row-detail { + color: $gray-500; +} diff --git a/ui-v2/app/styles/components/consul-service-list.scss b/ui-v2/app/styles/components/consul-service-list.scss new file mode 100644 index 000000000..1652d418e --- /dev/null +++ b/ui-v2/app/styles/components/consul-service-list.scss @@ -0,0 +1,11 @@ +@import './consul-service-list/index'; + +.consul-service-list > ul { + @extend %consul-service-list; +} +%consul-service-list > li { + @extend %consul-service-row; +} +%consul-service-row { + @extend %composite-row; +} diff --git a/ui-v2/app/styles/components/consul-service-list/index.scss b/ui-v2/app/styles/components/consul-service-list/index.scss new file mode 100644 index 000000000..62cfad5c0 --- /dev/null +++ b/ui-v2/app/styles/components/consul-service-list/index.scss @@ -0,0 +1,2 @@ +@import './layout'; +@import './skin'; diff --git a/ui-v2/app/styles/components/consul-service-list/layout.scss b/ui-v2/app/styles/components/consul-service-list/layout.scss new file mode 100644 index 000000000..3484961ca --- /dev/null +++ b/ui-v2/app/styles/components/consul-service-list/layout.scss @@ -0,0 +1,21 @@ +%consul-service-list { + // Used for every DOM-Recycle scroll pane + // TODO: Refactor to have all this DOM-Recycle styling in one place + overflow-x: hidden !important; +} +%consul-service-row > a > span:first-child { + margin-right: 4px; + width: 18px; + height: 18px; +} +%consul-service-row > a > span:nth-child(3) { + margin-left: 4px; + width: 16px; + height: 16px; +} +%consul-service-row > a > ul { + margin-left: 26px; +} +%consul-service-row .proxy::before { + margin-right: 4px; +} diff --git a/ui-v2/app/styles/components/consul-service-list/skin.scss b/ui-v2/app/styles/components/consul-service-list/skin.scss new file mode 100644 index 000000000..e2b499d5c --- /dev/null +++ b/ui-v2/app/styles/components/consul-service-list/skin.scss @@ -0,0 +1,43 @@ +%consul-service-row > a > span:nth-child(2) { + font-size: 1.125rem; + font-weight: $typo-weight-medium; +} +%consul-service-row > a > span:first-child, +%consul-service-row > a > span:nth-child(3) { + @extend %as-pseudo; +} +%consul-service-row .empty { + @extend %with-minus-square-fill-color-mask; + background-color: #7c8797; +} +%consul-service-row .kubernetes { + @extend %with-kubernetes-logo-color-icon; +} +%consul-service-row .terraform { + @extend %with-terraform-logo-color-icon; +} +%consul-service-row .nomad { + @extend %with-nomad-logo-color-icon; +} +%consul-service-row .consul { + @extend %with-consul-logo-color-icon; +} +%consul-service-row .aws { + @extend %with-logo-aws-color-icon; +} +%consul-service-row .passing { + @extend %with-check-circle-fill-color-mask; + background-color: $green-500; +} +%consul-service-row .warning { + @extend %with-alert-triangle-color-mask; + background-color: $orange-500; +} +%consul-service-row .critical { + @extend %with-cancel-square-fill-color-mask; + background-color: $red-500; +} +%consul-service-row .proxy::before { + @extend %with-swap-horizontal-mask, %as-pseudo; + background-color: $gray-500; +} diff --git a/ui-v2/app/styles/components/grid-collection.scss b/ui-v2/app/styles/components/grid-collection.scss new file mode 100644 index 000000000..491c3d79a --- /dev/null +++ b/ui-v2/app/styles/components/grid-collection.scss @@ -0,0 +1,39 @@ +.unhealthy > div, +.healthy > div { + @extend %card-grid; +} +.grid-collection { + height: 500px; + position: relative; +} +.healthy > div { + width: calc(100% + 23px); + min-height: 500px; +} +.unhealthy > div { + margin-bottom: 20px; +} +.healthy > div > ul > li { + padding-right: 23px; + padding-bottom: 20px; +} +%card-grid > ul, +%card-grid > ol { + list-style-type: none; + display: grid; + grid-auto-rows: 12px; +} +@media #{$--fixed-grid} { + %card-grid > ul, + %card-grid > ol { + grid-gap: 20px 20px; + grid-template-columns: repeat(4, minmax(220px, 1fr)); + } +} +@media #{$--lt-fixed-grid} { + %card-grid > ul, + %card-grid > ol { + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + grid-gap: 20px 2%; + } +} diff --git a/ui-v2/app/styles/components/index.scss b/ui-v2/app/styles/components/index.scss index 19d60deba..2c39e143d 100644 --- a/ui-v2/app/styles/components/index.scss +++ b/ui-v2/app/styles/components/index.scss @@ -3,6 +3,7 @@ @import './anchors'; @import './progress'; @import './buttons'; +@import './composite-row'; @import './secret-button'; @import './tabs'; @import './pill'; @@ -31,6 +32,8 @@ @import './tabular-details'; @import './tabular-collection'; @import './list-collection'; +@import './grid-collection'; +@import './consul-service-list'; /**/ diff --git a/ui-v2/app/styles/components/list-collection.scss b/ui-v2/app/styles/components/list-collection.scss index 1c8283691..dbe2063d1 100644 --- a/ui-v2/app/styles/components/list-collection.scss +++ b/ui-v2/app/styles/components/list-collection.scss @@ -1,39 +1,4 @@ -.unhealthy > div, -.healthy > div { - @extend %card-grid; -} .list-collection { height: 500px; position: relative; } -.healthy > div { - width: calc(100% + 23px); - min-height: 500px; -} -.unhealthy > div { - margin-bottom: 20px; -} -.healthy > div > ul > li { - padding-right: 23px; - padding-bottom: 20px; -} -%card-grid > ul, -%card-grid > ol { - list-style-type: none; - display: grid; - grid-auto-rows: 12px; -} -@media #{$--fixed-grid} { - %card-grid > ul, - %card-grid > ol { - grid-gap: 20px 20px; - grid-template-columns: repeat(4, minmax(220px, 1fr)); - } -} -@media #{$--lt-fixed-grid} { - %card-grid > ul, - %card-grid > ol { - grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); - grid-gap: 20px 2%; - } -} diff --git a/ui-v2/app/styles/components/pill.scss b/ui-v2/app/styles/components/pill.scss index 016e26542..fb693c545 100644 --- a/ui-v2/app/styles/components/pill.scss +++ b/ui-v2/app/styles/components/pill.scss @@ -1,6 +1,5 @@ @import '../base/components/pill/index'; -td strong, -%tag-list span { +td strong { @extend %pill; margin-right: 3px; } diff --git a/ui-v2/app/styles/components/tag-list/layout.scss b/ui-v2/app/styles/components/tag-list/layout.scss index ee482a895..4b8a342ff 100644 --- a/ui-v2/app/styles/components/tag-list/layout.scss +++ b/ui-v2/app/styles/components/tag-list/layout.scss @@ -5,17 +5,17 @@ // the default definition list layout used in edit pages // ideally we'd be more specific with those to say // only add padding to dl's in edit pages +%tag-list::before { + @extend %with-tag-mask, %as-pseudo; + transform: rotate(-45deg); + margin-right: 4px; +} %tag-list dd { display: inline-flex; - padding-left: 0; - flex-wrap: wrap; - justify-content: space-between; + padding-left: 0px; } -%tag-list dd:after { - content: ''; - flex: auto; -} -%tag-list dd > * { - margin-right: 3px; - margin-bottom: 10px; +%tag-list dd > *:not(:last-child)::after { + content: ', '; + white-space: pre; + display: inline; } diff --git a/ui-v2/app/styles/components/tag-list/skin.scss b/ui-v2/app/styles/components/tag-list/skin.scss index e69de29bb..ef5a8f9ea 100644 --- a/ui-v2/app/styles/components/tag-list/skin.scss +++ b/ui-v2/app/styles/components/tag-list/skin.scss @@ -0,0 +1,3 @@ +%tag-list::before { + background-color: $gray-500; +} diff --git a/ui-v2/app/templates/dc/nodes/index.hbs b/ui-v2/app/templates/dc/nodes/index.hbs index 905e16fac..d2da186ce 100644 --- a/ui-v2/app/templates/dc/nodes/index.hbs +++ b/ui-v2/app/templates/dc/nodes/index.hbs @@ -45,7 +45,7 @@

    Healthy Nodes

    - + {{#if (eq item.Address leader.Address)}} @@ -53,7 +53,7 @@ {{/if}} - +

    diff --git a/ui-v2/app/templates/dc/services/index.hbs b/ui-v2/app/templates/dc/services/index.hbs index d4817d929..1a30391a9 100644 --- a/ui-v2/app/templates/dc/services/index.hbs +++ b/ui-v2/app/templates/dc/services/index.hbs @@ -2,7 +2,7 @@

    - Services {{format-number items.length}} total + Services {{format-number services.length}} total

    @@ -14,7 +14,15 @@ - + + +
      +
    • {{format-number item.InstanceCount}} {{pluralize item.InstanceCount 'Instance' without-count=true}}
    • + {{#if (get withProxies item.Name)}}
    • connected with proxy
    • {{/if}} +
    • +
    +
    +

    diff --git a/ui-v2/package.json b/ui-v2/package.json index 3eaa98b7f..f0f216a13 100644 --- a/ui-v2/package.json +++ b/ui-v2/package.json @@ -115,8 +115,8 @@ "jsonlint": "^1.6.3", "lint-staged": "^9.2.5", "loader.js": "^4.7.0", - "ngraph.graph": "^18.0.3", "mnemonist": "^0.30.0", + "ngraph.graph": "^18.0.3", "node-sass": "^4.9.3", "pretender": "^3.2.0", "prettier": "^1.10.2", diff --git a/ui-v2/tests/acceptance/components/catalog-filter.feature b/ui-v2/tests/acceptance/components/catalog-filter.feature index 9eb37f1bc..ad8fd42df 100644 --- a/ui-v2/tests/acceptance/components/catalog-filter.feature +++ b/ui-v2/tests/acceptance/components/catalog-filter.feature @@ -129,15 +129,21 @@ Feature: components / catalog-filter Given 1 datacenter model with the value "dc-1" And 3 service models from yaml --- - - Tags: ['one', 'two', 'three'] + - Name: Service-0 + Kind: consul + Tags: ['one', 'two', 'three'] ChecksPassing: 0 ChecksWarning: 0 ChecksCritical: 1 - - Tags: ['two', 'three'] + - Name: Service-1 + Kind: consul + Tags: ['two', 'three'] ChecksPassing: 0 ChecksWarning: 1 ChecksCritical: 0 - - Tags: ['three'] + - Name: Service-2 + Kind: consul + Tags: ['three'] ChecksPassing: 1 ChecksWarning: 0 ChecksCritical: 0 @@ -162,4 +168,4 @@ Feature: components / catalog-filter --- s: 'status:critical' --- - And I see 1 service model + And I see 1 service model \ No newline at end of file diff --git a/ui-v2/tests/acceptance/dc/error.feature b/ui-v2/tests/acceptance/dc/error.feature index 7cb465ae7..2682471d3 100644 --- a/ui-v2/tests/acceptance/dc/error.feature +++ b/ui-v2/tests/acceptance/dc/error.feature @@ -6,7 +6,15 @@ Feature: dc / error: Recovering from a dc 500 error - dc-1 - dc-500 --- - And 3 service models + And 3 service models from yaml + --- + - Name: Service-0 + Kind: consul + - Name: Service-1 + Kind: consul + - Name: Service-2 + Kind: consul + --- And the url "/v1/internal/ui/services" responds with a 500 status When I visit the services page for yaml --- diff --git a/ui-v2/tests/acceptance/dc/list-blocking.feature b/ui-v2/tests/acceptance/dc/list-blocking.feature index 45e6e087a..7e6d92438 100644 --- a/ui-v2/tests/acceptance/dc/list-blocking.feature +++ b/ui-v2/tests/acceptance/dc/list-blocking.feature @@ -23,7 +23,6 @@ Feature: dc / list-blocking Where: ------------------------------------------------ | Page | Model | Url | - | services | service | services | | nodes | node | nodes | | intentions | intention | intentions | ------------------------------------------------ diff --git a/ui-v2/tests/acceptance/dc/list.feature b/ui-v2/tests/acceptance/dc/list.feature index efce1ec08..7a67f4cdd 100644 --- a/ui-v2/tests/acceptance/dc/list.feature +++ b/ui-v2/tests/acceptance/dc/list.feature @@ -13,7 +13,6 @@ Feature: dc / list: List Models Where: ------------------------------------------------- | Model | Page | Url | - | service | services | /dc-1/services | | node | nodes | /dc-1/nodes | | kv | kvs | /dc-1/kv | # | acl | acls | /dc-1/acls | diff --git a/ui-v2/tests/acceptance/dc/nspaces/manage.feature b/ui-v2/tests/acceptance/dc/nspaces/manage.feature index 9df85c3d9..24083b10f 100644 --- a/ui-v2/tests/acceptance/dc/nspaces/manage.feature +++ b/ui-v2/tests/acceptance/dc/nspaces/manage.feature @@ -13,7 +13,22 @@ Feature: dc / nspaces / manage : Managing Namespaces --- - dc-1 --- - And 6 service models + And 6 service models from yaml + --- + - Name: Service-0 + Kind: consul + - Name: Service-1 + Kind: consul + - Name: Service-2 + Kind: consul + - Name: Service-3 + Kind: consul + - Name: Service-4 + Kind: consul + - Name: Service-5 + Kind: consul + --- + When I visit the services page for yaml --- dc: dc-1 diff --git a/ui-v2/tests/acceptance/dc/services/dc-switch.feature b/ui-v2/tests/acceptance/dc/services/dc-switch.feature index e51472ebd..5b2d7d293 100644 --- a/ui-v2/tests/acceptance/dc/services/dc-switch.feature +++ b/ui-v2/tests/acceptance/dc/services/dc-switch.feature @@ -6,7 +6,21 @@ Feature: dc / services / dc-switch : Switching Datacenters - dc-1 - dc-2 --- - And 6 service models + And 6 service models from yaml + --- + - Name: Service-0 + Kind: consul + - Name: Service-1 + Kind: consul + - Name: Service-2 + Kind: consul + - Name: Service-3 + Kind: consul + - Name: Service-4 + Kind: consul + - Name: Service-5 + Kind: consul + --- When I visit the services page for yaml --- dc: dc-1 diff --git a/ui-v2/tests/acceptance/dc/services/index.feature b/ui-v2/tests/acceptance/dc/services/index.feature index d9df27df9..59bd3d598 100644 --- a/ui-v2/tests/acceptance/dc/services/index.feature +++ b/ui-v2/tests/acceptance/dc/services/index.feature @@ -2,24 +2,24 @@ Feature: dc / services / index: List Services Scenario: Given 1 datacenter model with the value "dc-1" - And 6 service models from yaml + And 4 service models from yaml --- - Name: Service 1 + Kind: consul ExternalSources: - consul - Name: Service 2 + Kind: consul ExternalSources: - nomad - Name: Service 3 + Kind: consul ExternalSources: - terraform - Name: Service 4 + Kind: consul ExternalSources: - kubernetes - - Name: Service 5 - ExternalSources: [] - - Name: Service 6 - ExternalSources: ~ --- When I visit the services page for yaml --- @@ -27,14 +27,12 @@ Feature: dc / services / index: List Services --- Then the url should be /dc-1/services And the title should be "Services - Consul" - Then I see 6 service models + Then I see 4 service models And I see externalSource on the services like yaml --- - consul - nomad - terraform - kubernetes - - ~ - - ~ --- diff --git a/ui-v2/tests/acceptance/dc/services/list-blocking.feature b/ui-v2/tests/acceptance/dc/services/list-blocking.feature new file mode 100644 index 000000000..c44578212 --- /dev/null +++ b/ui-v2/tests/acceptance/dc/services/list-blocking.feature @@ -0,0 +1,26 @@ +@setupApplicationTest +Feature: dc / services / list blocking + Scenario: Viewing the listing pages for service + Given 1 datacenter model with the value "dc-1" + Given 3 service models from yaml + --- + - Name: Service-0 + Kind: consul + - Name: Service-1 + Kind: consul + - Name: Service-2 + Kind: consul + --- + And a network latency of 100 + When I visit the services page for yaml + --- + dc: dc-1 + --- + Then the url should be /dc-1/services + And pause until I see 3 service models + And an external edit results in 5 service models + And pause until I see 3 service models + And an external edit results in 1 service model + And pause until I see 1 service model + And an external edit results in 0 service models + And pause until I see 0 service models diff --git a/ui-v2/tests/acceptance/dc/services/list.feature b/ui-v2/tests/acceptance/dc/services/list.feature new file mode 100644 index 000000000..db7317083 --- /dev/null +++ b/ui-v2/tests/acceptance/dc/services/list.feature @@ -0,0 +1,20 @@ +@setupApplicationTest +Feature: dc / services / list + Scenario: Listing service + Given 1 datacenter model with the value "dc-1" + And 3 service models from yaml + --- + - Name: Service-0 + Kind: consul + - Name: Service-1 + Kind: consul + - Name: Service-2 + Kind: consul + --- + When I visit the services page for yaml + --- + dc: dc-1 + --- + Then the url should be /dc-1/services + + Then I see 3 service models \ No newline at end of file diff --git a/ui-v2/tests/acceptance/steps/dc/services/list-blocking-steps.js b/ui-v2/tests/acceptance/steps/dc/services/list-blocking-steps.js new file mode 100644 index 000000000..ba1093295 --- /dev/null +++ b/ui-v2/tests/acceptance/steps/dc/services/list-blocking-steps.js @@ -0,0 +1,10 @@ +import steps from '../../steps'; + +// step definitions that are shared between features should be moved to the +// tests/acceptance/steps/steps.js file + +export default function(assert) { + return steps(assert).then('I should find a file', function() { + assert.ok(true, this.step); + }); +} diff --git a/ui-v2/tests/acceptance/steps/dc/services/list-steps.js b/ui-v2/tests/acceptance/steps/dc/services/list-steps.js new file mode 100644 index 000000000..ba1093295 --- /dev/null +++ b/ui-v2/tests/acceptance/steps/dc/services/list-steps.js @@ -0,0 +1,10 @@ +import steps from '../../steps'; + +// step definitions that are shared between features should be moved to the +// tests/acceptance/steps/steps.js file + +export default function(assert) { + return steps(assert).then('I should find a file', function() { + assert.ok(true, this.step); + }); +} diff --git a/ui-v2/tests/pages.js b/ui-v2/tests/pages.js index faac01a3d..f42a76e85 100644 --- a/ui-v2/tests/pages.js +++ b/ui-v2/tests/pages.js @@ -69,7 +69,7 @@ export default { index: create(index(visitable, collection)), dcs: create(dcs(visitable, clickable, attribute, collection)), services: create( - services(visitable, clickable, attribute, collection, page, catalogFilter, radiogroup) + services(visitable, clickable, text, attribute, collection, page, catalogFilter, radiogroup) ), service: create(service(visitable, attribute, collection, text, catalogFilter, tabgroup)), instance: create(instance(visitable, attribute, collection, text, tabgroup)), diff --git a/ui-v2/tests/pages/dc/services/index.js b/ui-v2/tests/pages/dc/services/index.js index 7b43e3618..b3399296c 100644 --- a/ui-v2/tests/pages/dc/services/index.js +++ b/ui-v2/tests/pages/dc/services/index.js @@ -1,11 +1,12 @@ -export default function(visitable, clickable, attribute, collection, page, filter) { +export default function(visitable, clickable, text, attribute, collection, page, filter) { + const service = { + name: text('a span:nth-child(2)'), + service: clickable('a'), + externalSource: attribute('data-test-external-source', '[data-test-external-source]'), + }; return { visit: visitable('/:dc/services'), - services: collection('[data-test-service]', { - name: attribute('data-test-service'), - service: clickable('a'), - externalSource: attribute('data-test-external-source', 'a span'), - }), + services: collection('.consul-service-list > ul > li:not(:first-child)', service), dcs: collection('[data-test-datacenter-picker]', { name: clickable('a'), }), diff --git a/ui-v2/yarn.lock b/ui-v2/yarn.lock index 8efec6add..2a53d0973 100644 --- a/ui-v2/yarn.lock +++ b/ui-v2/yarn.lock @@ -1211,9 +1211,9 @@ js-yaml "^3.13.1" "@hashicorp/consul-api-double@^2.6.2": - version "2.12.0" - resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.12.0.tgz#725078f770bbd0ef75a5f2498968c5c8891f90a2" - integrity sha512-8OcgesUjWQ8AjaXzbz3tGJQn1kM0sN6pLidGM7isNPUyYmIjIEXQzaeUQYzsfv0N2Ko9ZuOXYUsaBl8IK1KGow== + version "2.14.0" + resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.14.0.tgz#ecef725fc22490011a671bc0a285a16013ca5e53" + integrity sha512-1rGMg/XSHR2ROr8a7OVEwOUy8UWuYdNUMijMxCuFHR201vDAGK9EDmkJCPF2PfYsDrcsiyb/0dxIL6Mba9p32Q== "@hashicorp/ember-cli-api-double@^3.0.2": version "3.0.2"