mirror of https://github.com/status-im/consul.git
ui: New Confirmation Dialogs (#7007)
* ui: Change action-group to use new popup-menu component in intentions * ui: Slight amends to aria-menu to prevent scrolling * ui: Begin to use aria-menu/popover-menu for other elements * Use a simpler, hackier method to fix up zIndexing * ui: Implement new confirmation dialogs in other list views (#7080) This includes another amend to the popover-menu in order to allow mutiple confirmations/subpanels in the same popover menu. The functionality added here to allow this is likely to change in the future.
This commit is contained in:
parent
a65d941e76
commit
afafe677a3
|
@ -42,6 +42,7 @@ export default Component.extend({
|
|||
guid: '',
|
||||
expanded: false,
|
||||
orientation: 'vertical',
|
||||
keyboardAccess: true,
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
set(this, 'guid', this.dom.guid(this));
|
||||
|
@ -59,6 +60,9 @@ export default Component.extend({
|
|||
this._listeners.remove();
|
||||
},
|
||||
actions: {
|
||||
keypressClick: function(e) {
|
||||
e.target.dispatchEvent(new MouseEvent('click'));
|
||||
},
|
||||
keypress: function(e) {
|
||||
// If the event is from the trigger and its not an opening/closing
|
||||
// key then don't do anything
|
||||
|
@ -83,6 +87,8 @@ export default Component.extend({
|
|||
if (typeof keys[this.orientation][e.keyCode] === 'undefined') {
|
||||
return;
|
||||
}
|
||||
// prevent any scroll, or default actions
|
||||
e.preventDefault();
|
||||
const $focused = this.dom.element(`${MENU_ITEMS}:focus`, this.$menu);
|
||||
let i;
|
||||
if ($focused) {
|
||||
|
@ -95,11 +101,12 @@ export default Component.extend({
|
|||
},
|
||||
// TODO: The argument here needs to change to an event
|
||||
// see toggle-button.change
|
||||
change: function(open) {
|
||||
change: function(e) {
|
||||
const open = e.target.checked;
|
||||
if (open) {
|
||||
this.actions.open.apply(this, []);
|
||||
this.actions.open.apply(this, [e]);
|
||||
} else {
|
||||
this.actions.close.apply(this, []);
|
||||
this.actions.close.apply(this, [e]);
|
||||
}
|
||||
},
|
||||
close: function(e) {
|
||||
|
@ -127,6 +134,9 @@ export default Component.extend({
|
|||
this.$trigger.dispatchEvent(new MouseEvent('click'));
|
||||
return;
|
||||
}
|
||||
if (!this.keyboardAccess) {
|
||||
return;
|
||||
}
|
||||
this.actions.keypress.apply(this, [e]);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,6 +1,32 @@
|
|||
/*eslint ember/closure-actions: "warn"*/
|
||||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Slotted from 'block-slots';
|
||||
|
||||
export default Component.extend(Slotted, {
|
||||
tagName: '',
|
||||
dom: service('dom'),
|
||||
expanded: false,
|
||||
keyboardAccess: true,
|
||||
onchange: function() {},
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
this.guid = this.dom.guid(this);
|
||||
},
|
||||
actions: {
|
||||
change: function(e) {
|
||||
if (!e.target.checked) {
|
||||
[...this.dom.elements(`[id^=popover-menu-${this.guid}]`)].forEach(function($item) {
|
||||
$item.checked = false;
|
||||
});
|
||||
}
|
||||
this.onchange(e);
|
||||
},
|
||||
// Temporary send here so we can send route actions
|
||||
// easily. It kind of makes sense that you'll want to perform
|
||||
// route actions from a popup menu for the moment
|
||||
send: function() {
|
||||
this.sendAction(...arguments);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,134 +1,38 @@
|
|||
import CollectionComponent from 'ember-collection/components/ember-collection';
|
||||
import needsRevalidate from 'ember-collection/utils/needs-revalidate';
|
||||
import identity from 'ember-collection/utils/identity';
|
||||
import Grid from 'ember-collection/layouts/grid';
|
||||
import SlotsMixin from 'block-slots';
|
||||
import WithResizing from 'consul-ui/mixins/with-resizing';
|
||||
import style from 'ember-computed-style';
|
||||
|
||||
import { inject as service } from '@ember/service';
|
||||
import { computed, get, set } from '@ember/object';
|
||||
/**
|
||||
* Heavily extended `ember-collection` component
|
||||
* This adds support for z-index calculations to enable
|
||||
* Popup menus to pop over either rows above or below
|
||||
* the popup.
|
||||
* Additionally adds calculations for figuring out what the height
|
||||
* of the tabular component should be depending on the other elements
|
||||
* in the page.
|
||||
* Currently everything is here together for clarity, but to be split up
|
||||
* in the future
|
||||
*/
|
||||
import CollectionComponent from 'ember-collection/components/ember-collection';
|
||||
import needsRevalidate from 'ember-collection/utils/needs-revalidate';
|
||||
import Grid from 'ember-collection/layouts/grid';
|
||||
import style from 'ember-computed-style';
|
||||
import SlotsMixin from 'block-slots';
|
||||
import WithResizing from 'consul-ui/mixins/with-resizing';
|
||||
|
||||
// need to copy Cell in wholesale as there is no way to import it
|
||||
// there is no change made to `Cell` here, its only here as its
|
||||
// private in `ember-collection`
|
||||
// TODO: separate both Cell and ZIndexedGrid out
|
||||
class Cell {
|
||||
constructor(key, item, index, style) {
|
||||
this.key = key;
|
||||
this.hidden = false;
|
||||
this.item = item;
|
||||
this.index = index;
|
||||
this.style = style;
|
||||
}
|
||||
}
|
||||
// this is an amount of rows in the table NOT items
|
||||
// unlikely to have 10000 DOM rows ever :)
|
||||
const maxZIndex = 10000;
|
||||
// Adds z-index styling to the default Grid
|
||||
class ZIndexedGrid extends Grid {
|
||||
formatItemStyle(index, w, h, checked) {
|
||||
let style = super.formatItemStyle(index, w, h);
|
||||
// count backwards from maxZIndex
|
||||
let zIndex = maxZIndex - index;
|
||||
// apart from the row that contains an opened dropdown menu
|
||||
// this one should be highest z-index, so use max plus 1
|
||||
if (checked == index) {
|
||||
zIndex = maxZIndex + 1;
|
||||
}
|
||||
style += 'z-index: ' + zIndex;
|
||||
return style;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The tabular-collection can contain 'actions' the UI for which
|
||||
* uses dropdown 'action groups', so a group of different actions.
|
||||
* State makes use of native HTML state using radiogroups
|
||||
* to ensure that only a single dropdown can be open at one time.
|
||||
* Therefore we listen to change events to do anything extra when
|
||||
* a dropdown is opened (the change function is bound to the instance of
|
||||
* the `tabular-component` on init, hoisted here for visibility)
|
||||
*
|
||||
* The extra functionality we have here is to detect whether the opened
|
||||
* dropdown menu would be cut off or not if it 'dropped down'.
|
||||
* If it would be cut off we use CSS to 'drop it up' instead.
|
||||
* We also set this row to have the max z-index here, and mark this
|
||||
* row as the 'checked row' for when a scroll/grid re-calculation is
|
||||
* performed
|
||||
*/
|
||||
const change = function(e) {
|
||||
if (e instanceof MouseEvent) {
|
||||
return;
|
||||
}
|
||||
// TODO: Why am I getting a jQuery event here?!
|
||||
if (e instanceof Event) {
|
||||
const value = e.currentTarget.value;
|
||||
if (value != get(this, 'checked')) {
|
||||
set(this, 'checked', value);
|
||||
// 'actions_close' would mean that all menus have been closed
|
||||
// therefore we don't need to calculate
|
||||
if (e.currentTarget.getAttribute('id') !== 'actions_close') {
|
||||
const dom = get(this, 'dom');
|
||||
const formatItemStyle = Grid.prototype.formatItemStyle;
|
||||
|
||||
const $tr = dom.closest('tr', e.currentTarget);
|
||||
const $group = dom.sibling(e.currentTarget, 'div');
|
||||
const groupRect = $group.getBoundingClientRect();
|
||||
const groupBottom = groupRect.top + $group.clientHeight;
|
||||
|
||||
const $footer = dom.element('footer[role="contentinfo"]');
|
||||
const footerRect = $footer.getBoundingClientRect();
|
||||
const footerTop = footerRect.top;
|
||||
|
||||
if (groupBottom > footerTop) {
|
||||
$group.classList.add('above');
|
||||
} else {
|
||||
$group.classList.remove('above');
|
||||
}
|
||||
$tr.style.zIndex = maxZIndex + 1;
|
||||
}
|
||||
} else {
|
||||
set(this, 'checked', null);
|
||||
}
|
||||
} else if (e.detail && e.detail.index) {
|
||||
if (e.detail.confirming) {
|
||||
this.confirming.push(e.detail.index);
|
||||
} else {
|
||||
const pos = this.confirming.indexOf(e.detail.index);
|
||||
if (pos !== -1) {
|
||||
this.confirming.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
export default CollectionComponent.extend(SlotsMixin, WithResizing, {
|
||||
tagName: 'table',
|
||||
classNames: ['dom-recycling'],
|
||||
classNameBindings: ['hasActions'],
|
||||
attributeBindings: ['style'],
|
||||
dom: service('dom'),
|
||||
style: style('getStyle'),
|
||||
width: 1150,
|
||||
rowHeight: 50,
|
||||
maxHeight: 500,
|
||||
style: style('getStyle'),
|
||||
checked: null,
|
||||
hasCaption: false,
|
||||
dom: service('dom'),
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
this.change = change.bind(this);
|
||||
this.confirming = [];
|
||||
// TODO: The row height should auto calculate properly from the CSS
|
||||
this['cell-layout'] = new ZIndexedGrid(get(this, 'width'), get(this, 'rowHeight'));
|
||||
const o = this;
|
||||
this['cell-layout'] = new Grid(get(this, 'width'), get(this, 'rowHeight'));
|
||||
this['cell-layout'].formatItemStyle = function(itemIndex) {
|
||||
let style = formatItemStyle.apply(this, arguments);
|
||||
if (o.checked === itemIndex) {
|
||||
style = `${style};z-index: 1`;
|
||||
}
|
||||
return style;
|
||||
};
|
||||
},
|
||||
getStyle: computed('rowHeight', '_items', 'maxRows', 'maxHeight', function() {
|
||||
const maxRows = get(this, 'rows');
|
||||
|
@ -144,17 +48,24 @@ export default CollectionComponent.extend(SlotsMixin, WithResizing, {
|
|||
}),
|
||||
resize: function(e) {
|
||||
const $tbody = this.element;
|
||||
const dom = get(this, 'dom');
|
||||
const $appContent = dom.element('main > div');
|
||||
const $appContent = this.dom.element('main > div');
|
||||
if ($appContent) {
|
||||
const border = 1;
|
||||
const rect = $tbody.getBoundingClientRect();
|
||||
const $footer = dom.element('footer[role="contentinfo"]');
|
||||
const $footer = this.dom.element('footer[role="contentinfo"]');
|
||||
const space = rect.top + $footer.clientHeight + border;
|
||||
const height = e.detail.height - space;
|
||||
this.set('maxHeight', Math.max(0, height));
|
||||
// TODO: The row height should auto calculate properly from the CSS
|
||||
this['cell-layout'] = new ZIndexedGrid($appContent.clientWidth, get(this, 'rowHeight'));
|
||||
this['cell-layout'] = new Grid($appContent.clientWidth, get(this, 'rowHeight'));
|
||||
const o = this;
|
||||
this['cell-layout'].formatItemStyle = function(itemIndex) {
|
||||
let style = formatItemStyle.apply(this, arguments);
|
||||
if (o.checked === itemIndex) {
|
||||
style = `${style};z-index: 1`;
|
||||
}
|
||||
return style;
|
||||
};
|
||||
this.updateItems();
|
||||
this.updateScrollPosition();
|
||||
}
|
||||
|
@ -176,113 +87,39 @@ export default CollectionComponent.extend(SlotsMixin, WithResizing, {
|
|||
needsRevalidate(this);
|
||||
}
|
||||
},
|
||||
// need to overwrite this completely so I can pass through the checked index
|
||||
// unfortunately the nicest way I could think to do this is to copy this in wholesale
|
||||
// to add an extra argument for `formatItemStyle` in 3 places
|
||||
// tradeoff between changing as little code as possible in the original code
|
||||
updateCells: function() {
|
||||
if (!this._items) {
|
||||
return;
|
||||
}
|
||||
const numItems = get(this._items, 'length');
|
||||
if (this._cellLayout.length !== numItems) {
|
||||
this._cellLayout.length = numItems;
|
||||
}
|
||||
|
||||
var priorMap = this._cellMap;
|
||||
var cellMap = Object.create(null);
|
||||
|
||||
var index = this._cellLayout.indexAt(
|
||||
this._scrollLeft,
|
||||
this._scrollTop,
|
||||
this._clientWidth,
|
||||
this._clientHeight
|
||||
);
|
||||
var count = this._cellLayout.count(
|
||||
this._scrollLeft,
|
||||
this._scrollTop,
|
||||
this._clientWidth,
|
||||
this._clientHeight
|
||||
);
|
||||
var items = this._items;
|
||||
var bufferBefore = Math.min(index, this._buffer);
|
||||
index -= bufferBefore;
|
||||
count += bufferBefore;
|
||||
count = Math.min(count + this._buffer, get(items, 'length') - index);
|
||||
var i, style, itemIndex, itemKey, cell;
|
||||
|
||||
var newItems = [];
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
itemIndex = index + i;
|
||||
itemKey = identity(items.objectAt(itemIndex));
|
||||
if (priorMap) {
|
||||
cell = priorMap[itemKey];
|
||||
}
|
||||
if (cell) {
|
||||
// additional `checked` argument
|
||||
style = this._cellLayout.formatItemStyle(
|
||||
itemIndex,
|
||||
this._clientWidth,
|
||||
this._clientHeight,
|
||||
this.checked
|
||||
);
|
||||
set(cell, 'style', style);
|
||||
set(cell, 'hidden', false);
|
||||
set(cell, 'key', itemKey);
|
||||
cellMap[itemKey] = cell;
|
||||
} else {
|
||||
newItems.push(itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < this._cells.length; i++) {
|
||||
cell = this._cells[i];
|
||||
if (!cellMap[cell.key]) {
|
||||
if (newItems.length) {
|
||||
itemIndex = newItems.pop();
|
||||
let item = items.objectAt(itemIndex);
|
||||
itemKey = identity(item);
|
||||
// additional `checked` argument
|
||||
style = this._cellLayout.formatItemStyle(
|
||||
itemIndex,
|
||||
this._clientWidth,
|
||||
this._clientHeight,
|
||||
this.checked
|
||||
);
|
||||
set(cell, 'style', style);
|
||||
set(cell, 'key', itemKey);
|
||||
set(cell, 'index', itemIndex);
|
||||
set(cell, 'item', item);
|
||||
set(cell, 'hidden', false);
|
||||
cellMap[itemKey] = cell;
|
||||
} else {
|
||||
set(cell, 'hidden', true);
|
||||
set(cell, 'style', 'height: 0; display: none;');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < newItems.length; i++) {
|
||||
itemIndex = newItems[i];
|
||||
let item = items.objectAt(itemIndex);
|
||||
itemKey = identity(item);
|
||||
// additional `checked` argument
|
||||
style = this._cellLayout.formatItemStyle(
|
||||
itemIndex,
|
||||
this._clientWidth,
|
||||
this._clientHeight,
|
||||
this.checked
|
||||
);
|
||||
cell = new Cell(itemKey, item, itemIndex, style);
|
||||
cellMap[itemKey] = cell;
|
||||
this._cells.pushObject(cell);
|
||||
}
|
||||
this._cellMap = cellMap;
|
||||
},
|
||||
actions: {
|
||||
click: function(e) {
|
||||
return get(this, 'dom').clickFirstAnchor(e);
|
||||
return this.dom.clickFirstAnchor(e);
|
||||
},
|
||||
change: function(index, e = {}) {
|
||||
if (typeof index !== 'string') {
|
||||
return;
|
||||
}
|
||||
if (this.$tr) {
|
||||
this.$tr.style.zIndex = null;
|
||||
}
|
||||
if (e.target.checked && index != get(this, 'checked')) {
|
||||
set(this, 'checked', parseInt(index));
|
||||
const target = e.target;
|
||||
const $tr = this.dom.closest('tr', target);
|
||||
const $group = this.dom.sibling(target, 'div');
|
||||
const groupRect = $group.getBoundingClientRect();
|
||||
const groupBottom = groupRect.top + $group.clientHeight;
|
||||
|
||||
const $footer = this.dom.element('footer[role="contentinfo"]');
|
||||
const footerRect = $footer.getBoundingClientRect();
|
||||
const footerTop = footerRect.top;
|
||||
|
||||
if (groupBottom > footerTop) {
|
||||
$group.classList.add('above');
|
||||
} else {
|
||||
$group.classList.remove('above');
|
||||
}
|
||||
$tr.style.zIndex = 1;
|
||||
this.$tr = $tr;
|
||||
} else {
|
||||
set(this, 'checked', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ export default Component.extend({
|
|||
tagName: '',
|
||||
// TODO: reserved for the moment but we don't need it yet
|
||||
onblur: null,
|
||||
checked: false,
|
||||
onchange: function() {},
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
|
@ -32,6 +33,11 @@ export default Component.extend({
|
|||
click: function(e) {
|
||||
e.preventDefault();
|
||||
this.input.checked = !this.input.checked;
|
||||
// manually dispatched mouse events have a detail = 0
|
||||
// real mouse events have the number of click counts
|
||||
if (e.detail !== 0) {
|
||||
e.target.blur();
|
||||
}
|
||||
this.actions.change.apply(this, [e]);
|
||||
},
|
||||
change: function(e) {
|
||||
|
@ -40,15 +46,19 @@ export default Component.extend({
|
|||
this._listeners.remove();
|
||||
this._listeners.add(this.dom.document(), 'click', e => {
|
||||
if (this.dom.isOutside(this.label, e.target)) {
|
||||
this.input.checked = false;
|
||||
// TODO: This should be an event
|
||||
this.onchange(this.input.checked);
|
||||
this._listeners.remove();
|
||||
if (this.dom.isOutside(this.label.nextElementSibling, e.target)) {
|
||||
if (this.input.checked) {
|
||||
this.input.checked = false;
|
||||
// TODO: This should be an event
|
||||
this.onchange({ target: this.input });
|
||||
}
|
||||
this._listeners.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// TODO: This should be an event
|
||||
this.onchange(this.input.checked);
|
||||
this.onchange({ target: this.input });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,3 +12,9 @@
|
|||
%confirmation-alert > ul > li > * {
|
||||
width: 100%;
|
||||
}
|
||||
%confirmation-alert.warning header::before {
|
||||
margin-right: 5px;
|
||||
}
|
||||
%confirmation-alert.warning header {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
|
|
@ -24,3 +24,14 @@
|
|||
%confirmation-alert > ul > .dangerous > *:focus {
|
||||
@extend %frame-red-700;
|
||||
}
|
||||
%confirmation-alert.warning header {
|
||||
color: $orange-700;
|
||||
}
|
||||
%confirmation-alert.warning header::before {
|
||||
@extend %with-alert-triangle-mask, %as-pseudo;
|
||||
background-color: $yellow-500;
|
||||
margin-right: 5px;
|
||||
}
|
||||
%confirmation-alert p {
|
||||
color: $black;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
|
@ -0,0 +1,7 @@
|
|||
%display-toggle-siblings,
|
||||
%display-toggle-siblings ~ *:not(.animating):not(label) {
|
||||
display: none;
|
||||
}
|
||||
%display-toggle-siblings:checked ~ *:not(label) {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
%display-toggle-siblings ~ label {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
||||
|
||||
%menu-panel > ul > li > * {
|
||||
%menu-panel [role='separator'] {
|
||||
@extend %menu-panel-separator;
|
||||
}
|
||||
%menu-panel > div {
|
||||
@extend %menu-panel-header;
|
||||
}
|
||||
// %menu-panel > ul > li > *:not(div),
|
||||
%menu-panel [role='menuitem'] {
|
||||
@extend %internal-button;
|
||||
}
|
||||
%menu-panel > ul > li.dangerous > * {
|
||||
%menu-panel > ul > li.dangerous > *:not(div) {
|
||||
@extend %internal-button-dangerous;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,30 @@
|
|||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
%menu-panel [type='checkbox'] {
|
||||
display: none;
|
||||
}
|
||||
%menu-panel [type='checkbox'] ~ * {
|
||||
transition: transform 150ms, min-height 150ms, max-height 150ms;
|
||||
min-height: 0;
|
||||
}
|
||||
%menu-panel [type='checkbox']:checked ~ * {
|
||||
transform: translateX(calc(-100% - 10px));
|
||||
/* this needs to autocalculate */
|
||||
/* or be hardcoded */
|
||||
/* min-height: 143px; */
|
||||
}
|
||||
%menu-panel-sub-panel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(100% + 10px);
|
||||
}
|
||||
%menu-panel > ul > li > div[role='menu'] {
|
||||
@extend %menu-panel-sub-panel;
|
||||
}
|
||||
%menu-panel > ul > li > *:not(div[role='menu']) {
|
||||
position: relative;
|
||||
}
|
||||
%menu-panel:not(.left) {
|
||||
right: 0px;
|
||||
}
|
||||
|
@ -12,7 +36,7 @@
|
|||
top: 28px;
|
||||
}
|
||||
%menu-panel.above {
|
||||
bottom: 28px;
|
||||
bottom: 42px;
|
||||
}
|
||||
%menu-panel > ul {
|
||||
margin: 0;
|
||||
|
@ -26,3 +50,37 @@
|
|||
%menu-panel > ul > li > * {
|
||||
text-align: left !important;
|
||||
}
|
||||
%menu-panel-separator {
|
||||
padding-top: 0.35em;
|
||||
}
|
||||
%menu-panel-separator:not(:first-child) {
|
||||
margin-top: 0.35em;
|
||||
}
|
||||
%menu-panel-separator:not(:empty) {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 0.1em;
|
||||
}
|
||||
%menu-panel-header {
|
||||
padding: 10px;
|
||||
padding-left: 36px;
|
||||
}
|
||||
%menu-panel .is-active > *::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
right: 10px;
|
||||
}
|
||||
%menu-panel-header::before {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: calc(10px + 0.1em);
|
||||
}
|
||||
%menu-panel-header {
|
||||
max-width: fit-content;
|
||||
}
|
||||
@supports not (max-width: fit-content) {
|
||||
%menu-panel-header {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,3 +10,23 @@
|
|||
%menu-panel > ul > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
%menu-panel-separator {
|
||||
text-transform: uppercase;
|
||||
color: $gray-400;
|
||||
}
|
||||
%menu-panel-header + ul,
|
||||
%menu-panel-separator:not(:first-child) {
|
||||
border-top: $decor-border-100;
|
||||
border-color: $gray-300;
|
||||
}
|
||||
%menu-panel-header {
|
||||
background-color: $gray-050;
|
||||
}
|
||||
%menu-panel-header::before {
|
||||
@extend %with-info-circle-fill-color-icon, %as-pseudo;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
%menu-panel .is-active > *::after {
|
||||
@extend %with-check-plain-mask, %as-pseudo;
|
||||
background-color: $magenta-600;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@import '../display-toggle/index';
|
||||
@import '../toggle-button/index';
|
||||
@import '../menu-panel/index';
|
||||
@import '../confirmation-alert/index';
|
||||
@import './skin';
|
||||
@import './layout';
|
|
@ -0,0 +1,25 @@
|
|||
%more-popover-menu {
|
||||
@extend %display-toggle-siblings;
|
||||
}
|
||||
%more-popover-menu + label > * {
|
||||
@extend %toggle-button;
|
||||
}
|
||||
%more-popover-menu-panel {
|
||||
@extend %menu-panel;
|
||||
width: 192px;
|
||||
}
|
||||
%more-popover-menu + label + div {
|
||||
@extend %more-popover-menu-panel;
|
||||
}
|
||||
%more-popover-menu-panel:not(.above) {
|
||||
top: 38px;
|
||||
}
|
||||
%more-popover-menu-panel:not(.left) {
|
||||
right: 10px;
|
||||
}
|
||||
%more-popover-menu-panel li [role='menu'] {
|
||||
display: none;
|
||||
}
|
||||
%more-popover-menu-panel [id$='-']:first-child:checked ~ ul label[for$='-'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
%more-popover-menu + label > *::after {
|
||||
@extend %with-more-horizontal-icon, %as-pseudo;
|
||||
opacity: 0.7;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
%more-popover-menu + label > * {
|
||||
font-size: 0;
|
||||
}
|
|
@ -17,6 +17,10 @@
|
|||
@extend %with-icon;
|
||||
background-image: $alert-triangle-svg;
|
||||
}
|
||||
%with-alert-triangle-mask {
|
||||
@extend %with-mask;
|
||||
mask-image: $alert-triangle-svg;
|
||||
}
|
||||
|
||||
%with-arrow-down-icon {
|
||||
@extend %with-icon;
|
||||
|
|
|
@ -1,6 +1,32 @@
|
|||
@import './app-view/index';
|
||||
@import './filter-bar/index';
|
||||
@import '../base/components/buttons/index';
|
||||
|
||||
@import '../base/components/popover-menu/index';
|
||||
|
||||
%app-view-header .actions > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%more-popover-menu-panel [type='checkbox']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 143px;
|
||||
max-height: 143px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 163px;
|
||||
max-height: 163px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='delete']:checked ~ ul label[for$='delete'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ ul label[for$='logout'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='use']:checked ~ ul label[for$='use'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
||||
%app-view-header .actions label + div {
|
||||
// We need this extra to allow tooltips to show
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
main {
|
||||
@extend %app-view;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import './form-elements';
|
||||
@import './breadcrumbs';
|
||||
@import './anchors';
|
||||
@import './progress';
|
||||
|
@ -24,7 +25,6 @@
|
|||
@import './phrase-editor';
|
||||
@import './filter-bar';
|
||||
@import './tomography-graph';
|
||||
@import './action-group';
|
||||
@import './flash-message';
|
||||
@import './code-editor';
|
||||
@import './confirmation-dialog';
|
||||
|
|
|
@ -21,10 +21,3 @@
|
|||
%main-nav-horizontal-drop-nav {
|
||||
@extend %menu-panel;
|
||||
}
|
||||
/*TODO: %menu-panel? */
|
||||
%main-nav-horizontal-drop-nav [role='separator'] {
|
||||
@extend %main-nav-horizontal-drop-nav-separator;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav > div {
|
||||
@extend %main-nav-horizontal-drop-nav-header;
|
||||
}
|
||||
|
|
|
@ -1,64 +1,27 @@
|
|||
%main-nav-horizontal > ul > li,
|
||||
%main-nav-horizontal-drop-nav a {
|
||||
position: relative;
|
||||
}
|
||||
%main-nav-horizontal [type='checkbox'] ~ div {
|
||||
display: none;
|
||||
}
|
||||
%main-nav-horizontal [type='checkbox']:checked ~ div {
|
||||
display: block;
|
||||
}
|
||||
%main-nav-horizontal [type='checkbox'] + label > * {
|
||||
/* less space as the chevron adds space */
|
||||
padding-right: 4px !important;
|
||||
}
|
||||
%main-nav-horizontal > ul > li {
|
||||
position: relative;
|
||||
}
|
||||
%main-nav-horizontal-action {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
%main-nav-horizontal input + label > * {
|
||||
/* less space as the chevron adds space */
|
||||
padding-right: 4px !important;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav {
|
||||
z-index: 400;
|
||||
/* TODO: We should probably make menu-panel default to left hand side*/
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
/* TODO: Revisit this once its part of menu-panel as its probably */
|
||||
/* a property of that */
|
||||
%main-nav-horizontal-drop-nav-separator:not(:empty) {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 0.1em;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-separator {
|
||||
padding-top: 0.35em;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-separator:not(:first-child) {
|
||||
margin-top: 0.35em;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header {
|
||||
padding: 10px;
|
||||
padding-left: 36px;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header::before {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: calc(10px + 0.1em);
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header {
|
||||
max-width: fit-content;
|
||||
}
|
||||
@supports not (max-width: fit-content) {
|
||||
%main-nav-horizontal-drop-nav-header {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
%main-nav-horizontal-drop-nav .is-active > *::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
right: 10px;
|
||||
}
|
||||
@media #{$--lt-horizontal-nav} {
|
||||
%main-nav-horizontal-panel label span {
|
||||
visibility: visible !important;
|
||||
|
@ -120,9 +83,7 @@
|
|||
}
|
||||
%main-nav-horizontal-drop-nav {
|
||||
width: 180px;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header {
|
||||
text-align: left;
|
||||
top: 38px !important;
|
||||
}
|
||||
%main-nav-horizontal input + label > * {
|
||||
right: -15px;
|
||||
|
@ -132,9 +93,6 @@
|
|||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav {
|
||||
top: 38px !important;
|
||||
}
|
||||
}
|
||||
@media #{$--horizontal-nav} {
|
||||
%main-nav-horizontal-panel {
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
%main-nav-horizontal input {
|
||||
display: none;
|
||||
}
|
||||
%main-nav-horizontal input + label > *::after {
|
||||
%main-nav-horizontal [type='checkbox'] + label > *::after {
|
||||
@extend %as-pseudo;
|
||||
@extend %with-chevron-down-mask;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
background-color: $white;
|
||||
}
|
||||
%main-nav-horizontal input:checked + label > *::after {
|
||||
%main-nav-horizontal [type='checkbox']:checked + label > *::after {
|
||||
@extend %with-chevron-up-mask;
|
||||
}
|
||||
%main-nav-horizontal-toggle-button span {
|
||||
|
@ -57,23 +57,3 @@
|
|||
}
|
||||
}
|
||||
/**/
|
||||
%main-nav-horizontal-drop-nav-header {
|
||||
background-color: $gray-050;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-separator {
|
||||
text-transform: uppercase;
|
||||
color: $gray-400;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav .is-active > *::after {
|
||||
@extend %with-check-plain-mask, %as-pseudo;
|
||||
background-color: $magenta-600;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header + ul,
|
||||
%main-nav-horizontal-drop-nav-separator:not(:first-child) {
|
||||
border-top: $decor-border-100;
|
||||
border-color: $gray-300;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-header::before {
|
||||
@extend %with-info-circle-fill-color-icon, %as-pseudo;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
@import '../base/components/table/index';
|
||||
@import '../base/components/popover-menu/index';
|
||||
table {
|
||||
@extend %table, %table-flex;
|
||||
}
|
||||
|
||||
%table-actions > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%table-actions .confirmation-alert {
|
||||
@extend %confirmation-alert;
|
||||
}
|
||||
%table-actions > [type='checkbox'] + label {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
html.template-service.template-list td:first-child a span,
|
||||
html.template-node.template-show #services td:first-child a span,
|
||||
html.template-service.template-show #instances td:first-child a span {
|
||||
|
|
|
@ -19,6 +19,7 @@ fieldset > header,
|
|||
%app-view-content div > dl > dt,
|
||||
%table caption,
|
||||
%tbody-th,
|
||||
%confirmation-alert header,
|
||||
%form-element > span {
|
||||
@extend %h4;
|
||||
}
|
||||
|
@ -50,7 +51,7 @@ pre code,
|
|||
%form-element-label,
|
||||
%stats-card header a span,
|
||||
%footer,
|
||||
%main-nav-horizontal-drop-nav > div,
|
||||
%menu-panel-header,
|
||||
%app-view h1 span.kind-proxy {
|
||||
@extend %p2;
|
||||
}
|
||||
|
@ -59,7 +60,7 @@ pre code,
|
|||
%main-content p,
|
||||
%app-view > div.disabled > div,
|
||||
%form-element-note,
|
||||
%main-nav-horizontal-drop-nav-separator,
|
||||
%menu-panel-separator,
|
||||
%form-element-error > strong {
|
||||
@extend %p3;
|
||||
}
|
||||
|
@ -81,7 +82,7 @@ pre code,
|
|||
%splitter-card > header {
|
||||
font-weight: $typo-weight-bold;
|
||||
}
|
||||
%main-nav-horizontal-drop-nav-separator {
|
||||
%menu-panel-separator {
|
||||
font-weight: $typo-weight-medium;
|
||||
}
|
||||
/**/
|
||||
|
|
|
@ -1 +1,8 @@
|
|||
{{yield (action 'change') (action 'keypress') (concat 'component-aria-menu-trigger-' guid) (concat 'component-aria-menu-menu-' guid) (if expanded 'true' undefined)}}
|
||||
{{yield
|
||||
(action 'change')
|
||||
(action 'keypress')
|
||||
(concat 'component-aria-menu-trigger-' guid)
|
||||
(concat 'component-aria-menu-menu-' guid)
|
||||
(if expanded 'true' undefined)
|
||||
(action 'keypressClick')
|
||||
}}
|
|
@ -1,21 +1,25 @@
|
|||
{{yield}}
|
||||
{{#aria-menu as |change keydown ariaLabelledBy ariaControls expanded|}}
|
||||
{{#toggle-button onchange=change as |click|}}
|
||||
<button type="button" aria-haspopup="menu" onkeydown={{keydown}} onclick={{click}} id={{ariaLabelledBy}} aria-controls={{ariaControls}}>
|
||||
{{yield (concat 'popover-menu-' guid)}}
|
||||
{{#aria-menu keyboardAccess=keyboardAccess as |change keypress ariaLabelledBy ariaControls ariaExpanded keypressClick|}}
|
||||
{{#toggle-button checked=expanded onchange=(queue change (action 'change')) as |click|}}
|
||||
<button type="button" aria-haspopup="menu" onkeydown={{keypress}} onclick={{click}} id={{ariaLabelledBy}} aria-controls={{ariaControls}}>
|
||||
{{#yield-slot name='trigger'}}
|
||||
{{yield}}
|
||||
{{/yield-slot}}
|
||||
</button>
|
||||
{{/toggle-button}}
|
||||
<div>
|
||||
<input type="checkbox" id={{concat 'popover-menu-' guid '-'}} />
|
||||
{{#each submenus as |sub|}}
|
||||
<input type="checkbox" id={{concat 'popover-menu-' guid '-' sub}} />
|
||||
{{/each}}
|
||||
{{#yield-slot name='header'}}
|
||||
<div>
|
||||
{{yield}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{/yield-slot}}
|
||||
<ul role="menu" id={{ariaControls}} aria-labelledby={{ariaLabelledBy}} aria-expanded={{expanded}}>
|
||||
{{#yield-slot name='menu'}}
|
||||
<ul role="menu" id={{ariaControls}} aria-labelledby={{ariaLabelledBy}} aria-expanded={{ariaExpanded}}>
|
||||
{{#yield-slot name='menu' params=(block-params (concat 'popover-menu-' guid '-') send keypressClick) }}
|
||||
{{yield}}
|
||||
{{/yield-slot}}
|
||||
</ul>
|
||||
|
|
|
@ -82,25 +82,40 @@
|
|||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message="Are you sure you want to remove this Role?"}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.roles.edit' item.ID}}>Edit</a>
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a role="menuitem" tabindex="-1" href={{href-to 'dc.acls.roles.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Remove</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm Remove
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to remove this role?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'remove' item items}}>Remove</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'remove' item items}}>Remove</button>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
{{delete-confirmation message=message execute=execute cancel=cancel}}
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
|
||||
{{/block-slot}}
|
||||
{{/child-selector}}
|
||||
|
|
|
@ -3,23 +3,25 @@
|
|||
<caption>{{#yield-slot name='caption'}}{{yield}}{{/yield-slot}}</caption>
|
||||
{{/if}}
|
||||
<thead>
|
||||
<tr>
|
||||
{{#yield-slot name='header'}}{{yield}}{{/yield-slot}}
|
||||
<tr>
|
||||
{{#yield-slot name='header'}}{{yield}}{{/yield-slot}}
|
||||
{{#if hasActions }}
|
||||
<th class="actions">Actions<input type="radio" name="actions" id="actions_close" onchange={{action change}} value="" /></th>
|
||||
<th class="actions">Actions</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#ember-native-scrollable tagName='tbody' content-size=_contentSize scroll-left=_scrollLeft scroll-top=_scrollTop scrollChange=(action "scrollChange") clientSizeChange=(action "clientSizeChange")}}
|
||||
<tr></tr>
|
||||
{{#ember-native-scrollable tagName='tbody' content-size=_contentSize scroll-left=_scrollLeft scroll-top=_scrollTop scrollChange=(action 'scrollChange') clientSizeChange=(action "clientSizeChange")}}
|
||||
<tr></tr>
|
||||
{{~#each _cells as |cell index|~}}
|
||||
<tr data-test-tabular-row style={{{cell.style}}} onclick={{action 'click'}}>
|
||||
{{#yield-slot name='row'}}{{yield cell.item index}}{{/yield-slot}}
|
||||
<tr data-test-tabular-row style={{{cell.style}}} onclick={{action 'click'}}>
|
||||
{{#yield-slot name='row'}}{{yield cell.item index}}{{/yield-slot}}
|
||||
{{#if hasActions }}
|
||||
<td class="actions">
|
||||
{{#yield-slot name='actions' params=(block-params (concat index) change checked)}}{{yield cell.item index}}{{/yield-slot}}
|
||||
</td>
|
||||
<td class="actions">
|
||||
{{#yield-slot name='actions' params=(block-params (concat cell.index) (action 'change') checked)}}
|
||||
{{yield cell.item index}}
|
||||
{{/yield-slot}}
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</tr>
|
||||
{{~/each~}}
|
||||
{{/ember-native-scrollable}}
|
|
@ -1,4 +1,4 @@
|
|||
<input type="checkbox" id={{concat 'toggle-button-' guid}} onchange={{action 'change'}} />
|
||||
<input type="checkbox" checked={{if checked 'checked' undefined}} id={{concat 'toggle-button-' guid}} onchange={{action 'change'}} />
|
||||
<label for={{concat 'toggle-button-' guid}}>
|
||||
{{yield (action 'click')}}
|
||||
</label>
|
|
@ -1,102 +1,144 @@
|
|||
{{#app-view class="acl list" loading=isLoading}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
ACL Tokens <em>{{format-number items.length}} total</em>
|
||||
</h1>
|
||||
<label for="toolbar-toggle"></label>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='toolbar'}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
ACL Tokens <em>{{format-number items.length}} total</em>
|
||||
</h1>
|
||||
<label for="toolbar-toggle"></label>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='toolbar'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
{{acl-filter searchable=searchable filters=typeFilters search=filters.s type=filters.type onchange=(action 'filter')}}
|
||||
{{acl-filter searchable=searchable filters=typeFilters search=filters.s type=filters.type onchange=(action 'filter')}}
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'Name:asc' filtered) as |item index|
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'Name:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-acl="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.edit' item.ID}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{#if (eq item.Type 'management')}}
|
||||
<strong>{{item.Type}}</strong>
|
||||
{{else}}
|
||||
<span>{{item.Type}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#popover-menu
|
||||
expanded=(if (eq checked index) true false)
|
||||
onchange=(action change index)
|
||||
keyboardAccess=false
|
||||
submenus=(array 'logout' 'use' 'delete')
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-acl="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.edit' item.ID}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{#if (eq item.Type 'management')}}
|
||||
<strong>{{item.Type}}</strong>
|
||||
{{else}}
|
||||
<span>{{item.Type}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (eq item.ID token.SecretID) }}
|
||||
<li>
|
||||
<button type="button" data-test-logout {{action confirm 'logout' item}}>Stop using</button>
|
||||
</li>
|
||||
{{else}}
|
||||
|
||||
<li>
|
||||
<button type="button" data-test-use {{action confirm 'use' item}}>Use</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
<button type="button" data-test-clone {{action 'sendClone' item}}>Clone</button>
|
||||
</li>
|
||||
{{# if (not-eq item.ID 'anonymous') }}
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
<p>
|
||||
{{#if (eq name 'delete')}}
|
||||
Are you sure you want to delete this ACL token?
|
||||
{{else if (eq name 'logout')}}
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
{{ else if (eq name 'use')}}
|
||||
Are you sure you want to use this ACL token?
|
||||
{{/if}}
|
||||
</p>
|
||||
<button type="button" class="type-delete" {{action execute}}>
|
||||
{{#if (eq name 'delete')}}
|
||||
Confirm Delete
|
||||
{{else if (eq name 'logout')}}
|
||||
Confirm Logout
|
||||
{{ else if (eq name 'use')}}
|
||||
Confirm Use
|
||||
{{/if}}
|
||||
</button>
|
||||
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (eq item.ID token.SecretID) }}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Stop using</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm logout
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" onclick={{action send 'logout' item}}>Logout</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{else}}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm use
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to use this ACL token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button data-test-confirm-use tabindex="-1" type="button" onclick={{action send 'use' item}}>Use</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li role="none">
|
||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action 'sendClone' item}}>Duplicate</button>
|
||||
</li>
|
||||
{{# if (not-eq item.ID 'anonymous') }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'delete'}} 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 token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no ACLs.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no ACLs.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/app-view}}
|
|
@ -1,84 +1,100 @@
|
|||
{{#app-view class=(concat 'policy ' (if (not isAuthorized) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/policies/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='disabled'}}
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='authorization'}}
|
||||
{{partial 'dc/acls/authorization'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.policies.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'CreateIndex:desc' 'Name:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Datacenters</th>
|
||||
<th>Description</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-policy="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.policies.edit' item.ID}} class={{if (eq (policy/typeof item) 'policy-management') 'is-management'}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{join ', ' (policy/datacenters item)}}
|
||||
</td>
|
||||
<td data-test-description>
|
||||
<p>{{item.Description}}</p>
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Policy?"}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
{{#if (eq (policy/typeof item) 'policy-management')}}
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.policies.edit' item.ID}}>View</a>
|
||||
</li>
|
||||
{{else}}
|
||||
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.policies.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/policies/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
{{delete-confirmation message=message execute=execute cancel=cancel}}
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='disabled'}}
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='authorization'}}
|
||||
{{partial 'dc/acls/authorization'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.policies.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'CreateIndex:desc' 'Name:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Datacenters</th>
|
||||
<th>Description</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Policies.
|
||||
</p>
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-policy="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.policies.edit' item.ID}} class={{if (eq (policy/typeof item) 'policy-management') 'is-management'}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{join ', ' (policy/datacenters item)}}
|
||||
</td>
|
||||
<td data-test-description>
|
||||
<p>{{item.Description}}</p>
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
{{#if (eq (policy/typeof item) 'policy-management')}}
|
||||
<li role="none">
|
||||
<a role="menuitem" tabindex="-1" data-test-edit href={{href-to 'dc.acls.policies.edit' item.ID}}>View</a>
|
||||
</li>
|
||||
{{else}}
|
||||
|
||||
<li role="none">
|
||||
<a role="menuitem" tabindex="-1" data-test-edit href={{href-to 'dc.acls.policies.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 policy?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Policies.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/app-view}}
|
|
@ -1,79 +1,95 @@
|
|||
{{#app-view class=(concat 'role ' (if (not isAuthorized) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/roles/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='disabled'}}
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='authorization'}}
|
||||
{{partial 'dc/acls/authorization'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.roles.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/acls/roles/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
Access Controls
|
||||
</h1>
|
||||
{{#if isAuthorized }}
|
||||
{{partial 'dc/acls/nav'}}
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='disabled'}}
|
||||
{{partial 'dc/acls/disabled'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='authorization'}}
|
||||
{{partial 'dc/acls/authorization'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
<a data-test-create href="{{href-to 'dc.acls.roles.create'}}" class="type-create">Create</a>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search"}}
|
||||
</form>
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'CreateIndex:desc' 'Name:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Policies</th>
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'CreateIndex:desc' 'Name:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Policies</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-role="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.roles.edit' item.ID}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td data-test-description>
|
||||
<p>{{item.Description}}</p>
|
||||
</td>
|
||||
<td>
|
||||
{{#each item.Policies as |item|}}
|
||||
<strong data-test-policy class={{policy/typeof item}}>{{item.Name}}</strong>
|
||||
{{/each}}
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-role="{{item.Name}}">
|
||||
<a href={{href-to 'dc.acls.roles.edit' item.ID}}>{{item.Name}}</a>
|
||||
</td>
|
||||
<td data-test-description>
|
||||
<p>{{item.Description}}</p>
|
||||
</td>
|
||||
<td>
|
||||
{{#each item.Policies as |item|}}
|
||||
<strong data-test-policy class={{policy/typeof item}}>{{item.Name}}</strong>
|
||||
{{/each}}
|
||||
</td>
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a role="menuitem" tabindex="-1" href={{href-to 'dc.acls.roles.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 role?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Role?"}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.roles.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
{{delete-confirmation message=message execute=execute cancel=cancel}}
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Roles.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Roles.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/app-view}}
|
|
@ -64,66 +64,100 @@
|
|||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Token?"}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
{{#if false}}
|
||||
<li>
|
||||
{{#copy-button-feedback title="Copy AccessorID to the clipboard" copy=item.AccessorID name="AccessorID"}}Copy AccessorID{{/copy-button-feedback}}
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>Edit</a>
|
||||
</li>
|
||||
{{#popover-menu
|
||||
expanded=(if (eq checked index) true false)
|
||||
onchange=(action change index)
|
||||
keyboardAccess=false
|
||||
submenus=(array 'logout' 'use' 'delete')
|
||||
}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (not (token/is-legacy item))}}
|
||||
<li>
|
||||
<button type="button" data-test-clone {{action 'sendClone' item}}>Duplicate</button>
|
||||
</li>
|
||||
<li role="none">
|
||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action 'sendClone' item}}>Duplicate</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (eq item.AccessorID token.AccessorID) }}
|
||||
<li>
|
||||
<button type="button" data-test-logout {{action confirm 'logout' item}}>Stop using</button>
|
||||
</li>
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Stop using</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm logout
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" onclick={{action send 'logout' item}}>Logout</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{else}}
|
||||
|
||||
<li>
|
||||
<button type="button" data-test-use {{action confirm 'use' item}}>Use</button>
|
||||
</li>
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm use
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to use this ACL token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button data-test-confirm-use tabindex="-1" type="button" onclick={{action send 'use' item}}>Use</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#unless (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)) }}
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'delete'}} 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 token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/unless}}
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
<p>
|
||||
{{#if (eq name 'delete')}}
|
||||
{{message}}
|
||||
{{#if (eq item.AccessorID token.AccessorID)}}
|
||||
Warning: This is the token you are currently using!
|
||||
{{/if}}
|
||||
{{else if (eq name 'logout')}}
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
{{else if (eq name 'use')}}
|
||||
Are you sure you want to use this ACL token?
|
||||
{{/if}}
|
||||
</p>
|
||||
<button type="button" class="type-delete" {{action execute}}>
|
||||
{{#if (eq name 'delete')}}
|
||||
Confirm Delete
|
||||
{{else if (eq name 'logout')}}
|
||||
Confirm Logout
|
||||
{{ else if (eq name 'use')}}
|
||||
Confirm Use
|
||||
{{/if}}
|
||||
</button>
|
||||
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
|
|
|
@ -61,23 +61,39 @@
|
|||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message='Are you sure you want to delete this intention?'}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a href={{href-to 'dc.intentions.edit' item.ID}}>Edit</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message|}}
|
||||
{{delete-confirmation message=message execute=execute cancel=cancel}}
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a role="menuitem" tabindex="-1" href={{href-to '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={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
|
|
|
@ -1,81 +1,97 @@
|
|||
{{#app-view class="kv list" loading=isLoading}}
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/kv/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='breadcrumbs'}}
|
||||
<ol>
|
||||
{{#block-slot name='notification' as |status type|}}
|
||||
{{partial 'dc/kv/notifications'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='breadcrumbs'}}
|
||||
<ol>
|
||||
{{#if (not-eq parent.Key '/') }}
|
||||
<li><a href={{href-to 'dc.kv'}}>Key / Values</a></li>
|
||||
<li><a href={{href-to 'dc.kv'}}>Key / Values</a></li>
|
||||
{{/if}}
|
||||
{{#each (slice 0 -2 (split parent.Key '/')) as |breadcrumb index|}}
|
||||
<li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li>
|
||||
<li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
{{#if (eq parent.Key '/') }}
|
||||
Key / Value
|
||||
{{else}}
|
||||
{{ take 1 (drop 1 (reverse (split parent.Key '/'))) }}
|
||||
{{/if}}
|
||||
</h1>
|
||||
<label for="toolbar-toggle"></label>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='toolbar'}}
|
||||
</ol>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='header'}}
|
||||
<h1>
|
||||
{{#if (eq parent.Key '/')}}
|
||||
Key / Value
|
||||
{{else}}
|
||||
{{take 1 (drop 1 (reverse (split parent.Key '/')))}}
|
||||
{{/if}}
|
||||
</h1>
|
||||
<label for="toolbar-toggle"></label>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='toolbar'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search by name"}}
|
||||
</form>
|
||||
<form class="filter-bar">
|
||||
{{freetext-filter searchable=searchable value=s placeholder="Search by name"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions'}}
|
||||
{{#if (not-eq parent.Key '/') }}
|
||||
<a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
|
||||
<a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
|
||||
{{else}}
|
||||
<a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
|
||||
<a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'isFolder:desc' 'Key:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-kv="{{item.Key}}" class={{if item.isFolder 'folder' 'file' }}>
|
||||
<a href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{right-trim (left-trim item.Key parent.Key) '/'}}</a>
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message='Are you sure you want to delete this key?'}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a data-test-edit href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{if item.isFolder 'View' 'Edit'}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message|}}
|
||||
{{delete-confirmation message=message execute=execute cancel=cancel}}
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='content'}}
|
||||
{{#changeable-set dispatcher=searchable}}
|
||||
{{#block-slot name='set' as |filtered|}}
|
||||
{{#tabular-collection
|
||||
items=(sort-by 'isFolder:desc' 'Key:asc' filtered) as |item index|
|
||||
}}
|
||||
{{#block-slot name='header'}}
|
||||
<th>Name</th>
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Key / Value pairs.
|
||||
</p>
|
||||
{{#block-slot name='row'}}
|
||||
<td data-test-kv={{item.Key}} class={{if item.isFolder 'folder' 'file' }}>
|
||||
<a href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{right-trim (left-trim item.Key parent.Key) '/'}}</a>
|
||||
</td>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{if item.isFolder 'View' '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 key?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='empty'}}
|
||||
<p>
|
||||
There are no Key / Value pairs.
|
||||
</p>
|
||||
{{/block-slot}}
|
||||
{{/changeable-set}}
|
||||
{{/block-slot}}
|
||||
{{/app-view}}
|
|
@ -52,31 +52,39 @@
|
|||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='actions' as |index change checked|}}
|
||||
{{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Namespace?"}}
|
||||
{{#block-slot name='action' as |confirm|}}
|
||||
{{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
|
||||
<ul>
|
||||
<li>
|
||||
<a data-test-edit href={{href-to 'dc.nspaces.edit' item.Name}}>Edit</a>
|
||||
</li>
|
||||
{{#if (not-eq item.Name 'default')}}
|
||||
<li>
|
||||
<button type="button" class="type-delete" data-test-delete {{action confirm 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{/action-group}}
|
||||
{{#popover-menu expanded=(if (eq checked index) true false) onchange=(action change index) keyboardAccess=false}}
|
||||
{{#block-slot name='trigger'}}
|
||||
More
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='dialog' as |execute cancel message name|}}
|
||||
<p>
|
||||
{{message}}
|
||||
</p>
|
||||
<button type="button" class="type-delete" {{action execute}}>
|
||||
Confirm Delete
|
||||
</button>
|
||||
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
|
||||
{{#block-slot name='menu' as |confirm send keypressClick|}}
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.nspaces.edit' item.Name}}>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 key?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{confirm}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/block-slot}}
|
||||
{{/confirmation-dialog}}
|
||||
{{/popover-menu}}
|
||||
{{/block-slot}}
|
||||
{{/tabular-collection}}
|
||||
{{/block-slot}}
|
||||
|
|
|
@ -8,7 +8,7 @@ export default function(visitable, deletable, creatable, clickable, attribute, c
|
|||
acl: clickable('a'),
|
||||
actions: clickable('label'),
|
||||
use: clickable('[data-test-use]'),
|
||||
confirmUse: clickable('button.type-delete'),
|
||||
confirmUse: clickable('[data-test-confirm-use]'),
|
||||
})
|
||||
),
|
||||
filter: filter,
|
||||
|
|
|
@ -24,7 +24,7 @@ export default function(
|
|||
token: clickable('a'),
|
||||
actions: clickable('label'),
|
||||
use: clickable('[data-test-use]'),
|
||||
confirmUse: clickable('button.type-delete'),
|
||||
confirmUse: clickable('[data-test-confirm-use]'),
|
||||
clone: clickable('[data-test-clone]'),
|
||||
})
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue