ui: Gateway Addresses (#6075)
- Removes 'type' icons (basically the proxy icon, not the text itself) - Add support for Mesh Gateways plus their addresses This adds a 'Mesh Gateway' type label to service and service instance pages, plus a new 'Addresses' tab if the service is a Mesh Gateway showing a table of addresses for the service - plus tests
This commit is contained in:
parent
35a839952b
commit
b143a3bb66
|
@ -57,7 +57,7 @@ export default Controller.extend(WithEventSource, WithSearching, {
|
||||||
// take that off 50% (100% / number of fluid columns)
|
// take that off 50% (100% / number of fluid columns)
|
||||||
// also we added a Type column which we've currently fixed to 100px
|
// 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
|
// 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)`);
|
return htmlSafe(`width: calc(50% - ${Math.round(get(this, 'maxWidth') / 2)}px)`);
|
||||||
}),
|
}),
|
||||||
maxPassing: computed('items.[]', function() {
|
maxPassing: computed('items.[]', function() {
|
||||||
return max(get(this, 'items'), 'ChecksPassing');
|
return max(get(this, 'items'), 'ChecksPassing');
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { helper } from '@ember/component/helper';
|
||||||
|
|
||||||
|
export function objectEntries([obj = {}] /*, hash*/) {
|
||||||
|
return Object.entries(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default helper(objectEntries);
|
|
@ -17,6 +17,7 @@ export default Model.extend({
|
||||||
ExternalSources: attr(),
|
ExternalSources: attr(),
|
||||||
Meta: attr(),
|
Meta: attr(),
|
||||||
Address: attr('string'),
|
Address: attr('string'),
|
||||||
|
TaggedAddresses: attr(),
|
||||||
Port: attr('number'),
|
Port: attr('number'),
|
||||||
EnableTagOverride: attr('boolean'),
|
EnableTagOverride: attr('boolean'),
|
||||||
CreateIndex: attr('number'),
|
CreateIndex: attr('number'),
|
||||||
|
|
|
@ -18,7 +18,8 @@ export default Route.extend({
|
||||||
// connect-proxy or vice versa so leave as is for now
|
// connect-proxy or vice versa so leave as is for now
|
||||||
return hash({
|
return hash({
|
||||||
proxy:
|
proxy:
|
||||||
get(model.item, 'Kind') === 'connect-proxy'
|
// proxies and mesh-gateways can't have proxies themselves so don't even look
|
||||||
|
['connect-proxy', 'mesh-gateway'].includes(get(model.item, 'Kind'))
|
||||||
? null
|
? null
|
||||||
: proxyRepo.findInstanceBySlug(params.id, params.node, params.name, dc),
|
: proxyRepo.findInstanceBySlug(params.id, params.node, params.name, dc),
|
||||||
...model,
|
...model,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@import './app-view/index';
|
@import './app-view/index';
|
||||||
@import './filter-bar/index';
|
@import './filter-bar/index';
|
||||||
@import './buttons/index';
|
@import './buttons/index';
|
||||||
@import './type-icon/index';
|
|
||||||
main {
|
main {
|
||||||
@extend %app-view;
|
@extend %app-view;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +23,11 @@ main {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
%app-view h1 span.kind-proxy {
|
%app-view h1 span.kind-proxy {
|
||||||
@extend %type-icon, %with-proxy;
|
@extend %frame-gray-900;
|
||||||
|
@extend %pill;
|
||||||
|
}
|
||||||
|
%app-view h1 span.kind-proxy::before {
|
||||||
|
width: 0.3em !important;
|
||||||
}
|
}
|
||||||
%app-view h1 em {
|
%app-view h1 em {
|
||||||
color: $gray-600;
|
color: $gray-600;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
@import './icons/index';
|
@import './icons/index';
|
||||||
@import './table/index';
|
@import './table/index';
|
||||||
@import './type-icon/index';
|
|
||||||
|
|
||||||
html.template-service.template-list td:first-child a span,
|
html.template-service.template-list td:first-child a span,
|
||||||
html.template-node.template-show #services td:first-child a span,
|
html.template-node.template-show #services td:first-child a span,
|
||||||
|
@ -20,11 +19,6 @@ html.template-service.template-list main th:first-child {
|
||||||
td.folder {
|
td.folder {
|
||||||
@extend %with-folder;
|
@extend %with-folder;
|
||||||
}
|
}
|
||||||
td .kind-proxy {
|
|
||||||
@extend %type-icon, %with-proxy;
|
|
||||||
text-indent: -9000px !important;
|
|
||||||
width: 24px;
|
|
||||||
}
|
|
||||||
table:not(.sessions) tbody tr {
|
table:not(.sessions) tbody tr {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
@import './skin';
|
|
||||||
@import './layout';
|
|
|
@ -1,5 +0,0 @@
|
||||||
%type-icon {
|
|
||||||
display: inline-block;
|
|
||||||
text-indent: 20px;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
%type-icon {
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
background: $gray-100;
|
|
||||||
color: $gray-400;
|
|
||||||
}
|
|
|
@ -65,8 +65,7 @@ td strong,
|
||||||
%breadcrumbs li > *,
|
%breadcrumbs li > *,
|
||||||
%action-group-action,
|
%action-group-action,
|
||||||
%tab-nav,
|
%tab-nav,
|
||||||
%tooltip-bubble,
|
%tooltip-bubble {
|
||||||
%type-icon {
|
|
||||||
font-weight: $typo-weight-medium;
|
font-weight: $typo-weight-medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +112,7 @@ caption,
|
||||||
%tooltip-bubble,
|
%tooltip-bubble,
|
||||||
%healthchecked-resource strong,
|
%healthchecked-resource strong,
|
||||||
%footer,
|
%footer,
|
||||||
%type-icon {
|
%app-view h1 span.kind-proxy {
|
||||||
font-size: $typo-size-700;
|
font-size: $typo-size-700;
|
||||||
}
|
}
|
||||||
%toggle label span {
|
%toggle label span {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
html.template-instance.template-show #addresses table tr,
|
||||||
html.template-instance.template-show #upstreams table tr {
|
html.template-instance.template-show #upstreams table tr {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
{{#if item.TaggedAddresses }}
|
||||||
|
{{#tabular-collection
|
||||||
|
data-test-addresses
|
||||||
|
items=(object-entries item.TaggedAddresses) as |taggedAddress index|
|
||||||
|
}}
|
||||||
|
{{#block-slot 'header'}}
|
||||||
|
<th>Tag</th>
|
||||||
|
<th>Address</th>
|
||||||
|
{{/block-slot}}
|
||||||
|
{{#block-slot 'row'}}
|
||||||
|
{{#with (object-at 1 taggedAddress) as |address|}}
|
||||||
|
<td>
|
||||||
|
{{object-at 0 taggedAddress}}{{#if (and (eq address.Address item.Address) (eq address.Port item.Port))}} <em data-test-address-default>(default)</em>{{/if}}
|
||||||
|
</td>
|
||||||
|
<td data-test-address>
|
||||||
|
{{address.Address}}:{{address.Port}}
|
||||||
|
</td>
|
||||||
|
{{/with}}
|
||||||
|
{{/block-slot}}
|
||||||
|
{{/tabular-collection}}
|
||||||
|
{{else}}
|
||||||
|
<p>
|
||||||
|
There are no additional addresses.
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
|
@ -23,7 +23,6 @@
|
||||||
}}
|
}}
|
||||||
{{#block-slot 'header'}}
|
{{#block-slot 'header'}}
|
||||||
<th style={{remainingWidth}}>Service</th>
|
<th style={{remainingWidth}}>Service</th>
|
||||||
<th>Type</th>
|
|
||||||
<th style={{totalWidth}}>Health Checks<span><em>The number of health checks for the service on all nodes</em></span></th>
|
<th style={{totalWidth}}>Health Checks<span><em>The number of health checks for the service on all nodes</em></span></th>
|
||||||
<th style={{remainingWidth}}>Tags</th>
|
<th style={{remainingWidth}}>Tags</th>
|
||||||
{{/block-slot}}
|
{{/block-slot}}
|
||||||
|
@ -34,13 +33,6 @@
|
||||||
{{item.Name}}
|
{{item.Name}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
{{#if (eq item.Kind 'connect-proxy')}}
|
|
||||||
<span class="kind-proxy">Proxy</span>
|
|
||||||
{{else}}
|
|
||||||
|
|
||||||
{{/if}}
|
|
||||||
</td>
|
|
||||||
<td style={{totalWidth}}>
|
<td style={{totalWidth}}>
|
||||||
{{healthcheck-info
|
{{healthcheck-info
|
||||||
passing=item.ChecksPassing warning=item.ChecksWarning critical=item.ChecksCritical
|
passing=item.ChecksPassing warning=item.ChecksWarning critical=item.ChecksCritical
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
{{/with}}
|
{{/with}}
|
||||||
{{#if (eq item.Kind 'connect-proxy')}}
|
{{#if (eq item.Kind 'connect-proxy')}}
|
||||||
<span class="kind-proxy">Proxy</span>
|
<span class="kind-proxy">Proxy</span>
|
||||||
|
{{else if (eq item.Kind 'mesh-gateway')}}
|
||||||
|
<span class="kind-proxy">Mesh Gateway</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</h1>
|
</h1>
|
||||||
<dl>
|
<dl>
|
||||||
|
@ -64,10 +66,17 @@
|
||||||
{{tab-nav
|
{{tab-nav
|
||||||
items=(compact
|
items=(compact
|
||||||
(array
|
(array
|
||||||
'Service Checks'
|
'Service Checks'
|
||||||
'Node Checks'
|
'Node Checks'
|
||||||
(if (eq item.Kind 'connect-proxy') 'Upstreams' '')
|
(if
|
||||||
'Tags'
|
(eq item.Kind 'connect-proxy')
|
||||||
|
'Upstreams' ''
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(eq item.Kind 'mesh-gateway')
|
||||||
|
'Addresses' ''
|
||||||
|
)
|
||||||
|
'Tags'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
selected=selectedTab
|
selected=selectedTab
|
||||||
|
@ -75,10 +84,17 @@
|
||||||
{{#each
|
{{#each
|
||||||
(compact
|
(compact
|
||||||
(array
|
(array
|
||||||
(hash id=(slugify 'Service Checks') partial='dc/services/servicechecks')
|
(hash id=(slugify 'Service Checks') partial='dc/services/servicechecks')
|
||||||
(hash id=(slugify 'Node Checks') partial='dc/services/nodechecks')
|
(hash id=(slugify 'Node Checks') partial='dc/services/nodechecks')
|
||||||
(if (eq item.Kind 'connect-proxy') (hash id=(slugify 'Upstreams') partial='dc/services/upstreams') '')
|
(if
|
||||||
(hash id=(slugify 'Tags') partial='dc/services/tags')
|
(eq item.Kind 'connect-proxy')
|
||||||
|
(hash id=(slugify 'Upstreams') partial='dc/services/upstreams') ''
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(eq item.Kind 'mesh-gateway')
|
||||||
|
(hash id=(slugify 'Addresses') partial='dc/services/addresses') ''
|
||||||
|
)
|
||||||
|
(hash id=(slugify 'Tags') partial='dc/services/tags')
|
||||||
)
|
)
|
||||||
) as |panel|
|
) as |panel|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
{{/with}}
|
{{/with}}
|
||||||
{{#if (eq item.Service.Kind 'connect-proxy')}}
|
{{#if (eq item.Service.Kind 'connect-proxy')}}
|
||||||
<span class="kind-proxy">Proxy</span>
|
<span class="kind-proxy">Proxy</span>
|
||||||
|
{{else if (eq item.Service.Kind 'mesh-gateway')}}
|
||||||
|
<span class="kind-proxy">Mesh Gateway</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</h1>
|
</h1>
|
||||||
<label for="toolbar-toggle"></label>
|
<label for="toolbar-toggle"></label>
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
@setupApplicationTest
|
||||||
|
Feature: dc / services / instances / gateway: Show Gateway Service Instance
|
||||||
|
Scenario: A Gateway Service instance
|
||||||
|
Given 1 datacenter model with the value "dc1"
|
||||||
|
And 1 instance model from yaml
|
||||||
|
---
|
||||||
|
- Service:
|
||||||
|
Kind: mesh-gateway
|
||||||
|
Name: gateway
|
||||||
|
ID: gateway-with-id
|
||||||
|
TaggedAddresses:
|
||||||
|
lan:
|
||||||
|
Address: 127.0.0.1
|
||||||
|
Port: 8080
|
||||||
|
wan:
|
||||||
|
Address: 92.68.0.0
|
||||||
|
Port: 8081
|
||||||
|
---
|
||||||
|
When I visit the instance page for yaml
|
||||||
|
---
|
||||||
|
dc: dc1
|
||||||
|
service: gateway
|
||||||
|
node: node-0
|
||||||
|
id: gateway-with-id
|
||||||
|
---
|
||||||
|
Then the url should be /dc1/services/gateway/node-0/gateway-with-id
|
||||||
|
|
||||||
|
And I see serviceChecksIsSelected on the tabs
|
||||||
|
|
||||||
|
When I click addresses on the tabs
|
||||||
|
And I see addressesIsSelected on the tabs
|
||||||
|
And I see 2 of the addresses object
|
||||||
|
And I see address on the addresses like yaml
|
||||||
|
---
|
||||||
|
- 127.0.0.1:8080
|
||||||
|
- 92.68.0.0:8081
|
||||||
|
---
|
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { moduleForComponent, test } from 'ember-qunit';
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
|
||||||
|
moduleForComponent('object-entries', 'helper:object-entries', {
|
||||||
|
integration: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it renders', function(assert) {
|
||||||
|
this.set('inputValue', '1234');
|
||||||
|
|
||||||
|
this.render(hbs`{{object-entries inputValue}}`);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
this.$()
|
||||||
|
.text()
|
||||||
|
.trim(),
|
||||||
|
Object.entries('1234').toString()
|
||||||
|
);
|
||||||
|
});
|
|
@ -2,7 +2,7 @@ export default function(visitable, attribute, collection, text, radiogroup) {
|
||||||
return {
|
return {
|
||||||
visit: visitable('/:dc/services/:service/:node/:id'),
|
visit: visitable('/:dc/services/:service/:node/:id'),
|
||||||
externalSource: attribute('data-test-external-source', 'h1 span'),
|
externalSource: attribute('data-test-external-source', 'h1 span'),
|
||||||
tabs: radiogroup('tab', ['service-checks', 'node-checks', 'upstreams', 'tags']),
|
tabs: radiogroup('tab', ['service-checks', 'node-checks', 'addresses', 'upstreams', 'tags']),
|
||||||
serviceChecks: collection('#service-checks [data-test-healthchecks] li', {}),
|
serviceChecks: collection('#service-checks [data-test-healthchecks] li', {}),
|
||||||
nodeChecks: collection('#node-checks [data-test-healthchecks] li', {}),
|
nodeChecks: collection('#node-checks [data-test-healthchecks] li', {}),
|
||||||
upstreams: collection('#upstreams [data-test-tabular-row]', {
|
upstreams: collection('#upstreams [data-test-tabular-row]', {
|
||||||
|
@ -11,6 +11,9 @@ export default function(visitable, attribute, collection, text, radiogroup) {
|
||||||
type: text('[data-test-destination-type]'),
|
type: text('[data-test-destination-type]'),
|
||||||
address: text('[data-test-local-bind-address]'),
|
address: text('[data-test-local-bind-address]'),
|
||||||
}),
|
}),
|
||||||
|
addresses: collection('#addresses [data-test-tabular-row]', {
|
||||||
|
address: text('[data-test-address]'),
|
||||||
|
}),
|
||||||
proxy: {
|
proxy: {
|
||||||
type: attribute('data-test-proxy-type', '[data-test-proxy-type]'),
|
type: attribute('data-test-proxy-type', '[data-test-proxy-type]'),
|
||||||
destination: attribute('data-test-proxy-destination', '[data-test-proxy-destination]'),
|
destination: attribute('data-test-proxy-destination', '[data-test-proxy-destination]'),
|
||||||
|
|
Loading…
Reference in New Issue