From ab39638e072881f71eb6f8f21be68022760bbf62 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 30 Jul 2020 15:12:52 -0400 Subject: [PATCH 01/29] chore: Add "manage" button to user edit page --- .../scopes/scope/users/user/index.hbs | 21 +++++++++++-------- ui/core/translations/en-us.yaml | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs index d80978336..c50c14754 100644 --- a/ui/core/app/templates/scopes/scope/users/user/index.hbs +++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs @@ -8,6 +8,17 @@

{{t "resources.user"}}

+ + + + {{t 'actions.delete'}} + + + + @@ -17,19 +28,11 @@ - - - - {{t 'actions.delete'}} - diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 4075aa92a..08a14ff5b 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -65,6 +65,7 @@ form: type: Type identification: Username password: Password + manage: Manage errors: titles: unauthenticated-error: You are not signed in From 369ea937f5c0526f1b833433d2507cd4001f95f9 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 31 Jul 2020 10:37:23 -0400 Subject: [PATCH 02/29] chore: Use rose/dropdown comp in header utilities/dropdown --- .../styles/rose/components/_dropdown.scss | 16 +++- .../rose/components/header/_dropdown.scss | 81 ++----------------- .../styles/rose/utilities/_dropdown.scss | 4 +- .../templates/components/rose/dropdown.hbs | 2 +- .../components/rose/header/utilities.hbs | 2 +- 5 files changed, 23 insertions(+), 82 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index bd87f3acb..d4fb27f03 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -12,12 +12,22 @@ overflow: hidden; display: flex; align-items: center; - margin-right: sizing.rems(s); padding: 0 sizing.rems(xl) 0 sizing.rems(l); $lineHeight: 36 / 13; line-height: $lineHeight; - //color: var(--subtle); + // Hide default twistie triangle + // Webkit / Chromium + &::-webkit-details-marker { + display: none; + } + // Firefox + list-style-type: none; + &::marker { + display: none; + } + + // color: var(--subtle); background: url("data:image/svg+xml;utf-8,") no-repeat right sizing.rems(s) center; background-size: sizing.rems(m); @@ -84,7 +94,7 @@ .rose-dropdown-link, .rose-button-dropdown { - @include type.type(m, normal); + @include type.type(s, normal); display: block; // Targeting min-width of 200 min-width: (sizing.rems(m) + sizing.rems(xxs)) * 10; diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss index 5436c1b57..8e1c8766a 100644 --- a/addons/rose/addon/styles/rose/components/header/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -18,44 +18,17 @@ ) ); -.rose-header-dropdown { - position: relative; - display: inline-block; +.rose-header-utilities { + margin-right: sizing.rems(s); - .rose-header-dropdown-trigger { - cursor: default; - overflow: hidden; - display: flex; - align-items: center; + .rose-dropdown-trigger { background-size: sizing.rems(m); - margin-right: sizing.rems(s); padding-right: sizing.rems(l) - sizing.rems(xxs); $lineHeight: 48 / 16; line-height: $lineHeight; - &.icon-only { - padding-right: sizing.rems(m); - - .rose-header-dropdown-trigger-text { - // TODO: factor out into visually-hidden mixin utility - position: absolute; - left: -1000px; - top: -1000px; - width: 1px; - height: 1px; - opacity: 0; - } - } - - // Hide default twistie triangle - // Webkit / Chromium - &::-webkit-details-marker { - display: none; - } - // Firefox - list-style-type: none; - &::marker { - display: none; + .rose-icon { + --size: #{sizing.rems(l)}; } .rose-icon { @@ -66,51 +39,9 @@ vertical-align: top; } } - } - - .rose-header-dropdown-content { - $xs: sizing.rems(xs); // 8 - $xxs: sizing.rems(xxs); // 4 - position: absolute; - padding: $xxs 0; - border: 1px solid var(--ui-gray-subtler-2); - border-radius: sizing.rems(xxxs); - background: var(--subtle); - box-shadow: 0 $xxs $xxs rgba(var(--stark-components), var(--opacity-3)), - 0 $xxs $xs rgba(var(--stark-components), var(--opacity-4)); - z-index: 99; - } - - &.dropdown-right { - .rose-header-dropdown-content { - right: 0; - } - } - - .rose-header-dropdown-link, - .rose-button-header-dropdown { - @include type.type(m, normal); - display: block; - // Targeting min-width of 200 - min-width: (sizing.rems(m) + sizing.rems(xxs)) * 10; - padding: 0 sizing.rems(s); - margin: 0; - border: 0; - color: var(--stark); - background-color: transparent; - // target line height is 36, which is not a standard line height for this - // font size - $lineHeight: 36 / 16; - line-height: $lineHeight; - text-align: left; - text-decoration: none; &:hover { - background-color: var(--ui-gray-subtler-4); + background-color: unset; } } - - .rose-button-header-dropdown { - width: 100%; - } } diff --git a/addons/rose/addon/styles/rose/utilities/_dropdown.scss b/addons/rose/addon/styles/rose/utilities/_dropdown.scss index 059d2d56d..8368a9366 100644 --- a/addons/rose/addon/styles/rose/utilities/_dropdown.scss +++ b/addons/rose/addon/styles/rose/utilities/_dropdown.scss @@ -8,8 +8,8 @@ $dropdown-chevron: ( ); @mixin dropdown-style($name, $default) { - .rose-header-dropdown-#{$name} { - .rose-header-dropdown-trigger { + .rose-dropdown-#{$name} { + .rose-dropdown-trigger { color: map.get($default, color); background: url(map.get($dropdown-chevron, map.get($default, chevron))) no-repeat right center; diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index c65c640ba..7de02c1b7 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -1,6 +1,6 @@
diff --git a/addons/rose/addon/templates/components/rose/header/utilities.hbs b/addons/rose/addon/templates/components/rose/header/utilities.hbs index 6ee49e33f..cd0705a52 100644 --- a/addons/rose/addon/templates/components/rose/header/utilities.hbs +++ b/addons/rose/addon/templates/components/rose/header/utilities.hbs @@ -1,5 +1,5 @@
{{yield (hash - dropdown=(component 'rose/header/dropdown' alignRight=true) + dropdown=(component 'rose/dropdown' alignRight=true style="light") )}}
From 28c30d3244ed881699bf2502d16ef67a90ad3c18 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 31 Jul 2020 10:39:50 -0400 Subject: [PATCH 03/29] chore: Remove utilities/header/dropdown component in rose --- .../addon/components/rose/header/dropdown.js | 16 ---- .../components/rose/header/dropdown.hbs | 32 -------- .../app/components/rose/header/dropdown.js | 1 - .../components/rose/header/dropdown-test.js | 80 ------------------- 4 files changed, 129 deletions(-) delete mode 100644 addons/rose/addon/components/rose/header/dropdown.js delete mode 100644 addons/rose/addon/templates/components/rose/header/dropdown.hbs delete mode 100644 addons/rose/app/components/rose/header/dropdown.js delete mode 100644 addons/rose/tests/integration/components/rose/header/dropdown-test.js diff --git a/addons/rose/addon/components/rose/header/dropdown.js b/addons/rose/addon/components/rose/header/dropdown.js deleted file mode 100644 index 4a5897084..000000000 --- a/addons/rose/addon/components/rose/header/dropdown.js +++ /dev/null @@ -1,16 +0,0 @@ -import Component from '@ember/component'; -import layout from '../../../templates/components/rose/header/dropdown'; -import { action } from '@ember/object'; - -export default Component.extend({ - layout, - tagName: '', - - // Uses details widget state to close dropdown - @action - close(element) { - if (element.open) { - element.open = false; - } - }, -}); diff --git a/addons/rose/addon/templates/components/rose/header/dropdown.hbs b/addons/rose/addon/templates/components/rose/header/dropdown.hbs deleted file mode 100644 index cc874c284..000000000 --- a/addons/rose/addon/templates/components/rose/header/dropdown.hbs +++ /dev/null @@ -1,32 +0,0 @@ -
- - - - {{#if @icon}} - - {{/if}} - - - {{@text}} - - - - -
- {{yield (hash - link=(component "link-to" class="rose-header-dropdown-link") - button=(component "rose/button" style="header-dropdown") - )}} -
- -
diff --git a/addons/rose/app/components/rose/header/dropdown.js b/addons/rose/app/components/rose/header/dropdown.js deleted file mode 100644 index 16d89ac10..000000000 --- a/addons/rose/app/components/rose/header/dropdown.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'rose/components/rose/header/dropdown'; diff --git a/addons/rose/tests/integration/components/rose/header/dropdown-test.js b/addons/rose/tests/integration/components/rose/header/dropdown-test.js deleted file mode 100644 index 96806b98b..000000000 --- a/addons/rose/tests/integration/components/rose/header/dropdown-test.js +++ /dev/null @@ -1,80 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render, click, find, findAll } from '@ember/test-helpers'; -import hbs from 'htmlbars-inline-precompile'; - -module('Integration | Component | rose/header/dropdown', function (hooks) { - setupRenderingTest(hooks); - - test('it renders', async function (assert) { - await render(hbs``); - assert.ok(find('.rose-header-dropdown')); - }); - - test('it renders with html attributes', async function (assert) { - await render( - hbs`` - ); - assert.ok(find('#custom-id')); - assert.ok(find('.custom-class')); - }); - - test('it renders with trigger', async function (assert) { - await render(hbs``); - assert.equal( - find('.rose-header-dropdown-trigger').textContent.trim(), - 'Click me' - ); - }); - - test('it supports an icon', async function (assert) { - await render(hbs``); - assert.ok(find('svg')); - }); - - test('it supports icon-only display', async function (assert) { - await render(hbs``); - assert.ok(find('.icon-only')); - }); - - test('it supports right-aligned content', async function (assert) { - await render(hbs``); - assert.ok(find('.dropdown-right')); - }); - - test('it renders with content', async function (assert) { - await render(hbs` - - - - - - `); - assert.ok(find('.rose-header-dropdown-content')); - assert.equal(findAll('a').length, 2); - assert.equal(findAll('button').length, 3); - }); - - test('it is toggled on click on trigger content', async function (assert) { - await render(hbs``); - - assert.notOk(find('#dropdown').open); - await click('summary'); - assert.ok(find('#dropdown').open); - await click('summary'); - assert.notOk(find('#dropdown').open); - }); - - test('it is closed with outside click is triggered', async function (assert) { - await render(hbs` -
- -
- `); - - await click('summary'); - assert.ok(find('#dropdown').open); - await click('#wrapper'); - assert.notOk(find('#dropdown').open); - }); -}); From 8836611b08544603e7c49190629cc682d60a55d3 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 31 Jul 2020 15:49:07 -0400 Subject: [PATCH 04/29] chore: Use rose/dropdown comp in header nav comp --- .../rose/components/header/_dropdown.scss | 2 +- .../templates/components/rose/header/nav.hbs | 2 +- .../rose/tests/dummy/app/templates/index.hbs | 32 +++++++++++++++---- .../components/rose/header-test.js | 2 +- .../components/rose/header/nav-test.js | 2 +- .../components/rose/header/utilities-test.js | 2 +- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss index 8e1c8766a..5ffa927d3 100644 --- a/addons/rose/addon/styles/rose/components/header/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -18,7 +18,7 @@ ) ); -.rose-header-utilities { +.rose-header-utilities, .rose-header-nav { margin-right: sizing.rems(s); .rose-dropdown-trigger { diff --git a/addons/rose/addon/templates/components/rose/header/nav.hbs b/addons/rose/addon/templates/components/rose/header/nav.hbs index 2b2978e00..18458e10c 100644 --- a/addons/rose/addon/templates/components/rose/header/nav.hbs +++ b/addons/rose/addon/templates/components/rose/header/nav.hbs @@ -1,6 +1,6 @@ diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 2974ba49c..dba08ec08 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -1,6 +1,26 @@ - - - Key - Value - - + + + + + + Menu item + Menu item + Button menu item + + Section + Section + + + + + Menu item + Menu item + Button menu item + + + + diff --git a/addons/rose/tests/integration/components/rose/header-test.js b/addons/rose/tests/integration/components/rose/header-test.js index 7e0f57da7..2feb23438 100644 --- a/addons/rose/tests/integration/components/rose/header-test.js +++ b/addons/rose/tests/integration/components/rose/header-test.js @@ -53,6 +53,6 @@ module('Integration | Component | rose/header', function (hooks) { `); - assert.ok(find('.rose-header-dropdown')); + assert.ok(find('.rose-dropdown')); }); }); diff --git a/addons/rose/tests/integration/components/rose/header/nav-test.js b/addons/rose/tests/integration/components/rose/header/nav-test.js index d1c5a688d..fd713c0db 100644 --- a/addons/rose/tests/integration/components/rose/header/nav-test.js +++ b/addons/rose/tests/integration/components/rose/header/nav-test.js @@ -24,6 +24,6 @@ module('Integration | Component | rose/header/nav', function (hooks) { `); - assert.equal(findAll('.rose-header-dropdown').length, 2); + assert.equal(findAll('.rose-dropdown').length, 2); }); }); diff --git a/addons/rose/tests/integration/components/rose/header/utilities-test.js b/addons/rose/tests/integration/components/rose/header/utilities-test.js index 884266d8f..ba8de3f93 100644 --- a/addons/rose/tests/integration/components/rose/header/utilities-test.js +++ b/addons/rose/tests/integration/components/rose/header/utilities-test.js @@ -16,6 +16,6 @@ module('Integration | Component | rose/header/utilities', function (hooks) { `); - assert.equal(findAll('.rose-header-dropdown').length, 2); + assert.equal(findAll('.rose-dropdown').length, 2); }); }); From ed69d66939741c56a85d4ff4c8726e8c3bae6fab Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 15:42:51 -0400 Subject: [PATCH 05/29] chore: Add button styles to dropdown button --- .../components/rose/dropdown.stories.mdx | 24 ++++++++++++++++++- .../styles/rose/components/_dropdown.scss | 10 +++++--- .../templates/components/rose/button.hbs | 2 +- .../templates/components/rose/dropdown.hbs | 2 +- .../rose/tests/dummy/app/templates/index.hbs | 15 +++++++++++- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index 87c50f1f1..25a441767 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -7,7 +7,7 @@ import { text, boolean, select } from '@storybook/addon-knobs'; # Dropdown -A simple dropdown component with support for links and buttons. +A simple dropdown component with support for links and buttons. Dropdown buttons support pre-defined styles of `Rose::Button`. {{ @@ -43,3 +43,25 @@ A simple dropdown component with support for links and buttons. Button menu item ``` + +Dropdown content can be aligned to right edge of the component instead of the default left edge. The following example floats the component to right edge of the page inorder to provide enough space to display right aligned dropdown content. + +```htmlbars + + Menu item + Menu item + Button menu item + +``` + +Dropdown button styles can be supplied through a `style` attribute. + +```htmlbars + + Button menu item + Button - warning + Button - primary + Button - secondary + Button - ghost + +``` diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index d4fb27f03..58eac5a0a 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -93,7 +93,7 @@ } .rose-dropdown-link, - .rose-button-dropdown { + .rose-dropdown-button { @include type.type(s, normal); display: block; // Targeting min-width of 200 @@ -109,13 +109,17 @@ line-height: $lineHeight; text-align: left; text-decoration: none; + box-shadow: none; + text-shadow: none; + cursor: pointer; &:hover { - background-color: var(--ui-gray-subtler-4); + box-shadow: none; + text-shadow: none; } } - .rose-button-dropdown { + .rose-dropdown-button { width: 100%; } } diff --git a/addons/rose/addon/templates/components/rose/button.hbs b/addons/rose/addon/templates/components/rose/button.hbs index a8ac2acbd..6f5974289 100644 --- a/addons/rose/addon/templates/components/rose/button.hbs +++ b/addons/rose/addon/templates/components/rose/button.hbs @@ -2,7 +2,7 @@ ...attributes type={{if @submit "submit" "button"}} disabled={{if @disabled "disabled"}} - class="{{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}" + class="{{@class}} {{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}" > diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 7de02c1b7..8d2b75734 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -25,7 +25,7 @@
{{yield (hash link=(component "link-to" class="rose-dropdown-link") - button=(component "rose/button" style="dropdown") + button=(component "rose/button" class="rose-dropdown-button" style=this.style) )}}
diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index dba08ec08..72f1657d5 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -19,8 +19,21 @@ > Menu item Menu item - Button menu item + Button - default + Button - warning + Button - primary + Button - secondary + Button - ghost + + Menu item + Menu item + Button menu item + Button - warning + Button - primary + Button - secondary + Button - ghost + From 4ea307e5cf2a89197dbecab00d0dba5ecb7b38e1 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 15:43:22 -0400 Subject: [PATCH 06/29] style: yarn format --- addons/rose/addon/styles/rose/components/header/_dropdown.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss index 5ffa927d3..95f1f663f 100644 --- a/addons/rose/addon/styles/rose/components/header/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -18,7 +18,8 @@ ) ); -.rose-header-utilities, .rose-header-nav { +.rose-header-utilities, +.rose-header-nav { margin-right: sizing.rems(s); .rose-dropdown-trigger { From 2509b6a270af0670d74868690038bcd8804aa5f5 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 15:53:47 -0400 Subject: [PATCH 07/29] chore: Add "Manage" button to edit views for IAM resources --- .../scopes/scope/groups/group/index.hbs | 20 +++++++++++-------- .../scopes/scope/roles/role/index.hbs | 20 +++++++++++-------- .../scopes/scope/users/user/index.hbs | 3 ++- ui/core/translations/en-us.yaml | 3 +++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/ui/core/app/templates/scopes/scope/groups/group/index.hbs b/ui/core/app/templates/scopes/scope/groups/group/index.hbs index ac8915f59..ffe366e71 100644 --- a/ui/core/app/templates/scopes/scope/groups/group/index.hbs +++ b/ui/core/app/templates/scopes/scope/groups/group/index.hbs @@ -16,20 +16,24 @@ + + + + {{t 'actions.delete-group'}} + + + + - - - {{t 'actions.delete'}} - diff --git a/ui/core/app/templates/scopes/scope/roles/role/index.hbs b/ui/core/app/templates/scopes/scope/roles/role/index.hbs index 1b35c1929..c3d9734e0 100644 --- a/ui/core/app/templates/scopes/scope/roles/role/index.hbs +++ b/ui/core/app/templates/scopes/scope/roles/role/index.hbs @@ -8,20 +8,24 @@

{{t "resources.role"}}

+ + + + {{t 'actions.delete-role'}} + + + + - - - {{t 'actions.delete'}} - diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs index c50c14754..2261fa30b 100644 --- a/ui/core/app/templates/scopes/scope/users/user/index.hbs +++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs @@ -11,10 +11,11 @@ - {{t 'actions.delete'}} + {{t 'actions.delete-user'}} diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 08a14ff5b..181bcbf12 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -8,6 +8,9 @@ actions: deauthenticate: Deauthenticate choose-org: Choose Scope choose-different-org: Choose a Different Scope + delete-user: Delete user + delete-group: Delete group + delete-role: Delete role auth: titles: no-scopes: No Scopes Available From 22237958201fd81b46b05d8f005ebe789db0822b Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 16:00:39 -0400 Subject: [PATCH 08/29] chore: Add data-test tag for deauthenticate dropdown button --- ui/core/app/templates/application.hbs | 5 ++++- ui/core/tests/acceptance/authentication-test.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs index 0f0b66871..8a88d8271 100644 --- a/ui/core/app/templates/application.hbs +++ b/ui/core/app/templates/application.hbs @@ -26,7 +26,10 @@ @iconOnly={{true}} @icon="user-square-fill" as |dropdown| > - + {{t 'actions.deauthenticate'}} diff --git a/ui/core/tests/acceptance/authentication-test.js b/ui/core/tests/acceptance/authentication-test.js index 478e2f1dd..ca997453c 100644 --- a/ui/core/tests/acceptance/authentication-test.js +++ b/ui/core/tests/acceptance/authentication-test.js @@ -164,7 +164,7 @@ module('Acceptance | authentication', function (hooks) { await fillIn('[name="password"]', 'test'); await click('[type="submit"]'); assert.ok(currentSession().isAuthenticated); - await click('.rose-button-header-dropdown'); + await click('[data-test-deauthenticate]'); assert.notOk(currentSession().isAuthenticated); assert.equal(currentURL(), authMethodAuthenticateURL); }); From 26795b9359f83cc62a09e7c1590183bb6e459350 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 16:09:27 -0400 Subject: [PATCH 09/29] chore: Add dropdown right alignment tests --- addons/rose/addon/styles/rose/components/_dropdown.scss | 2 +- addons/rose/addon/templates/components/rose/dropdown.hbs | 2 +- .../tests/integration/components/rose/dropdown-test.js | 8 ++++++++ .../integration/components/rose/header/utilities-test.js | 7 +++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index 58eac5a0a..13e19785b 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -86,7 +86,7 @@ z-index: 99; } - &.dropdown-right { + &.rose-dropdown-right { .rose-dropdown-content { right: 0; } diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 8d2b75734..00ab21e62 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -1,6 +1,6 @@
diff --git a/addons/rose/tests/integration/components/rose/dropdown-test.js b/addons/rose/tests/integration/components/rose/dropdown-test.js index 3d4597c95..03c1b65e7 100644 --- a/addons/rose/tests/integration/components/rose/dropdown-test.js +++ b/addons/rose/tests/integration/components/rose/dropdown-test.js @@ -9,6 +9,7 @@ module('Integration | Component | rose/dropdown', function (hooks) { test('it renders', async function (assert) { await render(hbs``); assert.ok(find('.rose-dropdown')); + assert.notOk(find('.rose-dropdown-right')); }); test('it renders with html attributes', async function (assert) { @@ -32,6 +33,13 @@ module('Integration | Component | rose/dropdown', function (hooks) { assert.ok(find('.has-icon-only')); }); + test('it supports right aligned content', async function (assert) { + await render(hbs` + + `); + assert.ok(find('.rose-dropdown-right')); + }); + test('it renders with content', async function (assert) { await render(hbs` diff --git a/addons/rose/tests/integration/components/rose/header/utilities-test.js b/addons/rose/tests/integration/components/rose/header/utilities-test.js index ba8de3f93..1bb44de8e 100644 --- a/addons/rose/tests/integration/components/rose/header/utilities-test.js +++ b/addons/rose/tests/integration/components/rose/header/utilities-test.js @@ -18,4 +18,11 @@ module('Integration | Component | rose/header/utilities', function (hooks) { `); assert.equal(findAll('.rose-dropdown').length, 2); }); + + test('it renders nav dropdown elements as right aligned', async function (assert) { + await render(hbs` + + `); + assert.ok(find('.rose-dropdown.rose-dropdown-right')); + }); }); From 23c97c1f157577898d7f353b92ee39625a49bb00 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 10 Aug 2020 18:31:54 -0400 Subject: [PATCH 10/29] chore: Update dropdown chevron styles --- addons/rose/addon/components/rose/dropdown.js | 2 +- .../components/rose/dropdown.stories.mdx | 13 +++++++-- .../styles/rose/components/_dropdown.scss | 29 +++++++++++++++++-- .../rose/components/header/_dropdown.scss | 20 +------------ .../styles/rose/utilities/_dropdown.scss | 3 +- .../templates/components/rose/dropdown.hbs | 2 +- 6 files changed, 42 insertions(+), 27 deletions(-) diff --git a/addons/rose/addon/components/rose/dropdown.js b/addons/rose/addon/components/rose/dropdown.js index 4e6ffea81..33547b719 100644 --- a/addons/rose/addon/components/rose/dropdown.js +++ b/addons/rose/addon/components/rose/dropdown.js @@ -13,7 +13,7 @@ export default Component.extend({ /** * Closes the details element by setting its `open` attribute to `false`. * While the details element handles open/close functionality when clicking - * directly on the summar elemenet without JavaScript, we include this helper + * directly on the summary element without JavaScript, we include this helper * action to ensure that when the user clicks _outside_ of the element, * or _inside_ the content, it still closes. * @param {HTMLElement} element diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index 25a441767..86e1c3048 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -12,13 +12,22 @@ A simple dropdown component with support for links and buttons. Dropdown buttons {{ template: hbs` - + Menu item Menu item Button menu item `, - context: {} + context: { + style: select( + 'style', + { + 'light': 'light', + 'dark': 'dark', + }, + 'dark' + ), + } }} diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index 13e19785b..dd69ee8d3 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -2,6 +2,22 @@ @use '../utilities/type'; @use '../utilities/dropdown'; +@include dropdown.dropdown-style( + 'light', + ( + color: var(--white), + chevron: 'light', + ) +); + +@include dropdown.dropdown-style( + 'dark', + ( + color: var(--black), + chevron: 'dark', + ) +); + .rose-dropdown { position: relative; display: inline-block; @@ -27,9 +43,6 @@ display: none; } - // color: var(--subtle); - background: url("data:image/svg+xml;utf-8,") - no-repeat right sizing.rems(s) center; background-size: sizing.rems(m); &:hover { @@ -121,5 +134,15 @@ .rose-dropdown-button { width: 100%; + + &.rose-button-warning { + color: unset; + } + + // &.rose-button-warning { + // &:hover, &:focus { + // color: unset; + // } + // } } } diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss index 95f1f663f..0cfdaccdf 100644 --- a/addons/rose/addon/styles/rose/components/header/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -1,22 +1,5 @@ @use '../../variables/sizing'; @use '../../utilities/type'; -@use '../../utilities/dropdown'; - -@include dropdown.dropdown-style( - 'light', - ( - color: var(--white), - chevron: 'light', - ) -); - -@include dropdown.dropdown-style( - 'dark', - ( - color: var(--black), - chevron: 'dark', - ) -); .rose-header-utilities, .rose-header-nav { @@ -24,7 +7,6 @@ .rose-dropdown-trigger { background-size: sizing.rems(m); - padding-right: sizing.rems(l) - sizing.rems(xxs); $lineHeight: 48 / 16; line-height: $lineHeight; @@ -41,7 +23,7 @@ } } - &:hover { + &:hover, &:focus { background-color: unset; } } diff --git a/addons/rose/addon/styles/rose/utilities/_dropdown.scss b/addons/rose/addon/styles/rose/utilities/_dropdown.scss index 8368a9366..b7e2a5358 100644 --- a/addons/rose/addon/styles/rose/utilities/_dropdown.scss +++ b/addons/rose/addon/styles/rose/utilities/_dropdown.scss @@ -1,4 +1,5 @@ @use 'sass:map'; +@use '../variables/sizing'; $dropdown-chevron: ( 'light': @@ -12,7 +13,7 @@ $dropdown-chevron: ( .rose-dropdown-trigger { color: map.get($default, color); background: url(map.get($dropdown-chevron, map.get($default, chevron))) - no-repeat right center; + no-repeat right sizing.rems(s) center; } } } diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 00ab21e62..8c80b69e4 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -1,6 +1,6 @@
From cfe1d316365f44f2ff0b167ce15e474ed0194ea8 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 11 Aug 2020 10:14:45 -0400 Subject: [PATCH 11/29] chore: Update dropdown storybook Remove commented style --- addons/rose/addon/components/rose/dropdown.stories.mdx | 6 +++--- addons/rose/addon/styles/rose/components/_dropdown.scss | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index 86e1c3048..a89813392 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -7,7 +7,7 @@ import { text, boolean, select } from '@storybook/addon-knobs'; # Dropdown -A simple dropdown component with support for links and buttons. Dropdown buttons support pre-defined styles of `Rose::Button`. +A simple dropdown component with support for links and buttons. Supports `light` and `dark` styles, with latter being a default style. {{ @@ -53,7 +53,7 @@ A simple dropdown component with support for links and buttons. Dropdown buttons ``` -Dropdown content can be aligned to right edge of the component instead of the default left edge. The following example floats the component to right edge of the page inorder to provide enough space to display right aligned dropdown content. +Dropdown content can be aligned to right edge of the component instead of the default left edge, which is the default setting. The following example floats the component to right edge of the page inorder to provide enough space to display right aligned dropdown content. ```htmlbars @@ -63,7 +63,7 @@ Dropdown content can be aligned to right edge of the component instead of the de ``` -Dropdown button styles can be supplied through a `style` attribute. +Dropdown button styles support all `Rose::Button` styles through a `style` attribute. ```htmlbars diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index dd69ee8d3..8d083567d 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -138,11 +138,5 @@ &.rose-button-warning { color: unset; } - - // &.rose-button-warning { - // &:hover, &:focus { - // color: unset; - // } - // } } } From 518ce7c199e8d3a8c5e12d044b1f9a4ffa59f366 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 11 Aug 2020 18:59:34 -0400 Subject: [PATCH 12/29] chore: Update 'class' to 'classNames' attributes in dropdown --- addons/rose/addon/templates/components/rose/button.hbs | 2 +- addons/rose/addon/templates/components/rose/dropdown.hbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/rose/addon/templates/components/rose/button.hbs b/addons/rose/addon/templates/components/rose/button.hbs index 6f5974289..cd87dd8d8 100644 --- a/addons/rose/addon/templates/components/rose/button.hbs +++ b/addons/rose/addon/templates/components/rose/button.hbs @@ -2,7 +2,7 @@ ...attributes type={{if @submit "submit" "button"}} disabled={{if @disabled "disabled"}} - class="{{@class}} {{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}" + class="{{@classNames}} {{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}" > diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 8c80b69e4..c2be96f2d 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -25,7 +25,7 @@
{{yield (hash link=(component "link-to" class="rose-dropdown-link") - button=(component "rose/button" class="rose-dropdown-button" style=this.style) + button=(component "rose/button" classNames="rose-dropdown-button" style=this.style) )}}
From aa783e4d5a8c98690943b487f111ceb18c2ea131 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 11 Aug 2020 19:00:01 -0400 Subject: [PATCH 13/29] test: Update deauthenticate test data-test attribute --- ui/core/app/templates/application.hbs | 13 ------------- ui/core/tests/acceptance/authentication-test.js | 9 +++++++-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs index 8a88d8271..2422a624e 100644 --- a/ui/core/app/templates/application.hbs +++ b/ui/core/app/templates/application.hbs @@ -7,18 +7,6 @@ - {{!-- - - - {{t 'dev.menu-item'}} - {{t 'dev.menu-item'}} - {{t 'dev.button-menu-item'}} - - {{t 'dev.section'}} - {{t 'dev.section'}} - - --}} - {{#if this.session.isAuthenticated}} {{t 'actions.deauthenticate'}} diff --git a/ui/core/tests/acceptance/authentication-test.js b/ui/core/tests/acceptance/authentication-test.js index ca997453c..65d57018f 100644 --- a/ui/core/tests/acceptance/authentication-test.js +++ b/ui/core/tests/acceptance/authentication-test.js @@ -1,5 +1,5 @@ import { module, test } from 'qunit'; -import { visit, currentURL, fillIn, click, find } from '@ember/test-helpers'; +import { visit, currentURL, fillIn, click, find, findAll } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; @@ -158,13 +158,18 @@ module('Acceptance | authentication', function (hooks) { }); test('deauthentication redirects to first authenticate method', async function (assert) { + // TODO: Identify deauthenticate in menu through data-test attributes in non-production env only assert.expect(3); await visit(authMethodAuthenticateURL); await fillIn('[name="identification"]', 'test'); await fillIn('[name="password"]', 'test'); await click('[type="submit"]'); assert.ok(currentSession().isAuthenticated); - await click('[data-test-deauthenticate]'); + // Open header utilities dropdown + await click('.rose-header-utilities .rose-dropdown summary'); + // Find and click on last element in dropdown - should be deauthenticate button + const menu = findAll('.rose-header-utilities .rose-dropdown .rose-dropdown-content button'); + await click(menu[menu.length - 1]); assert.notOk(currentSession().isAuthenticated); assert.equal(currentURL(), authMethodAuthenticateURL); }); From 919e2f083b7286fb38d894fd79c54fa77604002d Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 11 Aug 2020 19:22:44 -0400 Subject: [PATCH 14/29] chore: Remove dropdown utilities sass file Move utilities sass file chevron definitions into dropdown styles in favour of a single dropdown style --- .../components/rose/dropdown.stories.mdx | 17 ++----------- .../styles/rose/components/_dropdown.scss | 25 ++++++------------- .../rose/components/header/_dropdown.scss | 10 +++++++- .../styles/rose/utilities/_dropdown.scss | 19 -------------- .../templates/components/rose/dropdown.hbs | 2 +- .../components/rose/header/utilities.hbs | 2 +- 6 files changed, 21 insertions(+), 54 deletions(-) delete mode 100644 addons/rose/addon/styles/rose/utilities/_dropdown.scss diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index a89813392..e77c8a73d 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -1,33 +1,21 @@ import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; import { hbs } from 'ember-cli-htmlbars'; -import { action } from '@storybook/addon-actions'; -import { text, boolean, select } from '@storybook/addon-knobs'; # Dropdown -A simple dropdown component with support for links and buttons. Supports `light` and `dark` styles, with latter being a default style. +A simple dropdown component with support for links and buttons. {{ template: hbs` - + Menu item Menu item Button menu item `, - context: { - style: select( - 'style', - { - 'light': 'light', - 'dark': 'dark', - }, - 'dark' - ), - } }} @@ -40,7 +28,6 @@ A simple dropdown component with support for links and buttons. Supports `light` Button menu item
`, - context: {} }}
diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/_dropdown.scss index 8d083567d..7a1bf9e53 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/_dropdown.scss @@ -1,22 +1,7 @@ @use '../variables/sizing'; @use '../utilities/type'; -@use '../utilities/dropdown'; -@include dropdown.dropdown-style( - 'light', - ( - color: var(--white), - chevron: 'light', - ) -); - -@include dropdown.dropdown-style( - 'dark', - ( - color: var(--black), - chevron: 'dark', - ) -); +$chevron: "data:image/svg+xml;utf-8,"; .rose-dropdown { position: relative; @@ -31,6 +16,8 @@ padding: 0 sizing.rems(xl) 0 sizing.rems(l); $lineHeight: 36 / 13; line-height: $lineHeight; + color: var(--black); + background: url($chevron) no-repeat right sizing.rems(s) center; // Hide default twistie triangle // Webkit / Chromium @@ -136,7 +123,11 @@ width: 100%; &.rose-button-warning { - color: unset; + color: var(--failure); + + &:hover { + color: var(--white); + } } } } diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss index 0cfdaccdf..c30f1371a 100644 --- a/addons/rose/addon/styles/rose/components/header/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -1,14 +1,18 @@ @use '../../variables/sizing'; @use '../../utilities/type'; +$chevron: "data:image/svg+xml;utf-8,"; + .rose-header-utilities, .rose-header-nav { margin-right: sizing.rems(s); .rose-dropdown-trigger { - background-size: sizing.rems(m); $lineHeight: 48 / 16; line-height: $lineHeight; + color: var(--white); + background: url($chevron) no-repeat right center; + background-size: sizing.rems(m); .rose-icon { --size: #{sizing.rems(l)}; @@ -28,3 +32,7 @@ } } } + +.rose-header-nav .rose-dropdown-trigger{ + padding-right: sizing.rems(l); +} diff --git a/addons/rose/addon/styles/rose/utilities/_dropdown.scss b/addons/rose/addon/styles/rose/utilities/_dropdown.scss deleted file mode 100644 index b7e2a5358..000000000 --- a/addons/rose/addon/styles/rose/utilities/_dropdown.scss +++ /dev/null @@ -1,19 +0,0 @@ -@use 'sass:map'; -@use '../variables/sizing'; - -$dropdown-chevron: ( - 'light': - "data:image/svg+xml;utf-8,", - 'dark': - "data:image/svg+xml;utf-8,", -); - -@mixin dropdown-style($name, $default) { - .rose-dropdown-#{$name} { - .rose-dropdown-trigger { - color: map.get($default, color); - background: url(map.get($dropdown-chevron, map.get($default, chevron))) - no-repeat right sizing.rems(s) center; - } - } -} diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index c2be96f2d..9386431d2 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -1,6 +1,6 @@
diff --git a/addons/rose/addon/templates/components/rose/header/utilities.hbs b/addons/rose/addon/templates/components/rose/header/utilities.hbs index cd0705a52..8c178538c 100644 --- a/addons/rose/addon/templates/components/rose/header/utilities.hbs +++ b/addons/rose/addon/templates/components/rose/header/utilities.hbs @@ -1,5 +1,5 @@
{{yield (hash - dropdown=(component 'rose/dropdown' alignRight=true style="light") + dropdown=(component 'rose/dropdown' alignRight=true) )}}
From 95d5b45d413f80c3e3109cc8fe172196c7e4a06f Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 11 Aug 2020 19:32:14 -0400 Subject: [PATCH 15/29] chore: Move role's manage button into updated layout --- ui/core/app/templates/scopes/scope/roles/role.hbs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/core/app/templates/scopes/scope/roles/role.hbs b/ui/core/app/templates/scopes/scope/roles/role.hbs index 552717330..848ae6a5c 100644 --- a/ui/core/app/templates/scopes/scope/roles/role.hbs +++ b/ui/core/app/templates/scopes/scope/roles/role.hbs @@ -10,6 +10,18 @@

{{t "resources.role"}}

+ + + + {{t 'actions.delete-role'}} + + + + From 0f63251ff294c4524be634898617c172f7a3b4e9 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 13 Aug 2020 11:12:31 -0400 Subject: [PATCH 16/29] chore: Rename dropdown alignRight attribute to: dropdownRight Remove unused `light` style dropdown def --- addons/rose/addon/components/rose/dropdown.js | 3 +++ addons/rose/addon/components/rose/dropdown.stories.mdx | 2 +- addons/rose/addon/templates/components/rose/dropdown.hbs | 2 +- addons/rose/addon/templates/components/rose/header/nav.hbs | 2 +- .../rose/addon/templates/components/rose/header/utilities.hbs | 2 +- addons/rose/tests/integration/components/rose/dropdown-test.js | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/rose/addon/components/rose/dropdown.js b/addons/rose/addon/components/rose/dropdown.js index 33547b719..8ae6f56e6 100644 --- a/addons/rose/addon/components/rose/dropdown.js +++ b/addons/rose/addon/components/rose/dropdown.js @@ -2,6 +2,9 @@ import Component from '@ember/component'; import layout from '../../templates/components/rose/dropdown'; import { action } from '@ember/object'; +/** + * A dropdown component composed of HTML disclosure elements: details and summary + */ export default Component.extend({ // =attributes diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index e77c8a73d..999b6278f 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -43,7 +43,7 @@ A simple dropdown component with support for links and buttons. Dropdown content can be aligned to right edge of the component instead of the default left edge, which is the default setting. The following example floats the component to right edge of the page inorder to provide enough space to display right aligned dropdown content. ```htmlbars - + Menu item Menu item Button menu item diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 9386431d2..6556bd0bc 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -1,6 +1,6 @@
diff --git a/addons/rose/addon/templates/components/rose/header/nav.hbs b/addons/rose/addon/templates/components/rose/header/nav.hbs index 18458e10c..a0858cc1a 100644 --- a/addons/rose/addon/templates/components/rose/header/nav.hbs +++ b/addons/rose/addon/templates/components/rose/header/nav.hbs @@ -1,6 +1,6 @@ diff --git a/addons/rose/addon/templates/components/rose/header/utilities.hbs b/addons/rose/addon/templates/components/rose/header/utilities.hbs index 8c178538c..e00d45e75 100644 --- a/addons/rose/addon/templates/components/rose/header/utilities.hbs +++ b/addons/rose/addon/templates/components/rose/header/utilities.hbs @@ -1,5 +1,5 @@
{{yield (hash - dropdown=(component 'rose/dropdown' alignRight=true) + dropdown=(component 'rose/dropdown' dropdownRight=true) )}}
diff --git a/addons/rose/tests/integration/components/rose/dropdown-test.js b/addons/rose/tests/integration/components/rose/dropdown-test.js index 03c1b65e7..0c0c22695 100644 --- a/addons/rose/tests/integration/components/rose/dropdown-test.js +++ b/addons/rose/tests/integration/components/rose/dropdown-test.js @@ -35,7 +35,7 @@ module('Integration | Component | rose/dropdown', function (hooks) { test('it supports right aligned content', async function (assert) { await render(hbs` - + `); assert.ok(find('.rose-dropdown-right')); }); From 30650962d91e659103bc84c0df158c970e57b001 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 14 Aug 2020 12:25:15 -0400 Subject: [PATCH 17/29] style: Add simple styles for rose/table --- .../styles/rose/components/table/_index.scss | 18 +--------- .../styles/rose/components/table/_table.scss | 34 +++++++++++++++++++ .../addon/templates/components/rose/table.hbs | 2 +- 3 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 addons/rose/addon/styles/rose/components/table/_table.scss diff --git a/addons/rose/addon/styles/rose/components/table/_index.scss b/addons/rose/addon/styles/rose/components/table/_index.scss index ef81e56e7..a801a8478 100644 --- a/addons/rose/addon/styles/rose/components/table/_index.scss +++ b/addons/rose/addon/styles/rose/components/table/_index.scss @@ -1,17 +1 @@ -@use '../../variables/sizing'; -@use '../../utilities/type'; - -.rose-table { - @include type.type(s, normal); - width: 100%; - - .rose-table-header { - background-color: var(--ui-gray-subtler-5); - text-align: left; - } - - .rose-table-cell { - border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3); - padding: sizing.rems(xs) sizing.rems(xxs); - } -} +@import 'table'; \ No newline at end of file diff --git a/addons/rose/addon/styles/rose/components/table/_table.scss b/addons/rose/addon/styles/rose/components/table/_table.scss new file mode 100644 index 000000000..a5dfb114d --- /dev/null +++ b/addons/rose/addon/styles/rose/components/table/_table.scss @@ -0,0 +1,34 @@ +@use '../../variables/sizing'; +@use '../../utilities/type'; +@use '../../variables/typography'; + +.rose-table { + @include type.type(s, normal); + width: 100%; + + .rose-table-row { + border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3); + border-left: none; + border-right: none; + text-align: left; + + .rose-table-cell, .rose-table-header-cell { + vertical-align: middle; + padding: 0 sizing.rems(s); + } + } + + .rose-table-header { + color: var(--ui-gray-starker-2); + + .rose-table-cell, .rose-table-header-cell { + padding: sizing.rems(xs) sizing.rems(s); + } + } + + .rose-table-body, .rose-table-footer { + .rose-table-cell, .rose-table-header-cell { + padding: sizing.rems(s) sizing.rems(s); + } + } +} diff --git a/addons/rose/addon/templates/components/rose/table.hbs b/addons/rose/addon/templates/components/rose/table.hbs index d50ec970e..655e7dbd4 100644 --- a/addons/rose/addon/templates/components/rose/table.hbs +++ b/addons/rose/addon/templates/components/rose/table.hbs @@ -12,6 +12,6 @@ classNames='rose-table-body') footer=(component 'rose/table/section' tagName='tfoot' - classNames='rose-table-foot') + classNames='rose-table-footer') )}} From 635ee53494b7a13bc583892d2b4d231cf07648df Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 14 Aug 2020 12:29:18 -0400 Subject: [PATCH 18/29] style: Remove unused style use --- addons/rose/addon/styles/rose/components/table/_table.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/rose/addon/styles/rose/components/table/_table.scss b/addons/rose/addon/styles/rose/components/table/_table.scss index a5dfb114d..64eb22b88 100644 --- a/addons/rose/addon/styles/rose/components/table/_table.scss +++ b/addons/rose/addon/styles/rose/components/table/_table.scss @@ -1,6 +1,5 @@ @use '../../variables/sizing'; @use '../../utilities/type'; -@use '../../variables/typography'; .rose-table { @include type.type(s, normal); From aa867f54d8df803b0068e0d8541f2327302842af Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 14 Aug 2020 17:40:31 -0400 Subject: [PATCH 19/29] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20initia?= =?UTF-8?q?l=20orgs=20routes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/controllers/scopes/scope/orgs.js | 17 ++++++ .../app/controllers/scopes/scope/orgs/new.js | 17 ++++++ ui/core/app/router.js | 37 +++++++----- ui/core/app/routes/scopes/scope/orgs.js | 15 +++++ ui/core/app/routes/scopes/scope/orgs/index.js | 4 ++ ui/core/app/routes/scopes/scope/orgs/new.js | 18 ++++++ ui/core/app/templates/scopes/scope/orgs.hbs | 3 + .../app/templates/scopes/scope/orgs/index.hbs | 56 +++++++++++++++++++ .../app/templates/scopes/scope/orgs/new.hbs | 17 ++++++ .../controllers/scopes/scope/orgs-test.js | 12 ++++ .../controllers/scopes/scope/orgs/new-test.js | 12 ++++ .../unit/routes/scopes/scope/orgs-test.js | 11 ++++ .../routes/scopes/scope/orgs/index-test.js | 11 ++++ .../unit/routes/scopes/scope/orgs/new-test.js | 11 ++++ ui/core/translations/en-us.yaml | 2 + 15 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 ui/core/app/controllers/scopes/scope/orgs.js create mode 100644 ui/core/app/controllers/scopes/scope/orgs/new.js create mode 100644 ui/core/app/routes/scopes/scope/orgs.js create mode 100644 ui/core/app/routes/scopes/scope/orgs/index.js create mode 100644 ui/core/app/routes/scopes/scope/orgs/new.js create mode 100644 ui/core/app/templates/scopes/scope/orgs.hbs create mode 100644 ui/core/app/templates/scopes/scope/orgs/index.hbs create mode 100644 ui/core/app/templates/scopes/scope/orgs/new.hbs create mode 100644 ui/core/tests/unit/controllers/scopes/scope/orgs-test.js create mode 100644 ui/core/tests/unit/controllers/scopes/scope/orgs/new-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/orgs-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/orgs/index-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/orgs/new-test.js diff --git a/ui/core/app/controllers/scopes/scope/orgs.js b/ui/core/app/controllers/scopes/scope/orgs.js new file mode 100644 index 000000000..9e553d5a3 --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/orgs.js @@ -0,0 +1,17 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeOrgsController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.orgs'); + } +} diff --git a/ui/core/app/controllers/scopes/scope/orgs/new.js b/ui/core/app/controllers/scopes/scope/orgs/new.js new file mode 100644 index 000000000..d41b81a96 --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/orgs/new.js @@ -0,0 +1,17 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeOrgsNewController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * @type {string} + */ + get breadCrumb() { + return this.intl.t('titles.new'); + } +} diff --git a/ui/core/app/router.js b/ui/core/app/router.js index cf5cea5d6..4521a8b75 100644 --- a/ui/core/app/router.js +++ b/ui/core/app/router.js @@ -9,24 +9,15 @@ export default class Router extends EmberRouter { Router.map(function () { this.route('scopes', function () { this.route('scope', { path: ':scope_id' }, function () { + this.route('authenticate', function () { this.route('method', { path: ':auth_method_id' }); }); - this.route('users', function () { - this.route('user', { path: ':user_id' }, function () {}); - this.route('new'); - }); - this.route('groups', function () { - this.route('group', { path: ':group_id' }, function () {}); - this.route('new'); - }); - this.route('roles', function () { - this.route('role', { path: ':role_id' }, function () { - this.route('grants'); - this.route('principals'); - }); + + this.route('orgs', function() { this.route('new'); }); + this.route('projects', function() { this.route('project', { path: ':project_id' }, function() { this.route('host-catalogs', function() { @@ -36,7 +27,27 @@ Router.map(function () { }); this.route('new'); }); + + this.route('users', function () { + this.route('user', { path: ':user_id' }, function () {}); + this.route('new'); + }); + + this.route('groups', function () { + this.route('group', { path: ':group_id' }, function () {}); + this.route('new'); + }); + + this.route('roles', function () { + this.route('role', { path: ':role_id' }, function () { + this.route('grants'); + this.route('principals'); + }); + this.route('new'); + }); + this.route('auth-methods', function() {}); + }); }); }); diff --git a/ui/core/app/routes/scopes/scope/orgs.js b/ui/core/app/routes/scopes/scope/orgs.js new file mode 100644 index 000000000..e8b0375b9 --- /dev/null +++ b/ui/core/app/routes/scopes/scope/orgs.js @@ -0,0 +1,15 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeOrgsRoute extends Route { + + // =methods + + /** + * Loads all scopes under the global scope. + * @return {Promise{[ScopeModel]}} + */ + async model() { + return this.store.query('scope', { scope_id: 'global' }); + } + +} diff --git a/ui/core/app/routes/scopes/scope/orgs/index.js b/ui/core/app/routes/scopes/scope/orgs/index.js new file mode 100644 index 000000000..4a344e13a --- /dev/null +++ b/ui/core/app/routes/scopes/scope/orgs/index.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeOrgsIndexRoute extends Route { +} diff --git a/ui/core/app/routes/scopes/scope/orgs/new.js b/ui/core/app/routes/scopes/scope/orgs/new.js new file mode 100644 index 000000000..0337f2dce --- /dev/null +++ b/ui/core/app/routes/scopes/scope/orgs/new.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeOrgsNewRoute extends Route { + + // =methods + + /** + * Creates a new unsaved org scope belonging to the global scope. + * @return {ScopeModel} + */ + model() { + return this.store.createRecord('scope', { + type: 'org', + scopeID: 'global', + }); + } + +} diff --git a/ui/core/app/templates/scopes/scope/orgs.hbs b/ui/core/app/templates/scopes/scope/orgs.hbs new file mode 100644 index 000000000..35fbae66b --- /dev/null +++ b/ui/core/app/templates/scopes/scope/orgs.hbs @@ -0,0 +1,3 @@ +{{title (t "resources.orgs")}} + +{{outlet}} diff --git a/ui/core/app/templates/scopes/scope/orgs/index.hbs b/ui/core/app/templates/scopes/scope/orgs/index.hbs new file mode 100644 index 000000000..9abc5722e --- /dev/null +++ b/ui/core/app/templates/scopes/scope/orgs/index.hbs @@ -0,0 +1,56 @@ + + + + + + + +

{{t "resources.orgs"}}

+
+ + + {{#if @model}} + + {{t 'titles.new'}} + + {{/if}} + + + + + {{#if @model}} + + + {{#each @model as |org|}} + + {{/each}} + + + {{else}} + + + + + {{t 'descriptions.orgs-welcome'}} + + + + {{t 'titles.new'}} + + + + + {{/if}} + + + +
diff --git a/ui/core/app/templates/scopes/scope/orgs/new.hbs b/ui/core/app/templates/scopes/scope/orgs/new.hbs new file mode 100644 index 000000000..0e12b352e --- /dev/null +++ b/ui/core/app/templates/scopes/scope/orgs/new.hbs @@ -0,0 +1,17 @@ +{{title (t 'titles.new')}} + + + + + + + + +

{{t "titles.new"}}

+
+ + + + + +
diff --git a/ui/core/tests/unit/controllers/scopes/scope/orgs-test.js b/ui/core/tests/unit/controllers/scopes/scope/orgs-test.js new file mode 100644 index 000000000..f89afd0fc --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/orgs-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/orgs', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/orgs'); + assert.ok(controller); + }); +}); diff --git a/ui/core/tests/unit/controllers/scopes/scope/orgs/new-test.js b/ui/core/tests/unit/controllers/scopes/scope/orgs/new-test.js new file mode 100644 index 000000000..c6631a1ab --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/orgs/new-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/orgs/new', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/orgs/new'); + assert.ok(controller); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/orgs-test.js b/ui/core/tests/unit/routes/scopes/scope/orgs-test.js new file mode 100644 index 000000000..4b9d477c3 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/orgs-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/orgs', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/orgs'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/orgs/index-test.js b/ui/core/tests/unit/routes/scopes/scope/orgs/index-test.js new file mode 100644 index 000000000..c62bbc625 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/orgs/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/orgs/index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/orgs/index'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/orgs/new-test.js b/ui/core/tests/unit/routes/scopes/scope/orgs/new-test.js new file mode 100644 index 000000000..3cfdb8522 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/orgs/new-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/orgs/new', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/orgs/new'); + assert.ok(route); + }); +}); diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 2fe1ad5f8..c64e37ceb 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -27,6 +27,8 @@ resources: roles: Roles group: Group groups: Groups + orgs: Orgs + org: Org projects: Projects project: Project host-catalog: Host Catalog From 11e94aa0c35129caa17b659c21fd8ed397228469 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 14 Aug 2020 17:53:49 -0400 Subject: [PATCH 20/29] =?UTF-8?q?chore:=20=F0=9F=A4=96=20hide=20sidebar=20?= =?UTF-8?q?when=20in=20global=20scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/templates/scopes/scope.hbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/core/app/templates/scopes/scope.hbs b/ui/core/app/templates/scopes/scope.hbs index 37530455c..5f60d2607 100644 --- a/ui/core/app/templates/scopes/scope.hbs +++ b/ui/core/app/templates/scopes/scope.hbs @@ -1,6 +1,7 @@ {{#if this.session.isAuthenticated}} + {{#unless @model.isGlobal}} @@ -26,6 +27,7 @@ {{outlet "sidebar"}} + {{/unless}} {{/if}} From 560f5db43b69e679fe239b810f20213e37f4d163 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Mon, 17 Aug 2020 10:47:28 -0400 Subject: [PATCH 21/29] =?UTF-8?q?style:=20=F0=9F=92=84=20increase=20cell?= =?UTF-8?q?=20padding=20and=20header=20font=20weight?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../styles/rose/components/table/_table.scss | 38 ++++++++++--------- .../templates/scopes/scope/users/index.hbs | 8 ++-- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/table/_table.scss b/addons/rose/addon/styles/rose/components/table/_table.scss index 64eb22b88..ba63d37aa 100644 --- a/addons/rose/addon/styles/rose/components/table/_table.scss +++ b/addons/rose/addon/styles/rose/components/table/_table.scss @@ -6,28 +6,32 @@ width: 100%; .rose-table-row { - border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3); - border-left: none; - border-right: none; + border-bottom: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3); text-align: left; + } - .rose-table-cell, .rose-table-header-cell { - vertical-align: middle; - padding: 0 sizing.rems(s); + .rose-table-cell, + .rose-table-header-cell { + vertical-align: middle; + } + + .rose-table-header-cell { + @include type.type(s, semibold); + color: var(--ui-gray); + } + + .rose-table-header, + .rose-table-footer { + .rose-table-cell, + .rose-table-header-cell { + padding: sizing.rems(s); } } - .rose-table-header { - color: var(--ui-gray-starker-2); - - .rose-table-cell, .rose-table-header-cell { - padding: sizing.rems(xs) sizing.rems(s); - } - } - - .rose-table-body, .rose-table-footer { - .rose-table-cell, .rose-table-header-cell { - padding: sizing.rems(s) sizing.rems(s); + .rose-table-body { + .rose-table-cell, + .rose-table-header-cell { + padding: sizing.rems(l) sizing.rems(s); } } } diff --git a/ui/core/app/templates/scopes/scope/users/index.hbs b/ui/core/app/templates/scopes/scope/users/index.hbs index 1ee0f3ac2..fb0a06a09 100644 --- a/ui/core/app/templates/scopes/scope/users/index.hbs +++ b/ui/core/app/templates/scopes/scope/users/index.hbs @@ -21,21 +21,21 @@ - {{t 'form.label.name'}} - {{t 'form.label.description'}} + {{t 'form.label.name'}} + {{t 'form.label.description'}} {{#each @model as |user|}} - + {{user.name}} - + {{user.description}} {{/each}} From 2a49d4601f23077354a4e751b841821ff94e87c0 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Mon, 17 Aug 2020 12:25:07 -0400 Subject: [PATCH 22/29] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20new=20org=20?= =?UTF-8?q?functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/components/form/org/index.hbs | 49 ++++++++++++ ui/core/app/routes/scopes/scope/orgs.js | 41 ++++++++++ .../app/templates/scopes/scope/orgs/new.hbs | 6 +- ui/core/tests/acceptance/orgs-test.js | 76 +++++++++++++++++++ .../integration/components/form/org-test.js | 23 ++++++ 5 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 ui/core/app/components/form/org/index.hbs create mode 100644 ui/core/tests/acceptance/orgs-test.js create mode 100644 ui/core/tests/integration/components/form/org-test.js diff --git a/ui/core/app/components/form/org/index.hbs b/ui/core/app/components/form/org/index.hbs new file mode 100644 index 000000000..45adc26d0 --- /dev/null +++ b/ui/core/app/components/form/org/index.hbs @@ -0,0 +1,49 @@ + + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + + diff --git a/ui/core/app/routes/scopes/scope/orgs.js b/ui/core/app/routes/scopes/scope/orgs.js index e8b0375b9..f25a91cf9 100644 --- a/ui/core/app/routes/scopes/scope/orgs.js +++ b/ui/core/app/routes/scopes/scope/orgs.js @@ -1,7 +1,14 @@ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; export default class ScopesScopeOrgsRoute extends Route { + // =services + + @service intl; + @service notify; + // =methods /** @@ -12,4 +19,38 @@ export default class ScopesScopeOrgsRoute extends Route { return this.store.query('scope', { scope_id: 'global' }); } + // =actions + + /** + * Rollback changes on org. + * @param {ScopeModel} org + */ + @action + cancel(org) { + const { isNew } = org; + org.rollbackAttributes(); + if (isNew) this.transitionTo('scopes.scope.orgs'); + } + + /** + * Handle save org. + * @param {ScopeModel} org + * @param {Event} e + */ + @action + async save(org) { + const { isNew } = org; + try { + await org.save(); + this.refresh(); + this.notify.success( + this.intl.t(isNew ? 'notify.create-success' : 'notify.save-success') + ); + this.transitionTo('scopes.scope', org); + } catch (error) { + // TODO: replace with translated strings + this.notify.error(error.message, { closeAfter: null }); + } + } + } diff --git a/ui/core/app/templates/scopes/scope/orgs/new.hbs b/ui/core/app/templates/scopes/scope/orgs/new.hbs index 0e12b352e..d9fe8b361 100644 --- a/ui/core/app/templates/scopes/scope/orgs/new.hbs +++ b/ui/core/app/templates/scopes/scope/orgs/new.hbs @@ -11,7 +11,11 @@ - + diff --git a/ui/core/tests/acceptance/orgs-test.js b/ui/core/tests/acceptance/orgs-test.js new file mode 100644 index 000000000..5871fd404 --- /dev/null +++ b/ui/core/tests/acceptance/orgs-test.js @@ -0,0 +1,76 @@ +import { module, test } from 'qunit'; +//import { visit, currentURL, click, fillIn, find } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +//import a11yAudit from 'ember-a11y-testing/test-support/audit'; +//import { Response } from 'miragejs'; +import { + //authenticateSession, + // These are left here intentionally for future reference. + //currentSession, + //invalidateSession, +} from 'ember-simple-auth/test-support'; + +module('Acceptance | org', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + // let org; + // let orgID; + // let orgsURL; + // let newOrgURL; + // let existingOrg; + // let existingOrgURL; + // let getOrgScopesCount; + // let getFirstOrgScope; + // let initialOrgScopesCount; + // + // hooks.beforeEach(function () { + // authenticateSession({}); + // + // }); + + test('visiting orgs', async function (assert) { + assert.expect(0); + }); + + test('visiting orgs within a org scope redirects to the parent org scope', async function (assert) { + assert.expect(0); + }); + + test('can create new orgs', async function (assert) { + assert.expect(0); + }); + + test('can cancel create new orgs', async function (assert) { + assert.expect(0); + }); + + test('saving a new org with invalid fields displays error messages', async function (assert) { + assert.expect(0); + }); + + test('can save changes to existing org', async function (assert) { + assert.expect(0); + }); + + test('can cancel changes to existing org', async function (assert) { + assert.expect(0); + }); + + test('can delete org', async function (assert) { + assert.expect(0); + }); + + test('saving an existing org with invalid fields displays error messages', async function (assert) { + assert.expect(0); + }); + + test('errors are displayed when save org fails', async function (assert) { + assert.expect(0); + }); + + test('errors are displayed when delete org fails', async function (assert) { + assert.expect(0); + }); +}); diff --git a/ui/core/tests/integration/components/form/org-test.js b/ui/core/tests/integration/components/form/org-test.js new file mode 100644 index 000000000..76c3d9b8f --- /dev/null +++ b/ui/core/tests/integration/components/form/org-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | form/org', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + this.submit = () => {}; + this.cancel = () => {}; + + await render(hbs` + `); + + assert.ok(find('form')); + }); +}); From 7df2295058d39ba91ab1d8c70fc8a57e0ed99df8 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 17 Aug 2020 13:15:58 -0400 Subject: [PATCH 23/29] chore: Update rose/dropdown link and button components Instead of wrapping dropdown button component in rose/button, create a new simplified button. --- .../components/rose/dropdown.stories.mdx | 12 ++--- .../addon/components/rose/dropdown/button.js | 10 +++++ .../addon/components/rose/dropdown/link.js | 10 +++++ .../rose/components/dropdown/_button.scss | 34 ++++++++++++++ .../components/{ => dropdown}/_dropdown.scss | 45 +++---------------- .../rose/components/dropdown/_index.scss | 3 ++ .../rose/components/dropdown/_link.scss | 33 ++++++++++++++ .../templates/components/rose/dropdown.hbs | 9 ++-- .../components/rose/dropdown/button.hbs | 19 ++++++++ .../components/rose/dropdown/link.hbs | 8 ++++ .../app/components/rose/dropdown/button.js | 1 + .../rose/app/components/rose/dropdown/link.js | 1 + .../rose/tests/dummy/app/templates/index.hbs | 21 +++++---- .../components/rose/dropdown/button-test.js | 38 ++++++++++++++++ .../components/rose/dropdown/link-test.js | 31 +++++++++++++ .../scopes/scope/groups/group/index.hbs | 4 +- .../host-catalogs/host-catalog/index.hbs | 20 +++++---- .../scopes/scope/projects/project/index.hbs | 20 +++++---- .../app/templates/scopes/scope/roles/role.hbs | 4 +- .../scopes/scope/users/user/index.hbs | 4 +- ui/core/tests/acceptance/groups-test.js | 4 +- .../tests/acceptance/host-catalogs-test.js | 4 +- ui/core/tests/acceptance/projects-test.js | 4 +- ui/core/tests/acceptance/roles-test.js | 4 +- ui/core/tests/acceptance/users-test.js | 4 +- ui/core/translations/en-us.yaml | 2 + 26 files changed, 257 insertions(+), 92 deletions(-) create mode 100644 addons/rose/addon/components/rose/dropdown/button.js create mode 100644 addons/rose/addon/components/rose/dropdown/link.js create mode 100644 addons/rose/addon/styles/rose/components/dropdown/_button.scss rename addons/rose/addon/styles/rose/components/{ => dropdown}/_dropdown.scss (72%) create mode 100644 addons/rose/addon/styles/rose/components/dropdown/_index.scss create mode 100644 addons/rose/addon/styles/rose/components/dropdown/_link.scss create mode 100644 addons/rose/addon/templates/components/rose/dropdown/button.hbs create mode 100644 addons/rose/addon/templates/components/rose/dropdown/link.hbs create mode 100644 addons/rose/app/components/rose/dropdown/button.js create mode 100644 addons/rose/app/components/rose/dropdown/link.js create mode 100644 addons/rose/tests/integration/components/rose/dropdown/button-test.js create mode 100644 addons/rose/tests/integration/components/rose/dropdown/link-test.js diff --git a/addons/rose/addon/components/rose/dropdown.stories.mdx b/addons/rose/addon/components/rose/dropdown.stories.mdx index 999b6278f..c2f71d82f 100644 --- a/addons/rose/addon/components/rose/dropdown.stories.mdx +++ b/addons/rose/addon/components/rose/dropdown.stories.mdx @@ -13,6 +13,7 @@ A simple dropdown component with support for links and buttons. Menu item Menu item + Button menu item `, @@ -25,6 +26,7 @@ A simple dropdown component with support for links and buttons. Menu item Menu item + Button menu item `, @@ -46,18 +48,16 @@ Dropdown content can be aligned to right edge of the component instead of the de Menu item Menu item + Button menu item ``` -Dropdown button styles support all `Rose::Button` styles through a `style` attribute. +Dropdown supports `danger` styling through `style` attribute. ```htmlbars - Button menu item - Button - warning - Button - primary - Button - secondary - Button - ghost + Link - danger + Button - danger ``` diff --git a/addons/rose/addon/components/rose/dropdown/button.js b/addons/rose/addon/components/rose/dropdown/button.js new file mode 100644 index 000000000..6f776e15d --- /dev/null +++ b/addons/rose/addon/components/rose/dropdown/button.js @@ -0,0 +1,10 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/dropdown/button'; + +/** + * A dropdown button component based on simplified rose/button + */ +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/dropdown/link.js b/addons/rose/addon/components/rose/dropdown/link.js new file mode 100644 index 000000000..c6609fe05 --- /dev/null +++ b/addons/rose/addon/components/rose/dropdown/link.js @@ -0,0 +1,10 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/dropdown/link'; + +/** + * A dropdown link wrapper for LinkTo component. + */ +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/styles/rose/components/dropdown/_button.scss b/addons/rose/addon/styles/rose/components/dropdown/_button.scss new file mode 100644 index 000000000..bf6dc12c8 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/dropdown/_button.scss @@ -0,0 +1,34 @@ +@use '../../variables/sizing'; +@use '../../utilities/type'; + +.rose-dropdown-button { + @include type.type(s, normal); + display: block; + // Targeting min-width of 200 + min-width: (sizing.rems(m) + sizing.rems(xxs)) * 10; + border: 0; + margin: 0; + padding: 0 sizing.rems(s); + color: var(--stark); + background-color: transparent; + // target line height is 36, which is not a standard line height for this + // font size + $lineHeight: 36 / 16; + line-height: $lineHeight; + text-align: left; + text-decoration: none; + cursor: pointer; + + &.rose-dropdown-button-danger { + --background: var(--white); + --color: var(--failure); + + color: var(--color); + background-color: var(--background-color); + + &:hover { + --color: var(--white); + --background-color: var(--failure); + } + } +} \ No newline at end of file diff --git a/addons/rose/addon/styles/rose/components/_dropdown.scss b/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss similarity index 72% rename from addons/rose/addon/styles/rose/components/_dropdown.scss rename to addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss index 7a1bf9e53..cb3c964eb 100644 --- a/addons/rose/addon/styles/rose/components/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss @@ -1,5 +1,5 @@ -@use '../variables/sizing'; -@use '../utilities/type'; +@use '../../variables/sizing'; +@use '../../utilities/type'; $chevron: "data:image/svg+xml;utf-8,"; @@ -92,42 +92,9 @@ $chevron: "data:image/svg+xml;utf-8, @@ -24,8 +24,9 @@
{{yield (hash - link=(component "link-to" class="rose-dropdown-link") - button=(component "rose/button" classNames="rose-dropdown-button" style=this.style) + link=(component "rose/dropdown/link" style=this.style) + button=(component "rose/dropdown/button" style=this.style) + separator=(component "rose/anonymous" tagName="hr" class="rose-dropdown-separator") )}}
diff --git a/addons/rose/addon/templates/components/rose/dropdown/button.hbs b/addons/rose/addon/templates/components/rose/dropdown/button.hbs new file mode 100644 index 000000000..364a2ef18 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/dropdown/button.hbs @@ -0,0 +1,19 @@ + diff --git a/addons/rose/addon/templates/components/rose/dropdown/link.hbs b/addons/rose/addon/templates/components/rose/dropdown/link.hbs new file mode 100644 index 000000000..6b3bd413a --- /dev/null +++ b/addons/rose/addon/templates/components/rose/dropdown/link.hbs @@ -0,0 +1,8 @@ + + {{yield}} + \ No newline at end of file diff --git a/addons/rose/app/components/rose/dropdown/button.js b/addons/rose/app/components/rose/dropdown/button.js new file mode 100644 index 000000000..0def7a1c0 --- /dev/null +++ b/addons/rose/app/components/rose/dropdown/button.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/dropdown/button'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/dropdown/link.js b/addons/rose/app/components/rose/dropdown/link.js new file mode 100644 index 000000000..99ec355d3 --- /dev/null +++ b/addons/rose/app/components/rose/dropdown/link.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/dropdown/link'; \ No newline at end of file diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 72f1657d5..ab7081265 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -4,9 +4,11 @@ Menu item - Menu item + Menu item - danger + Button menu item + Section Section @@ -18,22 +20,19 @@ @icon="user-square-fill" as |dropdown| > Menu item - Menu item + Menu item - danger Button - default - Button - warning - Button - primary - Button - secondary - Button - ghost + + Button - danger Menu item - Menu item + Menu item - danger + + Button menu item - Button - warning - Button - primary - Button - secondary - Button - ghost + Button - danger diff --git a/addons/rose/tests/integration/components/rose/dropdown/button-test.js b/addons/rose/tests/integration/components/rose/dropdown/button-test.js new file mode 100644 index 000000000..11fc945a6 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/dropdown/button-test.js @@ -0,0 +1,38 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/dropdown/button', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-dropdown-button')); + }); + + test('it is type="button" by default', async function (assert) { + await render(hbs``); + assert.equal(find('button').type, 'button'); + }); + + test('it is type="submit" when @submit={{true}}', async function (assert) { + await render(hbs``); + assert.equal(find('button').type, 'submit'); + }); + + test('it is disabled when @disabled={{true}}', async function (assert) { + await render(hbs``); + assert.equal(find('button').disabled, true); + }); + + test('it adds a style class', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-dropdown-button-warning')); + }); + + test('it supports an icon-only type', async function (assert) { + await render(hbs``); + assert.ok(find('.has-icon-only .rose-icon')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/dropdown/link-test.js b/addons/rose/tests/integration/components/rose/dropdown/link-test.js new file mode 100644 index 000000000..a64b51bf8 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/dropdown/link-test.js @@ -0,0 +1,31 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/dropdown/link', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('a')); + assert.ok(find('.rose-dropdown-link')); + }); + + test('it renders with attributes', async function (assert) { + await render(hbs``); + assert.ok(find('#dropdown')); + }); + + test('it renders with content', async function (assert) { + await render(hbs` + content + `); + assert.equal(find('.rose-dropdown-link').textContent.trim(), 'content'); + }); + + test('it supports style', async function (assert) { + await render(hbs``); + assert.ok('.rose-dropdown-link-warning'); + }); +}); diff --git a/ui/core/app/templates/scopes/scope/groups/group/index.hbs b/ui/core/app/templates/scopes/scope/groups/group/index.hbs index ffe366e71..e78a0c548 100644 --- a/ui/core/app/templates/scopes/scope/groups/group/index.hbs +++ b/ui/core/app/templates/scopes/scope/groups/group/index.hbs @@ -17,9 +17,9 @@ - + diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/index.hbs index cb0a4a0cf..6d7c05659 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/index.hbs @@ -16,20 +16,24 @@ + + + + {{t 'actions.delete-host-catalog'}} + + + + - - - {{t 'actions.delete'}} - diff --git a/ui/core/app/templates/scopes/scope/projects/project/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/index.hbs index 5dccae834..c3bec3790 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/index.hbs @@ -16,20 +16,24 @@ + + + + {{t 'actions.delete-project'}} + + + + - - - {{t 'actions.delete'}} - diff --git a/ui/core/app/templates/scopes/scope/roles/role.hbs b/ui/core/app/templates/scopes/scope/roles/role.hbs index 9df55380b..397e9f504 100644 --- a/ui/core/app/templates/scopes/scope/roles/role.hbs +++ b/ui/core/app/templates/scopes/scope/roles/role.hbs @@ -11,9 +11,9 @@ - + diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs index 2261fa30b..6392e84f7 100644 --- a/ui/core/app/templates/scopes/scope/users/user/index.hbs +++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs @@ -9,9 +9,9 @@ - + diff --git a/ui/core/tests/acceptance/groups-test.js b/ui/core/tests/acceptance/groups-test.js index b619d09ce..0d622f1f0 100644 --- a/ui/core/tests/acceptance/groups-test.js +++ b/ui/core/tests/acceptance/groups-test.js @@ -133,7 +133,7 @@ module('Acceptance | groups', function (hooks) { assert.expect(1); const groupsCount = this.server.db.groups.length; await visit(groupURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.equal(this.server.db.groups.length, groupsCount - 1); }); @@ -210,7 +210,7 @@ module('Acceptance | groups', function (hooks) { ); }); await visit(groupURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.ok( find('[role="alert"]').textContent.trim(), 'Oops.', diff --git a/ui/core/tests/acceptance/host-catalogs-test.js b/ui/core/tests/acceptance/host-catalogs-test.js index 59bc08dcc..fada1730e 100644 --- a/ui/core/tests/acceptance/host-catalogs-test.js +++ b/ui/core/tests/acceptance/host-catalogs-test.js @@ -80,7 +80,7 @@ module('Acceptance | host catalogs', function (hooks) { authenticateSession({}); await visit(urls.hostCatalog); assert.equal(currentURL(), urls.hostCatalog); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.equal(this.server.db.hostCatalogs.length, hostCatalogsCount - 1); }); @@ -162,7 +162,7 @@ module('Acceptance | host catalogs', function (hooks) { }); authenticateSession({}); await visit(urls.hostCatalog); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); await a11yAudit(); assert.ok( find('[role="alert"]').textContent.trim(), diff --git a/ui/core/tests/acceptance/projects-test.js b/ui/core/tests/acceptance/projects-test.js index ced4a8f13..4af813592 100644 --- a/ui/core/tests/acceptance/projects-test.js +++ b/ui/core/tests/acceptance/projects-test.js @@ -135,7 +135,7 @@ module('Acceptance | projects', function (hooks) { test('can delete project', async function (assert) { assert.expect(1); await visit(existingProjectURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.equal(getProjectScopesCount(), initialProjectScopesCount - 1); }); @@ -212,7 +212,7 @@ module('Acceptance | projects', function (hooks) { ); }); await visit(existingProjectURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.ok( find('[role="alert"]').textContent.trim(), 'Oops.', diff --git a/ui/core/tests/acceptance/roles-test.js b/ui/core/tests/acceptance/roles-test.js index 2aa364f1b..14bd45a24 100644 --- a/ui/core/tests/acceptance/roles-test.js +++ b/ui/core/tests/acceptance/roles-test.js @@ -133,7 +133,7 @@ module('Acceptance | roles', function (hooks) { assert.expect(1); const rolesCount = this.server.db.roles.length; await visit(roleURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.equal(this.server.db.roles.length, rolesCount - 1); }); @@ -210,7 +210,7 @@ module('Acceptance | roles', function (hooks) { ); }); await visit(roleURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.ok( find('[role="alert"]').textContent.trim(), 'Oops.', diff --git a/ui/core/tests/acceptance/users-test.js b/ui/core/tests/acceptance/users-test.js index 31fa5c98e..55e4ac108 100644 --- a/ui/core/tests/acceptance/users-test.js +++ b/ui/core/tests/acceptance/users-test.js @@ -133,7 +133,7 @@ module('Acceptance | users', function (hooks) { assert.expect(1); const usersCount = this.server.db.users.length; await visit(userURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.equal(this.server.db.users.length, usersCount - 1); }); @@ -210,7 +210,7 @@ module('Acceptance | users', function (hooks) { ); }); await visit(userURL); - await click('.rose-button-warning'); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); assert.ok( find('[role="alert"]').textContent.trim(), 'Oops.', diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 6401bf775..41082f65e 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -12,6 +12,8 @@ actions: delete-user: Delete user delete-group: Delete group delete-role: Delete role + delete-project: Delete project + delete-host-catalog: Delete host catalog auth: titles: no-scopes: No Scopes Available From 4be7dc7003b29890018b87074976b11ca12009fa Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Mon, 17 Aug 2020 14:43:12 -0400 Subject: [PATCH 24/29] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20feature=20to?= =?UTF-8?q?=20display=20and=20authenticate=20with=20global?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/routes/scopes/index.js | 6 +-- ui/core/app/routes/scopes/scope.js | 19 ++++++-- .../app/routes/scopes/scope/authenticate.js | 13 +++--- .../scopes/scope/authenticate/method.js | 10 ++--- ui/core/mirage/scenarios/default.js | 7 ++- .../tests/acceptance/authentication-test.js | 44 +++++++++++-------- ui/core/translations/en-us.yaml | 1 + 7 files changed, 63 insertions(+), 37 deletions(-) diff --git a/ui/core/app/routes/scopes/index.js b/ui/core/app/routes/scopes/index.js index 562a27a15..b1ec77f7f 100644 --- a/ui/core/app/routes/scopes/index.js +++ b/ui/core/app/routes/scopes/index.js @@ -15,15 +15,15 @@ export default class ScopesIndexRoute extends Route { * @param {[ScopeModel]} model * @param {?ScopeModel} model.firstObject */ - redirect({ firstObject }) { + redirect() { const authenticatedScopeID = get( this.session, 'data.authenticated.scope.id' ); if (authenticatedScopeID) { this.transitionTo('scopes.scope', authenticatedScopeID); - } else if (firstObject) { - this.transitionTo('scopes.scope', firstObject.id); + } else { + this.transitionTo('scopes.scope', 'global'); } } } diff --git a/ui/core/app/routes/scopes/scope.js b/ui/core/app/routes/scopes/scope.js index 2707a238b..06158aa4d 100644 --- a/ui/core/app/routes/scopes/scope.js +++ b/ui/core/app/routes/scopes/scope.js @@ -1,6 +1,12 @@ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; export default class ScopesScopeRoute extends Route { + + // =services + + @service intl; + // =methods /** @@ -14,11 +20,18 @@ export default class ScopesScopeRoute extends Route { * @return {Promise{ScopeModel}} */ model({ scope_id: id }) { + // Since only global and org scopes are authenticatable, we can infer type + // from ID because global has a fixed ID. + const scopeType = id === 'global' ? 'global' : 'org'; return this.store.findRecord('scope', id).catch(() => { const maybeExistingScope = this.store.peekRecord('scope', id); - // TODO it's unclear if creating a temporary unsaved scope is reliable - // we may need to revert to a POJO. - return maybeExistingScope || this.store.createRecord('scope', { id }); + const scopeOptions = { id, scopeType }; + if (scopeType === 'global') { + scopeOptions.name = this.intl.t('titles.global'); + } + return maybeExistingScope || + this.store.createRecord('scope', scopeOptions); }); } + } diff --git a/ui/core/app/routes/scopes/scope/authenticate.js b/ui/core/app/routes/scopes/scope/authenticate.js index d7dae560d..ef08a1566 100644 --- a/ui/core/app/routes/scopes/scope/authenticate.js +++ b/ui/core/app/routes/scopes/scope/authenticate.js @@ -7,12 +7,6 @@ export default class ScopesScopeAuthenticateRoute extends Route { @service session; - // =attributes - - // TODO: this assumes we're in an org scope, but the "landing" - // for global scope is probably different. - routeIfAlreadyAuthenticated = 'scopes.scope.projects'; - // =methods /** @@ -37,7 +31,12 @@ export default class ScopesScopeAuthenticateRoute extends Route { redirect() { if (this.session.isAuthenticated) { - this.transitionTo(this.routeIfAlreadyAuthenticated); + const scope = this.modelFor('scopes.scope'); + if (scope.isGlobal) { + this.transitionTo('scopes.scope.orgs'); + } else { + this.transitionTo('scopes.scope.projects'); + } } } } diff --git a/ui/core/app/routes/scopes/scope/authenticate/method.js b/ui/core/app/routes/scopes/scope/authenticate/method.js index 5208b152d..ed1ebc026 100644 --- a/ui/core/app/routes/scopes/scope/authenticate/method.js +++ b/ui/core/app/routes/scopes/scope/authenticate/method.js @@ -9,10 +9,6 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route { @service notify; @service intl; - // =attributes - - routeAfterAuthentication = 'scopes.scope.projects'; - // =methods /** @@ -55,7 +51,11 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route { requestCookies, { scope, authMethod } ); - this.transitionTo(this.routeAfterAuthentication); + if (scope.isGlobal) { + this.transitionTo('scopes.scope.orgs'); + } else { + this.transitionTo('scopes.scope.projects'); + } } catch (e) { const errorMessage = this.intl.t('errors.titles.authentication-failed'); this.notify.error(errorMessage, { closeAfter: null }); diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js index 6f8e29775..e6bfe856c 100644 --- a/ui/core/mirage/scenarios/default.js +++ b/ui/core/mirage/scenarios/default.js @@ -2,7 +2,12 @@ export default function(server) { // Scope resources - const globalScope = server.create('scope', { id: 'global' }); // creates a global scope + // creates a global scope + const globalScope = server.create('scope', { + id: 'global', + type: 'global', + name: 'Global' + }); const orgScope = server.createList('scope', 3, { type: 'org', scope: { id: globalScope.id, type: globalScope.type } diff --git a/ui/core/tests/acceptance/authentication-test.js b/ui/core/tests/acceptance/authentication-test.js index 478e2f1dd..04107a7a9 100644 --- a/ui/core/tests/acceptance/authentication-test.js +++ b/ui/core/tests/acceptance/authentication-test.js @@ -23,8 +23,11 @@ module('Acceptance | authentication', function (hooks) { let scope; let authMethod; let authMethodID; + let globalAuthenticateURL; let authenticateURL; let authMethodAuthenticateURL; + let authMethodGlobalAuthenticateURL; + let orgsURL; let projectsURL; hooks.beforeEach(function () { @@ -45,21 +48,14 @@ module('Acceptance | authentication', function (hooks) { authMethodID = authMethod.id; scopesURL = `/scopes`; orgScopeURL = `/scopes/${orgScopeID}`; + globalAuthenticateURL = `/scopes/global/authenticate`; authenticateURL = `/scopes/${orgScopeID}/authenticate`; + authMethodGlobalAuthenticateURL = `/scopes/global/authenticate/${authMethodID}`; authMethodAuthenticateURL = `/scopes/${orgScopeID}/authenticate/${authMethodID}`; + orgsURL = `/scopes/global/orgs`; projectsURL = `/scopes/${orgScopeID}/projects`; }); - - test('visiting scopes when there are none shows a message', async function (assert) { - assert.expect(2); - this.server.get('/scopes', () => new Response(404)); - await visit(scopesURL); - await a11yAudit(); - assert.equal(currentURL(), scopesURL); - assert.ok(find('.rose-message')); - }); - test('visiting auth methods authenticate route redirects to first auth method', async function (assert) { assert.expect(1); await visit(authenticateURL); @@ -96,19 +92,19 @@ module('Acceptance | authentication', function (hooks) { assert.equal(currentURL(), authMethodAuthenticateURL); }); - test('visiting any authentication parent route while unauthenticated redirects to first authenticate method', async function (assert) { + test('visiting any authentication parent route while unauthenticated redirects to first global authenticate method', async function (assert) { assert.expect(3); await visit(indexURL); - assert.equal(currentURL(), authMethodAuthenticateURL); + assert.equal(currentURL(), authMethodGlobalAuthenticateURL); await visit(scopesURL); - assert.equal(currentURL(), authMethodAuthenticateURL); + assert.equal(currentURL(), authMethodGlobalAuthenticateURL); assert.notOk(currentSession().isAuthenticated); }); - test('visiting projects while unauthenticated redirects to first authenticate method', async function (assert) { + test('visiting projects while unauthenticated redirects to first global authenticate method', async function (assert) { assert.expect(2); await visit(projectsURL); - assert.equal(currentURL(), authMethodAuthenticateURL); + assert.equal(currentURL(), authMethodGlobalAuthenticateURL); assert.notOk(currentSession().isAuthenticated); }); @@ -119,7 +115,7 @@ module('Acceptance | authentication', function (hooks) { assert.equal(currentURL(), authMethodAuthenticateURL); }); - test('visiting any authentication parent route while already authenticated redirects to projects', async function (assert) { + test('visiting any authentication parent route while already authenticated with an org redirects to projects', async function (assert) { assert.expect(6); authenticateSession({ scope }); await visit(indexURL); @@ -135,6 +131,18 @@ module('Acceptance | authentication', function (hooks) { assert.ok(currentSession().isAuthenticated); }); + test('visiting index or scopes routes while already authenticated with global redirects to orgs', async function (assert) { + assert.expect(4); + authenticateSession({ scope: { id: globalScope.id, type: globalScope.type } }); + await visit(indexURL); + assert.equal(currentURL(), orgsURL); + await visit(scopesURL); + assert.equal(currentURL(), orgsURL); + await visit(globalAuthenticateURL); + assert.equal(currentURL(), orgsURL); + assert.ok(currentSession().isAuthenticated); + }); + test('failed authentication shows a notification message', async function (assert) { assert.expect(3); await visit(authMethodAuthenticateURL); @@ -157,7 +165,7 @@ module('Acceptance | authentication', function (hooks) { assert.ok(currentSession().isAuthenticated); }); - test('deauthentication redirects to first authenticate method', async function (assert) { + test('deauthentication redirects to first global authenticate method', async function (assert) { assert.expect(3); await visit(authMethodAuthenticateURL); await fillIn('[name="identification"]', 'test'); @@ -166,6 +174,6 @@ module('Acceptance | authentication', function (hooks) { assert.ok(currentSession().isAuthenticated); await click('.rose-button-header-dropdown'); assert.notOk(currentSession().isAuthenticated); - assert.equal(currentURL(), authMethodAuthenticateURL); + assert.equal(currentURL(), authMethodGlobalAuthenticateURL); }); }); diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index c64e37ceb..0758222ee 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -52,6 +52,7 @@ titles: grants: Permissions new-grant: New Grant principals: Principals + global: Global descriptions: host-catalogs: Overview of collections of hosts and host sets. empty-set: There are no items to display yet. You may be able to add items or try back later. From d9d429cb9d3ca715821b95331d21314ec02cf410 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Mon, 17 Aug 2020 14:56:19 -0400 Subject: [PATCH 25/29] =?UTF-8?q?chore:=20=F0=9F=A4=96=20global=20should?= =?UTF-8?q?=20be=20sorted=20to=20first=20place?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/scopes/scope/authenticate.js | 21 +++++++++++++++++++ .../templates/scopes/scope/authenticate.hbs | 2 +- .../scopes/scope/authenticate-test.js | 12 +++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 ui/core/app/controllers/scopes/scope/authenticate.js create mode 100644 ui/core/tests/unit/controllers/scopes/scope/authenticate-test.js diff --git a/ui/core/app/controllers/scopes/scope/authenticate.js b/ui/core/app/controllers/scopes/scope/authenticate.js new file mode 100644 index 000000000..b982a3c1c --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/authenticate.js @@ -0,0 +1,21 @@ +import Controller from '@ember/controller'; +import { sort } from '@ember/object/computed'; + +export default class ScopesScopeAuthenticateController extends Controller { + + // =attributes + + /** + * @type {Array} + */ + @sort('model.scopes', (a, b) => { + if (a.isGlobal) { + return -1; + } else if (b.isGlobal) { + return 1; + } + return 0; + }) + sortedScopes; + +} diff --git a/ui/core/app/templates/scopes/scope/authenticate.hbs b/ui/core/app/templates/scopes/scope/authenticate.hbs index 43b329188..75a60893f 100644 --- a/ui/core/app/templates/scopes/scope/authenticate.hbs +++ b/ui/core/app/templates/scopes/scope/authenticate.hbs @@ -14,7 +14,7 @@ @text={{t "actions.choose-different-org"}} @icon="user-organization" as |dropdown|> - {{#each @model.scopes as |scope|}} + {{#each this.sortedScopes as |scope|}} {{scope.displayName}} diff --git a/ui/core/tests/unit/controllers/scopes/scope/authenticate-test.js b/ui/core/tests/unit/controllers/scopes/scope/authenticate-test.js new file mode 100644 index 000000000..41bd58b67 --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/authenticate-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/authenticate', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/authenticate'); + assert.ok(controller); + }); +}); From e7875849ecee2faeb27dacb623801009c5bb327a Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 18 Aug 2020 16:20:32 -0400 Subject: [PATCH 26/29] =?UTF-8?q?fix:=20=F0=9F=90=9B=20move=20headers=20to?= =?UTF-8?q?=20prototype=20and=20send=20with=20scopes=20requests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/authenticators/password.js | 45 ++++++++++++++++- ui/core/app/session-stores/application.js | 34 +------------ .../unit/authenticators/password-test.js | 50 +++++++++++++++++++ .../unit/session-stores/application-test.js | 41 --------------- 4 files changed, 95 insertions(+), 75 deletions(-) create mode 100644 ui/core/tests/unit/authenticators/password-test.js delete mode 100644 ui/core/tests/unit/session-stores/application-test.js diff --git a/ui/core/app/authenticators/password.js b/ui/core/app/authenticators/password.js index a70c89ac7..88bf63c0a 100644 --- a/ui/core/app/authenticators/password.js +++ b/ui/core/app/authenticators/password.js @@ -37,9 +37,52 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator { * @param {string} scopeID * @return {string} */ - buildDeauthEndpointURL({ org_id: scopeID }) { + buildDeauthEndpointURL({ scope: { id: scopeID } }) { const adapter = this.store.adapterFor('application'); const options = { adapterOptions: { method: 'deauthenticate' } }; return adapter.buildURL('scope', scopeID, options, 'findRecord'); } + + /** + * Intercepts the authenticate response, if any, and assigns the returned + * token to all future requests via `addTokenToAuthorization`. + * Returns the response data as normal. + * @override + */ + authenticate() { + return super.authenticate(...arguments) + .then(data => { + const token = data?.token; + if (token) this.addTokenToAuthorization(token); + return data; + }); + } + + /** + * When restoring the session (say, on load), assigns the session token + * to all future requests via `addTokenToAuthorization`. + * @override + * @param {object} data + * @return {object} + */ + restore(data) { + const token = data?.token; + if (token) this.addTokenToAuthorization(token); + return super.restore(data); + } + + /** + * Assigns a token string all future requests via the `Authorization` header + * on the application adapter prototype. Only application and adapters that + * extend the application adapter receive this header (which is most). + * @param {string} token + */ + addTokenToAuthorization(token) { + const adapterPrototype = + this.store.adapterFor('application').constructor.prototype; + const headers = adapterPrototype?.headers; + if (!headers) adapterPrototype.headers = {}; + adapterPrototype.headers.Authorization = null; + if (token) adapterPrototype.headers.Authorization = `Bearer ${token}`; + } } diff --git a/ui/core/app/session-stores/application.js b/ui/core/app/session-stores/application.js index 401a98b44..681b7b12e 100644 --- a/ui/core/app/session-stores/application.js +++ b/ui/core/app/session-stores/application.js @@ -1,38 +1,6 @@ import LocalStorageSessionStore from 'auth/session-stores/local-storage'; -import { inject as service } from '@ember/service'; -import { get } from '@ember/object'; -//import config from '../config/environment'; -export default class ApplicationSessionStore extends LocalStorageSessionStore { - @service store; - - /** - * If the auth sessionData includes a token, apply it as a bearer token in the - * application adapter's Authorization header. Otherwise clear the header. - * @param {object} sessionData - * @return {object} - */ - persist(sessionData) { - this.addTokenToAuthorization(sessionData); - //this.addScopeToSession(sessionData); - return super.persist(...arguments); - } - - /** - * If the session has a full token, it is added as a bearer token to the - * `Authorization` header for all API requests. - * @param {object} sessionData - */ - addTokenToAuthorization(sessionData) { - const token = get(sessionData, 'authenticated.token'); - const adapter = this.store.adapterFor('application'); - const headers = get(adapter, 'headers'); - if (!headers) adapter.headers = {}; - adapter.headers.Authorization = null; - if (token) adapter.headers.Authorization = `Bearer ${token}`; - } - -} +export default class ApplicationSessionStore extends LocalStorageSessionStore {} // import CookieSessionStore from 'auth/session-stores/cookie'; // import config from '../config/environment'; diff --git a/ui/core/tests/unit/authenticators/password-test.js b/ui/core/tests/unit/authenticators/password-test.js new file mode 100644 index 000000000..21786ec86 --- /dev/null +++ b/ui/core/tests/unit/authenticators/password-test.js @@ -0,0 +1,50 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; + +module('Unit | Authenticator | password', function (hooks) { + setupTest(hooks); + setupMirage(hooks); + + let store; + let applicationAdapter; + let session; + let authenticator; + + hooks.beforeEach(function () { + store = this.owner.lookup('service:store'); + applicationAdapter = store.adapterFor('application'); + session = this.owner.lookup('service:session'); + authenticator = this.owner.lookup('authenticator:password'); + session.invalidate(); + }); + + hooks.afterEach(function () { + session.invalidate(); + }); + + test('it does not add an authorization header to application adapter on restore if no token is present', async function (assert) { + assert.expect(1); + authenticator.restore({ token: null }); + assert.notOk(applicationAdapter?.headers?.Authorization); + }); + + test('it adds an authorization header to application adapter on restore', async function (assert) { + assert.expect(1); + authenticator.restore({ token: 'token1234' }); + assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); + }); + + test('it adds an authorization header to application adapter on authenticate', async function (assert) { + assert.expect(1); + const creds = { identification: 'foo', password: 'bar' }; + const scope = { id: 'global' }; + const authMethod = { id: 'paum_1234' }; + await authenticator.authenticate( + creds, + null, + { scope, authMethod } + ); + assert.equal(applicationAdapter.headers.Authorization, 'Bearer thetokenstring'); + }); +}); diff --git a/ui/core/tests/unit/session-stores/application-test.js b/ui/core/tests/unit/session-stores/application-test.js deleted file mode 100644 index 6a3e908bc..000000000 --- a/ui/core/tests/unit/session-stores/application-test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('Unit | Session Store | application', function (hooks) { - setupTest(hooks); - - let store; - let applicationAdapter; - let sessionStore; - - hooks.beforeEach(function () { - store = this.owner.lookup('service:store'); - applicationAdapter = store.adapterFor('application'); - sessionStore = this.owner.lookup('session-store:application'); - sessionStore.clear(); - }); - - hooks.afterEach(function () { - sessionStore.clear(); - }); - - test('it does not add an authorization header to application adapter on persist if no token is present', async function (assert) { - assert.expect(1); - sessionStore.persist({ authenticated: { token: null } }); - assert.notOk(applicationAdapter.headers.Authorization); - }); - - test('it adds an authorization header to application adapter on persist', async function (assert) { - assert.expect(1); - sessionStore.persist({ authenticated: { token: 'token1234' } }); - assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); - }); - - test('it adds an authorization header to application adapter which already has headers on persist', async function (assert) { - assert.expect(2); - applicationAdapter.headers = { foo: 'bar' }; - sessionStore.persist({ authenticated: { token: 'token1234' } }); - assert.equal(applicationAdapter.headers.foo, 'bar'); - assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); - }); -}); From 74b399b122ef830ad93c8d45dfe1fd7b3f068a19 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 18 Aug 2020 16:49:45 -0400 Subject: [PATCH 27/29] =?UTF-8?q?fix:=20=F0=9F=90=9B=20all=20top=20level?= =?UTF-8?q?=20routes=20should=20redirect=20in=20unauthenticated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/routes/scopes/scope/auth-methods.js | 8 ++++++++ ui/core/app/routes/scopes/scope/groups.js | 8 ++++++++ ui/core/app/routes/scopes/scope/orgs.js | 8 ++++++++ ui/core/app/routes/scopes/scope/roles.js | 8 ++++++++ ui/core/app/routes/scopes/scope/users.js | 8 ++++++++ ui/core/tests/unit/authenticators/password-test.js | 6 ------ 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/ui/core/app/routes/scopes/scope/auth-methods.js b/ui/core/app/routes/scopes/scope/auth-methods.js index ffad801fa..0e35b2c28 100644 --- a/ui/core/app/routes/scopes/scope/auth-methods.js +++ b/ui/core/app/routes/scopes/scope/auth-methods.js @@ -7,9 +7,17 @@ export default class ScopesScopeAuthMethodsRoute extends Route { @service intl; @service notify; + @service session; // =methods + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.transitionTo('index'); + } + /** * Load all auth-methods under current scope * @return {Promise[AuthMethodModel]} diff --git a/ui/core/app/routes/scopes/scope/groups.js b/ui/core/app/routes/scopes/scope/groups.js index 7eed4406e..c2c75c8fb 100644 --- a/ui/core/app/routes/scopes/scope/groups.js +++ b/ui/core/app/routes/scopes/scope/groups.js @@ -7,9 +7,17 @@ export default class ScopesScopeGroupsRoute extends Route { @service intl; @service notify; + @service session; // =methods + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.transitionTo('index'); + } + /** * Load all groups under current scope * @return {Promise[GroupModel]} diff --git a/ui/core/app/routes/scopes/scope/orgs.js b/ui/core/app/routes/scopes/scope/orgs.js index f25a91cf9..c2fa56ffc 100644 --- a/ui/core/app/routes/scopes/scope/orgs.js +++ b/ui/core/app/routes/scopes/scope/orgs.js @@ -8,9 +8,17 @@ export default class ScopesScopeOrgsRoute extends Route { @service intl; @service notify; + @service session; // =methods + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.transitionTo('index'); + } + /** * Loads all scopes under the global scope. * @return {Promise{[ScopeModel]}} diff --git a/ui/core/app/routes/scopes/scope/roles.js b/ui/core/app/routes/scopes/scope/roles.js index 84cf2ae0f..b0418e399 100644 --- a/ui/core/app/routes/scopes/scope/roles.js +++ b/ui/core/app/routes/scopes/scope/roles.js @@ -7,9 +7,17 @@ export default class ScopesScopeRolesRoute extends Route { @service intl; @service notify; + @service session; // =methods + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.transitionTo('index'); + } + /** * Load all roles under current scope. * @return {Promise{[RoleModel]}} diff --git a/ui/core/app/routes/scopes/scope/users.js b/ui/core/app/routes/scopes/scope/users.js index f1982b769..20731c90f 100644 --- a/ui/core/app/routes/scopes/scope/users.js +++ b/ui/core/app/routes/scopes/scope/users.js @@ -7,9 +7,17 @@ export default class ScopesScopeUsersRoute extends Route { @service intl; @service notify; + @service session; // =methods + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.transitionTo('index'); + } + /** * Load all users under current scope. * @return {Promise{[UserModel]}} diff --git a/ui/core/tests/unit/authenticators/password-test.js b/ui/core/tests/unit/authenticators/password-test.js index 21786ec86..8bf59c9ee 100644 --- a/ui/core/tests/unit/authenticators/password-test.js +++ b/ui/core/tests/unit/authenticators/password-test.js @@ -23,12 +23,6 @@ module('Unit | Authenticator | password', function (hooks) { session.invalidate(); }); - test('it does not add an authorization header to application adapter on restore if no token is present', async function (assert) { - assert.expect(1); - authenticator.restore({ token: null }); - assert.notOk(applicationAdapter?.headers?.Authorization); - }); - test('it adds an authorization header to application adapter on restore', async function (assert) { assert.expect(1); authenticator.restore({ token: 'token1234' }); From d101870253cf1bf09472e966db75dfcca81c1886 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 18 Aug 2020 16:58:17 -0400 Subject: [PATCH 28/29] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20issue=20where?= =?UTF-8?q?=20global=20doesn't=20redirect=20to=20orgs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/routes/scopes/scope.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/core/app/routes/scopes/scope.js b/ui/core/app/routes/scopes/scope.js index 06158aa4d..08cd2d207 100644 --- a/ui/core/app/routes/scopes/scope.js +++ b/ui/core/app/routes/scopes/scope.js @@ -22,11 +22,11 @@ export default class ScopesScopeRoute extends Route { model({ scope_id: id }) { // Since only global and org scopes are authenticatable, we can infer type // from ID because global has a fixed ID. - const scopeType = id === 'global' ? 'global' : 'org'; + const type = id === 'global' ? 'global' : 'org'; return this.store.findRecord('scope', id).catch(() => { const maybeExistingScope = this.store.peekRecord('scope', id); - const scopeOptions = { id, scopeType }; - if (scopeType === 'global') { + const scopeOptions = { id, type }; + if (type === 'global') { scopeOptions.name = this.intl.t('titles.global'); } return maybeExistingScope || From abb778996e2af7faa7b9a12f1fda07314ae3de1c Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 19 Aug 2020 13:58:57 -0400 Subject: [PATCH 29/29] style: tweak dropdown styles for line-height, proportion, and hover states --- .../rose/components/dropdown/_button.scss | 36 +++++++------ .../rose/components/dropdown/_dropdown.scss | 16 +++--- .../rose/components/dropdown/_link.scss | 35 ++++++------ .../rose/components/header/_dropdown.scss | 54 ++++++++++--------- .../styles/rose/components/header/_nav.scss | 1 + .../rose/components/header/_utilities.scss | 1 + .../rose/tests/dummy/app/templates/index.hbs | 2 +- 7 files changed, 78 insertions(+), 67 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/dropdown/_button.scss b/addons/rose/addon/styles/rose/components/dropdown/_button.scss index bf6dc12c8..58b78e4a1 100644 --- a/addons/rose/addon/styles/rose/components/dropdown/_button.scss +++ b/addons/rose/addon/styles/rose/components/dropdown/_button.scss @@ -2,33 +2,35 @@ @use '../../utilities/type'; .rose-dropdown-button { - @include type.type(s, normal); + @include type.type(s); display: block; - // Targeting min-width of 200 - min-width: (sizing.rems(m) + sizing.rems(xxs)) * 10; + box-sizing: border-box; + width: 100%; + // Targeting min-width of ~200 + min-width: (sizing.rems(m) + sizing.rems(xs)) * 10; border: 0; - margin: 0; padding: 0 sizing.rems(s); - color: var(--stark); - background-color: transparent; - // target line height is 36, which is not a standard line height for this - // font size - $lineHeight: 36 / 16; - line-height: $lineHeight; - text-align: left; text-decoration: none; - cursor: pointer; + text-align: left; + $line-height: 36 / 14; + line-height: $line-height; + + --background-color: transparent; + --color: var(--stark); + color: var(--color); + background-color: var(--background-color); + + &:hover { + --background-color: var(--ui-gray-subtler-5); + } &.rose-dropdown-button-danger { - --background: var(--white); + --background-color: var(--white); --color: var(--failure); - color: var(--color); - background-color: var(--background-color); - &:hover { --color: var(--white); --background-color: var(--failure); } } -} \ No newline at end of file +} diff --git a/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss b/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss index cb3c964eb..34b2753b0 100644 --- a/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss +++ b/addons/rose/addon/styles/rose/components/dropdown/_dropdown.scss @@ -1,6 +1,8 @@ @use '../../variables/sizing'; @use '../../utilities/type'; +$xs: sizing.rems(xs); // 8 +$xxs: sizing.rems(xxs); // 4 $chevron: "data:image/svg+xml;utf-8,"; .rose-dropdown { @@ -13,11 +15,11 @@ $chevron: "data:image/svg+xml;utf-8, .rose-dropdown-trigger { background-color: var(--ui-gray-subtler-4); } .rose-dropdown-content { - $xs: sizing.rems(xs); // 8 - $xxs: sizing.rems(xxs); // 4 position: absolute; padding: $xxs 0; border: 1px solid var(--ui-gray-subtler-2); @@ -96,5 +95,6 @@ $chevron: "data:image/svg+xml;utf-8,"; -.rose-header-utilities, -.rose-header-nav { - margin-right: sizing.rems(s); +.rose-header { + .rose-dropdown { + &, + &[open] { + .rose-dropdown-trigger { + color: var(--white); + background: url($chevron) no-repeat right sizing.rems(s) center; + background-size: sizing.rems(m); - .rose-dropdown-trigger { - $lineHeight: 48 / 16; - line-height: $lineHeight; - color: var(--white); - background: url($chevron) no-repeat right center; - background-size: sizing.rems(m); + $yPadding: sizing.rems(xxxs); + $rightPadding: sizing.rems(xs) + sizing.rems(l); + padding: $yPadding $rightPadding $yPadding sizing.rems(s); - .rose-icon { - --size: #{sizing.rems(l)}; - } + &.has-icon-only { + padding-left: sizing.rems(xs); + } - .rose-icon { - display: inline-block; - height: var(--size); + .rose-icon { + --size: #{sizing.rems(l)}; + } - > svg { - vertical-align: top; + .rose-icon { + display: inline-block; + height: var(--size); + + > svg { + vertical-align: top; + } + } + + &:hover, &:focus { + background-color: transparent; + } } } - - &:hover, &:focus { - background-color: unset; - } } } - -.rose-header-nav .rose-dropdown-trigger{ - padding-right: sizing.rems(l); -} diff --git a/addons/rose/addon/styles/rose/components/header/_nav.scss b/addons/rose/addon/styles/rose/components/header/_nav.scss index 6e50ec714..1eee38086 100644 --- a/addons/rose/addon/styles/rose/components/header/_nav.scss +++ b/addons/rose/addon/styles/rose/components/header/_nav.scss @@ -6,6 +6,7 @@ display: flex; flex-wrap: wrap; align-items: center; + margin-right: sizing.rems(s); @media (max-width: media.width(small)) { padding: 0 20px; diff --git a/addons/rose/addon/styles/rose/components/header/_utilities.scss b/addons/rose/addon/styles/rose/components/header/_utilities.scss index ad28137ff..6632a2597 100644 --- a/addons/rose/addon/styles/rose/components/header/_utilities.scss +++ b/addons/rose/addon/styles/rose/components/header/_utilities.scss @@ -6,4 +6,5 @@ flex-wrap: wrap; flex-direction: row-reverse; align-items: center; + margin-right: sizing.rems(s); } diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index ab7081265..529b6c7c5 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -2,7 +2,7 @@ - + Menu item Menu item - danger