ui: Redesign - Service Detail Page (#7655)

* Create ConsulServiceInstanceList with styling and test
* Implement ConsulServiceInstanceList to Service Detail page
* Implement ConsulExternalSource to Services Show page header
* Update services/show page object

* Update the styling of CompositeRow

* Refactor ConsulServiceList component and styling

* Update ConsulExternalSource to say 'Registered via...'

* Upgrade consul-api-double to patch 2.14.1

* Fix up tests to not use Kind in service models

* Update ListCollection with clickFirstAnchor action

* Add $typo-size-450 to typography base variables
This commit is contained in:
Kenia 2020-04-21 10:21:52 -04:00 committed by John Cowen
parent 455dfe0a1b
commit 958991db94
43 changed files with 403 additions and 291 deletions

View File

@ -1,17 +1,19 @@
{{#let (if _externalSource _externalSource (service/external-source item)) as |externalSource|}}
{{#if externalSource}}
{{#if (has-block)}}
{{yield
(component 'consul-external-source' item=item _externalSource=externalSource)
}}
{{else}}
<span data-test-external-source={{externalSource}} class="consul-external-source source-{{externalSource}}">
{{#if (eq externalSource 'aws')}}
<span>Synced from {{uppercase externalSource}}</span>
{{else}}
<span>Synced from {{capitalize externalSource}}</span>
{{/if}}
</span>
{{#if item}}
{{#let (if _externalSource _externalSource (service/external-source item)) as |externalSource|}}
{{#if externalSource}}
{{#if (has-block)}}
{{yield
(component 'consul-external-source' item=item _externalSource=externalSource)
}}
{{else}}
<span data-test-external-source={{externalSource}} class="consul-external-source source-{{externalSource}}">
{{#if (eq externalSource 'aws')}}
<span>Registered via {{uppercase externalSource}}</span>
{{else}}
<span>Registered via {{capitalize externalSource}}</span>
{{/if}}
</span>
{{/if}}
{{/if}}
{{/if}}
{{/let}}
{{/let}}
{{/if}}

View File

@ -0,0 +1,47 @@
{{yield}}
{{#if (gt items.length 0)}}
<ListCollection @cellHeight={{73}} @items={{items}} class="consul-service-instance-list" as |item index|>
<a href={{href-to routeName item.Service.Service item.Node.Node (or item.Service.ID item.Service.Service)}}>
{{item.Service.ID}}
</a>
<ul>
<ConsulExternalSource @item={{item.Service}} as |ExternalSource|>
<li>
<ExternalSource />
</li>
</ConsulExternalSource>
{{#with (reject-by 'ServiceID' '' item.Checks) as |checks|}}
<li class={{service/instance-checks checks}}>
{{checks.length}} service checks
</li>
{{/with}}
{{#with (filter-by 'ServiceID' '' item.Checks) as |checks|}}
<li class={{service/instance-checks checks}}>
{{checks.length}} node checks
</li>
{{/with}}
{{#if (get proxies item.Service.ID)}}
<li class="proxy">
connected with proxy
</li>
{{/if}}
{{#if (gt item.Node.Node.length 0)}}
<li class="node">
<a href={{href-to 'dc.nodes.show' item.Node.Node}}>{{item.Node.Node}}</a>
</li>
{{/if}}
<li class="address" data-test-address>
{{#if (not-eq item.Service.Address '')}}
{{item.Service.Address}}:{{item.Service.Port}}
{{else}}
{{item.Node.Address}}:{{item.Service.Port}}
{{/if}}
</li>
{{#if (gt item.Service.Tags.length 0)}}
<li>
<TagList @items={{item.Service.Tags}}/>
</li>
{{/if}}
</ul>
</ListCollection>
{{/if}}

View File

@ -0,0 +1,5 @@
import Component from '@ember/component';
export default Component.extend({
tagName: '',
});

View File

@ -1,14 +1,30 @@
{{yield}}
{{#if (gt items.length 0)}}
<ListCollection @cellHeight={{73}} @items={{items}} class="consul-service-list" as |item index|>
<a href={{href-to routeName item.Name}}>
<span class={{service/health-checks item}}></span>
<span>
{{item.Name}}
</span>
<YieldSlot @name="metadata" @params={{block-params item}}>
{{yield}}
</YieldSlot>
<a href={{href-to routeName item.Name}} class={{service/health-checks item}}>
{{item.Name}}
</a>
<ul>
<ConsulExternalSource @item={{item}} as |ExternalSource|>
<li>
<ExternalSource />
</li>
</ConsulExternalSource>
{{#if (not-eq item.InstanceCount 0)}}
<li>
{{format-number item.InstanceCount}} {{pluralize item.InstanceCount 'Instance' without-count=true}}
</li>
{{/if}}
{{#if (get proxies item.Name)}}
<li class="proxy">
connected with proxy
</li>
{{/if}}
{{#if (gt items.Tags.length 0)}}
<li>
<TagList @items={{item.Tags}}/>
</li>
{{/if}}
</ul>
</ListCollection>
{{/if}}

View File

@ -1,6 +1,5 @@
import Component from '@ember/component';
import Slotted from 'block-slots';
export default Component.extend(Slotted, {
export default Component.extend({
tagName: '',
});

View File

@ -1,6 +1,6 @@
<EmberNativeScrollable @tagName="ul" @content-size={{_contentSize}} @scroll-left={{_scrollLeft}} @scroll-top={{_scrollTop}} @scrollChange={{action "scrollChange"}} @clientSizeChange={{action "clientSizeChange"}}>
<li></li>
{{~#each _cells as |cell|~}}
<li style={{{cell.style}}}>{{yield cell.item cell.index }}</li>
<li onclick={{action 'click'}} style={{{cell.style}}}>{{yield cell.item cell.index }}</li>
{{~/each~}}
</EmberNativeScrollable>

View File

@ -45,4 +45,9 @@ export default Component.extend(WithResizing, {
this.updateScrollPosition();
}
},
actions: {
click: function(e) {
return this.dom.clickFirstAnchor(e, 'li');
},
},
});

View File

@ -21,19 +21,19 @@ export default Controller.extend(WithEventSource, WithSearching, {
}),
services: computed('items.[]', function() {
return this.items.filter(function(item) {
return item.Kind === 'consul';
return typeof item.Kind === 'undefined';
});
}),
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;
});
this.items
.filter(function(item) {
return item.Kind === 'connect-proxy';
})
.forEach(item => {
proxies[item.Name.replace('-proxy', '')] = true;
});
return proxies;
}),
});

View File

@ -3,6 +3,7 @@ import { get, computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import WithSearching from 'consul-ui/mixins/with-searching';
export default Controller.extend(WithSearching, {
dom: service('dom'),
items: alias('item.Nodes'),
@ -23,4 +24,12 @@ export default Controller.extend(WithSearching, {
.add(this.items)
.search(get(this, this.searchParams.serviceInstance));
}),
keyedProxies: computed('proxies.[]', function() {
const proxies = {};
this.proxies.forEach(item => {
proxies[item.ServiceProxy.DestinationServiceID] = true;
});
return proxies;
}),
});

View File

@ -0,0 +1,36 @@
import { helper } from '@ember/component/helper';
export function healthChecks([items], hash) {
let ChecksCritical = 0;
let ChecksWarning = 0;
let ChecksPassing = 0;
items.forEach(item => {
switch (item.Status) {
case 'critical':
ChecksCritical += 1;
break;
case 'warning':
ChecksWarning += 1;
break;
case 'passing':
ChecksPassing += 1;
break;
default:
break;
}
});
switch (true) {
case ChecksCritical !== 0:
return 'critical';
case ChecksWarning !== 0:
return 'warning';
case ChecksPassing !== 0:
return 'passing';
default:
return 'empty';
}
}
export default helper(healthChecks);

View File

@ -7,6 +7,7 @@ export default Route.extend({
repo: service('repository/service'),
intentionRepo: service('repository/intention'),
chainRepo: service('repository/discovery-chain'),
proxyRepo: service('repository/proxy'),
settings: service('settings'),
model: function(params, transition = {}) {
const dc = this.modelFor('dc').dc.Name;
@ -16,12 +17,11 @@ export default Route.extend({
intentions: this.intentionRepo.findByService(params.name, dc, nspace),
urls: this.settings.findBySlug('urls'),
dc: dc,
nspace: nspace,
}).then(model => {
return hash({
chain: ['connect-proxy', 'mesh-gateway'].includes(get(model, 'item.Service.Kind'))
? null
: this.chainRepo.findBySlug(params.name, dc, nspace).catch(function(e) {
return ['connect-proxy', 'mesh-gateway'].includes(get(model, 'item.Service.Kind'))
? model
: hash({
chain: this.chainRepo.findBySlug(params.name, dc, nspace).catch(function(e) {
const code = get(e, 'errors.firstObject.status');
// Currently we are specifically catching a 500, but we return null
// by default, so null for all errors.
@ -38,8 +38,9 @@ export default Route.extend({
return null;
}
}),
...model,
});
proxies: this.proxyRepo.findAllBySlug(params.name, dc, nspace),
...model,
});
});
},
setupController: function(controller, model) {

View File

@ -6,6 +6,7 @@ $typo-size-100: 3.5rem;
$typo-size-200: 1.8rem;
$typo-size-300: 1.3rem;
$typo-size-400: 1.2rem;
$typo-size-450: 1.125rem;
$typo-size-500: 1rem;
$typo-size-600: 0.875rem;
$typo-size-700: 0.8125rem;

View File

@ -115,4 +115,11 @@ main {
#toolbar-toggle:checked + * {
display: block;
}
html.template-service.template-show #toolbar-toggle + * {
display: block;
padding: 4px;
}
html.template-service.template-show .actions {
display: none;
}
}

View File

@ -20,6 +20,16 @@
%app-view-header dt {
font-weight: bold;
}
%app-view-header .title-bar {
display: flex;
align-items: center;
}
%app-view-header .title-bar > h1 {
border: 0;
}
%app-view-header .title-bar > span {
margin-left: 8px;
}
/* units */
%app-view {
margin-top: 50px;

View File

@ -1,13 +1,13 @@
@import './layout';
@import './skin';
%composite-row a:hover,
%composite-row a:focus,
%composite-row a:active {
%composite-row:hover,
%composite-row:focus,
%composite-row:active {
@extend %composite-row-intent;
}
%composite-row > a > span {
%composite-row > a {
@extend %composite-row-header;
}
%composite-row > a > ul {
%composite-row > ul {
@extend %composite-row-detail;
}

View File

@ -1,4 +1,5 @@
%composite-row a {
%composite-row {
cursor: pointer;
display: block;
box-sizing: border-box;
padding: 12px;
@ -19,3 +20,6 @@
%composite-row-detail > li:not(:first-child) {
margin-left: 12px;
}
%composite-row-detail .node::before {
margin-top: 2px;
}

View File

@ -1,9 +1,7 @@
%composite-row {
list-style-type: none;
}
%composite-row a {
border-top-color: $gray-200;
border-bottom-color: $gray-200;
border-bottom-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
}
@ -17,3 +15,41 @@
%composite-row-detail {
color: $gray-500;
}
%composite-row:last-child {
border-bottom-color: $gray-200;
}
// Health Checks
%composite-row .passing::before {
@extend %with-check-circle-fill-color-mask, %as-pseudo;
background-color: $green-500;
}
%composite-row .warning::before {
@extend %with-alert-triangle-color-mask, %as-pseudo;
background-color: $orange-500;
}
%composite-row .critical::before {
@extend %with-cancel-square-fill-color-mask, %as-pseudo;
background-color: $red-500;
}
// Metadata
%composite-row .node a {
color: $gray-500;
}
%composite-row .node a:hover {
color: $color-action;
text-decoration: underline;
}
%composite-row .node::before {
@extend %with-git-commit-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row .address::before {
@extend %with-public-default-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row .proxy::before {
@extend %with-swap-horizontal-mask, %as-pseudo;
background-color: $gray-500;
}

View File

@ -1,17 +1,19 @@
.consul-external-source {
background-color: $gray-100;
padding: 0 8px;
height: 16px;
line-height: 12px;
margin-top: 3px;
border-radius: $decor-radius-100;
height: 18px;
line-height: 0.7rem;
}
.consul-external-source > span {
font-size: 14px;
font-weight: normal;
position: relative;
top: -1px;
color: $gray-500;
}
.consul-external-source::before {
font-size: 0.7em;
width: 14px;
height: 14px;
margin-right: 2px;
position: relative;
top: 2px;

View File

@ -0,0 +1,9 @@
.consul-service-instance-list > ul {
@extend %consul-service-instance-list;
}
%consul-service-instance-list > li:not(:first-child) {
@extend %consul-service-instance-row;
}
%consul-service-instance-row {
@extend %composite-row;
}

View File

@ -1,5 +1,3 @@
@import './consul-service-list/index';
.consul-service-list > ul {
@extend %consul-service-list;
}
@ -9,3 +7,6 @@
%consul-service-row {
@extend %composite-row;
}
%consul-service-row > ul {
margin-left: 26px;
}

View File

@ -1,2 +0,0 @@
@import './layout';
@import './skin';

View File

@ -1,16 +0,0 @@
%consul-service-row > a > span:first-child {
margin-right: 4px;
width: 16px;
height: 16px;
}
%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;
}

View File

@ -1,30 +0,0 @@
%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;
}
// Health Checks
%consul-service-row .empty {
@extend %with-minus-square-fill-mask;
background-color: #7c8797;
}
%consul-service-row .passing {
@extend %with-check-circle-fill-mask;
background-color: $green-500;
}
%consul-service-row .warning {
@extend %with-alert-triangle-mask;
background-color: $orange-500;
}
%consul-service-row .critical {
@extend %with-cancel-square-fill-mask;
background-color: $red-500;
}
%consul-service-row .proxy::before {
@extend %with-git-commit-mask, %as-pseudo;
background-color: $gray-500;
}

View File

@ -1,7 +1,8 @@
%filter-bar {
padding: 14px;
padding: 4px;
display: block;
margin-top: 0 !important;
margin-bottom: 8px !important;
}
@media #{$--horizontal-filters} {
%filter-bar {
@ -19,6 +20,6 @@
}
@media #{$--lt-horizontal-filters} {
%filter-bar > *:first-child {
margin-bottom: 12px;
margin: 2px 0;
}
}

View File

@ -34,6 +34,7 @@
@import './list-collection';
@import './grid-collection';
@import './consul-service-list';
@import './consul-service-instance-list';
/**/

View File

@ -109,6 +109,13 @@ pre code,
}
/**/
/* composite row */
%composite-row-header {
font-size: $typo-size-450;
font-weight: $typo-weight-medium;
}
/**/
/* TODO: We have nothing else with a 500 */
/* either make this the biggest %p or don't use it */
%app-view h1 em {

View File

@ -14,21 +14,7 @@
<BlockSlot @name="content">
<ChangeableSet @dispatcher={{searchable}}>
<BlockSlot @name="set" as |filtered|>
<ConsulServiceList @routeName="dc.services.show" @items={{filtered}}>
<BlockSlot @name="metadata" as |item|>
<ul>
<ConsulExternalSource @item={{item}} as |ExternalSource|>
<li>
<ExternalSource />
</li>
</ConsulExternalSource>
<li>{{format-number item.InstanceCount}} {{pluralize item.InstanceCount 'Instance' without-count=true}}</li>
{{#if (get withProxies item.Name)}}<li class="proxy">connected with proxy</li>{{/if}}
<li><TagList @items={{item.Tags}}/></li>
</ul>
</BlockSlot>
</ConsulServiceList>
</BlockSlot>
<ConsulServiceList @routeName="dc.services.show" @items={{filtered}} @proxies={{proxies}}/> </BlockSlot>
<BlockSlot @name="empty">
<p>
There are no services.

View File

@ -10,29 +10,21 @@
</ol>
</BlockSlot>
<BlockSlot @name="header">
<h1>
{{item.Service.Service}}
{{#let (service/external-source item.Service) as |externalSource| }}
{{#if externalSource }}
<span data-test-external-source={{externalSource}} style={{concat 'background-image: var(--' externalSource '-icon)'}} data-tooltip="Registered via {{externalSource}}">Registered via {{externalSource}}</span>
{{/if}}
{{/let}}
{{#if (eq item.Service.Kind 'connect-proxy')}}
<span class="kind-proxy">Proxy</span>
{{else if (eq item.Service.Kind 'mesh-gateway')}}
<span class="kind-proxy">Mesh Gateway</span>
{{/if}}
</h1>
<label for="toolbar-toggle"></label>
<TabNav @items={{
compact
(array
(hash label="Instances" href=(href-to "dc.services.show.instances") selected=(is-href "dc.services.show.instances"))
(hash label="Intentions" href=(href-to "dc.services.show.intentions") selected=(is-href "dc.services.show.intentions"))
<div class="title-bar">
<h1>
{{item.Service.Service}}
</h1>
<ConsulExternalSource @item={{item.Service}} />
</div>
<TabNav @items={{
compact
(array
(hash label="Instances" href=(href-to "dc.services.show.instances") selected=(is-href "dc.services.show.instances"))
(hash label="Intentions" href=(href-to "dc.services.show.intentions") selected=(is-href "dc.services.show.intentions"))
(if (not-eq chain) (hash label="Routing" href=(href-to "dc.services.show.routing") selected=(is-href "dc.services.show.routing")) '')
(hash label="Tags" href=(href-to "dc.services.show.tags") selected=(is-href "dc.services.show.tags"))
)
}}/>
(hash label="Tags" href=(href-to "dc.services.show.tags") selected=(is-href "dc.services.show.tags"))
)
}}/>
</BlockSlot>
<BlockSlot @name="actions">
{{#if urls.service}}

View File

@ -8,48 +8,7 @@
{{/if}}
<ChangeableSet @dispatcher={{searchable}}>
<BlockSlot @name="set" as |filtered|>
<TabularCollection
data-test-instances
@items={{filtered}} as |item index|
>
<BlockSlot @name="header">
<th>ID</th>
<th>Node</th>
<th>Address</th>
<th>Node Checks</th>
<th>Service Checks</th>
</BlockSlot>
<BlockSlot @name="row">
<td data-test-id={{item.Service.ID}}>
<a href={{href-to 'dc.services.instance' item.Service.Service item.Node.Node (or item.Service.ID item.Service.Service)}}>
{{#let (service/external-source item.Service) as |externalSource| }}
{{#if externalSource }}
<span data-test-external-source={{externalSource}} style={{concat 'background-image: var(--' externalSource '-icon)'}}></span>
{{else}}
<span></span>
{{/if}}
{{/let}}
{{or item.Service.ID item.Service.Service}}
</a>
</td>
<td data-test-node>
<a href={{href-to 'dc.nodes.show' item.Node.Node}}>{{item.Node.Node}}</a>
</td>
<td data-test-address>
{{item.Service.Address}}:{{item.Service.Port}}
</td>
<td>
{{#with (reject-by 'ServiceID' '' item.Checks) as |checks|}}
<HealthcheckInfo @passing={{filter-by "Status" "passing" checks}} @warning={{filter-by "Status" "warning" checks}} @critical={{filter-by "Status" "critical" checks}} />
{{/with}}
</td>
<td>
{{#with (filter-by 'ServiceID' '' item.Checks) as |checks|}}
<HealthcheckInfo @passing={{filter-by "Status" "passing" checks}} @warning={{filter-by "Status" "warning" checks}} @critical={{filter-by "Status" "critical" checks}} />
{{/with}}
</td>
</BlockSlot>
</TabularCollection>
<ConsulServiceInstanceList @routeName="dc.services.instance" @items={{filtered}} @proxies={{keyedProxies}}/>
</BlockSlot>
<BlockSlot @name="empty">
<p>

View File

@ -14,7 +14,11 @@ const clickEvent = function($el) {
export default function(closest, click = clickEvent) {
// TODO: Decide whether we should use `e` for ease
// or `target`/`el`
return function(e) {
// TODO: currently, using a string stopElement to tell the func
// where to stop looking and currenlty default is 'tr' because
// it's backwards compatible.
// Long-term this func shouldn't default to 'tr'
return function(e, stopElement = 'tr') {
// click on row functionality
// so if you click the actual row but not a link
// find the first link and fire that instead
@ -26,9 +30,7 @@ export default function(closest, click = clickEvent) {
case 'button':
return;
}
// TODO: why should this be restricted to a tr
// closest should probably be relaced with a finder function
const $a = closest('tr', e.target).querySelector('a');
const $a = closest(stopElement, e.target).querySelector('a');
if ($a) {
click($a);
}

View File

@ -127,26 +127,30 @@ Feature: components / catalog-filter
-------------------------------------------------
Scenario: Freetext filtering the service listing
Given 1 datacenter model with the value "dc-1"
And 3 service models from yaml
And 6 service models from yaml
---
- Name: Service-0
Kind: consul
Tags: ['one', 'two', 'three']
ChecksPassing: 0
ChecksWarning: 0
ChecksCritical: 1
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
Tags: ['two', 'three']
ChecksPassing: 0
ChecksWarning: 1
ChecksCritical: 0
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
Tags: ['three']
ChecksPassing: 1
ChecksWarning: 0
ChecksCritical: 0
- Name: Service-2-proxy
Kind: 'connect-proxy'
---
When I visit the services page for yaml
---

View File

@ -6,14 +6,17 @@ Feature: dc / error: Recovering from a dc 500 error
- dc-1
- dc-500
---
And 3 service models from yaml
And 6 service models from yaml
---
- Name: Service-0
Kind: consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
- Name: Service-2-proxy
Kind: 'connect-proxy'
---
And the url "/v1/internal/ui/services" responds with a 500 status
When I visit the services page for yaml

View File

@ -32,7 +32,7 @@ Feature: dc / list-blocking
When I visit the [Page] page for yaml
---
dc: dc-1
service: service-0-proxy
service: service
---
Then the url should be /dc-1/[Url]
And pause until I see 3 [Model] models
@ -45,5 +45,5 @@ Feature: dc / list-blocking
Where:
-----------------------------------------------------------------
| Page | Model | Url |
| service | instance | services/service-0-proxy/instances |
| service | instance | services/service/instances |
-----------------------------------------------------------------

View File

@ -13,20 +13,26 @@ Feature: dc / nspaces / manage : Managing Namespaces
---
- dc-1
---
And 6 service models from yaml
And 12 service models from yaml
---
- Name: Service-0
Kind: consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
- Name: Service-2-proxy
Kind: 'connect-proxy'
- Name: Service-3
Kind: consul
- Name: Service-3-proxy
Kind: 'connect-proxy'
- Name: Service-4
Kind: consul
- Name: Service-4-proxy
Kind: 'connect-proxy'
- Name: Service-5
Kind: consul
- Name: Service-5-proxy
Kind: 'connect-proxy'
---
When I visit the services page for yaml

View File

@ -6,21 +6,28 @@ Feature: dc / services / dc-switch : Switching Datacenters
- dc-1
- dc-2
---
And 6 service models from yaml
And 12 service models from yaml
---
- Name: Service-0
Kind: consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
- Name: Service-2-proxy
Kind: 'connect-proxy'
- Name: Service-3
Kind: consul
- Name: Service-3-proxy
Kind: 'connect-proxy'
- Name: Service-4
Kind: consul
- Name: Service-4-proxy
Kind: 'connect-proxy'
- Name: Service-5
Kind: consul
- Name: Service-5-proxy
Kind: 'connect-proxy'
---
When I visit the services page for yaml
---
dc: dc-1

View File

@ -2,36 +2,42 @@
Feature: dc / services / index: List Services
Scenario:
Given 1 datacenter model with the value "dc-1"
And 4 service models from yaml
And 10 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
Kind: consul
ExternalSources:
- aws
- Name: Service-0
ExternalSources:
- consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
ExternalSources:
- nomad
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
ExternalSources:
- terraform
- Name: Service-2-proxy
Kind: 'connect-proxy'
- Name: Service-3
ExternalSources:
- kubernetes
- Name: Service-3-proxy
Kind: 'connect-proxy'
- Name: Service-4
ExternalSources:
- aws
- Name: Service-4-proxy
Kind: 'connect-proxy'
---
When I visit the services page for yaml
---
dc: dc-1
---
Then the url should be /dc-1/services
And the title should be "Services - Consul"
Then I see 4 service models
Then I see 5 service models
And I see externalSource on the services like yaml
---
- consul

View File

@ -2,14 +2,17 @@
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
And 6 service models from yaml
---
- Name: Service-0
Kind: consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
- Name: Service-2-proxy
Kind: 'connect-proxy'
---
And a network latency of 100
When I visit the services page for yaml

View File

@ -2,14 +2,17 @@
Feature: dc / services / list
Scenario: Listing service
Given 1 datacenter model with the value "dc-1"
And 3 service models from yaml
And 6 service models from yaml
---
- Name: Service-0
Kind: consul
- Name: Service-0-proxy
Kind: 'connect-proxy'
- Name: Service-1
Kind: consul
- Name: Service-1-proxy
Kind: 'connect-proxy'
- Name: Service-2
Kind: consul
- Name: Service-2-proxy
Kind: 'connect-proxy'
---
When I visit the services page for yaml
---

View File

@ -6,7 +6,6 @@ Feature: dc / services / Show Routing for Service
And 1 service model from yaml
---
- Service:
Kind: consul
Name: service-0
ID: service-0-with-id
---
@ -17,31 +16,12 @@ Feature: dc / services / Show Routing for Service
---
And the title should be "service-0 - Consul"
And I see routing on the tabs
Scenario: Given a service proxy, the Routing tab should not display
Given 1 datacenter model with the value "dc1"
And 1 node models
And 1 service model from yaml
---
- Service:
Kind: connect-proxy
Name: service-0-proxy
ID: service-0-proxy-with-id
---
When I visit the service page for yaml
---
dc: dc1
service: service-0-proxy
---
And the title should be "service-0-proxy - Consul"
And I don't see routing on the tabs
Scenario: Given connect is disabled, the Routing tab should not display or error
Given 1 datacenter model with the value "dc1"
And 1 node models
And 1 service model from yaml
---
- Service:
Kind: consul
Name: service-0
ID: service-0-with-id
---

View File

@ -0,0 +1,26 @@
import { module, skip } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | consul-service-instance-list', function(hooks) {
setupRenderingTest(hooks);
skip('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<ConsulServiceInstanceList />`);
assert.equal(this.element.textContent.trim(), '');
// Template block usage:
await render(hbs`
<ConsulServiceInstanceList>
template block text
</ConsulServiceInstanceList>
`);
assert.equal(this.element.textContent.trim(), 'template block text');
});
});

View File

@ -78,16 +78,7 @@ export default {
services(visitable, clickable, text, attribute, collection, page, catalogFilter, radiogroup)
),
service: create(
service(
visitable,
clickable,
attribute,
collection,
text,
consulIntentionList,
catalogFilter,
tabgroup
)
service(visitable, attribute, collection, text, consulIntentionList, catalogFilter, tabgroup)
),
instance: create(instance(visitable, attribute, collection, text, tabgroup)),
nodes: create(nodes(visitable, clickable, attribute, collection, catalogFilter)),

View File

@ -1,16 +1,9 @@
export default function(
visitable,
clickable,
attribute,
collection,
text,
intentions,
filter,
tabs
) {
export default function(visitable, attribute, collection, text, intentions, filter, tabs) {
return {
visit: visitable('/:dc/services/:service'),
externalSource: attribute('data-test-external-source', 'h1 span'),
externalSource: attribute('data-test-external-source', '[data-test-external-source]', {
scope: '.title-bar',
}),
dashboardAnchor: {
href: attribute('href', '[data-test-dashboard-anchor]'),
},
@ -18,7 +11,7 @@ export default function(
filter: filter,
// TODO: These need to somehow move to subpages
instances: collection('#instances [data-test-tabular-row]', {
instances: collection('.consul-service-instance-list > ul > li:not(:first-child)', {
address: text('[data-test-address]'),
}),
intentions: intentions(),

View File

@ -1211,9 +1211,9 @@
js-yaml "^3.13.1"
"@hashicorp/consul-api-double@^2.6.2":
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==
version "2.14.1"
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.14.1.tgz#c4beefa853368319324a6092fc4eb4371f9f8ffc"
integrity sha512-ZJtjkAuFHqcLTRjVaqx4NYnkZ17v5/DjaDhjH/kRVBx0gXcyKUEeMe34g69PfqgRo6ZYMVYMbSDq0JHTGcIShQ==
"@hashicorp/ember-cli-api-double@^3.0.2":
version "3.0.2"