diff --git a/ui-v2/app/controllers/dc/nodes/show.js b/ui-v2/app/controllers/dc/nodes/show.js index 80c4c32870..b93c00f00d 100644 --- a/ui-v2/app/controllers/dc/nodes/show.js +++ b/ui-v2/app/controllers/dc/nodes/show.js @@ -15,7 +15,12 @@ export default Controller.extend(WithFiltering, { }, setProperties: function() { this._super(...arguments); - set(this, 'selectedTab', 'health-checks'); + // the default selected tab depends on whether you have any healthchecks or not + // so check the length here. + // This method is called immediately after `Route::setupController`, and done here rather than there + // as this is a variable used purely for view level things, if the view was different we might not + // need this variable + set(this, 'selectedTab', get(this.item, 'Checks.length') > 0 ? 'health-checks' : 'services'); }, filter: function(item, { s = '' }) { const term = s.toLowerCase(); diff --git a/ui-v2/app/controllers/dc/services/index.js b/ui-v2/app/controllers/dc/services/index.js index 373ca6f30d..a0cc0bd399 100644 --- a/ui-v2/app/controllers/dc/services/index.js +++ b/ui-v2/app/controllers/dc/services/index.js @@ -37,17 +37,17 @@ export default Controller.extend(WithHealthFiltering, { item.hasStatus(status) ); }, - totalWidth: computed('{maxPassing,maxWarning,maxCritical}', 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); }), - thWidth: computed('totalWidth', function() { - return widthDeclaration(get(this, 'totalWidth')); + totalWidth: computed('maxWidth', function() { + return widthDeclaration(get(this, 'maxWidth')); }), - remainingWidth: computed('totalWidth', function() { - return htmlSafe(`width: calc(50% - ${Math.round(get(this, 'totalWidth') / 2)}px)`); + remainingWidth: computed('maxWidth', function() { + return htmlSafe(`width: calc(50% - ${Math.round(get(this, 'maxWidth') / 2)}px)`); }), maxPassing: computed('items', function() { return max(get(this, 'items'), 'ChecksPassing'); diff --git a/ui-v2/app/helpers/css-var.js b/ui-v2/app/helpers/css-var.js new file mode 100644 index 0000000000..13665f8cf9 --- /dev/null +++ b/ui-v2/app/helpers/css-var.js @@ -0,0 +1,12 @@ +import { helper } from '@ember/component/helper'; +const cssVars = { + '--kubernetes-color-svg': `url('data:image/svg+xml;charset=UTF-8,')`, + '--terraform-color-svg': `url('data:image/svg+xml;charset=UTF-8,')`, + '--nomad-color-svg': `url('data:image/svg+xml;charset=UTF-8,')`, + '--consul-color-svg': `url('data:image/svg+xml;charset=UTF-8,')`, +}; +export function cssVar(params, hash) { + return typeof cssVars[params[0]] !== 'undefined' ? cssVars[params[0]] : params[1]; +} + +export default helper(cssVar); diff --git a/ui-v2/app/helpers/service/external-source.js b/ui-v2/app/helpers/service/external-source.js new file mode 100644 index 0000000000..32cc4f3dd0 --- /dev/null +++ b/ui-v2/app/helpers/service/external-source.js @@ -0,0 +1,16 @@ +import { helper } from '@ember/component/helper'; +import { get } from '@ember/object'; + +export function serviceExternalSource(params, hash) { + let source = get(params[0], 'ExternalSources.firstObject'); + if (!source) { + source = get(params[0], 'Meta.external-source'); + } + const prefix = typeof hash.prefix === 'undefined' ? '' : hash.prefix; + if (source) { + return `${prefix}${source}`; + } + return; +} + +export default helper(serviceExternalSource); diff --git a/ui-v2/app/models/service.js b/ui-v2/app/models/service.js index b3e4d540d2..c8e71ae05d 100644 --- a/ui-v2/app/models/service.js +++ b/ui-v2/app/models/service.js @@ -14,6 +14,8 @@ export default Model.extend({ }, }), Kind: attr('string'), + ExternalSources: attr(), + Meta: attr(), Address: attr('string'), Port: attr('number'), EnableTagOverride: attr('boolean'), diff --git a/ui-v2/app/styles/app.scss b/ui-v2/app/styles/app.scss index f7eea00ae9..b8c1b2d9bd 100644 --- a/ui-v2/app/styles/app.scss +++ b/ui-v2/app/styles/app.scss @@ -29,6 +29,7 @@ @import 'components/confirmation-dialog'; @import 'components/feedback-dialog'; @import 'components/notice'; +@import 'components/with-tooltip'; @import 'core/typography'; @import 'core/layout'; diff --git a/ui-v2/app/styles/base/icons/index.scss b/ui-v2/app/styles/base/icons/index.scss new file mode 100644 index 0000000000..58d7695495 --- /dev/null +++ b/ui-v2/app/styles/base/icons/index.scss @@ -0,0 +1,3 @@ +$consul-color-svg: url('data:image/svg+xml;charset=UTF-8,'); +$nomad-color-svg: url('data:image/svg+xml;charset=UTF-8,'); +$terraform-color-svg: url('data:image/svg+xml;charset=UTF-8,'); diff --git a/ui-v2/app/styles/base/index.scss b/ui-v2/app/styles/base/index.scss index e48bb67d47..1f66f3803b 100644 --- a/ui-v2/app/styles/base/index.scss +++ b/ui-v2/app/styles/base/index.scss @@ -1,3 +1,4 @@ @import './decoration/index'; @import './color/index'; @import './typography/index'; +@import './icons/index'; diff --git a/ui-v2/app/styles/components/healthchecked-resource/layout.scss b/ui-v2/app/styles/components/healthchecked-resource/layout.scss index 630905bdda..d22fffc043 100644 --- a/ui-v2/app/styles/components/healthchecked-resource/layout.scss +++ b/ui-v2/app/styles/components/healthchecked-resource/layout.scss @@ -12,10 +12,6 @@ white-space: nowrap; } %healthchecked-resource, -%healthchecked-resource li { - border-color: $ui-gray-200; -} -%healthchecked-resource, %healthchecked-resource header, %healthchecked-resource li { position: relative; @@ -76,3 +72,10 @@ .healthy .healthchecked-resource li:only-child strong { display: none; } +%healthchecked-resource ul:empty { + position: absolute; + top: 18px; + right: 20px; + width: 1em; + height: 1em; +} diff --git a/ui-v2/app/styles/components/healthchecked-resource/skin.scss b/ui-v2/app/styles/components/healthchecked-resource/skin.scss index e800763170..0938e5f26f 100644 --- a/ui-v2/app/styles/components/healthchecked-resource/skin.scss +++ b/ui-v2/app/styles/components/healthchecked-resource/skin.scss @@ -1,3 +1,14 @@ +%healthchecked-resource { + border: $decor-border-100; + box-shadow: 0 4px 8px 0 rgba($ui-black, 0.05); +} +%healthchecked-resource li { + border-top: $decor-border-100; +} +%healthchecked-resource, +%healthchecked-resource li { + border-color: $ui-gray-200; +} %healthchecked-resource li.passing { color: $ui-color-success; } @@ -7,17 +18,16 @@ %healthchecked-resource li.critical { color: $ui-color-failure; } -%healthchecked-resource { - border: $decor-border-100; - box-shadow: 0 4px 8px 0 rgba($ui-black, 0.05); -} %healthchecked-resource:hover, %healthchecked-resource:focus { box-shadow: 0 8px 10px 0 rgba($ui-black, 0.1); } -%healthchecked-resource li { - border-top: $decor-border-100; -} %healthchecked-resource { border-radius: $radius-small; } +%healthchecked-resource ul:empty { + @extend %with-no-healthchecks; +} +%healthchecked-resource ul:empty::before { + color: $ui-gray-400; +} diff --git a/ui-v2/app/styles/components/icons/index.scss b/ui-v2/app/styles/components/icons/index.scss index 56699a270b..8d0f693a1c 100644 --- a/ui-v2/app/styles/components/icons/index.scss +++ b/ui-v2/app/styles/components/icons/index.scss @@ -1,15 +1,35 @@ -%pseudo-icon { - width: 1em; - height: 1em; - position: absolute; - top: 50%; - margin-top: -0.6em; +/*TODO: The old pseudo-icon was to specific */ +/* make a temporary one with the -- prefix */ +/* to make it more reusable temporarily */ +%--pseudo-icon { display: block; content: ''; + visibility: visible; + position: absolute; + top: 50%; background-repeat: no-repeat; background-position: center center; +} +%pseudo-icon-bg-img { + @extend %--pseudo-icon; + background-size: contain; + background-color: transparent; +} +%pseudo-icon-css { + @extend %--pseudo-icon; + width: 1em; + height: 1em; + margin-top: -0.6em; background-color: currentColor; - visibility: visible; +} +%pseudo-icon { + @extend %pseudo-icon-css; +} +%with-external-source-icon { + background-repeat: no-repeat; + background-size: contain; + width: 18px; + height: 18px; } %with-dot { content: ''; @@ -135,6 +155,10 @@ @extend %pseudo-icon; background-image: url('data:image/svg+xml;charset=UTF-8,'); } +%with-minus { + @extend %pseudo-icon; + background-image: url('data:image/svg+xml;charset=UTF-8,'); +} %with-warning-icon-orange { @extend %pseudo-icon; background-image: url('data:image/svg+xml;charset=UTF-8,'); @@ -183,3 +207,7 @@ @extend %with-cross; border-radius: 20%; } +%with-no-healthchecks::before { + @extend %with-minus; + border-radius: 20%; +} diff --git a/ui-v2/app/styles/components/list-collection.scss b/ui-v2/app/styles/components/list-collection.scss index 595a4a1c30..0b90ee9d90 100644 --- a/ui-v2/app/styles/components/list-collection.scss +++ b/ui-v2/app/styles/components/list-collection.scss @@ -8,6 +8,7 @@ } .healthy > div { width: calc(100% + 23px); + min-height: 500px; } .unhealthy > div { margin-bottom: 20px; diff --git a/ui-v2/app/styles/components/product/app-view.scss b/ui-v2/app/styles/components/product/app-view.scss index f1ad635b20..f8bfb7a6fb 100644 --- a/ui-v2/app/styles/components/product/app-view.scss +++ b/ui-v2/app/styles/components/product/app-view.scss @@ -30,6 +30,9 @@ display: flex; align-items: flex-start; } +%app-view h1 span { + @extend %with-external-source-icon; +} %app-view { margin-top: 50px; } diff --git a/ui-v2/app/styles/components/table.scss b/ui-v2/app/styles/components/table.scss index f6131fdf33..b7e9dc3183 100644 --- a/ui-v2/app/styles/components/table.scss +++ b/ui-v2/app/styles/components/table.scss @@ -11,6 +11,12 @@ td dt.warning { td dt.critical { @extend %with-critical; } +td span.zero { + @extend %with-no-healthchecks; + display: block; + text-indent: 20px; + color: $ui-gray-400; +} table:not(.sessions) tr { cursor: pointer; } diff --git a/ui-v2/app/styles/components/tabular-collection.scss b/ui-v2/app/styles/components/tabular-collection.scss index 6620da9c6c..3999fe20a0 100644 --- a/ui-v2/app/styles/components/tabular-collection.scss +++ b/ui-v2/app/styles/components/tabular-collection.scss @@ -16,6 +16,17 @@ table tr > * { tr > * dl { float: left; } +/* TODO: putting this here is less than ideal */ +/* but this is another area where I am specifically */ +/* targetting table-like things. This is now a prime */ +/* area for a bit of refactoring/reorganizing */ +html.template-service.template-list td:first-child a span, +html.template-node.template-show #services td:first-child a span { + @extend %with-external-source-icon; + float: left; + margin-right: 10px; + margin-top: 2px; +} html.template-service.template-list main table tr { @extend %services-row; } @@ -34,7 +45,6 @@ html.template-node.template-show main table tr { html.template-node.template-show main table.sessions tr { @extend %node-sessions-row; } - @media #{$--horizontal-session-list} { %node-sessions-row > * { // (100% / 7) - (300px / 6) - (120px / 6) diff --git a/ui-v2/app/styles/components/with-tooltip.scss b/ui-v2/app/styles/components/with-tooltip.scss new file mode 100644 index 0000000000..9ae6b79596 --- /dev/null +++ b/ui-v2/app/styles/components/with-tooltip.scss @@ -0,0 +1,9 @@ +@import './with-tooltip/index'; +%app-view h1 span { + @extend %with-tooltip; +} +%app-view h1 span { + text-indent: -9000px; + font-size: 0; + top: -9px; +} diff --git a/ui-v2/app/styles/components/with-tooltip/index.scss b/ui-v2/app/styles/components/with-tooltip/index.scss new file mode 100644 index 0000000000..bc18252196 --- /dev/null +++ b/ui-v2/app/styles/components/with-tooltip/index.scss @@ -0,0 +1,2 @@ +@import './skin'; +@import './layout'; diff --git a/ui-v2/app/styles/components/with-tooltip/layout.scss b/ui-v2/app/styles/components/with-tooltip/layout.scss new file mode 100644 index 0000000000..4bc6593075 --- /dev/null +++ b/ui-v2/app/styles/components/with-tooltip/layout.scss @@ -0,0 +1,39 @@ +%with-tooltip { + position: relative; + display: inline-flex; + justify-content: center; + align-items: center; +} +%with-tooltip::before, +%with-tooltip::after { + position: absolute; +} +%with-tooltip::before { + padding: 10px; + bottom: calc(100% + 5px); + text-align: center; + white-space: nowrap; + content: attr(data-tooltip); + // incase you are using text-indent to hide the + // text of the element %with-tooltip + text-indent: 0; +} +%with-tooltip::after { + content: ''; + left: 50%; + margin-left: -5px; + top: -10px; + width: 10px; + height: 10px; + transform: rotate(45deg); +} +%with-tooltip::after, +%with-tooltip::before { + display: none; +} +%with-tooltip:hover::after, +%with-tooltip:hover::before, +%with-tooltip:focus::after, +%with-tooltip:focus::before { + display: block; +} diff --git a/ui-v2/app/styles/components/with-tooltip/skin.scss b/ui-v2/app/styles/components/with-tooltip/skin.scss new file mode 100644 index 0000000000..1617d21d98 --- /dev/null +++ b/ui-v2/app/styles/components/with-tooltip/skin.scss @@ -0,0 +1,9 @@ +%with-tooltip::before, +%with-tooltip::after { + color: $ui-white; + background-color: $ui-gray-800; +} +%with-tooltip::before { + border-radius: $decor-radius-200; + box-shadow: 0 3px 1px 0 rgba($ui-black, 0.12); +} diff --git a/ui-v2/app/styles/core/typography.scss b/ui-v2/app/styles/core/typography.scss index 259db1cf41..3095fa1b78 100644 --- a/ui-v2/app/styles/core/typography.scss +++ b/ui-v2/app/styles/core/typography.scss @@ -48,7 +48,8 @@ td a { th, %breadcrumbs a, %action-group a, -%tab-nav { +%tab-nav, +%with-tooltip::before { font-weight: $typo-weight-medium; } main label a[rel*='help'], @@ -86,6 +87,7 @@ td { font-size: $typo-size-600; } th, +%with-tooltip::before, %healthchecked-resource strong, %footer { font-size: $typo-size-700; diff --git a/ui-v2/app/templates/components/healthchecked-resource.hbs b/ui-v2/app/templates/components/healthchecked-resource.hbs index 4b3f9bcbf9..cbf3f961f9 100644 --- a/ui-v2/app/templates/components/healthchecked-resource.hbs +++ b/ui-v2/app/templates/components/healthchecked-resource.hbs @@ -1,12 +1,12 @@ -
+
{{address}} {{name}} {{service}}
-