ui: Redesign Node Lock Sessions Tab (#8535)

* Add delay svg icon

* Create ConsulLockSessionList component

* Implement ConsulLockSession component in Lock Sessions tab

* Create format-time helper

* Add Invalidate button and fix up styling

* Fixup and add additional tests
This commit is contained in:
Kenia 2020-08-20 10:29:16 -04:00 committed by GitHub
parent 2128f40fc2
commit 0807a5ba14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 256 additions and 64 deletions

View File

@ -0,0 +1,24 @@
## ConsulLockSessionList
```
<ConsulLockSessionList
@items={{items}}
@onInvalidate={{action send 'invalidateSession'}}
/>
```
A presentational component for rendering Node Lock Sessions
### Arguments
| Argument/Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `array` | | An array of Node Lock Sessions |
| `onInvalidate` | `function` | | An action to confirm when the `Invalidate` action is clicked and confirmed |
### See
- [Component Source Code](./index.js)
- [Template Source Code](./index.hbs)
---

View File

@ -0,0 +1,74 @@
{{#if (gt items.length 0)}}
<ListCollection @items={{items}} class="consul-lock-session-list" as |item index|>
<BlockSlot @name="header">
<span>{{item.Name}}</span>
</BlockSlot>
<BlockSlot @name="details">
<dl>
<dt>
<CopyButton
@value={{item.ID}}
@name="ID"
/>
</dt>
<dd>{{item.ID}}</dd>
</dl>
<dl class="lock-delay">
<dt>
<Tooltip>
Delay
</Tooltip>
</dt>
<dd data-test-session-delay>{{format-time item.LockDelay}}</dd>
</dl>
<dl class="ttl">
<dt>
<Tooltip>
TTL
</Tooltip>
</dt>
<dd data-test-session-ttl={{item.TTL}}>{{item.TTL}}</dd>
</dl>
<dl class="behavior">
<dt>
<Tooltip>
Behavior
</Tooltip>
</dt>
<dd>{{item.Behavior}}</dd>
</dl>
<dl class="checks">
<dt>
<Tooltip>
Checks
</Tooltip>
</dt>
<dd>
{{#each item.Checks as |item|}}
<span>{{item}}</span>
{{/each}}
</dd>
</dl>
</BlockSlot>
<BlockSlot @name="actions">
<ConfirmationDialog @message="Are you sure you want to invalidate this session?">
<BlockSlot @name="action" as |confirm|>
<button data-test-delete
type="button"
class="type-delete"
onclick={{queue (action confirm onInvalidate item) (refresh-route)}}
>
Invalidate
</button>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<button type="button" class="type-delete" {{action execute}}>Confirm Invalidate</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
</BlockSlot>
</ConfirmationDialog>
</BlockSlot>
</ListCollection>
{{/if}}

View File

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

View File

@ -0,0 +1,29 @@
import { helper } from '@ember/component/helper';
export default helper(function formatTime([params], hash) {
let day, hour, minute, seconds;
seconds = Math.floor(params / 1000);
minute = Math.floor(seconds / 60);
seconds = seconds % 60;
hour = Math.floor(minute / 60);
minute = minute % 60;
day = Math.floor(hour / 24);
hour = hour % 24;
const time = {
day: day,
hour: hour,
minute: minute,
seconds: seconds,
};
switch (true) {
case time.day !== 0:
return time.day + 'd';
case time.hour !== 0:
return time.hour + 'h';
case time.minute !== 0:
return time.minute + 'm';
default:
return time.seconds + 's';
}
});

View File

@ -39,6 +39,7 @@ $consul-logo-color-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0
$copy-action-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M13.82 3C13.4 1.84 12.3 1 11 1c-1.3 0-2.4.84-2.82 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-9.03-.952V5c0-1.1-.9-2-2-2h-4.18zM9 13H6v2h3v-2zm-3 6h5v-2H6v2zM6 9v2h6V9H6zm5-6c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM4 21V5h2v1.007h10V5h2v5.992h2.003V17H18v4H4zm11.99-3v-3H23v-2h-7.01v-3L12 14l3.99 4z" fill="%23000"/></svg>');
$copy-success-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.82 3C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16.025c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-4.18zM12 3c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 15l-4-4 1.41-1.41L10 15.17l6.59-6.59L18 10l-8 8z" fill="%23000"/></svg>');
$database-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.571 3.429c-3.157 0-5.714.642-5.714 1.428 0 .786 2.557 1.429 5.714 1.429 3.158 0 5.715-.643 5.715-1.429S14.729 3.43 11.57 3.43zm0 7.142C6.843 10.571 3 9.286 3 7.714V4.857C3 3.286 6.843 2 11.571 2c4.729 0 8.572 1.286 8.572 2.857v2.857c0 1.572-3.843 2.857-8.572 2.857zm0 5.715C6.843 16.286 3 15 3 13.429V10.57c0-.157.057-.3.129-.442.042-.086.1-.186.171-.272C4.257 11.086 7.586 12 11.571 12c3.986 0 7.315-.914 8.272-2.143.071.086.128.186.171.272.072.142.129.3.129.442v2.858c0 1.571-3.843 2.857-8.572 2.857zm0 5.714C6.843 22 3 20.714 3 19.143v-2.857c0-.243.129-.486.3-.715.957 1.229 4.286 2.143 8.271 2.143 3.986 0 7.315-.914 8.272-2.143.186.229.3.472.3.715v2.857C20.143 20.714 16.3 22 11.57 22z" fill="%23000"/></svg>');
$delay-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 18.75C15.7279 18.75 18.75 15.7279 18.75 12H21C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3V5.25C8.27208 5.25 5.25 8.27208 5.25 12C5.25 15.7279 8.27208 18.75 12 18.75ZM20.7532 9.89814L18.565 10.4217C18.4822 10.0756 18.3727 9.73993 18.2387 9.41684L20.3171 8.55497C20.4961 8.98676 20.6425 9.43551 20.7532 9.89814ZM19.6749 7.29702L17.7576 8.47443C17.5721 8.17235 17.3633 7.88568 17.1336 7.61701L18.8438 6.15496C19.1495 6.5125 19.4276 6.89428 19.6749 7.29702ZM17.8451 5.15624L16.383 6.86647C16.1144 6.63679 15.8277 6.42798 15.5256 6.24247L16.703 4.32513C17.1058 4.57245 17.4876 4.85058 17.8451 5.15624ZM15.4451 3.68298L14.5832 5.76136C14.2601 5.62738 13.9245 5.51787 13.5784 5.43507L14.1019 3.24683C14.5645 3.35751 15.0133 3.50392 15.4451 3.68298ZM15.0609 14.0147L12.75 12.364V8.25H11.25V12.75V13.136L11.5641 13.3603L14.1891 15.2353L15.0609 14.0147Z" fill="%236F7682"/></svg>');
$deny-alt-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10-2.257 0-4.34.748-6.014 2.01L7.328 5.35a8.125 8.125 0 0 1 11.32 11.32l.264.264-.325.326L6.375 5.049l-.028.028-.755-.755A9.979 9.979 0 0 0 2 12c0 5.523 4.477 10 10 10s10-4.477 10-10zM5.63 6.956l-.005.006-.562-.562-.354.354.615.614a8.125 8.125 0 0 0 11.308 11.308l.805.805.354-.353-.753-.753a.157.157 0 0 0 .006-.005l-2.726-2.726-.006.005-.88-.88.006-.005-2.139-2.139h-.011l-1.25-1.25h.011L5.63 6.955zm7.722 4.419l1.25 1.25h.998l-.502.496.88.88L18 12l-5.053-5-.884.875 3.537 3.5h-2.248zm-4.021 0H6v1.25h4.58l-1.25-1.25zm3.746 3.746l-1.014 1.004.884.875 1.01-.999-.88-.88z" fill="%23000"/></svg>');
$deny-color-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 16 16 " xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="%23282C2E" d="M8.79 4l-.737.71L11 7.556H3V8.57h8l-2.947 2.844.736.711L13 8.062z"/><rect stroke="%23C73445" stroke-width="1.5" x=".75" y=".75" width="14.5" height="14.5" rx="7.25"/><path d="M3.5 3.5l9 9" stroke="%23C73445" stroke-width="1.5" stroke-linecap="square"/></g></svg>');
$deny-default-svg: url('data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12s4.477 10 10 10 10-4.477 10-10zM6.956 5.63A8.125 8.125 0 0 1 18.37 17.044l-2.72-2.72L18 12l-5.053-5-.884.875 3.537 3.5h-2.9L6.957 5.63zM5.63 6.956A8.125 8.125 0 0 0 17.044 18.37l-2.726-2.726L12.948 17l-.885-.875 1.375-1.36-2.139-2.14H6v-1.25h4.05l-4.42-4.42zm8.32 5.669l.821.82.829-.82h-1.65z" fill="%23000"/></svg>');

View File

@ -398,6 +398,16 @@
mask-image: $database-svg;
}
%with-delay-icon {
@extend %with-icon;
background-image: $delay-svg;
}
%with-delay-mask {
@extend %with-mask;
-webkit-mask-image: $delay-svg;
mask-image: $delay-svg;
}
%with-deny-alt-icon {
@extend %with-icon;
background-image: $deny-alt-svg;

View File

@ -13,6 +13,9 @@
.consul-role-list > ul > li:not(:first-child) {
@extend %with-composite-row-intent;
}
.consul-lock-session-list ul > li:not(:first-child) {
@extend %with-one-action-row;
}
/*TODO: This hides the icons-less dt's in the below lists as */
/* they don't have tooltips */
.consul-nspace-list > ul > li:not(:first-child) dt,

View File

@ -12,6 +12,20 @@
/* whilst this isn't in the designs this makes our temporary rollover look better */
padding-left: 12px;
}
%with-one-action-row {
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: 50% 50%;
// only one action applies to these rows
grid-template-areas:
'header actions'
'detail actions';
padding-top: 10px;
padding-bottom: 10px;
padding-right: 12px;
}
%composite-row-header {
grid-area: header;
align-self: start;

View File

@ -106,6 +106,22 @@
@extend %with-protocol-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row-detail dl.lock-delay dt::before {
@extend %with-delay-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row-detail dl.ttl dt::before {
@extend %with-history-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row-detail dl.behavior dt::before {
@extend %with-info-circle-outline-mask, %as-pseudo;
background-color: $gray-500;
}
%composite-row-detail dl.checks dt::before {
@extend %with-health-mask, %as-pseudo;
background-color: $gray-500;
}
// In this case we do not need a background on the icon
%composite-row .combined-address .copy-button button:hover,
%composite-row-detail dt .copy-button button:hover {

View File

@ -1,57 +1,7 @@
<div id="lock-sessions" class="tab-section">
<div role="tabpanel">
{{#if (gt sessions.length 0)}}
<TabularCollection
data-test-sessions
class="sessions"
@items={{sessions}} as |item index|
>
<BlockSlot @name="header">
<th>Name</th>
<th>ID</th>
<th>Delay</th>
<th>TTL</th>
<th>Behavior</th>
<th>Checks</th>
<th>&nbsp;</th>
</BlockSlot>
<BlockSlot @name="row">
<td>
{{item.Name}}
</td>
<td>
{{item.ID}}
</td>
<td>
{{item.LockDelay}}
</td>
<td data-test-session-ttl="{{item.TTL}}">
{{item.TTL}}
</td>
<td>
{{item.Behavior}}
</td>
<td>
{{#if (gt item.Checks.length 0)}}
{{ join ', ' item.Checks}}
{{/if}}
</td>
<td>
<ConfirmationDialog @message="Are you sure you want to invalidate this session?">
<BlockSlot @name="action" as |confirm|>
<button data-test-delete type="button" class="type-delete" onclick={{queue (action confirm 'invalidateSession' item) (refresh-route)}}>Invalidate</button>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<button type="button" class="type-delete" {{action execute}}>Confirm Invalidate</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
</BlockSlot>
</ConfirmationDialog>
</td>
</BlockSlot>
</TabularCollection>
<ConsulLockSessionList @items={{sessions}} @onInvalidate={{action send 'invalidateSession'}}/>
{{else}}
<EmptyState>
<BlockSlot @name="body">

View File

@ -26,3 +26,26 @@ Feature: dc / nodes / sessions / list: List Lock Sessions
- 30s
- 60m
---
Scenario: Given 2 session with LockDelay in milliseconds
Given 1 datacenter model with the value "dc1"
And 1 node model from yaml
---
ID: node-0
---
And 2 session models from yaml
---
- LockDelay: 120000
- LockDelay: 18000000
---
When I visit the node page for yaml
---
dc: dc1
node: node-0
---
And I click lockSessions on the tabs
Then I see lockSessionsIsSelected on the tabs
Then I see delay on the sessions like yaml
---
- 2m
- 5h
---

View File

@ -0,0 +1,26 @@
import { module, skip } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | consul-lock-session-list', function(hooks) {
setupRenderingTest(hooks);
skip('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<ConsulLockSessionList />`);
assert.equal(this.element.textContent.trim(), '');
// Template block usage:
await render(hbs`
<ConsulLockSessionList>
template block text
</ConsulLockSessionList>
`);
assert.equal(this.element.textContent.trim(), 'template block text');
});
});

View File

@ -0,0 +1,17 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Helper | format-time', function(hooks) {
setupRenderingTest(hooks);
// Replace this with your real tests.
test('it renders', async function(assert) {
this.set('inputValue', '7200000');
await render(hbs`{{format-time inputValue}}`);
assert.equal(this.element.textContent.trim(), '2h');
});
});

View File

@ -16,12 +16,12 @@ export default function(visitable, deletable, clickable, attribute, collection,
port: attribute('data-test-service-port', '[data-test-service-port]'),
externalSource: attribute('data-test-external-source', '[data-test-external-source]'),
}),
sessions: collection(
'#lock-sessions [data-test-tabular-row]',
deletable({
sessions: collection('.consul-lock-session-list [data-test-list-row]', {
TTL: attribute('data-test-session-ttl', '[data-test-session-ttl]'),
})
),
delay: text('[data-test-session-delay]'),
actions: clickable('label'),
...deletable(),
}),
metadata: collection('#metadata [data-test-tabular-row]', {}),
};
}