ui: Add simple intention check interface to per service intentions (#8899)
This commit is contained in:
parent
3e89a88aec
commit
80f9d53781
|
@ -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"> </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"> </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>
|
|
|
@ -1,6 +0,0 @@
|
||||||
import Component from '@ember/component';
|
|
||||||
|
|
||||||
export default Component.extend({
|
|
||||||
tagName: '',
|
|
||||||
ondelete: function() {},
|
|
||||||
});
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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}}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,4 @@
|
||||||
|
@import './components';
|
||||||
|
@import './skin';
|
||||||
|
@import './layout';
|
||||||
|
|
|
@ -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"> </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"> </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>
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue