mirror of https://github.com/status-im/consul.git
ui: Redesign - Instance Detail Proxy Info tab (#7745)
* Fix clickFirstAnchor bug * Create Proxy Info Tab for Instance Detail Page * Create tests for ProxyInfo and update other scenarios with Proxy data * ui: Refactors our app-view/%app-view component (#7752) Co-authored-by: John Cowen <johncowen@users.noreply.github.com>
This commit is contained in:
parent
abc43b6a0f
commit
4b2ff91b45
|
@ -45,19 +45,25 @@
|
|||
</FlashMessage>
|
||||
{{/each}}
|
||||
<div>
|
||||
<div class="actions">
|
||||
{{#if authorized}}
|
||||
<YieldSlot @name="actions">{{yield}}</YieldSlot>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{#if authorized}}
|
||||
<nav aria-label="Breadcrumb">
|
||||
<YieldSlot @name="breadcrumbs">{{yield}}</YieldSlot>
|
||||
</nav>
|
||||
{{/if}}
|
||||
<YieldSlot @name="header">{{yield}}</YieldSlot>
|
||||
<div class="title">
|
||||
<YieldSlot @name="header">
|
||||
{{yield}}
|
||||
</YieldSlot>
|
||||
<div class="actions">
|
||||
{{#if authorized}}
|
||||
<YieldSlot @name="actions">{{yield}}</YieldSlot>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<YieldSlot @name="nav">
|
||||
{{yield}}
|
||||
</YieldSlot>
|
||||
</div>
|
||||
</div>
|
||||
{{#if authorized}}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({});
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
||||
|
|
|
@ -7,8 +7,13 @@
|
|||
</BlockSlot>
|
||||
<BlockSlot @name="content">
|
||||
<dl>
|
||||
{{#if (eq item.ServiceName "")}}
|
||||
<dt>NodeName</dt>
|
||||
<dd>{{item.Node}}</dd>
|
||||
{{else}}
|
||||
<dt>ServiceName</dt>
|
||||
<dd>{{or item.ServiceName '-'}}</dd>
|
||||
<dd>{{item.ServiceName}}</dd>
|
||||
{{/if}}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>CheckID</dt>
|
||||
|
|
|
@ -47,7 +47,7 @@ export default Component.extend(WithResizing, {
|
|||
},
|
||||
actions: {
|
||||
click: function(e) {
|
||||
return this.dom.clickFirstAnchor(e, 'li');
|
||||
return this.dom.clickFirstAnchor(e, '.list-collection > ul > li');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -31,6 +31,9 @@ export const routes = {
|
|||
healthchecks: {
|
||||
_options: { path: '/health-checks' },
|
||||
},
|
||||
proxy: {
|
||||
_options: { path: '/proxy' },
|
||||
},
|
||||
upstreams: {
|
||||
_options: { path: '/upstreams' },
|
||||
},
|
||||
|
|
|
@ -16,12 +16,25 @@ export default Route.extend({
|
|||
// its highly unlikely that a service will suddenly change to being a
|
||||
// connect-proxy or vice versa so leave as is for now
|
||||
return hash({
|
||||
proxy:
|
||||
proxyMeta:
|
||||
// proxies and mesh-gateways can't have proxies themselves so don't even look
|
||||
['connect-proxy', 'mesh-gateway'].includes(get(model.item, 'Kind'))
|
||||
? null
|
||||
: this.proxyRepo.findInstanceBySlug(params.id, params.node, params.name, dc, nspace),
|
||||
...model,
|
||||
}).then(model => {
|
||||
if (typeof get(model, 'proxyMeta.ServiceID') === 'undefined') {
|
||||
return model;
|
||||
}
|
||||
const proxyName = get(model, 'proxyMeta.ServiceName');
|
||||
const proxyID = get(model, 'proxyMeta.ServiceID');
|
||||
const proxyNode = get(model, 'proxyMeta.Node');
|
||||
return hash({
|
||||
// Proxies have identical dc/nspace as their parent instance
|
||||
// No need to use Proxy's dc/nspace response
|
||||
proxy: this.repo.findInstanceBySlug(proxyID, proxyNode, proxyName, dc, nspace),
|
||||
...model,
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import Route from '@ember/routing/route';
|
||||
|
||||
export default Route.extend({
|
||||
model: function() {
|
||||
const parent = this.routeName
|
||||
.split('.')
|
||||
.slice(0, -1)
|
||||
.join('.');
|
||||
return this.modelFor(parent);
|
||||
},
|
||||
setupController: function(controller, model) {
|
||||
controller.setProperties(model);
|
||||
},
|
||||
});
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
@import 'routes/dc/settings/index';
|
||||
@import 'routes/dc/nodes/index';
|
||||
@import 'routes/dc/services/index';
|
||||
@import 'routes/dc/intention/index';
|
||||
@import 'routes/dc/kv/index';
|
||||
@import 'routes/dc/acls/index';
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
%table td.no-actions ~ .actions {
|
||||
display: none;
|
||||
}
|
||||
%table td:not(.actions),
|
||||
%table td:not(.actions) > *:only-child {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
@ -41,6 +40,7 @@
|
|||
}
|
||||
%table td {
|
||||
height: 50px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
%table caption {
|
||||
margin-bottom: 0.8em;
|
||||
|
|
|
@ -22,9 +22,12 @@
|
|||
display: inline-block;
|
||||
padding: 16px 13px;
|
||||
}
|
||||
%tab-section section h3 {
|
||||
margin: 24px 0;
|
||||
%tab-section section {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
%tab-section section:not(:last-child) {
|
||||
border-bottom: 1px solid $gray-200;
|
||||
}
|
||||
%tab-section section > h3 {
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
|
|
@ -4,66 +4,19 @@
|
|||
|
||||
@import '../base/components/popover-menu/index';
|
||||
|
||||
%app-view-header .actions > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%more-popover-menu-panel [type='checkbox']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 143px;
|
||||
max-height: 143px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 163px;
|
||||
max-height: 163px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='delete']:checked ~ ul label[for$='delete'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ ul label[for$='logout'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='use']:checked ~ ul label[for$='use'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
||||
%app-view-header .actions label + div {
|
||||
// We need this extra to allow tooltips to show
|
||||
%app-view-actions label + div {
|
||||
/* We need this extra to allow tooltips to show */
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
main {
|
||||
@extend %app-view;
|
||||
}
|
||||
%app-view > div > header {
|
||||
@extend %app-view-header;
|
||||
}
|
||||
%app-view > div > div {
|
||||
@extend %app-view-content;
|
||||
}
|
||||
%app-view header form {
|
||||
%app-view-header form {
|
||||
@extend %filter-bar;
|
||||
}
|
||||
@media #{$--lt-spacious-page-header} {
|
||||
%app-view-header .actions {
|
||||
margin-top: 9px;
|
||||
}
|
||||
}
|
||||
// TODO: This should be its own component
|
||||
%app-view h1 {
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
%app-view h1 span[data-tooltip] {
|
||||
@extend %with-external-source-icon;
|
||||
margin-top: 13px;
|
||||
}
|
||||
%app-view h1 span.kind-proxy {
|
||||
@extend %frame-gray-900;
|
||||
@extend %pill;
|
||||
}
|
||||
%app-view h1 span.kind-proxy::before {
|
||||
width: 0.3em !important;
|
||||
}
|
||||
%app-view h1 em {
|
||||
color: $gray-600;
|
||||
}
|
||||
%app-view-header .actions a,
|
||||
%app-view-header .actions button {
|
||||
%app-view-actions a,
|
||||
%app-view-actions button {
|
||||
@extend %button-compact;
|
||||
}
|
||||
%app-view-content div > dl {
|
||||
|
@ -97,12 +50,14 @@ main {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
@media #{$--lt-spacious-page-header} {
|
||||
%app-view-actions {
|
||||
margin-top: 9px;
|
||||
}
|
||||
}
|
||||
// reduced search magnifying icon layout
|
||||
@media #{$--lt-horizontal-selects} {
|
||||
%app-view header h1 {
|
||||
display: inline-block;
|
||||
}
|
||||
%app-view header h1 {
|
||||
%app-view-header h1 {
|
||||
display: inline-block;
|
||||
}
|
||||
// on the instance detail page we don't have the magnifier
|
||||
|
|
|
@ -1,2 +1,14 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
||||
%app-view > div > header {
|
||||
@extend %app-view-header;
|
||||
}
|
||||
%app-view-header .title {
|
||||
@extend %app-view-title;
|
||||
}
|
||||
%app-view-header .actions {
|
||||
@extend %app-view-actions;
|
||||
}
|
||||
%app-view > div > div {
|
||||
@extend %app-view-content;
|
||||
}
|
||||
|
|
|
@ -1,67 +1,61 @@
|
|||
/* layout */
|
||||
%app-view-header > div:last-of-type > div:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
%app-view {
|
||||
position: relative;
|
||||
}
|
||||
%app-view-header .actions {
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 9px;
|
||||
}
|
||||
%app-view-header dl {
|
||||
float: left;
|
||||
margin-top: 25px;
|
||||
margin-right: 50px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
%app-view-header dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
%app-view-header dd > a {
|
||||
color: $black;
|
||||
}
|
||||
%app-view-header .title-bar {
|
||||
%app-view-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
%app-view-header .title-bar > h1 {
|
||||
border: 0;
|
||||
%app-view-actions {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
%app-view-header .title-bar > span {
|
||||
margin-left: 8px;
|
||||
%app-view-header dl {
|
||||
float: left;
|
||||
}
|
||||
/* units */
|
||||
%app-view {
|
||||
margin-top: 50px;
|
||||
}
|
||||
/* give anything after the header a bit of room */
|
||||
%app-view-header + div > *:first-child {
|
||||
margin-top: 1.8em;
|
||||
}
|
||||
%app-view h2 {
|
||||
%app-view-title {
|
||||
padding-bottom: 0.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
%app-view-header .actions > *:not(:last-child) {
|
||||
%app-view-title > :not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
%app-view-actions {
|
||||
margin-top: 9px;
|
||||
}
|
||||
%app-view-actions > *:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
// content
|
||||
%app-view-content div > dl > dt {
|
||||
position: absolute;
|
||||
%app-view-header dl {
|
||||
margin-top: 19px;
|
||||
margin-bottom: 23px;
|
||||
margin-right: 50px;
|
||||
}
|
||||
%app-view-content div > dl {
|
||||
position: relative;
|
||||
|
||||
/* content */
|
||||
%app-view-content h2 {
|
||||
padding-bottom: 0.2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
%app-view-content-empty {
|
||||
margin-top: 0;
|
||||
padding: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
%app-view-content form:not(:last-child) {
|
||||
margin-bottom: 2.2em;
|
||||
/* this should probably be its own component */
|
||||
%app-view-content div > dl {
|
||||
position: relative;
|
||||
}
|
||||
%app-view-content div > dl > dt {
|
||||
position: absolute;
|
||||
}
|
||||
%app-view-content div > dl > dt {
|
||||
width: 140px;
|
||||
|
@ -73,7 +67,8 @@
|
|||
min-height: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
// TODO: Think about an %app-form or similar
|
||||
/* */
|
||||
/* TODO: Think about an %app-form or similar */
|
||||
%app-view-content fieldset:not(.freetext-filter) {
|
||||
padding-bottom: 0.3em;
|
||||
margin-bottom: 2em;
|
||||
|
|
|
@ -1,52 +1,33 @@
|
|||
/*TODO: Rename this to %app-view-brand-icon or similar */
|
||||
%with-external-source-icon {
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
||||
--kubernetes-icon: #{$kubernetes-logo-color-svg};
|
||||
--terraform-icon: #{$terraform-logo-color-svg};
|
||||
--nomad-icon: #{$nomad-logo-color-svg};
|
||||
--consul-icon: #{$consul-logo-color-svg};
|
||||
--aws-icon: #{$aws-logo-color-svg};
|
||||
%app-view-content-empty {
|
||||
@extend %frame-gray-500;
|
||||
}
|
||||
%app-view h2,
|
||||
%app-view fieldset {
|
||||
%app-view-title {
|
||||
border-bottom: $decor-border-200;
|
||||
}
|
||||
%app-view fieldset h2 {
|
||||
%app-view-content h2,
|
||||
%app-view-content fieldset {
|
||||
border-bottom: $decor-border-200;
|
||||
}
|
||||
%app-view-content fieldset h2 {
|
||||
border-bottom: none;
|
||||
}
|
||||
@media #{$--horizontal-selects} {
|
||||
%app-view header h1 {
|
||||
border-bottom: $decor-border-200;
|
||||
}
|
||||
%app-view-header h1 > em {
|
||||
color: $gray-600;
|
||||
}
|
||||
@media #{$--lt-horizontal-selects} {
|
||||
%app-view header > div > div:last-child {
|
||||
border-bottom: $decor-border-200;
|
||||
}
|
||||
}
|
||||
%app-view header > div > div:last-child,
|
||||
%app-view header h1,
|
||||
%app-view h2,
|
||||
%app-view fieldset {
|
||||
border-color: $gray-200;
|
||||
}
|
||||
// We know that any sibling navs might have a top border
|
||||
// by default. As its squashed up to a h1, in this
|
||||
// case hide its border to avoid double border
|
||||
@media #{$--horizontal-selects} {
|
||||
%app-view header h1 ~ nav {
|
||||
border-top: 0 !important;
|
||||
}
|
||||
%app-view-header dd > a {
|
||||
color: $black;
|
||||
}
|
||||
%app-view-content div > dl > dd {
|
||||
color: $gray-400;
|
||||
}
|
||||
[role='tabpanel'] > p:only-child,
|
||||
.template-error > div,
|
||||
%app-view-content > p:only-child {
|
||||
@extend %frame-gray-500;
|
||||
%app-view-title,
|
||||
%app-view-content h2,
|
||||
%app-view-content fieldset {
|
||||
border-color: $gray-200;
|
||||
}
|
||||
// We know that any sibling navs might have a top border
|
||||
// by default. As its squashed up to a %app-view-title, in this
|
||||
// case hide its border to avoid double border
|
||||
%app-view-title ~ nav {
|
||||
border-top: 0 !important;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
@import './layout';
|
||||
@import './skin';
|
||||
%composite-row:hover,
|
||||
%composite-row:focus,
|
||||
%composite-row:active {
|
||||
%with-composite-row-intent:hover,
|
||||
%with-composite-row-intent:focus,
|
||||
%with-composite-row-intent:active {
|
||||
@extend %composite-row-intent;
|
||||
}
|
||||
%composite-row > a {
|
||||
%composite-row > a,
|
||||
%composite-row > p {
|
||||
@extend %composite-row-header;
|
||||
}
|
||||
%composite-row > ul {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
%composite-row {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
padding-right: 0;
|
||||
border: 1px solid;
|
||||
}
|
||||
%composite-row-header {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
%composite-row-intent {
|
||||
border: 1px solid;
|
||||
position: relative;
|
||||
|
@ -23,3 +25,11 @@
|
|||
%composite-row-detail .node::before {
|
||||
margin-top: 2px;
|
||||
}
|
||||
// In this case we do not need a background on the icon
|
||||
%composite-row-detail .port button {
|
||||
padding: 0 !important;
|
||||
margin-top: 1px !important;
|
||||
}
|
||||
%composite-row-detail .port button:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
%composite-row-intent {
|
||||
border-color: $gray-200;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
%composite-row-header {
|
||||
color: $black;
|
||||
|
@ -53,3 +54,11 @@
|
|||
@extend %with-swap-horizontal-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
}
|
||||
%composite-row .datacenter::before {
|
||||
@extend %with-user-organization-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
}
|
||||
%composite-row .nspace::before {
|
||||
@extend %with-folder-outline-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
@extend %consul-service-instance-row;
|
||||
}
|
||||
%consul-service-instance-row {
|
||||
@extend %composite-row;
|
||||
@extend %composite-row, %with-composite-row-intent;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
@extend %consul-service-row;
|
||||
}
|
||||
%consul-service-row {
|
||||
@extend %composite-row;
|
||||
@extend %composite-row, %with-composite-row-intent;
|
||||
}
|
||||
%consul-service-row > ul {
|
||||
margin-left: 26px;
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
@import './layout';
|
||||
|
||||
%dom-recycling-table {
|
||||
@extend %table-flex;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
%filter-bar {
|
||||
padding: 4px;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
%filter-bar + :not(.notice) {
|
||||
margin-top: 1.8em;
|
||||
}
|
||||
@media #{$--horizontal-filters} {
|
||||
%filter-bar {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
%healthcheck-output {
|
||||
display: flex;
|
||||
|
||||
padding: 20px 16px;
|
||||
padding-right: 24px;
|
||||
|
||||
}
|
||||
%healthcheck-output:not(:last-child) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
%healthcheck-output::before {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
}
|
||||
%healthcheck-output::before {
|
||||
@extend %as-pseudo;
|
||||
min-width: 26px;
|
||||
min-height: 26px;
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
@media #{$--lt-spacious-healthcheck-output} {
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
@import '../base/components/table/index';
|
||||
@import '../base/components/popover-menu/index';
|
||||
table {
|
||||
@extend %table, %table-flex;
|
||||
%main-content table {
|
||||
@extend %table;
|
||||
}
|
||||
|
||||
%table-actions > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%more-popover-menu-panel [type='checkbox']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 143px;
|
||||
max-height: 143px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 183px;
|
||||
max-height: 183px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='delete']:checked ~ ul label[for$='delete'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ ul label[for$='logout'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='use']:checked ~ ul label[for$='use'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
||||
%table-actions .confirmation-alert {
|
||||
@extend %confirmation-alert;
|
||||
}
|
||||
|
@ -16,18 +30,27 @@ table {
|
|||
right: 15px;
|
||||
}
|
||||
|
||||
html.template-service.template-list td:first-child a span,
|
||||
html.template-node.template-show #services td:first-child a span,
|
||||
html.template-service.template-show #instances td:first-child a span {
|
||||
/*TODO: Rename this to %app-view-brand-icon or similar */
|
||||
%with-external-source-icon {
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
||||
--kubernetes-icon: #{$kubernetes-logo-color-svg};
|
||||
--terraform-icon: #{$terraform-logo-color-svg};
|
||||
--nomad-icon: #{$nomad-logo-color-svg};
|
||||
--consul-icon: #{$consul-logo-color-svg};
|
||||
--aws-icon: #{$aws-logo-color-svg};
|
||||
}
|
||||
html.template-node.template-show #services td:first-child a span {
|
||||
@extend %with-external-source-icon;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
/* This nudges the th in for the external source icons */
|
||||
html.template-node.template-show #services th:first-child,
|
||||
html.template-service.template-show #instances th:first-child,
|
||||
html.template-service.template-list main th:first-child {
|
||||
html.template-node.template-show #services th:first-child {
|
||||
text-indent: 28px;
|
||||
}
|
||||
|
||||
|
@ -73,18 +96,12 @@ th span em {
|
|||
html.template-policy.template-list tr > :nth-child(2) {
|
||||
display: none;
|
||||
}
|
||||
html.template-service.template-list tr > :nth-child(2) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media #{$--lt-wide-table} {
|
||||
/* hide actions on narrow screens, you can always click in do everything from there */
|
||||
tr > .actions {
|
||||
display: none;
|
||||
}
|
||||
html.template-service.template-list tr > :last-child {
|
||||
display: none;
|
||||
}
|
||||
html.template-node.template-show #services tr > :last-child {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ pre code,
|
|||
%notice p,
|
||||
%flash-message p,
|
||||
%filter-bar input,
|
||||
%phrase-editor input {
|
||||
%phrase-editor input,
|
||||
%tab-section section p {
|
||||
@extend %p1;
|
||||
}
|
||||
%menu-panel dl,
|
||||
|
@ -79,6 +80,7 @@ pre code,
|
|||
%button {
|
||||
font-weight: $typo-weight-semibold;
|
||||
}
|
||||
%app-view-header dt,
|
||||
%menu-panel dt,
|
||||
%route-card section dt,
|
||||
%route-card header:not(.short) dd,
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
.proxy-upstreams > ul {
|
||||
@extend %proxy-upstreams-list;
|
||||
}
|
||||
%proxy-upstreams-list > li {
|
||||
@extend %composite-row;
|
||||
}
|
||||
.proxy-exposed-paths tbody tr {
|
||||
@extend %proxy-exposed-paths-row;
|
||||
cursor: default !important;
|
||||
}
|
||||
%proxy-exposed-paths-row:hover {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
%proxy-exposed-paths-row .combined-address button:hover {
|
||||
// In this case we do not need a background on the icon
|
||||
background-color: transparent !important;
|
||||
}
|
|
@ -16,9 +16,11 @@
|
|||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="disabled">
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="disabled">
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
{{ item.Node }}
|
||||
</h1>
|
||||
<label for="toolbar-toggle"></label>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
<TabNav @items={{
|
||||
compact
|
||||
(array
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
</ol>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="header">
|
||||
<div class="title-bar">
|
||||
<h1>
|
||||
{{ item.ID }}
|
||||
</h1>
|
||||
<ConsulExternalSource @item={{item}} />
|
||||
</div>
|
||||
<h1>
|
||||
{{ item.ID }}
|
||||
</h1>
|
||||
<ConsulExternalSource @item={{item}} />
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
<dl>
|
||||
<dt>Service Name</dt>
|
||||
<dd><a href="{{href-to 'dc.services.show' item.Service}}">{{item.Service}}</a></dd>
|
||||
|
@ -24,44 +24,19 @@
|
|||
<dt>Node Name</dt>
|
||||
<dd><a href="{{href-to 'dc.nodes.show' item.Node.Node}}">{{item.Node.Node}}</a></dd>
|
||||
</dl>
|
||||
{{#if proxy.ServiceName}}
|
||||
<dl>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{#if (eq item.Kind 'connect-proxy')}}
|
||||
{{#if item.Proxy.DestinationServiceID}}
|
||||
<dl>
|
||||
<dt data-test-proxy-destination="instance">Dest. Service Instance</dt>
|
||||
<dd><a href="{{href-to 'dc.services.instance' item.Proxy.DestinationServiceName item.Node.Node item.Proxy.DestinationServiceID}}">{{item.Proxy.DestinationServiceID}}</a></dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Local Service Address</dt>
|
||||
<dd>{{item.Proxy.LocalServiceAddress}}:{{item.Proxy.LocalServicePort}}</dd>
|
||||
</dl>
|
||||
{{else}}
|
||||
<dl>
|
||||
<dt data-test-proxy-destination="service">Dest. Service</dt>
|
||||
<dd><a href="{{href-to 'dc.services.show' item.Proxy.DestinationServiceName}}">{{item.Proxy.DestinationServiceName}}</a></dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="content">
|
||||
<TabNav @items={{
|
||||
compact
|
||||
(array
|
||||
(hash label="Health Checks" href=(href-to "dc.services.instance.healthchecks") selected=(is-href "dc.services.instance.healthchecks"))
|
||||
(if
|
||||
(eq item.Kind 'connect-proxy')
|
||||
(hash label="Upstreams" href=(href-to "dc.services.instance.upstreams") selected=(is-href "dc.services.instance.upstreams")) ""
|
||||
)
|
||||
(if
|
||||
(and (eq item.Kind 'connect-proxy') (gt item.Proxy.Expose.Paths.length 0))
|
||||
(hash label="Exposed Paths" href=(href-to "dc.services.instance.exposedpaths") selected=(is-href "dc.services.instance.exposedpaths")) ""
|
||||
)
|
||||
(if
|
||||
(eq item.Kind 'mesh-gateway')
|
||||
(hash label="Addresses" href=(href-to "dc.services.instance.addresses") selected=(is-href "dc.services.instance.addresses")) ""
|
||||
)
|
||||
(if proxy
|
||||
(hash label="Proxy Info" href=(href-to "dc.services.instance.proxy") selected=(is-href "dc.services.instance.proxy"))
|
||||
|
||||
)
|
||||
(hash label="Tags" href=(href-to "dc.services.instance.tags") selected=(is-href "dc.services.instance.tags"))
|
||||
(hash label="Metadata" href=(href-to "dc.services.instance.metadata") selected=(is-href "dc.services.instance.metadata"))
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
<div id="exposed-paths" class="tab-section">
|
||||
<div role="tabpanel">
|
||||
<p>
|
||||
You can expose individual HTTP paths like /metrics through Envoy for external services like Prometheus.
|
||||
</p>
|
||||
<TabularCollection
|
||||
data-test-exposedpaths
|
||||
class="exposedpaths"
|
||||
@items={{item.Proxy.Expose.Paths}} as |path index|
|
||||
>
|
||||
<BlockSlot @name="header">
|
||||
<th>Path</th>
|
||||
<th>Protocol</th>
|
||||
<th>Listener port</th>
|
||||
<th>Local path port</th>
|
||||
<th>Combined address<span><em role="tooltip">Service address, listener port, and path all combined into one URL.</em></span></th>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="row">
|
||||
<td>
|
||||
<span>{{path.Path}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{path.Protocol}}
|
||||
</td>
|
||||
<td>
|
||||
{{path.ListenerPort}}
|
||||
</td>
|
||||
<td>
|
||||
{{path.LocalPathPort}}
|
||||
</td>
|
||||
<td>
|
||||
<span data-test-combined-address>{{item.Address}}:{{path.ListenerPort}}{{path.Path}}</span>
|
||||
</td>
|
||||
</BlockSlot>
|
||||
</TabularCollection>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,96 @@
|
|||
<div class="tab-section">
|
||||
<div role="tabpanel">
|
||||
{{#if (or (gt proxy.ServiceChecks.length 0) (gt proxy.NodeChecks.length 0))}}
|
||||
<section>
|
||||
<h3>Proxy health checks</h3>
|
||||
<HealthcheckList data-test-proxy-checks @items={{append proxy.ServiceChecks proxy.NodeChecks}} />
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if (gt proxy.Proxy.Upstreams.length 0)}}
|
||||
<section class="proxy-upstreams">
|
||||
<h3>Upstreams</h3>
|
||||
<ul data-test-proxy-upstreams>
|
||||
{{#let proxy.Datacenter as |proxyDatacenter|}}
|
||||
{{#each proxy.Proxy.Upstreams as |item|}}
|
||||
<li>
|
||||
<p data-test-destination-name>
|
||||
{{item.DestinationName}}
|
||||
</p>
|
||||
<ul>
|
||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||
{{#if (not-eq item.DestinationType 'prepared_query')}}
|
||||
<li class="nspace">
|
||||
{{or item.DestinationNamespace 'default'}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (and (not-eq item.Datacenter proxyDatacenter) (not-eq item.Datacenter ""))}}
|
||||
<li class="datacenter">
|
||||
{{item.Datacenter}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (gt item.LocalBindPort 0)}}
|
||||
{{#let (concat (or item.LocalBindAddress '127.0.0.1') ':' item.LocalBindPort) as |combinedAddress| }}
|
||||
<li class="port">
|
||||
<CopyButtonFeedback
|
||||
@copy={{combinedAddress}}
|
||||
@name="Address"
|
||||
/>
|
||||
<span>{{combinedAddress}}</span>
|
||||
</li>
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
</ul>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if (gt proxy.Proxy.Upstreams.length 0)}}
|
||||
<section class="proxy-exposed-paths">
|
||||
<h3>Exposed paths</h3>
|
||||
<p>
|
||||
The following list shows individual HTTP paths exposed through Envoy for external services like Prometheus. Read more about this in our documentation.
|
||||
</p>
|
||||
<table data-test-proxy-exposed-paths>
|
||||
<thead>
|
||||
<th>Path</th>
|
||||
<th>Protocol</th>
|
||||
<th>Listener port</th>
|
||||
<th>Local path port</th>
|
||||
<th>Combined address<span><em role="tooltip">Service address, listener port, and path all combined into one URL.</em></span></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each proxy.Proxy.Expose.Paths as |path|}}
|
||||
<tr>
|
||||
<td>
|
||||
<span>{{or path.Path '-'}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{or path.Protocol '-'}}
|
||||
</td>
|
||||
<td>
|
||||
{{or path.ListenerPort '-'}}
|
||||
</td>
|
||||
<td>
|
||||
{{or path.LocalPathPort '-'}}
|
||||
</td>
|
||||
{{#let (concat item.Address ':' path.ListenerPort path.Path) as |combinedAddress| }}
|
||||
<td class="combined-address">
|
||||
{{#if combinedAddress}}
|
||||
<span data-test-combined-address>{{combinedAddress}}</span>
|
||||
<CopyButtonFeedback @copy={{combinedAddress}} @name="Combined Address" />
|
||||
{{else}}
|
||||
{{'-'}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/let}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
|
@ -1,43 +0,0 @@
|
|||
<div id="upstreams" class="tab-section">
|
||||
<div role="tabpanel">
|
||||
{{#if (gt item.Proxy.Upstreams.length 0) }}
|
||||
<TabularCollection
|
||||
data-test-upstreams
|
||||
@items={{item.Proxy.Upstreams}} as |item index|
|
||||
>
|
||||
<BlockSlot @name="header">
|
||||
<th>Upstream</th>
|
||||
<th>Datacenter</th>
|
||||
<th>Type</th>
|
||||
<th>Local Bind Address</th>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="row">
|
||||
<td>
|
||||
<a data-test-destination-name>
|
||||
{{item.DestinationName}}
|
||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||
{{#if (not-eq item.DestinationType 'prepared_query')}}
|
||||
{{! TODO: slugify }}
|
||||
<em class={{concat 'nspace-' (or item.DestinationNamespace 'default')}}>{{or item.DestinationNamespace 'default'}}</em>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</a>
|
||||
</td>
|
||||
<td data-test-destination-datacenter>
|
||||
{{item.Datacenter}}
|
||||
</td>
|
||||
<td data-test-destination-type>
|
||||
{{item.DestinationType}}
|
||||
</td>
|
||||
<td data-test-local-bind-address>
|
||||
{{item.LocalBindAddress}}:{{item.LocalBindPort}}
|
||||
</td>
|
||||
</BlockSlot>
|
||||
</TabularCollection>
|
||||
{{else}}
|
||||
<p>
|
||||
There are no upstreams.
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
|
@ -10,19 +10,19 @@
|
|||
</ol>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="header">
|
||||
<div class="title-bar">
|
||||
<h1>
|
||||
{{item.Service.Service}}
|
||||
</h1>
|
||||
<ConsulExternalSource @item={{item.Service}} />
|
||||
</div>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="nav">
|
||||
{{#if (not item.Service.Kind)}}
|
||||
<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")) '')
|
||||
(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"))
|
||||
)
|
||||
}}/>
|
||||
|
@ -36,4 +36,4 @@
|
|||
<BlockSlot @name="content">
|
||||
{{outlet}}
|
||||
</BlockSlot>
|
||||
</AppView>
|
||||
</AppView>
|
|
@ -2,6 +2,12 @@
|
|||
Feature: dc / services / instances / gateway: Show Gateway Service Instance
|
||||
Scenario: A Gateway Service instance
|
||||
Given 1 datacenter model with the value "dc1"
|
||||
Given 1 proxy model from yaml
|
||||
---
|
||||
- ServiceProxy:
|
||||
DestinationServiceName: service-1
|
||||
DestinationServiceID: ~
|
||||
---
|
||||
And 1 instance model from yaml
|
||||
---
|
||||
- Service:
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / services / instances / show: Proxy Info tab
|
||||
Background:
|
||||
Given 1 datacenter model with the value "dc1"
|
||||
Scenario: A Service instance without a Proxy does not display Proxy Info tab
|
||||
Given 1 proxy model from yaml
|
||||
---
|
||||
- ServiceProxy:
|
||||
DestinationServiceName: service-1
|
||||
DestinationServiceID: ~
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I don't see proxyInfo on the tabs
|
||||
Scenario: A Service instance with a Proxy displays Proxy Info tab
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I see proxyInfo on the tabs
|
||||
|
||||
When I click proxyInfo on the tabs
|
||||
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/proxy
|
||||
And I see proxyInfoIsSelected on the tabs
|
||||
@notNamespaceable
|
||||
Scenario: A Proxy with health checks, upstreams, and exposed paths displays all info
|
||||
Given 2 instance models from yaml
|
||||
---
|
||||
- Service:
|
||||
ID: service-0-with-id
|
||||
Kind: consul
|
||||
Node:
|
||||
Node: node-0
|
||||
- Service:
|
||||
ID: service-0-with-id-proxy
|
||||
Kind: connect-proxy
|
||||
Proxy:
|
||||
DestinationServiceName: service-0
|
||||
Expose:
|
||||
Checks: false
|
||||
Paths:
|
||||
- Path: /grpc-metrics
|
||||
Protocol: grpc
|
||||
LocalPathPort: 8081
|
||||
ListenerPort: 8080
|
||||
- Path: /http-metrics
|
||||
Protocol: http
|
||||
LocalPathPort: 8082
|
||||
ListenerPort: 8083
|
||||
- Path: /http-metrics-2
|
||||
Protocol: http
|
||||
LocalPathPort: 8083
|
||||
ListenerPort: 8084
|
||||
Upstreams:
|
||||
- DestinationType: service
|
||||
DestinationName: service-2
|
||||
DestinationNamespace: default
|
||||
LocalBindAddress: 127.0.0.1
|
||||
LocalBindPort: 1111
|
||||
- DestinationType: prepared_query
|
||||
DestinationName: service-3
|
||||
LocalBindAddress: 127.0.0.1
|
||||
LocalBindPort: 1112
|
||||
Node:
|
||||
Node: node-0
|
||||
Checks:
|
||||
- Name: Service check
|
||||
ServiceID: service-0-proxy
|
||||
Output: Output of check
|
||||
Status: passing
|
||||
- Name: Service check
|
||||
ServiceID: service-0-proxy
|
||||
Output: Output of check
|
||||
Status: warning
|
||||
- Name: Service check
|
||||
Type: http
|
||||
ServiceID: service-0-proxy
|
||||
Output: Output of check
|
||||
Status: critical
|
||||
- Name: Node check
|
||||
ServiceID: ""
|
||||
Output: Output of check
|
||||
Status: passing
|
||||
- Name: Node check
|
||||
ServiceID: ""
|
||||
Output: Output of check
|
||||
Status: warning
|
||||
- Name: Node check
|
||||
ServiceID: ""
|
||||
Output: Output of check
|
||||
Status: critical
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I see proxyInfo on the tabs
|
||||
|
||||
When I click proxyInfo on the tabs
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/proxy
|
||||
|
||||
And I see 6 of the proxyChecks object
|
||||
|
||||
And I see 2 of the upstreams object
|
||||
And I see name on the upstreams like yaml
|
||||
---
|
||||
- service-2
|
||||
- service-3
|
||||
---
|
||||
Scenario: A Proxy without health checks does not display Proxy Health section
|
||||
And 2 instance models from yaml
|
||||
---
|
||||
- Service:
|
||||
ID: service-0-with-id
|
||||
Kind: consul
|
||||
Node:
|
||||
Node: node-0
|
||||
- Service:
|
||||
ID: service-0-with-id-proxy
|
||||
Kind: connect-proxy
|
||||
Node:
|
||||
Node: node-0
|
||||
Checks: []
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I see proxyInfo on the tabs
|
||||
|
||||
When I click proxyInfo on the tabs
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/proxy
|
||||
And I see 0 of the proxyChecks object
|
||||
Scenario: A Proxy without upstreams does not display Upstreams section
|
||||
And 2 instance models from yaml
|
||||
---
|
||||
- Service:
|
||||
ID: service-0-with-id
|
||||
Kind: consul
|
||||
Node:
|
||||
Node: node-0
|
||||
- Service:
|
||||
ID: service-0-with-id-proxy
|
||||
Kind: connect-proxy
|
||||
Proxy:
|
||||
Upstreams: []
|
||||
Node:
|
||||
Node: node-0
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I see proxyInfo on the tabs
|
||||
|
||||
When I click proxyInfo on the tabs
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/proxy
|
||||
And I see 0 of the upstreams object
|
||||
Scenario: A Proxy without exposed path does not display Exposed Paths section
|
||||
And 2 instance models from yaml
|
||||
---
|
||||
- Service:
|
||||
ID: service-0-with-id
|
||||
Kind: consul
|
||||
Node:
|
||||
Node: node-0
|
||||
- Service:
|
||||
ID: service-0-with-id-proxy
|
||||
Kind: connect-proxy
|
||||
Proxy:
|
||||
Expose:
|
||||
Checks: false
|
||||
Paths: []
|
||||
Node:
|
||||
Node: node-0
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I see proxyInfo on the tabs
|
||||
|
||||
When I click proxyInfo on the tabs
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/proxy
|
||||
And I see 0 of the exposedPaths object
|
||||
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ Feature: dc / services / instances / show: Show Service Instance
|
|||
Node:
|
||||
Node: node-0
|
||||
- Service:
|
||||
ID: service-0-with-id
|
||||
ID: service-1-with-id
|
||||
Tags: ['Tag1', 'Tag2']
|
||||
Meta:
|
||||
consul-dashboard-url: http://url.com
|
||||
|
@ -47,14 +47,20 @@ Feature: dc / services / instances / show: Show Service Instance
|
|||
Status: critical
|
||||
---
|
||||
Scenario: A Service instance has no Proxy
|
||||
Given 1 proxy model from yaml
|
||||
---
|
||||
- ServiceProxy:
|
||||
DestinationServiceName: service-1
|
||||
DestinationServiceID: ~
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: another-node
|
||||
id: service-0-with-id
|
||||
id: service-1-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/another-node/service-0-with-id/health-checks
|
||||
Then the url should be /dc1/services/service-0/instances/another-node/service-1-with-id/health-checks
|
||||
Then I see externalSource like "nomad"
|
||||
|
||||
And I don't see upstreams on the tabs
|
||||
|
@ -71,9 +77,15 @@ Feature: dc / services / instances / show: Show Service Instance
|
|||
When I click metadata on the tabs
|
||||
And I see metadataIsSelected on the tabs
|
||||
And I see 3 of the metadata object
|
||||
And the title should be "service-0-with-id - Consul"
|
||||
And the title should be "service-1-with-id - Consul"
|
||||
|
||||
Scenario: A Service instance warns when deregistered whilst blocking
|
||||
Given 1 proxy model from yaml
|
||||
---
|
||||
- ServiceProxy:
|
||||
DestinationServiceName: service-1
|
||||
DestinationServiceID: ~
|
||||
---
|
||||
Given settings from yaml
|
||||
---
|
||||
consul:client:
|
||||
|
@ -91,3 +103,19 @@ Feature: dc / services / instances / show: Show Service Instance
|
|||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And an external edit results in 0 instance models
|
||||
And pause until I see the text "deregistered" in "[data-notification]"
|
||||
Scenario: A Service instance without a Proxy does not display Proxy Info tab
|
||||
Given 1 proxy model from yaml
|
||||
---
|
||||
- ServiceProxy:
|
||||
DestinationServiceName: service-1
|
||||
DestinationServiceID: ~
|
||||
---
|
||||
When I visit the instance page for yaml
|
||||
---
|
||||
dc: dc1
|
||||
service: service-0
|
||||
node: node-0
|
||||
id: service-0-with-id
|
||||
---
|
||||
Then the url should be /dc1/services/service-0/instances/node-0/service-0-with-id/health-checks
|
||||
And I don't see proxy on the tabs
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -2,31 +2,18 @@ export default function(visitable, attribute, collection, text, tabs) {
|
|||
return {
|
||||
visit: visitable('/:dc/services/:service/instances/:node/:id'),
|
||||
externalSource: attribute('data-test-external-source', '[data-test-external-source]', {
|
||||
scope: '.title-bar',
|
||||
scope: '.title',
|
||||
}),
|
||||
tabs: tabs('tab', [
|
||||
'health-checks',
|
||||
'addresses',
|
||||
'upstreams',
|
||||
'exposed-paths',
|
||||
'tags',
|
||||
'metadata',
|
||||
]),
|
||||
serviceChecks: collection('[data-test-service-checks] li', {
|
||||
exposed: attribute('data-test-exposed', '[data-test-exposed]'),
|
||||
}),
|
||||
nodeChecks: collection('[data-test-node-checks] li', {
|
||||
exposed: attribute('data-test-exposed', '[data-test-exposed]'),
|
||||
}),
|
||||
upstreams: collection('#upstreams [data-test-tabular-row]', {
|
||||
tabs: tabs('tab', ['health-checks', 'proxy-info', 'addresses', 'tags', 'metadata']),
|
||||
serviceChecks: collection('[data-test-service-checks] li'),
|
||||
nodeChecks: collection('[data-test-node-checks] li'),
|
||||
upstreams: collection('[data-test-proxy-upstreams] > li', {
|
||||
name: text('[data-test-destination-name]'),
|
||||
datacenter: text('[data-test-destination-datacenter]'),
|
||||
type: text('[data-test-destination-type]'),
|
||||
address: text('[data-test-local-bind-address]'),
|
||||
}),
|
||||
exposedPaths: collection('#exposed-paths [data-test-tabular-row]', {
|
||||
exposedPaths: collection('[data-test-proxy-exposed-paths] > tbody tr', {
|
||||
combinedAddress: text('[data-test-combined-address]'),
|
||||
}),
|
||||
proxyChecks: collection('[data-test-proxy-checks] li'),
|
||||
addresses: collection('#addresses [data-test-tabular-row]', {
|
||||
address: text('[data-test-address]'),
|
||||
}),
|
||||
|
|
|
@ -2,7 +2,7 @@ export default function(visitable, attribute, collection, text, intentions, filt
|
|||
return {
|
||||
visit: visitable('/:dc/services/:service'),
|
||||
externalSource: attribute('data-test-external-source', '[data-test-external-source]', {
|
||||
scope: '.title-bar',
|
||||
scope: '.title',
|
||||
}),
|
||||
dashboardAnchor: {
|
||||
href: attribute('href', '[data-test-dashboard-anchor]'),
|
||||
|
|
Loading…
Reference in New Issue