mirror of https://github.com/status-im/consul.git
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:
parent
2128f40fc2
commit
0807a5ba14
|
@ -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)
|
||||
|
||||
---
|
|
@ -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}}
|
|
@ -0,0 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -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';
|
||||
}
|
||||
});
|
|
@ -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>');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,65 +1,15 @@
|
|||
<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> </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">
|
||||
<p>
|
||||
There are no Lock Sessions for this Node. For more information, view <a href="{{ env 'CONSUL_DOCS_URL'}}/internals/sessions.html" rel="noopener noreferrer" target="_blank">our documentation</a>
|
||||
</p>
|
||||
</BlockSlot>
|
||||
</EmptyState>
|
||||
<EmptyState>
|
||||
<BlockSlot @name="body">
|
||||
<p>
|
||||
There are no Lock Sessions for this Node. For more information, view <a href="{{ env 'CONSUL_DOCS_URL'}}/internals/sessions.html" rel="noopener noreferrer" target="_blank">our documentation</a>
|
||||
</p>
|
||||
</BlockSlot>
|
||||
</EmptyState>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
|
@ -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');
|
||||
});
|
||||
});
|
|
@ -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({
|
||||
TTL: attribute('data-test-session-ttl', '[data-test-session-ttl]'),
|
||||
})
|
||||
),
|
||||
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]', {}),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue