ui: Add simple intention check interface to per service intentions (#8899)

This commit is contained in:
John Cowen 2020-10-09 15:47:36 +01:00 committed by GitHub
parent 3e89a88aec
commit 80f9d53781
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 229 additions and 151 deletions

View File

@ -1,111 +0,0 @@
<DataWriter
@sink={{concat '/' dc '/' nspace '/intention/'}}
@type="intention"
@ondelete={{action ondelete}}
as |writer|>
<BlockSlot @name="content">
{{#if (gt items.length 0)}}
<TabularCollection class="consul-intention-list"
@items={{items}}
@rowHeight={{59}}
as |item index|>
<BlockSlot @name="header">
<th class="source">Source</th>
<th class="intent">&nbsp;</th>
<th class="destination">Destination</th>
<th class="permissions">
Permissions
<span>
<Tooltip>Permissions intercept an Intention's traffic using L7 criteria, such as path prefixes and http headers.</Tooltip>
</span>
</th>
<th class="meta">&nbsp;</th>
</BlockSlot>
<BlockSlot @name="row">
<td class="source" data-test-intention={{item.ID}}>
<a href={{href-to (or routeName 'dc.intentions.edit') item.ID}} data-test-intention-source={{item.SourceName}}>
{{#if (eq item.SourceName '*') }}
All Services (*)
{{else}}
{{item.SourceName}}
{{/if}}
{{! TODO: slugify }}
<em class={{concat 'nspace-' (or item.SourceNS 'default')}}>{{or item.SourceNS 'default'}}</em>
</a>
</td>
{{#let (or item.Action "L7 rules") as |intent|}}
<td class="intent intent-{{slugify intent}}" data-test-intention-action={{intent}}>
<strong>{{capitalize intent}}</strong>
</td>
{{/let}}
<td class="destination" data-test-intention-destination="{{item.DestinationName}}">
<span>
{{#if (eq item.DestinationName '*') }}
All Services (*)
{{else}}
{{item.DestinationName}}
{{/if}}
{{! TODO: slugify }}
<em class={{concat 'nspace-' (or item.DestinationNS 'default')}}>{{or item.DestinationNS 'default'}}</em>
</span>
</td>
<td class="permissions">
{{#if (gt item.Permissions.length 0)}}
<span>{{pluralize item.Permissions.length 'Permission'}}</span>
{{/if}}
</td>
<td class="meta">
{{#if item.IsManagedByCRD}}
<ConsulExternalSource @item={{item}} @label="Managed by CRD" />
{{/if}}
</td>
</BlockSlot>
<BlockSlot @name="actions" as |index change checked|>
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}}>
<BlockSlot @name="trigger">
More
</BlockSlot>
<BlockSlot @name="menu" as |confirm send keypressClick change|>
{{#if item.IsEditable}}
<li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or routeName 'dc.intentions.edit') item.ID}}>Edit</a>
</li>
<li role="none" class="dangerous">
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
<div role="menu">
<div class="confirmation-alert warning">
<div>
<header>
Confirm Delete
</header>
<p>
Are you sure you want to delete this intention?
</p>
</div>
<ul>
<li class="dangerous">
<button tabindex="-1" type="button" class="type-delete" onclick={{queue (action change) (action writer.delete item)}}>Delete</button>
</li>
<li>
<label for={{confirm}}>Cancel</label>
</li>
</ul>
</div>
</div>
</li>
{{else}}
<li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or routeName 'dc.intentions.edit') item.ID}}>View</a>
</li>
{{/if}}
</BlockSlot>
</PopoverMenu>
</BlockSlot>
</TabularCollection>
{{else}}
{{yield}}
{{/if}}
</BlockSlot>
</DataWriter>

View File

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

View File

@ -1,19 +0,0 @@
@import './skin';
@import './layout';
.consul-intention-list td.source,
.consul-intention-list td.destination {
@extend %tbody-th;
}
.consul-intention-list td strong {
@extend %pill-700;
}
.consul-intention-list td.intent-allow strong {
@extend %pill-allow;
}
.consul-intention-list td.intent-deny strong {
@extend %pill-deny;
}
.consul-intention-list td.intent-l7-rules strong {
@extend %pill-l7;
}

View File

@ -0,0 +1,25 @@
{{#let
(from-entries (array
(array 'allow' 'Allowed')
(array 'deny' 'Denied')
(array '' 'L7 Rules')
))
as |titles|}}
<div
class={{concat 'consul-intention-list-check ' 'notice ' (or @item.Action 'permissions')}}
...attributes
>
<h3>
{{get titles (or @item.Action '')}}
</h3>
<p>
{{#if (eq @item.Action 'allow')}}
Yes, {{item.SourceName}} is allowed to connect to {{@item.DestinationName}} due to the highest precedence intention below:
{{else if (eq @item.Action 'deny')}}
No, {{@item.SourceName}} is not allowed to connect to {{@item.DestinationName}} due to the highest precedence intention below:
{{else}}
{{@item.SourceName}} may or may not be allowed to connect with {{@item.DestinationName}} through its L7 rules.
{{/if}}
</p>
</div>
{{/let}}

View File

@ -0,0 +1,27 @@
.consul-intention-list {
td.source,
td.destination {
@extend %tbody-th;
}
td strong {
@extend %pill-700;
}
td.intent-allow strong {
@extend %pill-allow;
}
td.intent-deny strong {
@extend %pill-deny;
}
td.intent-l7-rules strong {
@extend %pill-l7;
}
.notice.allow {
@extend %notice-success;
}
.notice.deny {
@extend %notice-error;
}
.notice.permissions {
@extend %notice-info;
}
}

View File

@ -0,0 +1,27 @@
<div
class="consul-intention-list"
...attributes
>
<DataWriter
@sink={{concat '/' @dc '/' @nspace '/intention/'}}
@type="intention"
@ondelete={{action @ondelete}}
as |writer|>
<BlockSlot @name="content">
{{#let (hash
Check=(component 'consul/intention/list/check')
Table=(component 'consul/intention/list/table' delete=writer.delete items=@items)
) as |api|}}
{{#if (gt @items.length 0)}}
{{yield api to="idle"}}
{{else}}
{{yield api to="empty"}}
{{/if}}
{{/let}}
</BlockSlot>
</DataWriter>
</div>

View File

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

View File

@ -0,0 +1,99 @@
<TabularCollection
class="consul-intention-list-table"
...attributes
@items={{@items}}
@rowHeight={{59}}
as |item index|>
<BlockSlot @name="header">
<th class="source">Source</th>
<th class="intent">&nbsp;</th>
<th class="destination">Destination</th>
<th class="permissions">
Permissions
<span>
<Tooltip>Permissions intercept an Intention's traffic using L7 criteria, such as path prefixes and http headers.</Tooltip>
</span>
</th>
<th class="meta">&nbsp;</th>
</BlockSlot>
<BlockSlot @name="row">
<td class="source" data-test-intention={{item.ID}}>
<a href={{href-to (or @routeName 'dc.intentions.edit') item.ID}} data-test-intention-source={{item.SourceName}}>
{{#if (eq item.SourceName '*') }}
All Services (*)
{{else}}
{{item.SourceName}}
{{/if}}
{{! TODO: slugify }}
<em class={{concat 'nspace-' (or item.SourceNS 'default')}}>{{or item.SourceNS 'default'}}</em>
</a>
</td>
{{#let (or item.Action "L7 rules") as |intent|}}
<td class="intent intent-{{slugify intent}}" data-test-intention-action={{intent}}>
<strong>{{capitalize intent}}</strong>
</td>
{{/let}}
<td class="destination" data-test-intention-destination={{item.DestinationName}}>
<span>
{{#if (eq item.DestinationName '*') }}
All Services (*)
{{else}}
{{item.DestinationName}}
{{/if}}
{{! TODO: slugify }}
<em class={{concat 'nspace-' (or item.DestinationNS 'default')}}>{{or item.DestinationNS 'default'}}</em>
</span>
</td>
<td class="permissions">
{{#if (gt item.Permissions.length 0)}}
<span>{{pluralize item.Permissions.length 'Permission'}}</span>
{{/if}}
</td>
<td class="meta">
{{#if item.IsManagedByCRD}}
<ConsulExternalSource @item={{item}} @label="Managed by CRD" />
{{/if}}
</td>
</BlockSlot>
<BlockSlot @name="actions" as |index change checked|>
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}}>
<BlockSlot @name="trigger">
More
</BlockSlot>
<BlockSlot @name="menu" as |confirm send keypressClick change|>
{{#if item.IsEditable}}
<li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or routeName 'dc.intentions.edit') item.ID}}>Edit</a>
</li>
<li role="none" class="dangerous">
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
<div role="menu">
<div class="confirmation-alert warning">
<div>
<header>
Confirm Delete
</header>
<p>
Are you sure you want to delete this intention?
</p>
</div>
<ul>
<li class="dangerous">
<button tabindex="-1" type="button" class="type-delete" onclick={{queue (action change) (action @delete item)}}>Delete</button>
</li>
<li>
<label for={{confirm}}>Cancel</label>
</li>
</ul>
</div>
</div>
</li>
{{else}}
<li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or @routeName 'dc.intentions.edit') item.ID}}>View</a>
</li>
{{/if}}
</BlockSlot>
</PopoverMenu>
</BlockSlot>
</TabularCollection>

View File

@ -61,7 +61,7 @@
* when convienient * when convienient
**/ **/
@import 'consul-ui/components/consul-intention-list'; @import 'consul-ui/components/consul/intention/list';
@import 'consul-ui/components/consul-intention-form/fieldsets'; @import 'consul-ui/components/consul-intention-form/fieldsets';
@import 'consul-ui/components/consul-intention-permission-list'; @import 'consul-ui/components/consul-intention-permission-list';
@import 'consul-ui/components/consul-intention-permission-form'; @import 'consul-ui/components/consul-intention-permission-form';

View File

@ -17,6 +17,9 @@
@extend %with-cancel-square-fill-color-icon; @extend %with-cancel-square-fill-color-icon;
} }
/**/ /**/
.notice.success {
@extend %notice-success;
}
.notice.warning { .notice.warning {
@extend %notice-warning; @extend %notice-warning;
} }

View File

@ -42,10 +42,14 @@
{{#let (sort-by (comparator 'intention' sort) filtered) as |sorted|}} {{#let (sort-by (comparator 'intention' sort) filtered) as |sorted|}}
<ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}> <ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}>
<BlockSlot @name="content" as |searched|> <BlockSlot @name="content" as |searched|>
<ConsulIntentionList <Consul::Intention::List
@items={{searched}} @items={{searched}}
@ondelete={{refresh-route}} @ondelete={{refresh-route}}
> >
<:idle as |list|>
<list.Table />
</:idle>
<:empty as |list|>
<EmptyState @allowLogin={{true}}> <EmptyState @allowLogin={{true}}>
<BlockSlot @name="header"> <BlockSlot @name="header">
<h2> <h2>
@ -74,7 +78,8 @@
</li> </li>
</BlockSlot> </BlockSlot>
</EmptyState> </EmptyState>
</ConsulIntentionList> </:empty>
</Consul::Intention::List>
</BlockSlot> </BlockSlot>
</ChangeableSet> </ChangeableSet>
{{/let}} {{/let}}

View File

@ -31,19 +31,33 @@
{{#let (sort-by (comparator 'intention' sort) filtered) as |sorted|}} {{#let (sort-by (comparator 'intention' sort) filtered) as |sorted|}}
<ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}> <ChangeableSet @dispatcher={{searchable 'intention' sorted}} @terms={{search}}>
<BlockSlot @name="content" as |searched|> <BlockSlot @name="content" as |searched|>
<ConsulIntentionList
<Consul::Intention::List
@items={{searched}} @items={{searched}}
@ondelete={{refresh-route}} @ondelete={{refresh-route}}
@routeName="dc.services.show.intentions.edit" @routeName="dc.services.show.intentions.edit"
> >
<EmptyState> <:idle as |list|>
<BlockSlot @name="body"> {{#if (eq searched.length 1)}}
<p> {{#let searched.firstObject as |item|}}
There are no intentions {{if (gt items.length 0) 'found '}} for this service. {{#if (eq search item.SourceName)}}
</p> <list.Check @item={{item}} />
</BlockSlot> {{/if}}
</EmptyState> {{/let}}
</ConsulIntentionList> {{/if}}
<list.Table />
</:idle>
<:empty as |list|>
<EmptyState>
<BlockSlot @name="body">
<p>
There are no intentions {{if (gt items.length 0) 'found '}} for this service.
</p>
</BlockSlot>
</EmptyState>
</:empty>
</Consul::Intention::List>
</BlockSlot> </BlockSlot>
</ChangeableSet> </ChangeableSet>
{{/let}} {{/let}}

View File

@ -100,6 +100,7 @@
"ember-load-initializers": "^2.1.1", "ember-load-initializers": "^2.1.1",
"ember-math-helpers": "^2.4.0", "ember-math-helpers": "^2.4.0",
"ember-maybe-import-regenerator": "^0.1.6", "ember-maybe-import-regenerator": "^0.1.6",
"ember-named-blocks-polyfill": "^0.2.3",
"ember-on-helper": "^0.1.0", "ember-on-helper": "^0.1.0",
"ember-page-title": "^5.2.3", "ember-page-title": "^5.2.3",
"ember-power-select": "^4.0.3", "ember-power-select": "^4.0.3",

View File

@ -41,7 +41,7 @@ import tokenListFactory from 'consul-ui/components/token-list/pageobject';
import consulTokenListFactory from 'consul-ui/components/consul-token-list/pageobject'; import consulTokenListFactory from 'consul-ui/components/consul-token-list/pageobject';
import consulRoleListFactory from 'consul-ui/components/consul-role-list/pageobject'; import consulRoleListFactory from 'consul-ui/components/consul-role-list/pageobject';
import consulPolicyListFactory from 'consul-ui/components/consul-policy-list/pageobject'; import consulPolicyListFactory from 'consul-ui/components/consul-policy-list/pageobject';
import consulIntentionListFactory from 'consul-ui/components/consul-intention-list/pageobject'; import consulIntentionListFactory from 'consul-ui/components/consul/intention/list/pageobject';
import consulNspaceListFactory from 'consul-ui/components/consul-nspace-list/pageobject'; import consulNspaceListFactory from 'consul-ui/components/consul-nspace-list/pageobject';
import consulKvListFactory from 'consul-ui/components/consul-kv-list/pageobject'; import consulKvListFactory from 'consul-ui/components/consul-kv-list/pageobject';

View File

@ -6115,6 +6115,15 @@ ember-modifier-manager-polyfill@^1.1.0:
ember-cli-version-checker "^2.1.2" ember-cli-version-checker "^2.1.2"
ember-compatibility-helpers "^1.2.0" ember-compatibility-helpers "^1.2.0"
ember-named-blocks-polyfill@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/ember-named-blocks-polyfill/-/ember-named-blocks-polyfill-0.2.3.tgz#05fb3b40cff98a0d30e8c3b1e3d2155951007d84"
integrity sha512-RrhkgWmfte2lRuOmRWWa7sS2Eo6W3O0VybK0iPhhnLvk7VtUSOmFxuDlhAtEaJ0lBieISrNcmSIZRnmgca/HcA==
dependencies:
ember-cli-babel "^7.19.0"
ember-cli-htmlbars "^4.3.1"
ember-cli-version-checker "^5.1.1"
ember-native-dom-helpers@^0.6.3: ember-native-dom-helpers@^0.6.3:
version "0.6.3" version "0.6.3"
resolved "https://registry.yarnpkg.com/ember-native-dom-helpers/-/ember-native-dom-helpers-0.6.3.tgz#31c88b6eb8e1bb99ee594d19de8f0270d1d5eb35" resolved "https://registry.yarnpkg.com/ember-native-dom-helpers/-/ember-native-dom-helpers-0.6.3.tgz#31c88b6eb8e1bb99ee594d19de8f0270d1d5eb35"