mirror of https://github.com/status-im/consul.git
ui: Create and use collapsible notices component (#10270)
* Create and use collapsible notices * Refactor collapsible-notices * Split up the topology acceptance tests * Add acceptance tests for tproxy notices * Add component file * Adds additional TProxy notices tests * Adds conditional to only show collapsable if more than 2 notices are present * Adds changelog * Refactorting the conditonal for collapsing the notices * Renaming undefinedIntention to be notDefinedIntention * Refactor tests
This commit is contained in:
parent
da31e0449e
commit
f3efde3843
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
ui: Create a collapsible notices component for the Topology tab
|
||||
```
|
|
@ -0,0 +1,66 @@
|
|||
# CollapsibleNotices
|
||||
|
||||
Used as a wrapper to collapse the details of `<Notices/>`.
|
||||
|
||||
```hbs preview-template
|
||||
<CollapsibleNotices>
|
||||
<Notice
|
||||
@type="error"
|
||||
role="alert"
|
||||
as |notice|>
|
||||
<notice.Header>
|
||||
<h3>Header</h3>
|
||||
</notice.Header>
|
||||
<notice.Body>
|
||||
<p>
|
||||
Body
|
||||
</p>
|
||||
</notice.Body>
|
||||
</Notice>
|
||||
<Notice
|
||||
@type="info"
|
||||
as |notice|>
|
||||
<notice.Header>
|
||||
<h3>Header</h3>
|
||||
</notice.Header>
|
||||
<notice.Body>
|
||||
<p>
|
||||
Body
|
||||
</p>
|
||||
</notice.Body>
|
||||
<notice.Footer>
|
||||
<p>
|
||||
Footer
|
||||
</p>
|
||||
</notice.Footer>
|
||||
</Notice>
|
||||
<Notice
|
||||
@type="warning"
|
||||
as |notice|>
|
||||
<notice.Header>
|
||||
<h3>Header</h3>
|
||||
</notice.Header>
|
||||
<notice.Body>
|
||||
<p>
|
||||
Body
|
||||
</p>
|
||||
</notice.Body>
|
||||
<notice.Footer>
|
||||
<p>
|
||||
Footer
|
||||
</p>
|
||||
</notice.Footer>
|
||||
</Notice>
|
||||
</CollapsibleNotices>
|
||||
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
No arguments required. Wrap this component around the needed notices.
|
||||
|
||||
## See
|
||||
|
||||
- [Template Source Code](./index.hbs)
|
||||
|
||||
---
|
|
@ -0,0 +1,10 @@
|
|||
<div class="collapsible-notices {{if this.collapsed 'collapsed'}}">
|
||||
<div class="notices">
|
||||
{{yield}}
|
||||
</div>
|
||||
{{#if this.collapsed}}
|
||||
<button type="button" class="expand" {{on 'click' (set this 'collapsed' false)}}>{{t "components.app.collapsible-notices.expand"}}</button>
|
||||
{{else}}
|
||||
<button type="button" class="collapse" {{on 'click' (set this 'collapsed' true)}}>{{t "components.app.collapsible-notices.collapse"}}</button>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
import Component from '@glimmer/component';
|
||||
|
||||
export default class CollapsibleNotices extends Component {}
|
|
@ -0,0 +1,31 @@
|
|||
.collapsible-notices {
|
||||
display: grid;
|
||||
grid-template-columns: auto 168px;;
|
||||
grid-template-rows: auto 55px;
|
||||
grid-template-areas:
|
||||
"notices notices"
|
||||
". toggle-button";
|
||||
&.collapsed p {
|
||||
display: none;
|
||||
}
|
||||
.notices {
|
||||
grid-area: notices;
|
||||
:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
button {
|
||||
@extend %button;
|
||||
color: $color-action;
|
||||
float: right;
|
||||
grid-area: toggle-button;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
button.expand::before {
|
||||
@extend %with-chevron-down-mask, %as-pseudo;
|
||||
}
|
||||
button.collapse::before {
|
||||
@extend %with-chevron-up-mask, %as-pseudo;
|
||||
}
|
||||
}
|
|
@ -19,23 +19,27 @@ export default class Topology extends Model {
|
|||
@attr() Downstreams; // Service[],
|
||||
@attr() meta; // {}
|
||||
|
||||
@computed('Upstreams', 'Downstreams')
|
||||
get undefinedIntention() {
|
||||
let undefinedUpstream = false;
|
||||
@computed('Downstreams')
|
||||
get notDefinedIntention() {
|
||||
let undefinedDownstream = false;
|
||||
|
||||
undefinedUpstream =
|
||||
this.Upstreams.filter(
|
||||
item =>
|
||||
item.Source === 'specific-intention' && !item.TransparentProxy && item.Intention.Allowed
|
||||
).length !== 0;
|
||||
|
||||
undefinedDownstream =
|
||||
this.Downstreams.filter(
|
||||
item =>
|
||||
item.Source === 'specific-intention' && !item.TransparentProxy && item.Intention.Allowed
|
||||
).length !== 0;
|
||||
|
||||
return undefinedUpstream || undefinedDownstream;
|
||||
return undefinedDownstream;
|
||||
}
|
||||
|
||||
@computed('FilteredByACL', 'DefaultAllow', 'WildcardIntention', 'notDefinedIntention')
|
||||
get collapsible() {
|
||||
if (this.DefaultAllow && this.FilteredByACLs && this.notDefinedIntention) {
|
||||
return true;
|
||||
} else if (this.WildcardIntention && this.FilteredByACLs && this.notDefinedIntention) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
@import 'consul-ui/components/consul/auth-method';
|
||||
|
||||
@import 'consul-ui/components/role-selector';
|
||||
@import 'consul-ui/components/collapsible-notices';
|
||||
@import 'consul-ui/components/topology-metrics';
|
||||
@import 'consul-ui/components/topology-metrics/card';
|
||||
@import 'consul-ui/components/topology-metrics/source-type';
|
||||
|
|
|
@ -21,44 +21,92 @@ as |route|>
|
|||
</li>
|
||||
</BlockSlot>
|
||||
</EmptyState>
|
||||
{{else}}
|
||||
{{#if topology.collapsible}}
|
||||
<CollapsibleNotices>
|
||||
{{#if topology.FilteredByACLs}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='filtered-by-acls'
|
||||
@type="info"
|
||||
@for="limited-access"
|
||||
@action={{false}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.DefaultAllow}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='default-allow'
|
||||
@type="warning"
|
||||
@for="default-allow"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.WildcardIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='wildcard-intention'
|
||||
@type="warning"
|
||||
@for="wildcard-intention"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.notDefinedIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='not-defined-intention'
|
||||
@type="warning"
|
||||
@for="not-defined-intention"
|
||||
@link="{{env 'CONSUL_DOCS_URL'}}/connect/registration/service-registration#upstreams"
|
||||
@internal={{false}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
</CollapsibleNotices>
|
||||
{{else}}
|
||||
{{#if topology.FilteredByACLs}}
|
||||
<TopologyMetrics::Notice
|
||||
@type="info"
|
||||
@for="limited-access"
|
||||
@action={{false}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.DefaultAllow}}
|
||||
<TopologyMetrics::Notice
|
||||
@type="warning"
|
||||
@for="default-allow"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.WildcardIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
@type="warning"
|
||||
@for="wildcard-intention"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.undefinedIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
@type="warning"
|
||||
@for="not-defined-intention"
|
||||
@link="{{env 'CONSUL_DOCS_URL'}}/connect/registration/service-registration#upstreams"
|
||||
@internal={{false}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='filtered-by-acls'
|
||||
@type="info"
|
||||
@for="limited-access"
|
||||
@action={{false}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.DefaultAllow}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='default-allow'
|
||||
@type="warning"
|
||||
@for="default-allow"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.WildcardIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='wildcard-intention'
|
||||
@type="warning"
|
||||
@for="wildcard-intention"
|
||||
@internal={{true}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if topology.notDefinedIntention}}
|
||||
<TopologyMetrics::Notice
|
||||
data-test-notice='not-defined-intention'
|
||||
@type="warning"
|
||||
@for="not-defined-intention"
|
||||
@link="{{env 'CONSUL_DOCS_URL'}}/connect/registration/service-registration#upstreams"
|
||||
@internal={{false}}
|
||||
@action={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
|
||||
<TopologyMetrics
|
||||
@nspace={{nspace}}
|
||||
@dc={{dc.Name}}
|
||||
@service={{items.firstObject}}
|
||||
@topology={{topology}}
|
||||
|
||||
@metricsHref={{render-template urls.service (hash
|
||||
Datacenter=dc.Name
|
||||
Service=items.firstObject
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / services / show / topology: Intention Create
|
||||
Feature: dc / services / show / topology / intentions
|
||||
Background:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And the local datacenter is "datacenter"
|
||||
|
@ -27,27 +27,7 @@ Feature: dc / services / show / topology: Intention Create
|
|||
Datacenter: datacenter
|
||||
Intention: {}
|
||||
---
|
||||
Scenario: Metrics is not enabled with prometheus provider
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
And I don't see the "[data-test-sparkline]" element
|
||||
Scenario: Metrics is enabled with prometheus provider
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And the local datacenter is "datacenter"
|
||||
And ui_config from yaml
|
||||
---
|
||||
metrics_proxy_enabled: true
|
||||
metrics_provider: 'prometheus'
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
And I see the "[data-test-sparkline]" element
|
||||
|
||||
Scenario: Allow a connection between service and upstream by saving an intention
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
|
@ -67,4 +47,3 @@ Feature: dc / services / show / topology: Intention Create
|
|||
When I click ".consul-topology-metrics [data-test-action]"
|
||||
And I click ".consul-topology-metrics [data-test-confirm]"
|
||||
And "[data-notification]" has the "error" class
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / services / show / topology / metrics
|
||||
Background:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And the local datacenter is "datacenter"
|
||||
And 1 intention model from yaml
|
||||
---
|
||||
SourceNS: default
|
||||
SourceName: web
|
||||
DestinationNS: default
|
||||
DestinationName: db
|
||||
ID: intention-id
|
||||
---
|
||||
And 1 node model
|
||||
And 1 service model from yaml
|
||||
---
|
||||
- Service:
|
||||
Name: web
|
||||
Kind: ~
|
||||
---
|
||||
And 1 topology model from yaml
|
||||
---
|
||||
Downstreams: []
|
||||
Upstreams:
|
||||
- Name: db
|
||||
Namespace: default
|
||||
Datacenter: datacenter
|
||||
Intention: {}
|
||||
---
|
||||
Scenario: Metrics is not enabled with prometheus provider
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
And I don't see the "[data-test-sparkline]" element
|
||||
Scenario: Metrics is enabled with prometheus provider
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And the local datacenter is "datacenter"
|
||||
And ui_config from yaml
|
||||
---
|
||||
metrics_proxy_enabled: true
|
||||
metrics_provider: 'prometheus'
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
And I see the "[data-test-sparkline]" element
|
|
@ -0,0 +1,101 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / services / show / topology / tproxy
|
||||
Background:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And the local datacenter is "datacenter"
|
||||
And 1 intention model from yaml
|
||||
---
|
||||
SourceNS: default
|
||||
SourceName: web
|
||||
DestinationNS: default
|
||||
DestinationName: db
|
||||
ID: intention-id
|
||||
---
|
||||
And 1 node model
|
||||
And 1 service model from yaml
|
||||
---
|
||||
- Service:
|
||||
Name: web
|
||||
Kind: ~
|
||||
---
|
||||
Scenario: Deafult allow is set to true
|
||||
Given 1 topology model from yaml
|
||||
---
|
||||
FilteredByACLs: false
|
||||
TransparentProxy: false
|
||||
DefaultAllow: true
|
||||
WildcardIntention: false
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
Then the url should be /datacenter/services/web/topology
|
||||
And I see the tabs.topologyTab.defaultAllowNotice object
|
||||
Scenario: WildcardIntetions and FilteredByACLs are set to true
|
||||
Given 1 topology model from yaml
|
||||
---
|
||||
FilteredByACLs: true
|
||||
TransparentProxy: false
|
||||
DefaultAllow: false
|
||||
WildcardIntention: true
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
Then the url should be /datacenter/services/web/topology
|
||||
And I see the tabs.topologyTab.filteredByACLs object
|
||||
And I see the tabs.topologyTab.wildcardIntention object
|
||||
Scenario: TProxy for a downstream is set to false
|
||||
Given 1 topology model from yaml
|
||||
---
|
||||
FilteredByACLs: false
|
||||
TransparentProxy: false
|
||||
DefaultAllow: false
|
||||
WildcardIntention: false
|
||||
Downstreams:
|
||||
- Name: db
|
||||
Namespace: default
|
||||
Datacenter: datacenter
|
||||
Intention:
|
||||
Allowed: true
|
||||
Source: specific-intention
|
||||
TransparentProxy: false
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
Then the url should be /datacenter/services/web/topology
|
||||
And I see the tabs.topologyTab.notDefinedIntention object
|
||||
Scenario: TProxy for a downstream is set to true
|
||||
Given 1 topology model from yaml
|
||||
---
|
||||
FilteredByACLs: false
|
||||
TransparentProxy: false
|
||||
DefaultAllow: false
|
||||
WildcardIntention: false
|
||||
Downstreams:
|
||||
- Name: db
|
||||
Namespace: default
|
||||
Datacenter: datacenter
|
||||
Intention:
|
||||
Allowed: true
|
||||
Source: specific-intention
|
||||
TransparentProxy: true
|
||||
---
|
||||
When I visit the service page for yaml
|
||||
---
|
||||
dc: datacenter
|
||||
service: web
|
||||
---
|
||||
Then the url should be /datacenter/services/web/topology
|
||||
And I don't see the tabs.topologyTab.notDefinedIntention object
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import steps from '../../../steps';
|
||||
import steps from '../../../../steps';
|
||||
|
||||
// step definitions that are shared between features should be moved to the
|
||||
// tests/acceptance/steps/steps.js file
|
|
@ -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,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);
|
||||
});
|
||||
}
|
|
@ -157,7 +157,16 @@ export default {
|
|||
)
|
||||
),
|
||||
service: create(
|
||||
service(visitable, clickable, attribute, collection, text, consulIntentionList, tabgroup)
|
||||
service(
|
||||
visitable,
|
||||
clickable,
|
||||
attribute,
|
||||
isPresent,
|
||||
collection,
|
||||
text,
|
||||
consulIntentionList,
|
||||
tabgroup
|
||||
)
|
||||
),
|
||||
instance: create(
|
||||
instance(
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
export default function(visitable, clickable, attribute, collection, text, intentions, tabs) {
|
||||
export default function(
|
||||
visitable,
|
||||
clickable,
|
||||
attribute,
|
||||
isPresent,
|
||||
collection,
|
||||
text,
|
||||
intentions,
|
||||
tabs
|
||||
) {
|
||||
const page = {
|
||||
visit: visitable('/:dc/services/:service'),
|
||||
externalSource: attribute('data-test-external-source', '[data-test-external-source]', {
|
||||
|
@ -26,6 +35,20 @@ export default function(visitable, clickable, attribute, collection, text, inten
|
|||
}),
|
||||
intentionList: intentions(),
|
||||
};
|
||||
page.tabs.topologyTab = {
|
||||
defaultAllowNotice: {
|
||||
see: isPresent('[data-test-notice="default-allow"]'),
|
||||
},
|
||||
filteredByACLs: {
|
||||
see: isPresent('[data-test-notice="filtered-by-acls"]'),
|
||||
},
|
||||
wildcardIntention: {
|
||||
see: isPresent('[data-test-notice="wildcard-intention"]'),
|
||||
},
|
||||
notDefinedIntention: {
|
||||
see: isPresent('[data-test-notice="not-defined-intention"]'),
|
||||
},
|
||||
};
|
||||
page.tabs.upstreamsTab = {
|
||||
services: collection('.consul-upstream-list > ul > li:not(:first-child)', {
|
||||
name: text('[data-test-service-name]'),
|
||||
|
|
|
@ -5,3 +5,6 @@ toggle_menu: Toggle Menu
|
|||
# therefore potentially do not need the word 'navigation' adding to them
|
||||
main: Main
|
||||
complementary: Complementary
|
||||
collapsible-notices:
|
||||
expand: Expand Banners
|
||||
collapse: Collapse Banners
|
Loading…
Reference in New Issue