diff --git a/ui-v2/app/components/confirmation-alert/action/index.hbs b/ui-v2/app/components/confirmation-alert/action/index.hbs new file mode 100644 index 000000000..bb711add6 --- /dev/null +++ b/ui-v2/app/components/confirmation-alert/action/index.hbs @@ -0,0 +1,3 @@ +
  • + +
  • diff --git a/ui-v2/app/components/confirmation-alert/action/index.js b/ui-v2/app/components/confirmation-alert/action/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/confirmation-alert/action/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/confirmation-alert/index.hbs b/ui-v2/app/components/confirmation-alert/index.hbs new file mode 100644 index 000000000..24e553ae5 --- /dev/null +++ b/ui-v2/app/components/confirmation-alert/index.hbs @@ -0,0 +1,22 @@ +{{yield}} +
    +
    +
    + {{yield}} +
    + {{yield}} +
    + +
    \ No newline at end of file diff --git a/ui-v2/app/components/confirmation-alert/index.js b/ui-v2/app/components/confirmation-alert/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/confirmation-alert/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/consul-policy-list/README.mdx b/ui-v2/app/components/consul-policy-list/README.mdx new file mode 100644 index 000000000..185b91a4c --- /dev/null +++ b/ui-v2/app/components/consul-policy-list/README.mdx @@ -0,0 +1,24 @@ +## ConsulPolicyList + +``` + +``` + +A presentational component for rendering Consul ACL policies + +### Arguments + +| Argument/Attribute | Type | Default | Description | +| --- | --- | --- | --- | +| `items` | `array` | | An array of ACL policies | +| `ondelete` | `function` | | An action to execute when the `Delete` action is clicked | + +### See + +- [Component Source Code](./index.js) +- [TemplateSource Code](./index.hbs) + +--- diff --git a/ui-v2/app/components/consul-policy-list/index.hbs b/ui-v2/app/components/consul-policy-list/index.hbs new file mode 100644 index 000000000..cf5985f11 --- /dev/null +++ b/ui-v2/app/components/consul-policy-list/index.hbs @@ -0,0 +1,67 @@ +{{#if (gt items.length 0)}} + + +{{#if (eq (policy/typeof item) 'policy-management')}} +
    +
    + + Global Management Policy + +
    +
    +{{/if}} + {{item.Name}} +
    + +
    +
    + Datacenters +
    +
    + {{join ', ' (policy/datacenters item)}} +
    +
    +
    +
    Description
    +
    + {{item.Description}} +
    +
    +
    + + + + +{{#if (eq (policy/typeof item) 'policy-management')}} + View +{{else}} + Edit +{{/if}} + + +{{#if (not-eq (policy/typeof item) 'policy-management')}} + + + Delete + + + + + Confirm delete + + +

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

    +
    + + Delete + +
    +
    +
    +{{/if}} +
    +
    +
    +{{/if}} \ No newline at end of file diff --git a/ui-v2/app/components/consul-policy-list/index.js b/ui-v2/app/components/consul-policy-list/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/consul-policy-list/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/consul-policy-list/pageobject.js b/ui-v2/app/components/consul-policy-list/pageobject.js new file mode 100644 index 000000000..529c9d501 --- /dev/null +++ b/ui-v2/app/components/consul-policy-list/pageobject.js @@ -0,0 +1,8 @@ +export default (collection, clickable, attribute, text, actions) => () => { + return collection('.consul-policy-list li:not(:first-child)', { + name: attribute('data-test-policy', '[data-test-policy]'), + description: text('[data-test-description]'), + policy: clickable('a'), + ...actions(['edit', 'delete']), + }); +}; diff --git a/ui-v2/app/components/consul-role-list/README.mdx b/ui-v2/app/components/consul-role-list/README.mdx new file mode 100644 index 000000000..f7c4edc58 --- /dev/null +++ b/ui-v2/app/components/consul-role-list/README.mdx @@ -0,0 +1,24 @@ +## ConsulRoleList + +``` + +``` + +A presentational component for rendering Consul ACL roles + +### Arguments + +| Argument/Attribute | Type | Default | Description | +| --- | --- | --- | --- | +| `items` | `array` | | An array of ACL roles | +| `ondelete` | `function` | | An action to execute when the `Delete` action is clicked | + +### See + +- [Component Source Code](./index.js) +- [TemplateSource Code](./index.hbs) + +--- diff --git a/ui-v2/app/components/consul-role-list/index.hbs b/ui-v2/app/components/consul-role-list/index.hbs new file mode 100644 index 000000000..ac3d734c8 --- /dev/null +++ b/ui-v2/app/components/consul-role-list/index.hbs @@ -0,0 +1,45 @@ +{{#if (gt items.length 0)}} + + + {{item.Name}} + + + +
    +
    Description
    +
    + {{item.Description}} +
    +
    +
    + + + + + Edit + + + + + Delete + + + + + Confirm delete + + +

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

    +
    + + Delete + +
    +
    +
    +
    +
    +
    +{{/if}} \ No newline at end of file diff --git a/ui-v2/app/components/consul-role-list/index.js b/ui-v2/app/components/consul-role-list/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/consul-role-list/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/consul-role-list/pageobject.js b/ui-v2/app/components/consul-role-list/pageobject.js new file mode 100644 index 000000000..9650a8f98 --- /dev/null +++ b/ui-v2/app/components/consul-role-list/pageobject.js @@ -0,0 +1,9 @@ +export default (collection, clickable, attribute, text, actions) => () => { + return collection('.consul-role-list li:not(:first-child)', { + name: attribute('data-test-role', '[data-test-role]'), + description: text('[data-test-description]'), + policy: text('[data-test-policy].policy', { multiple: true }), + serviceIdentity: text('[data-test-policy].policy-service-identity', { multiple: true }), + ...actions(['edit', 'delete']), + }); +}; diff --git a/ui-v2/app/components/consul-token-list/index.hbs b/ui-v2/app/components/consul-token-list/index.hbs index a82b84237..cdf2509ba 100644 --- a/ui-v2/app/components/consul-token-list/index.hbs +++ b/ui-v2/app/components/consul-token-list/index.hbs @@ -1,10 +1,10 @@ {{#if (gt items.length 0)}} - + {{#if (eq item.AccessorID token.AccessorID)}}
    - + Your token
    @@ -19,50 +19,7 @@ {{if item.Local 'local' 'global' }}
    -{{#let (policy/group item.Policies) as |policies|}} - {{#let (get policies 'management') as |management|}} - {{#if (gt management.length 0)}} -
    -
    - Management -
    -
    - {{#each (get policies 'management') as |item|}} - {{item.Name}} - {{/each}} -
    -
    - {{/if}} - {{/let}} - {{#let (get policies 'identities') as |identities|}} - {{#if (gt identities.length 0)}} -
    -
    Identities
    -
    - {{#each identities as |item|}} - {{if (eq item.template 'service-identity') 'Service' 'Node'}} Identity: {{item.Name}} - {{/each}} -
    -
    - {{/if}} - {{/let}} - {{#let (append (get policies 'policies') item.Roles) as |policies|}} - {{#if (gt policies.length 0)}} -
    -
    Rules
    -
    - {{#if (token/is-legacy item) }} - Legacy tokens have embedded rules. - {{ else }} - {{#each policies as |item|}} - {{item.Name}} - {{/each}} - {{/if}} -
    -
    - {{/if}} - {{/let}} -{{/let}} +
    Description
    @@ -70,98 +27,86 @@
    - -
    - - - More - - -
  • - Edit -
  • -{{#if (not (token/is-legacy item))}} -
  • - -
  • -{{/if}} -{{#if (eq item.AccessorID token.AccessorID) }} -
  • - -
    -
    -
    -
    - 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}} -{{#unless (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)) }} -
  • - -
    -
    -
    -
    - Confirm Delete -
    -

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

    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
  • -{{/unless}} -
    -
    -
    + + + + + Edit + + + {{#if (not (token/is-legacy item))}} + + + Duplicate + + + {{/if}} + {{#if (eq item.AccessorID token.AccessorID)}} + + + Logout + + + + + Confirm logout + + +

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

    +
    + + Logout + +
    +
    +
    + {{else}} + + + Use + + + + + Confirm use + + +

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

    +
    + + Use + +
    +
    +
    + {{/if}} + {{#if (not (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)))}} + + + Delete + + + + + Confirm delete + + +

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

    +
    + + Delete + +
    +
    +
    + {{/if}} +
    {{/if}} \ No newline at end of file diff --git a/ui-v2/app/components/consul-token-list/pageobject.js b/ui-v2/app/components/consul-token-list/pageobject.js index f03055cfc..ba0945385 100644 --- a/ui-v2/app/components/consul-token-list/pageobject.js +++ b/ui-v2/app/components/consul-token-list/pageobject.js @@ -1,4 +1,4 @@ -export default (collection, clickable, attribute, text, deletable) => () => { +export default (collection, clickable, attribute, text, actions) => () => { return collection('.consul-token-list li:not(:first-child)', { id: attribute('data-test-token', '[data-test-token]'), description: text('[data-test-description]'), @@ -6,10 +6,6 @@ export default (collection, clickable, attribute, text, deletable) => () => { role: text('[data-test-policy].role', { multiple: true }), serviceIdentity: text('[data-test-policy].policy-service-identity', { multiple: true }), token: clickable('a'), - actions: clickable('label'), - use: clickable('[data-test-use]'), - confirmUse: clickable('[data-test-confirm-use]'), - clone: clickable('[data-test-clone]'), - ...deletable(), + ...actions(['edit', 'delete', 'use', 'logout', 'clone']), }); }; diff --git a/ui-v2/app/components/consul-token-ruleset-list/README.mdx b/ui-v2/app/components/consul-token-ruleset-list/README.mdx new file mode 100644 index 000000000..43da3ed93 --- /dev/null +++ b/ui-v2/app/components/consul-token-ruleset-list/README.mdx @@ -0,0 +1,22 @@ +## ConsulTokenRulesetList + +``` + +``` + +A presentational component for rendering Consul ACL token 'rulesets'. Rulesets are the various 'rule-type' things that belong to a token such as policies, identities and roles, and in the case of legacy tokens, the old style string based rules property. + +### Arguments + +| Argument/Attribute | Type | Default | Description | +| --- | --- | --- | --- | +| `item` | `array` | | An ACL token | + +### See + +- [Component Source Code](./index.js) +- [TemplateSource Code](./index.hbs) + +--- diff --git a/ui-v2/app/components/consul-token-ruleset-list/index.hbs b/ui-v2/app/components/consul-token-ruleset-list/index.hbs new file mode 100644 index 000000000..036276b2f --- /dev/null +++ b/ui-v2/app/components/consul-token-ruleset-list/index.hbs @@ -0,0 +1,49 @@ +{{#let (policy/group item.Policies) as |policies|}} + {{#let (get policies 'management') as |management|}} + {{#if (gt management.length 0)}} +
    +
    + Management +
    +
    + {{#each (get policies 'management') as |item|}} + {{item.Name}} + {{/each}} +
    +
    + {{/if}} + {{/let}} + {{#let (get policies 'identities') as |identities|}} + {{#if (gt identities.length 0)}} +
    +
    Identities
    +
    + {{#each identities as |item|}} + {{item.Name}} + {{/each}} +
    +
    + {{/if}} + {{/let}} + {{#if (token/is-legacy item) }} +
    +
    Rules
    +
    + Legacy tokens have embedded rules. +
    +
    + {{else}} + {{#let (append (get policies 'policies') (or item.Roles (array))) as |policies|}} + {{#if (gt policies.length 0)}} +
    +
    Rules
    +
    + {{#each policies as |item|}} + {{item.Name}} + {{/each}} +
    +
    + {{/if}} + {{/let}} + {{/if}} +{{/let}} diff --git a/ui-v2/app/components/consul-token-ruleset-list/index.js b/ui-v2/app/components/consul-token-ruleset-list/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/consul-token-ruleset-list/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/list-collection/index.hbs b/ui-v2/app/components/list-collection/index.hbs index 9a759031f..d83b07604 100644 --- a/ui-v2/app/components/list-collection/index.hbs +++ b/ui-v2/app/components/list-collection/index.hbs @@ -11,9 +11,17 @@
  • {{~#each _cells as |cell|~}}
  • -
    {{yield cell.item cell.index checked (action "change")}}
    -
    {{yield cell.item cell.index checked (action "change")}}
    -
    {{yield cell.item cell.index checked (action "change")}}
    +
    {{yield cell.item cell.index}}
    +
    {{yield cell.item cell.index}}
    + +
    + {{yield cell.item cell.index}} +
    +
  • {{~/each~}} \ No newline at end of file diff --git a/ui-v2/app/components/menu-panel/index.hbs b/ui-v2/app/components/menu-panel/index.hbs index c0188e052..a07a62866 100644 --- a/ui-v2/app/components/menu-panel/index.hbs +++ b/ui-v2/app/components/menu-panel/index.hbs @@ -1,15 +1,21 @@ {{yield}} +{{#let (hash + change=(action "change") +) as |api|}} \ No newline at end of file + +{{/let}} \ No newline at end of file diff --git a/ui-v2/app/components/menu-panel/index.js b/ui-v2/app/components/menu-panel/index.js index 3d0b05e3b..01c78ed68 100644 --- a/ui-v2/app/components/menu-panel/index.js +++ b/ui-v2/app/components/menu-panel/index.js @@ -1,7 +1,26 @@ 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'), + actions: { + change: function(e) { + const id = e.target.getAttribute('id'); + const $trigger = this.dom.element(`[for='${id}']`); + const $panel = this.dom.element('[role=menu]', $trigger.parentElement); + const $menuPanel = this.dom.closest('.menu-panel', $panel); + if (e.target.checked) { + $panel.style.display = 'block'; + const height = $panel.offsetHeight + 2; + $menuPanel.style.maxHeight = $menuPanel.style.minHeight = `${height}px`; + } else { + $panel.style.display = null; + $menuPanel.style.maxHeight = null; + $menuPanel.style.minHeight = '0'; + } + }, + }, }); diff --git a/ui-v2/app/components/more-popover-menu/action/index.hbs b/ui-v2/app/components/more-popover-menu/action/index.hbs new file mode 100644 index 000000000..c56b2ee2f --- /dev/null +++ b/ui-v2/app/components/more-popover-menu/action/index.hbs @@ -0,0 +1,28 @@ +{{yield}} +
  • +{{#if hasConfirmation}} + +
    + {{yield}} +
    +{{else if href}} + + + {{yield}} + + +{{else}} + +{{/if}} +
  • diff --git a/ui-v2/app/components/more-popover-menu/action/index.js b/ui-v2/app/components/more-popover-menu/action/index.js new file mode 100644 index 000000000..e98665c1a --- /dev/null +++ b/ui-v2/app/components/more-popover-menu/action/index.js @@ -0,0 +1,26 @@ +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; +import { set } from '@ember/object'; + +import Slotted from 'block-slots'; + +export default Component.extend(Slotted, { + tagName: '', + dom: service('dom'), + init: function() { + this._super(...arguments); + this.guid = this.dom.guid(this); + }, + didInsertElement: function() { + this._super(...arguments); + this.menu.addSubmenu(this.guid); + }, + didDestroyElement: function() { + this._super(...arguments); + this.menu.removeSubmenu(this.guid); + }, + willRender: function() { + this._super(...arguments); + set(this, 'hasConfirmation', this._isRegistered('confirmation')); + }, +}); diff --git a/ui-v2/app/components/more-popover-menu/index.hbs b/ui-v2/app/components/more-popover-menu/index.hbs new file mode 100644 index 000000000..4ff23e885 --- /dev/null +++ b/ui-v2/app/components/more-popover-menu/index.hbs @@ -0,0 +1,15 @@ +
    + + + More + + + {{yield (component 'more-popover-menu/action' menu=(hash + addSubmenu=api.addSubmenu + removeSubmenu=api.removeSubmenu + confirm=confirm + keypressClick=keypressClick + ))}} + + +
    diff --git a/ui-v2/app/components/more-popover-menu/index.js b/ui-v2/app/components/more-popover-menu/index.js new file mode 100644 index 000000000..479865264 --- /dev/null +++ b/ui-v2/app/components/more-popover-menu/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/components/more-popover-menu/pageobject.js b/ui-v2/app/components/more-popover-menu/pageobject.js new file mode 100644 index 000000000..2198b2a75 --- /dev/null +++ b/ui-v2/app/components/more-popover-menu/pageobject.js @@ -0,0 +1,17 @@ +export default (clickable, confirmation) => (actions, scope) => { + return actions.reduce( + (prev, item) => { + const itemScope = `[data-test-${item}-action]`; + return { + ...prev, + [item]: clickable(`${itemScope} [role='menuitem']`), + [`confirm${item.charAt(0).toUpperCase()}${item.substr(1)}`]: clickable( + `${itemScope} [role='menu'] button` + ), + }; + }, + { + actions: clickable('label'), + } + ); +}; diff --git a/ui-v2/app/components/popover-menu/index.hbs b/ui-v2/app/components/popover-menu/index.hbs index c1442e856..080ae2f33 100644 --- a/ui-v2/app/components/popover-menu/index.hbs +++ b/ui-v2/app/components/popover-menu/index.hbs @@ -1,4 +1,4 @@ -{{yield (concat 'popover-menu-' guid)}} +{{yield}} - + - {{#each submenus as |sub|}} - - {{/each}} + {{#each submenus as |sub|}} + + {{/each}} {{#if hasHeader}} - {{#yield-slot name="header"}}{{yield}}{{else}}{{/yield-slot}} + {{yield (hash + addSubmenu=(action 'addSubmenu') + removeSubmenu=(action 'removeSubmenu') + )}} + {{#yield-slot name="header"}}{{else}}{{/yield-slot}} {{/if}} - {{yield}} + {{yield (hash + addSubmenu=(action 'addSubmenu') + removeSubmenu=(action 'removeSubmenu') + )}} diff --git a/ui-v2/app/components/popover-menu/index.js b/ui-v2/app/components/popover-menu/index.js index 9f68520ed..2229e9f4e 100644 --- a/ui-v2/app/components/popover-menu/index.js +++ b/ui-v2/app/components/popover-menu/index.js @@ -16,11 +16,22 @@ export default Component.extend(Slotted, { init: function() { this._super(...arguments); this.guid = this.dom.guid(this); + this.submenus = []; }, willRender: function() { set(this, 'hasHeader', this._isRegistered('header')); }, actions: { + addSubmenu: function(name) { + set(this, 'submenus', this.submenus.concat(name)); + }, + removeSubmenu: function(name) { + const pos = this.submenus.indexOf(name); + if (pos !== -1) { + this.submenus.splice(pos, 1); + set(this, 'submenus', this.submenus); + } + }, change: function(e) { if (!e.target.checked) { [...this.dom.elements(`[id^=popover-menu-${this.guid}]`)].forEach(function($item) { diff --git a/ui-v2/app/helpers/policy/typeof.js b/ui-v2/app/helpers/policy/typeof.js index ec4b5e441..87c0591e3 100644 --- a/ui-v2/app/helpers/policy/typeof.js +++ b/ui-v2/app/helpers/policy/typeof.js @@ -3,13 +3,16 @@ import { get } from '@ember/object'; const MANAGEMENT_ID = '00000000-0000-0000-0000-000000000001'; export function typeOf(params, hash) { const item = params[0]; + const template = get(item, 'template'); switch (true) { + case typeof template === 'undefined': + return 'role'; + case template === 'service-identity': + return 'policy-service-identity'; + case template === 'node-identity': + return 'policy-node-identity'; case get(item, 'ID') === MANAGEMENT_ID: return 'policy-management'; - case typeof get(item, 'template') === 'undefined': - return 'role'; - case get(item, 'template') !== '': - return 'policy-service-identity'; default: return 'policy'; } 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 6f6c0d933..0684daed5 100644 --- a/ui-v2/app/styles/base/components/confirmation-alert/skin.scss +++ b/ui-v2/app/styles/base/components/confirmation-alert/skin.scss @@ -6,6 +6,7 @@ background-color: $yellow-050; border-top-left-radius: $decor-radius-200; border-top-right-radius: $decor-radius-200; + cursor: default; } %confirmation-alert > ul { list-style: none; 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 7614f3aeb..9dcf2fa6b 100644 --- a/ui-v2/app/styles/base/components/menu-panel/layout.scss +++ b/ui-v2/app/styles/base/components/menu-panel/layout.scss @@ -4,15 +4,16 @@ %menu-panel [type='checkbox'] { display: none; } -%menu-panel [type='checkbox'] ~ * { - transition: transform 150ms, min-height 150ms, max-height 150ms; +%menu-panel { + overflow: hidden; + transition: min-height 150ms, max-height 150ms; min-height: 0; } +%menu-panel [type='checkbox'] ~ * { + transition: transform 150ms; +} %menu-panel [type='checkbox']:checked ~ * { transform: translateX(calc(-100% - 10px)); - /* this needs to autocalculate */ - /* or be hardcoded */ - /* min-height: 143px; */ } %menu-panel [role='menuitem'] { display: flex; @@ -27,7 +28,19 @@ position: absolute; top: 0; left: calc(100% + 10px); + display: none; } +/* TODO: once everything is using ListCollection */ +/* this can go */ +%menu-panel [type='checkbox']:checked ~ * { + /* this needs to autocalculate */ + min-height: 143px; + max-height: 143px; +} +%menu-panel [id$='-']:first-child:checked ~ ul label[for$='-'] + [role='menu'] { + display: block; +} +/**/ %menu-panel dl { padding: 0.9em 1em; } diff --git a/ui-v2/app/styles/base/components/popover-menu/index.scss b/ui-v2/app/styles/base/components/popover-menu/index.scss index f8731956b..3e513da57 100644 --- a/ui-v2/app/styles/base/components/popover-menu/index.scss +++ b/ui-v2/app/styles/base/components/popover-menu/index.scss @@ -1,18 +1,17 @@ @import './skin'; @import './layout'; -%with-popover-menu > input { +%with-popover-menu > [type='checkbox'] { @extend %popover-menu; } %popover-menu { @extend %display-toggle-siblings; } -%popover-menu + label + div { - @extend %popover-menu-panel; -} %popover-menu + label > * { @extend %toggle-button; } -%more-popover-menu-panel, +%popover-menu + label + div { + @extend %popover-menu-panel; +} %popover-menu-panel { @extend %menu-panel; } diff --git a/ui-v2/app/styles/base/components/popover-menu/layout.scss b/ui-v2/app/styles/base/components/popover-menu/layout.scss index 012d2a8c7..862ca7981 100644 --- a/ui-v2/app/styles/base/components/popover-menu/layout.scss +++ b/ui-v2/app/styles/base/components/popover-menu/layout.scss @@ -1,56 +1,12 @@ %with-popover-menu { position: relative; } -%with-popover-menu > [type='checkbox'] { - @extend %popover-menu; -} -%more-popover-menu { - @extend %display-toggle-siblings; -} -%more-popover-menu + label > * { - @extend %toggle-button; -} -%more-popover-menu-panel { - overflow: hidden; - width: 192px; -} -%more-popover-menu + label + div { - @extend %more-popover-menu-panel; -} -%more-popover-menu-panel:not(.above) { - top: 48px; -} -%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; -} -%popover-menu { - @extend %display-toggle-siblings; -} -%popover-menu + label > * { - @extend %toggle-button; -} %popover-menu-panel { - @extend %menu-panel; width: 192px; } -%popover-menu + label + div { - @extend %popover-menu-panel; -} %popover-menu-panel:not(.above) { top: 38px; } %popover-menu-panel:not(.left) { - right: 10px; -} -%popover-menu-panel li [role='menu'] { - display: none; -} -%popover-menu-panel [id$='-']:first-child:checked ~ ul label[for$='-'] + [role='menu'] { - display: block; + right: 5px; } diff --git a/ui-v2/app/styles/base/components/popover-menu/skin.scss b/ui-v2/app/styles/base/components/popover-menu/skin.scss index df9b801f8..fdda44399 100644 --- a/ui-v2/app/styles/base/components/popover-menu/skin.scss +++ b/ui-v2/app/styles/base/components/popover-menu/skin.scss @@ -4,13 +4,3 @@ height: 16px; margin-left: 16px; } -%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; - background-color: $transparent; -} diff --git a/ui-v2/app/styles/components/composite-row.scss b/ui-v2/app/styles/components/composite-row.scss index 0ae43420b..e60110cac 100644 --- a/ui-v2/app/styles/components/composite-row.scss +++ b/ui-v2/app/styles/components/composite-row.scss @@ -10,28 +10,23 @@ .consul-gateway-service-list > ul > li:not(:first-child), .consul-service-instance-list > ul > li:not(:first-child), .consul-service-list > ul > li:not(:first-child), -.consul-token-list > ul > li:not(:first-child) { +.consul-token-list > ul > li:not(:first-child), +.consul-policy-list > ul > li:not(:first-child), +.consul-role-list > ul > li:not(:first-child) { @extend %with-composite-row-intent; } /*TODO: This hides the icons-less dt's in the below lists as */ /* they don't have tooltips */ -.consul-token-list > ul > li:not(:first-child) dt { +.consul-token-list > ul > li:not(:first-child) dt, +.consul-policy-list > ul li:not(:first-child) dl:not(.datacenter) dt, +.consul-role-list > ul > li:not(:first-child) dt { display: none; } /* TODO: the service list has a 1px offset */ +.consul-policy-list dl.datacenter dt, .consul-service-list li > div:first-child > dl:first-child dd { margin-top: 1px; } -.proxy-exposed-paths tbody tr { - cursor: default !important; -} -.proxy-exposed-paths tbody tr:hover { - box-shadow: none !important; -} -.proxy-exposed-paths tbody tr .combined-address button:hover { - // In this case we do not need a background on the icon - background-color: $transparent !important; -} .proxy-exposed-paths > ul, .proxy-upstreams > ul { border-top: 1px solid $gray-200; diff --git a/ui-v2/app/styles/components/composite-row/skin.scss b/ui-v2/app/styles/components/composite-row/skin.scss index 59ed63e6f..45589a5a7 100644 --- a/ui-v2/app/styles/components/composite-row/skin.scss +++ b/ui-v2/app/styles/components/composite-row/skin.scss @@ -33,9 +33,12 @@ margin-right: 3px; } %composite-row-detail .policy-management::before { + margin-right: 3px; +} +%composite-row-detail .policy-management::before, +%composite-row-header .policy-management dd::before { @extend %with-star-fill-mask, %as-pseudo; background-color: var(--brand-600); - margin-right: 3px; } // Health Checks %composite-row-detail li.passing::before, diff --git a/ui-v2/app/styles/components/more-popover-menu.scss b/ui-v2/app/styles/components/more-popover-menu.scss index 7d7fb6f0f..951c344ac 100644 --- a/ui-v2/app/styles/components/more-popover-menu.scss +++ b/ui-v2/app/styles/components/more-popover-menu.scss @@ -1,18 +1,24 @@ -.more-popover-menu > [type='checkbox'] { +.more-popover-menu { @extend %more-popover-menu; } -%more-popover-menu-panel [type='checkbox']:checked ~ * { - /* this needs to autocalculate */ - min-height: 143px; - max-height: 143px; +%more-popover-menu { + @extend %with-popover-menu; } -%more-popover-menu-panel [id$='logout']:checked ~ * { - /* this needs to autocalculate */ - min-height: 183px; - max-height: 183px; +%more-popover-menu > [type='checkbox'] + label { + @extend %more-popover-menu-trigger; } -%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'] { +/* This gives the trigger a slightly larger invisible hit area */ +%more-popover-menu-trigger { + padding: 7px; display: block; } +%more-popover-menu-trigger > * { + font-size: 0; + background-color: $transparent; + padding: 0; +} +%more-popover-menu-trigger > *::after { + @extend %with-more-horizontal-mask, %as-pseudo; + background-color: $gray-900; + margin: 0; +} diff --git a/ui-v2/app/styles/components/pill.scss b/ui-v2/app/styles/components/pill.scss index 4094f5e16..0d2f09f6d 100644 --- a/ui-v2/app/styles/components/pill.scss +++ b/ui-v2/app/styles/components/pill.scss @@ -2,44 +2,21 @@ td strong { @extend %pill; margin-right: 3px; } -// For the moment pills with classes are iconed ones -%pill:not([class]) { - @extend %frame-gray-900; -} -%pill[class] { - padding-left: 0; - margin-right: 16px; -} -%pill[class]::before { - @extend %as-pseudo; - margin-right: 3px; -} -%pill.policy::before { - @extend %with-file-fill-icon; - opacity: 0.3; -} -%pill.policy-management::before { - @extend %with-star-icon; -} -%pill.role::before { - @extend %with-user-plain-icon; - opacity: 0.3; -} - -// TODO: These are related to the pill icons, but also to the tables -// All of this icon assigning stuff should probably go in the eventual -// refactored /components/icons.scss file - -span.policy-management a::after { - @extend %with-star-icon, %as-pseudo; - margin-left: 3px; -} span.policy-service-identity, +span.policy-node-identity, .consul-external-source, .consul-kind { @extend %reduced-pill; } -span.policy-service-identity::before { - width: 0; +span.policy-service-identity::before, +span.policy-node-identity::before { + display: inline-block; + width: auto; +} +span.policy-node-identity::before { + content: 'Node Identity: '; +} +span.policy-service-identity::before { + content: 'Service Identity: '; } diff --git a/ui-v2/app/styles/components/table.scss b/ui-v2/app/styles/components/table.scss index 1bc25d71d..e86da9302 100644 --- a/ui-v2/app/styles/components/table.scss +++ b/ui-v2/app/styles/components/table.scss @@ -1,19 +1,13 @@ %main-content table { @extend %table; } -%table-actions > [type='checkbox'] { +%table-actions { @extend %more-popover-menu; -} -%table-actions .confirmation-alert { - @extend %confirmation-alert; + overflow: visible; } %table-actions > [type='checkbox'] + label { position: absolute; - top: 8px; - right: 15px; -} -%table-actions .menu-panel:not(.above) { - top: 38px !important; + right: 5px; } /*TODO: Rename this to %app-view-brand-icon or similar */ diff --git a/ui-v2/app/templates/dc/acls/policies/-view.hbs b/ui-v2/app/templates/dc/acls/policies/-view.hbs index 19464f922..bbdfe7422 100644 --- a/ui-v2/app/templates/dc/acls/policies/-view.hbs +++ b/ui-v2/app/templates/dc/acls/policies/-view.hbs @@ -1,5 +1,5 @@

    Management This global-management token is built into Consul's policy system. You can apply this special policy to tokens for full access. This policy is not editable or removeable, but can be ignored by not applying it to any tokens. Learn more in our documentation.

    -
    +
    Name
    {{item.Name}}
    diff --git a/ui-v2/app/templates/dc/acls/policies/index.hbs b/ui-v2/app/templates/dc/acls/policies/index.hbs index bfc2284ee..c1baae410 100644 --- a/ui-v2/app/templates/dc/acls/policies/index.hbs +++ b/ui-v2/app/templates/dc/acls/policies/index.hbs @@ -40,66 +40,10 @@ {{/if}} - - - Name - Datacenters - Description - - - - {{item.Name}} - - - {{join ', ' (policy/datacenters item)}} - - -

    {{item.Description}}

    - -
    - - - - More - - -{{#if (eq (policy/typeof item) 'policy-management')}} -
  • - View -
  • -{{else}} - -
  • - Edit -
  • -
  • - -
    -
    -
    -
    - Confirm Delete -
    -

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

    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
  • -{{/if}} -
    -
    -
    -
    +
    diff --git a/ui-v2/app/templates/dc/acls/roles/index.hbs b/ui-v2/app/templates/dc/acls/roles/index.hbs index 2cab993c3..9fe9de761 100644 --- a/ui-v2/app/templates/dc/acls/roles/index.hbs +++ b/ui-v2/app/templates/dc/acls/roles/index.hbs @@ -40,61 +40,10 @@ {{/if}} - - - Name - Description - Policies - - - - {{item.Name}} - - -

    {{item.Description}}

    - - - {{#each item.Policies as |item|}} - {{item.Name}} - {{/each}} - -
    - - - - More - - -
  • - Edit -
  • -
  • - -
    -
    -
    -
    - Confirm Delete -
    -

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

    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
  • -
    -
    -
    -
    +
    diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/index.feature b/ui-v2/tests/acceptance/dc/acls/tokens/index.feature index 16377e453..5645f9c47 100644 --- a/ui-v2/tests/acceptance/dc/acls/tokens/index.feature +++ b/ui-v2/tests/acceptance/dc/acls/tokens/index.feature @@ -77,7 +77,7 @@ Feature: dc / acls / tokens / index: ACL Token List s: Si-Search --- And I see 1 token model - And I see 1 token model with the serviceIdentity "Service Identity: Si-Search" + And I see 1 token model with the serviceIdentity "Si-Search" Scenario: I see the legacy message if I have one legacy token Given 1 datacenter model with the value "dc-1" And 3 token models from yaml diff --git a/ui-v2/tests/pages.js b/ui-v2/tests/pages.js index 4d56644e8..33bd49153 100644 --- a/ui-v2/tests/pages.js +++ b/ui-v2/tests/pages.js @@ -33,8 +33,13 @@ import policyFormFactory from 'consul-ui/components/policy-form/pageobject'; import policySelectorFactory from 'consul-ui/components/policy-selector/pageobject'; import roleFormFactory from 'consul-ui/components/role-form/pageobject'; import roleSelectorFactory from 'consul-ui/components/role-selector/pageobject'; + +import morePopoverMenuFactory from 'consul-ui/components/more-popover-menu/pageobject'; + import tokenListFactory from 'consul-ui/components/token-list/pageobject'; import consulTokenListFactory from 'consul-ui/components/consul-token-list/pageobject'; +import consulRoleListFactory from 'consul-ui/components/consul-role-list/pageobject'; +import consulPolicyListFactory from 'consul-ui/components/consul-policy-list/pageobject'; import consulIntentionListFactory from 'consul-ui/components/consul-intention-list/pageobject'; // pages @@ -86,8 +91,31 @@ const policyForm = policyFormFactory(submitable, cancelable, radiogroup, text); const policySelector = policySelectorFactory(clickable, deletable, collection, alias, policyForm); const roleForm = roleFormFactory(submitable, cancelable, policySelector); const roleSelector = roleSelectorFactory(clickable, deletable, collection, alias, roleForm); + +const morePopoverMenu = morePopoverMenuFactory(clickable); + const consulIntentionList = consulIntentionListFactory(collection, clickable, attribute, deletable); -const consulTokenList = consulTokenListFactory(collection, clickable, attribute, text, deletable); +const consulTokenList = consulTokenListFactory( + collection, + clickable, + attribute, + text, + morePopoverMenu +); +const consulRoleList = consulRoleListFactory( + collection, + clickable, + attribute, + text, + morePopoverMenu +); +const consulPolicyList = consulPolicyListFactory( + collection, + clickable, + attribute, + text, + morePopoverMenu +); const page = pageFactory(clickable, attribute, is, authForm); @@ -115,22 +143,9 @@ export default { kv: create(kv(visitable, attribute, submitable, deletable, cancelable, clickable)), acls: create(acls(visitable, deletable, creatable, clickable, attribute, collection, aclFilter)), acl: create(acl(visitable, submitable, deletable, cancelable, clickable)), - policies: create( - policies( - visitable, - deletable, - creatable, - clickable, - attribute, - collection, - text, - freetextFilter - ) - ), + policies: create(policies(visitable, creatable, consulPolicyList, freetextFilter)), policy: create(policy(visitable, submitable, deletable, cancelable, clickable, tokenList)), - roles: create( - roles(visitable, deletable, creatable, clickable, attribute, collection, text, freetextFilter) - ), + roles: create(roles(visitable, creatable, consulRoleList, freetextFilter)), // TODO: This needs a policyList role: create(role(visitable, submitable, deletable, cancelable, policySelector, tokenList)), tokens: create(tokens(visitable, creatable, text, consulTokenList, freetextFilter)), diff --git a/ui-v2/tests/pages/dc/acls/policies/index.js b/ui-v2/tests/pages/dc/acls/policies/index.js index 3bf96bf1a..7b196ba34 100644 --- a/ui-v2/tests/pages/dc/acls/policies/index.js +++ b/ui-v2/tests/pages/dc/acls/policies/index.js @@ -1,24 +1,7 @@ -export default function( - visitable, - deletable, - creatable, - clickable, - attribute, - collection, - text, - filter -) { +export default function(visitable, creatable, policies, filter) { return creatable({ visit: visitable('/:dc/acls/policies'), - policies: collection( - '[data-test-tabular-row]', - deletable({ - name: attribute('data-test-policy', '[data-test-policy]'), - description: text('[data-test-description]'), - policy: clickable('a'), - actions: clickable('label'), - }) - ), + policies: policies(), filter: filter(), }); } diff --git a/ui-v2/tests/pages/dc/acls/roles/index.js b/ui-v2/tests/pages/dc/acls/roles/index.js index 35b665992..b226f708a 100644 --- a/ui-v2/tests/pages/dc/acls/roles/index.js +++ b/ui-v2/tests/pages/dc/acls/roles/index.js @@ -1,25 +1,8 @@ -export default function( - visitable, - deletable, - creatable, - clickable, - attribute, - collection, - text, - filter -) { - return creatable({ +export default function(visitable, creatable, roles, filter) { + return { visit: visitable('/:dc/acls/roles'), - roles: collection( - '[data-test-tabular-row]', - deletable({ - name: attribute('data-test-role', '[data-test-role]'), - description: text('[data-test-description]'), - policy: text('[data-test-policy].policy', { multiple: true }), - serviceIdentity: text('[data-test-policy].policy-service-identity', { multiple: true }), - actions: clickable('label'), - }) - ), + roles: roles(), filter: filter(), - }); + ...creatable(), + }; }