From afafe677a3b87e39b889889da98ab345a8f0c73b Mon Sep 17 00:00:00 2001 From: John Cowen Date: Wed, 22 Jan 2020 12:08:29 +0000 Subject: [PATCH] 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. --- ui-v2/app/components/aria-menu.js | 16 +- ui-v2/app/components/popover-menu.js | 26 ++ ui-v2/app/components/tabular-collection.js | 283 ++++-------------- ui-v2/app/components/toggle-button.js | 20 +- .../components/confirmation-alert/layout.scss | 6 + .../components/confirmation-alert/skin.scss | 11 + .../base/components/display-toggle/index.scss | 2 + .../components/display-toggle/layout.scss | 7 + .../base/components/display-toggle/skin.scss | 3 + .../base/components/menu-panel/index.scss | 11 +- .../base/components/menu-panel/layout.scss | 60 +++- .../base/components/menu-panel/skin.scss | 20 ++ .../base/components/popover-menu/index.scss | 6 + .../base/components/popover-menu/layout.scss | 25 ++ .../base/components/popover-menu/skin.scss | 9 + .../styles/base/icons/icon-placeholders.scss | 4 + ui-v2/app/styles/components/app-view.scss | 26 ++ ui-v2/app/styles/components/index.scss | 2 +- .../components/main-nav-horizontal/index.scss | 7 - .../main-nav-horizontal/layout.scss | 58 +--- .../components/main-nav-horizontal/skin.scss | 24 +- ui-v2/app/styles/components/table.scss | 13 + ui-v2/app/styles/core/typography.scss | 7 +- ui-v2/app/templates/components/aria-menu.hbs | 9 +- .../app/templates/components/popover-menu.hbs | 16 +- .../templates/components/role-selector.hbs | 43 ++- .../components/tabular-collection.hbs | 26 +- .../templates/components/toggle-button.hbs | 2 +- ui-v2/app/templates/dc/acls/index.hbs | 234 +++++++++------ .../app/templates/dc/acls/policies/index.hbs | 174 ++++++----- ui-v2/app/templates/dc/acls/roles/index.hbs | 162 +++++----- ui-v2/app/templates/dc/acls/tokens/index.hbs | 138 +++++---- ui-v2/app/templates/dc/intentions/index.hbs | 50 ++-- ui-v2/app/templates/dc/kv/index.hbs | 152 +++++----- ui-v2/app/templates/dc/nspaces/index.hbs | 54 ++-- ui-v2/tests/pages/dc/acls/index.js | 2 +- ui-v2/tests/pages/dc/acls/tokens/index.js | 2 +- 37 files changed, 949 insertions(+), 761 deletions(-) create mode 100644 ui-v2/app/styles/base/components/display-toggle/index.scss create mode 100644 ui-v2/app/styles/base/components/display-toggle/layout.scss create mode 100644 ui-v2/app/styles/base/components/display-toggle/skin.scss create mode 100644 ui-v2/app/styles/base/components/popover-menu/index.scss create mode 100644 ui-v2/app/styles/base/components/popover-menu/layout.scss create mode 100644 ui-v2/app/styles/base/components/popover-menu/skin.scss diff --git a/ui-v2/app/components/aria-menu.js b/ui-v2/app/components/aria-menu.js index 2e44215e25..50f63afa4d 100644 --- a/ui-v2/app/components/aria-menu.js +++ b/ui-v2/app/components/aria-menu.js @@ -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]); }, }); diff --git a/ui-v2/app/components/popover-menu.js b/ui-v2/app/components/popover-menu.js index a7be4db131..55c1ba5262 100644 --- a/ui-v2/app/components/popover-menu.js +++ b/ui-v2/app/components/popover-menu.js @@ -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); + }, + }, }); diff --git a/ui-v2/app/components/tabular-collection.js b/ui-v2/app/components/tabular-collection.js index 9a7c107ba8..b50708d92d 100644 --- a/ui-v2/app/components/tabular-collection.js +++ b/ui-v2/app/components/tabular-collection.js @@ -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); + } }, }, }); diff --git a/ui-v2/app/components/toggle-button.js b/ui-v2/app/components/toggle-button.js index ed8148f0be..9ead016799 100644 --- a/ui-v2/app/components/toggle-button.js +++ b/ui-v2/app/components/toggle-button.js @@ -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 }); }, }, }); diff --git a/ui-v2/app/styles/base/components/confirmation-alert/layout.scss b/ui-v2/app/styles/base/components/confirmation-alert/layout.scss index 748a38d94a..8903dcf1f9 100644 --- a/ui-v2/app/styles/base/components/confirmation-alert/layout.scss +++ b/ui-v2/app/styles/base/components/confirmation-alert/layout.scss @@ -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; +} diff --git a/ui-v2/app/styles/base/components/confirmation-alert/skin.scss b/ui-v2/app/styles/base/components/confirmation-alert/skin.scss index 0f79e6329d..6f6c0d933d 100644 --- a/ui-v2/app/styles/base/components/confirmation-alert/skin.scss +++ b/ui-v2/app/styles/base/components/confirmation-alert/skin.scss @@ -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; +} diff --git a/ui-v2/app/styles/base/components/display-toggle/index.scss b/ui-v2/app/styles/base/components/display-toggle/index.scss new file mode 100644 index 0000000000..bc18252196 --- /dev/null +++ b/ui-v2/app/styles/base/components/display-toggle/index.scss @@ -0,0 +1,2 @@ +@import './skin'; +@import './layout'; diff --git a/ui-v2/app/styles/base/components/display-toggle/layout.scss b/ui-v2/app/styles/base/components/display-toggle/layout.scss new file mode 100644 index 0000000000..050c10f5bc --- /dev/null +++ b/ui-v2/app/styles/base/components/display-toggle/layout.scss @@ -0,0 +1,7 @@ +%display-toggle-siblings, +%display-toggle-siblings ~ *:not(.animating):not(label) { + display: none; +} +%display-toggle-siblings:checked ~ *:not(label) { + display: block; +} diff --git a/ui-v2/app/styles/base/components/display-toggle/skin.scss b/ui-v2/app/styles/base/components/display-toggle/skin.scss new file mode 100644 index 0000000000..923a9a578c --- /dev/null +++ b/ui-v2/app/styles/base/components/display-toggle/skin.scss @@ -0,0 +1,3 @@ +%display-toggle-siblings ~ label { + cursor: pointer; +} diff --git a/ui-v2/app/styles/base/components/menu-panel/index.scss b/ui-v2/app/styles/base/components/menu-panel/index.scss index 68e1f00252..1ada891d33 100644 --- a/ui-v2/app/styles/base/components/menu-panel/index.scss +++ b/ui-v2/app/styles/base/components/menu-panel/index.scss @@ -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; } diff --git a/ui-v2/app/styles/base/components/menu-panel/layout.scss b/ui-v2/app/styles/base/components/menu-panel/layout.scss index 740cd7088e..2f66be1ec8 100644 --- a/ui-v2/app/styles/base/components/menu-panel/layout.scss +++ b/ui-v2/app/styles/base/components/menu-panel/layout.scss @@ -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; + } +} diff --git a/ui-v2/app/styles/base/components/menu-panel/skin.scss b/ui-v2/app/styles/base/components/menu-panel/skin.scss index 9d122d7510..67dab26828 100644 --- a/ui-v2/app/styles/base/components/menu-panel/skin.scss +++ b/ui-v2/app/styles/base/components/menu-panel/skin.scss @@ -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; +} diff --git a/ui-v2/app/styles/base/components/popover-menu/index.scss b/ui-v2/app/styles/base/components/popover-menu/index.scss new file mode 100644 index 0000000000..20c95035a8 --- /dev/null +++ b/ui-v2/app/styles/base/components/popover-menu/index.scss @@ -0,0 +1,6 @@ +@import '../display-toggle/index'; +@import '../toggle-button/index'; +@import '../menu-panel/index'; +@import '../confirmation-alert/index'; +@import './skin'; +@import './layout'; diff --git a/ui-v2/app/styles/base/components/popover-menu/layout.scss b/ui-v2/app/styles/base/components/popover-menu/layout.scss new file mode 100644 index 0000000000..dec50bbe23 --- /dev/null +++ b/ui-v2/app/styles/base/components/popover-menu/layout.scss @@ -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; +} diff --git a/ui-v2/app/styles/base/components/popover-menu/skin.scss b/ui-v2/app/styles/base/components/popover-menu/skin.scss new file mode 100644 index 0000000000..c0e6ae727f --- /dev/null +++ b/ui-v2/app/styles/base/components/popover-menu/skin.scss @@ -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; +} diff --git a/ui-v2/app/styles/base/icons/icon-placeholders.scss b/ui-v2/app/styles/base/icons/icon-placeholders.scss index c3af9e1d76..154a328938 100644 --- a/ui-v2/app/styles/base/icons/icon-placeholders.scss +++ b/ui-v2/app/styles/base/icons/icon-placeholders.scss @@ -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; diff --git a/ui-v2/app/styles/components/app-view.scss b/ui-v2/app/styles/components/app-view.scss index ac73b2c806..3e45ed58b4 100644 --- a/ui-v2/app/styles/components/app-view.scss +++ b/ui-v2/app/styles/components/app-view.scss @@ -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; } diff --git a/ui-v2/app/styles/components/index.scss b/ui-v2/app/styles/components/index.scss index 445d0d8f8f..a22ddb6498 100644 --- a/ui-v2/app/styles/components/index.scss +++ b/ui-v2/app/styles/components/index.scss @@ -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'; diff --git a/ui-v2/app/styles/components/main-nav-horizontal/index.scss b/ui-v2/app/styles/components/main-nav-horizontal/index.scss index e2b4044f74..ae5d8bd337 100644 --- a/ui-v2/app/styles/components/main-nav-horizontal/index.scss +++ b/ui-v2/app/styles/components/main-nav-horizontal/index.scss @@ -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; -} diff --git a/ui-v2/app/styles/components/main-nav-horizontal/layout.scss b/ui-v2/app/styles/components/main-nav-horizontal/layout.scss index 6bbdd50edc..18ebff5884 100644 --- a/ui-v2/app/styles/components/main-nav-horizontal/layout.scss +++ b/ui-v2/app/styles/components/main-nav-horizontal/layout.scss @@ -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 { diff --git a/ui-v2/app/styles/components/main-nav-horizontal/skin.scss b/ui-v2/app/styles/components/main-nav-horizontal/skin.scss index 5789d79dd7..d0ea088e04 100644 --- a/ui-v2/app/styles/components/main-nav-horizontal/skin.scss +++ b/ui-v2/app/styles/components/main-nav-horizontal/skin.scss @@ -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; -} diff --git a/ui-v2/app/styles/components/table.scss b/ui-v2/app/styles/components/table.scss index 442040e746..0bb3e1b789 100644 --- a/ui-v2/app/styles/components/table.scss +++ b/ui-v2/app/styles/components/table.scss @@ -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 { diff --git a/ui-v2/app/styles/core/typography.scss b/ui-v2/app/styles/core/typography.scss index d6c789cf94..5b2791fb74 100644 --- a/ui-v2/app/styles/core/typography.scss +++ b/ui-v2/app/styles/core/typography.scss @@ -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; } /**/ diff --git a/ui-v2/app/templates/components/aria-menu.hbs b/ui-v2/app/templates/components/aria-menu.hbs index d185868c85..8fa3ad5aed 100644 --- a/ui-v2/app/templates/components/aria-menu.hbs +++ b/ui-v2/app/templates/components/aria-menu.hbs @@ -1 +1,8 @@ -{{yield (action 'change') (action 'keypress') (concat 'component-aria-menu-trigger-' guid) (concat 'component-aria-menu-menu-' guid) (if expanded 'true' undefined)}} \ No newline at end of file +{{yield + (action 'change') + (action 'keypress') + (concat 'component-aria-menu-trigger-' guid) + (concat 'component-aria-menu-menu-' guid) + (if expanded 'true' undefined) + (action 'keypressClick') +}} \ No newline at end of file diff --git a/ui-v2/app/templates/components/popover-menu.hbs b/ui-v2/app/templates/components/popover-menu.hbs index 125a9223c7..e6d31a34aa 100644 --- a/ui-v2/app/templates/components/popover-menu.hbs +++ b/ui-v2/app/templates/components/popover-menu.hbs @@ -1,21 +1,25 @@ -{{yield}} -{{#aria-menu as |change keydown ariaLabelledBy ariaControls expanded|}} - {{#toggle-button onchange=change as |click|}} - {{/toggle-button}}
+ + {{#each submenus as |sub|}} + + {{/each}} {{#yield-slot name='header'}}
{{yield}}
{{else}} {{/yield-slot}} -
+ + {{/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}} diff --git a/ui-v2/app/templates/components/tabular-collection.hbs b/ui-v2/app/templates/components/tabular-collection.hbs index 6e462ddfd7..29186a1e7c 100644 --- a/ui-v2/app/templates/components/tabular-collection.hbs +++ b/ui-v2/app/templates/components/tabular-collection.hbs @@ -3,23 +3,25 @@ {{#yield-slot name='caption'}}{{yield}}{{/yield-slot}} {{/if}} - - {{#yield-slot name='header'}}{{yield}}{{/yield-slot}} + + {{#yield-slot name='header'}}{{yield}}{{/yield-slot}} {{#if hasActions }} - Actions + Actions {{/if}} - + - {{#ember-native-scrollable tagName='tbody' content-size=_contentSize scroll-left=_scrollLeft scroll-top=_scrollTop scrollChange=(action "scrollChange") clientSizeChange=(action "clientSizeChange")}} - + {{#ember-native-scrollable tagName='tbody' content-size=_contentSize scroll-left=_scrollLeft scroll-top=_scrollTop scrollChange=(action 'scrollChange') clientSizeChange=(action "clientSizeChange")}} + {{~#each _cells as |cell index|~}} - - {{#yield-slot name='row'}}{{yield cell.item index}}{{/yield-slot}} + + {{#yield-slot name='row'}}{{yield cell.item index}}{{/yield-slot}} {{#if hasActions }} - - {{#yield-slot name='actions' params=(block-params (concat index) change checked)}}{{yield cell.item index}}{{/yield-slot}} - + + {{#yield-slot name='actions' params=(block-params (concat cell.index) (action 'change') checked)}} + {{yield cell.item index}} + {{/yield-slot}} + {{/if}} - + {{~/each~}} {{/ember-native-scrollable}} \ No newline at end of file diff --git a/ui-v2/app/templates/components/toggle-button.hbs b/ui-v2/app/templates/components/toggle-button.hbs index 65d2db6743..5ed4861532 100644 --- a/ui-v2/app/templates/components/toggle-button.hbs +++ b/ui-v2/app/templates/components/toggle-button.hbs @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/ui-v2/app/templates/dc/acls/index.hbs b/ui-v2/app/templates/dc/acls/index.hbs index ae64e19a87..88c50c2e55 100644 --- a/ui-v2/app/templates/dc/acls/index.hbs +++ b/ui-v2/app/templates/dc/acls/index.hbs @@ -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'}} -

- ACL Tokens {{format-number items.length}} total -

- - {{/block-slot}} - {{#block-slot name='actions'}} - Create - {{/block-slot}} - {{#block-slot name='toolbar'}} + {{#block-slot name='notification' as |status type|}} + {{partial 'dc/acls/notifications'}} + {{/block-slot}} + {{#block-slot name='header'}} +

+ ACL Tokens {{format-number items.length}} total +

+ + {{/block-slot}} + {{#block-slot name='actions'}} + Create + {{/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'}} + Name + Type + {{/block-slot}} + {{#block-slot name='row'}} + + {{item.Name}} + + + {{#if (eq item.Type 'management')}} + {{item.Type}} + {{else}} + {{item.Type}} + {{/if}} + + {{/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'}} - Name - Type - {{/block-slot}} - {{#block-slot name='row'}} - - {{item.Name}} - - - {{#if (eq item.Type 'management')}} - {{item.Type}} - {{else}} - {{item.Type}} - {{/if}} - - {{/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')}} - - {{/action-group}} - {{/block-slot}} - {{#block-slot name='dialog' as |execute cancel message name|}} -

- {{#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}} -

- - - {{/block-slot}} - {{/confirmation-dialog}} - {{/block-slot}} - {{/tabular-collection}} + {{#block-slot name='trigger'}} + More + {{/block-slot}} + {{#block-slot name='menu' as |confirm send keypressClick|}} +
  • + Edit +
  • + {{#if (eq item.ID token.SecretID) }} +
  • + +
    +
    +
    +
    + Confirm logout +
    +

    + Are you sure you want to stop using this ACL token? This will log you out. +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • + {{else}} +
  • + +
    +
    +
    +
    + Confirm use +
    +

    + Are you sure you want to use this ACL token? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • + {{/if}} +
  • + +
  • + {{# if (not-eq item.ID 'anonymous') }} +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this token? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • + {{/if}} + {{/block-slot}} + {{/popover-menu}} {{/block-slot}} - {{#block-slot name='empty'}} -

    - There are no ACLs. -

    - {{/block-slot}} - {{/changeable-set}} - {{/block-slot}} + {{/tabular-collection}} + {{/block-slot}} + {{#block-slot name='empty'}} +

    + There are no ACLs. +

    + {{/block-slot}} + {{/changeable-set}} + {{/block-slot}} {{/app-view}} \ No newline at end of file diff --git a/ui-v2/app/templates/dc/acls/policies/index.hbs b/ui-v2/app/templates/dc/acls/policies/index.hbs index 5fca02afe8..3f34079e63 100644 --- a/ui-v2/app/templates/dc/acls/policies/index.hbs +++ b/ui-v2/app/templates/dc/acls/policies/index.hbs @@ -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'}} -

    - Access Controls -

    - {{#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'}} - Create - {{/block-slot}} - {{#block-slot name='content'}} -{{#if (gt items.length 0) }} -
    - {{freetext-filter searchable=searchable value=s placeholder="Search"}} -
    -{{/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'}} - Name - Datacenters - Description - {{/block-slot}} - {{#block-slot name='row'}} - - {{item.Name}} - - - {{join ', ' (policy/datacenters item)}} - - -

    {{item.Description}}

    - - {{/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')}} - - {{/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'}} + Create + {{/block-slot}} + {{#block-slot name='content'}} +{{#if (gt items.length 0) }} +
    + {{freetext-filter searchable=searchable value=s placeholder="Search"}} +
    +{{/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'}} + Name + Datacenters + Description {{/block-slot}} - {{#block-slot name='empty'}} -

    - There are no Policies. -

    + {{#block-slot name='row'}} + + {{item.Name}} + + + {{join ', ' (policy/datacenters item)}} + + +

    {{item.Description}}

    + {{/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')}} +
  • + View +
  • +{{else}} + +
  • + Edit +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this policy? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • +{{/if}} + {{/block-slot}} + {{/popover-menu}} + {{/block-slot}} + {{/tabular-collection}} + {{/block-slot}} + {{#block-slot name='empty'}} +

    + There are no Policies. +

    + {{/block-slot}} + {{/changeable-set}} + {{/block-slot}} {{/app-view}} \ No newline at end of file diff --git a/ui-v2/app/templates/dc/acls/roles/index.hbs b/ui-v2/app/templates/dc/acls/roles/index.hbs index aa5bc02773..c455b62db0 100644 --- a/ui-v2/app/templates/dc/acls/roles/index.hbs +++ b/ui-v2/app/templates/dc/acls/roles/index.hbs @@ -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'}} -

    - Access Controls -

    - {{#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'}} - Create - {{/block-slot}} - {{#block-slot name='content'}} + {{#block-slot name='notification' as |status type|}} + {{partial 'dc/acls/roles/notifications'}} + {{/block-slot}} + {{#block-slot name='header'}} +

    + Access Controls +

    + {{#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'}} + Create + {{/block-slot}} + {{#block-slot name='content'}} {{#if (gt items.length 0) }} -
    - {{freetext-filter searchable=searchable value=s placeholder="Search"}} -
    +
    + {{freetext-filter searchable=searchable value=s placeholder="Search"}} +
    {{/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'}} - Name - Description - Policies + {{#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'}} + Name + Description + Policies + {{/block-slot}} + {{#block-slot name='row'}} + + {{item.Name}} + + +

    {{item.Description}}

    + + + {{#each item.Policies as |item|}} + {{item.Name}} + {{/each}} + + {{/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'}} - - {{item.Name}} - - -

    {{item.Description}}

    - - - {{#each item.Policies as |item|}} - {{item.Name}} - {{/each}} - + {{#block-slot name='menu' as |confirm send keypressClick|}} +
  • + Edit +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this role? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • {{/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')}} - - {{/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'}} -

    - There are no Roles. -

    - {{/block-slot}} - {{/changeable-set}} - {{/block-slot}} + {{/popover-menu}} + {{/block-slot}} + {{/tabular-collection}} + {{/block-slot}} + {{#block-slot name='empty'}} +

    + There are no Roles. +

    + {{/block-slot}} + {{/changeable-set}} + {{/block-slot}} {{/app-view}} \ No newline at end of file diff --git a/ui-v2/app/templates/dc/acls/tokens/index.hbs b/ui-v2/app/templates/dc/acls/tokens/index.hbs index 281f6c2622..30368466ee 100644 --- a/ui-v2/app/templates/dc/acls/tokens/index.hbs +++ b/ui-v2/app/templates/dc/acls/tokens/index.hbs @@ -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')}} - - {{/action-group}} {{/block-slot}} - {{#block-slot name='dialog' as |execute cancel message name|}} -

    - {{#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}} -

    - - - {{/block-slot}} - {{/confirmation-dialog}} + {{/popover-menu}} {{/block-slot}} {{/tabular-collection}} {{/block-slot}} diff --git a/ui-v2/app/templates/dc/intentions/index.hbs b/ui-v2/app/templates/dc/intentions/index.hbs index b689a4bb7d..461589101a 100644 --- a/ui-v2/app/templates/dc/intentions/index.hbs +++ b/ui-v2/app/templates/dc/intentions/index.hbs @@ -61,23 +61,39 @@ {{/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')}} - - {{/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|}} +
  • + Edit +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this intention? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • + {{/block-slot}} + {{/popover-menu}} {{/block-slot}} {{/tabular-collection}} {{/block-slot}} diff --git a/ui-v2/app/templates/dc/kv/index.hbs b/ui-v2/app/templates/dc/kv/index.hbs index 39bc4ff300..1ab92b8386 100644 --- a/ui-v2/app/templates/dc/kv/index.hbs +++ b/ui-v2/app/templates/dc/kv/index.hbs @@ -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'}} -
      + {{#block-slot name='notification' as |status type|}} + {{partial 'dc/kv/notifications'}} + {{/block-slot}} + {{#block-slot name='breadcrumbs'}} +
        {{#if (not-eq parent.Key '/') }} -
      1. Key / Values
      2. +
      3. Key / Values
      4. {{/if}} {{#each (slice 0 -2 (split parent.Key '/')) as |breadcrumb index|}} -
      5. {{breadcrumb}}
      6. +
      7. {{breadcrumb}}
      8. {{/each}} -
      - {{/block-slot}} - {{#block-slot name='header'}} -

      - {{#if (eq parent.Key '/') }} - Key / Value - {{else}} - {{ take 1 (drop 1 (reverse (split parent.Key '/'))) }} - {{/if}} -

      - - {{/block-slot}} - {{#block-slot name='toolbar'}} +
    + {{/block-slot}} + {{#block-slot name='header'}} +

    + {{#if (eq parent.Key '/')}} + Key / Value + {{else}} + {{take 1 (drop 1 (reverse (split parent.Key '/')))}} + {{/if}} +

    + + {{/block-slot}} + {{#block-slot name='toolbar'}} {{#if (gt items.length 0) }} -
    - {{freetext-filter searchable=searchable value=s placeholder="Search by name"}} -
    +
    + {{freetext-filter searchable=searchable value=s placeholder="Search by name"}} +
    {{/if}} - {{/block-slot}} - {{#block-slot name='actions'}} + {{/block-slot}} + {{#block-slot name='actions'}} {{#if (not-eq parent.Key '/') }} - Create + Create {{else}} - Create + Create {{/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'}} - Name - {{/block-slot}} - {{#block-slot name='row'}} - - {{right-trim (left-trim item.Key parent.Key) '/'}} - - {{/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')}} - - {{/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'}} + Name {{/block-slot}} - {{#block-slot name='empty'}} -

    - There are no Key / Value pairs. -

    + {{#block-slot name='row'}} + + {{right-trim (left-trim item.Key parent.Key) '/'}} + {{/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 item.isFolder 'View' 'Edit'}} +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this key? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • + {{/block-slot}} + {{/popover-menu}} + {{/block-slot}} + {{/tabular-collection}} + {{/block-slot}} + {{#block-slot name='empty'}} +

    + There are no Key / Value pairs. +

    + {{/block-slot}} + {{/changeable-set}} + {{/block-slot}} {{/app-view}} \ No newline at end of file diff --git a/ui-v2/app/templates/dc/nspaces/index.hbs b/ui-v2/app/templates/dc/nspaces/index.hbs index 903845b64e..a3bf104750 100644 --- a/ui-v2/app/templates/dc/nspaces/index.hbs +++ b/ui-v2/app/templates/dc/nspaces/index.hbs @@ -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')}} - - {{/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|}} -

    - {{message}} -

    - - + {{#block-slot name='menu' as |confirm send keypressClick|}} +
  • + Edit +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this key? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • {{/block-slot}} - {{/confirmation-dialog}} + {{/popover-menu}} {{/block-slot}} {{/tabular-collection}} {{/block-slot}} diff --git a/ui-v2/tests/pages/dc/acls/index.js b/ui-v2/tests/pages/dc/acls/index.js index f8b6b53fad..39d851965b 100644 --- a/ui-v2/tests/pages/dc/acls/index.js +++ b/ui-v2/tests/pages/dc/acls/index.js @@ -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, diff --git a/ui-v2/tests/pages/dc/acls/tokens/index.js b/ui-v2/tests/pages/dc/acls/tokens/index.js index a6ee639bbc..8b02b6bbb3 100644 --- a/ui-v2/tests/pages/dc/acls/tokens/index.js +++ b/ui-v2/tests/pages/dc/acls/tokens/index.js @@ -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]'), }) ),