ui: Adds CRD popover 'informed action' for intentions managed by CRDs (#10100)

* ui: Adds CRD popover 'informed action' for intentions add via CRDs
This commit is contained in:
John Cowen 2021-05-04 17:21:54 +01:00 committed by GitHub
parent ed1082510d
commit 4533a5e959
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 90 additions and 5 deletions

3
.changelog/10100.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: Added CRD popover 'informed action' for intentions managed by CRDs
```

View File

@ -129,6 +129,12 @@ export default Component.extend({
}, },
open: function(e) { open: function(e) {
set(this, 'expanded', true); set(this, 'expanded', true);
const $items = [...this.dom.elements(MENU_ITEMS, this.$menu)];
if ($items.length === 0) {
this.dom
.element('input[type="checkbox"]', this.$menu.parentElement)
.dispatchEvent(new MouseEvent('click'));
}
// Take the trigger out of the tabbing whilst the menu is open // Take the trigger out of the tabbing whilst the menu is open
this.$trigger.setAttribute('tabindex', '-1'); this.$trigger.setAttribute('tabindex', '-1');
this._listeners.add(this.dom.document(), { this._listeners.add(this.dom.document(), {

View File

@ -20,6 +20,9 @@
tr > *:last-child { tr > *:last-child {
width: 60px; width: 60px;
} }
.menu-panel.confirmation {
width: 200px;
}
} }
@media #{$--lt-horizontal-nav} { @media #{$--lt-horizontal-nav} {

View File

@ -54,7 +54,10 @@ as |item index|>
</td> </td>
</BlockSlot> </BlockSlot>
<BlockSlot @name="actions" as |index change checked|> <BlockSlot @name="actions" as |index change checked|>
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}}> <PopoverMenu
@expanded={{if (eq checked index) true false}}
@onchange={{action change index}} @keyboardAccess={{false}}
>
<BlockSlot @name="trigger"> <BlockSlot @name="trigger">
More More
</BlockSlot> </BlockSlot>
@ -100,7 +103,38 @@ as |item index|>
</li> </li>
{{else}} {{else}}
<li role="none"> <li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or @routeName 'dc.intentions.edit') item.ID}}>View</a> <div role="menu">
<InformedAction
class="info kubernetes"
>
<:header>
Managed by CRD
</:header>
<:body>
<p>
This intention is being managed through an Intention Custom Resource in your Kubernetes cluster. It is view only in the UI.
</p>
</:body>
<:actions as |Actions|>
<Actions.Action>
<Action
tabindex="-1"
class="action"
@href={{href-to (or @routeName 'dc.intentions.edit') item.ID}}
>
View
</Action>
</Actions.Action>
<Actions.Action>
<Action
@onclick={{action change}}
>
Cancel
</Action>
</Actions.Action>
</:actions>
</InformedAction>
</div>
</li> </li>
{{/if}} {{/if}}
</BlockSlot> </BlockSlot>

View File

@ -66,6 +66,13 @@
background-color: $yellow-050; background-color: $yellow-050;
} }
} }
/* brands */
&.kubernetes {
header::before {
@extend %with-logo-kubernetes-color-icon, %without-mask, %as-pseudo;
}
}
/**/
> ul > .action > * { > ul > .action > * {
color: $blue-500; color: $blue-500;
} }

View File

@ -2,7 +2,14 @@
{{#let (hash {{#let (hash
change=(action "change") change=(action "change")
) as |api|}} ) as |api|}}
<div class="menu-panel {{position}}"> <div
class={{join ' ' (compact (array
'menu-panel'
position
(if isConfirmation 'confirmation')
))}}
{{did-insert (action 'connect')}}
>
<YieldSlot @name="controls"> <YieldSlot @name="controls">
{{yield api}} {{yield api}}
</YieldSlot> </YieldSlot>

View File

@ -1,12 +1,27 @@
import Component from '@ember/component'; import Component from '@ember/component';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { next } from '@ember/runloop';
import { set } from '@ember/object';
import Slotted from 'block-slots'; import Slotted from 'block-slots';
export default Component.extend(Slotted, { export default Component.extend(Slotted, {
tagName: '', tagName: '',
dom: service('dom'), dom: service('dom'),
isConfirmation: false,
actions: { actions: {
connect: function($el) {
next(() => {
// if theres only a single choice in the menu and it doesn't have an
// immediate button/link/label to click then it will be a
// confirmation/informed action
const isConfirmationMenu = this.dom.element(
'li:only-child > [role="menu"]:first-child',
$el
);
set(this, 'isConfirmation', typeof isConfirmationMenu !== 'undefined');
});
},
change: function(e) { change: function(e) {
const id = e.target.getAttribute('id'); const id = e.target.getAttribute('id');
const $trigger = this.dom.element(`[for='${id}']`); const $trigger = this.dom.element(`[for='${id}']`);

View File

@ -9,12 +9,15 @@
transition: min-height 150ms, max-height 150ms; transition: min-height 150ms, max-height 150ms;
min-height: 0; min-height: 0;
} }
%menu-panel [type='checkbox'] ~ * { %menu-panel:not(.confirmation) [type='checkbox'] ~ * {
transition: transform 150ms; transition: transform 150ms;
} }
%menu-panel [type='checkbox']:checked ~ * { %menu-panel [type='checkbox']:checked ~ * {
transform: translateX(calc(-100% - 10px)); transform: translateX(calc(-100% - 10px));
} }
%menu-panel.confirmation [role='menu'] {
min-height: 200px !important;
}
%menu-panel [role='menuitem'] { %menu-panel [role='menuitem'] {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -37,7 +40,8 @@
min-height: 143px; min-height: 143px;
max-height: 143px; max-height: 143px;
} }
%menu-panel [id$='-']:first-child:checked ~ ul label[for$='-'] + [role='menu'] { %menu-panel [id$='-']:first-child:checked ~ ul label[for$='-'] * [role='menu'],
%menu-panel [id$='-']:first-child:checked ~ ul > li > [role='menu'] {
display: block; display: block;
} }
/**/ /**/

View File

@ -1874,3 +1874,9 @@
-webkit-mask-image: $webhook-svg; -webkit-mask-image: $webhook-svg;
mask-image: $webhook-svg; mask-image: $webhook-svg;
} }
%without-mask {
-webkit-mask-image: none;
mask-image: none;
background-color: $transparent !important;
}