Refactor hds side nav to hds app side nav and header (#3032)
* refactor: 💡 use hds app header and app side nav * style: 💄 fix dark-mode colors for side nav and app header * style: 💄 cleanup * style: 💄 simplify selector * refactor: 💡 move util (param finder) to core addon * refactor: 💡 move scope picker to core addon * refactor: 💡 use hds header and app side nav in ui/desktop * refactor: 💡 clean up ui/desktop files * refactor: 💡 remove uneeded header components * refactor: 💡 remove uneeded global layout * Add missing copyright headers * style: 💄 adjust foreground and background colors to fix contras * style: 💄 remove uneeded stylelint disables * style: 💄 fix dark mode styling in desktop ui * refactor: 💡 readd user-select style * test: 💍 fix tests + e2e tests for admin and desktop UIs * refactor: 💡 clean up uneeded main elements and fix color link * Add missing copyright headers * fix: 🐛 e2e test selectors for ui/desktop * style: 💄 revert link color change * refactor: 💡 remove hds override * fix: 🐛 scope dropdown for desktop * fix: 🐛 max-height to desktop scope dropdown * Add missing copyright headers * chore: 🤖 update lockfile due to webpack update
This commit is contained in:
1 parent
aaabfbe54d
commit
b1b49edb39
94 files changed
+784
-1178
No files matched your search
@@ -8,6 +8,8 @@ import { service } from '@ember/service';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { defaultValidator } from 'ember-a11y-refocus';
|
||||
import { paramValueFinder } from 'core/utils/param-value-finder';
|
||||
|
||||
export default class ApplicationController extends Controller {
|
||||
// =services
|
||||
@@ -17,6 +19,9 @@ export default class ApplicationController extends Controller {
|
||||
@service ipc;
|
||||
@service session;
|
||||
@service('browser/window') window;
|
||||
@service router;
|
||||
@service scope;
|
||||
@service intl;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -34,6 +39,30 @@ export default class ApplicationController extends Controller {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns display name and icon for current scope.
|
||||
* @type {object}
|
||||
*/
|
||||
get currentScope() {
|
||||
if (this.scope.org.isOrg) {
|
||||
return { name: this.scope.org.displayName, icon: 'org' };
|
||||
} else {
|
||||
return { name: this.intl.t('titles.global'), icon: 'globe' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows side navigation only for routes nested under a scope
|
||||
* and if user has been authenticated.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get showSideNav() {
|
||||
return (
|
||||
this.router.currentRouteName.startsWith('scopes.scope') &&
|
||||
this.session.isAuthenticated
|
||||
);
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
@@ -128,4 +157,29 @@ export default class ApplicationController extends Controller {
|
||||
super.willDestroy(...arguments);
|
||||
this.removeOnAppQuitListener?.();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom route change validation to prevent refocus when
|
||||
* user is attempting to search, filter, or sort.
|
||||
* @param {object} transition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
customRouteChangeValidator(transition) {
|
||||
if (!transition.to || !transition.from) {
|
||||
return true;
|
||||
}
|
||||
if (transition.to.name === transition.from.name) {
|
||||
const toParams = paramValueFinder(
|
||||
transition.to.localName,
|
||||
transition.to.parent,
|
||||
);
|
||||
const fromParams = paramValueFinder(
|
||||
transition.from.localName,
|
||||
transition.from.parent,
|
||||
);
|
||||
// Return false to prevent refocus when routes have equivalent dynamic segments (params).
|
||||
return JSON.stringify(toParams) !== JSON.stringify(fromParams);
|
||||
}
|
||||
return defaultValidator(transition);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Controller from '@ember/controller';
|
||||
import { service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeController extends Controller {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
}
|
||||
@@ -53,12 +53,12 @@ export default class ScopesScopeRoute extends Route {
|
||||
*/
|
||||
async afterModel(model) {
|
||||
// First, load orgs and, if necessary, projects
|
||||
let orgs, projects;
|
||||
let orgs;
|
||||
orgs = await this.store
|
||||
.query('scope', { scope_id: 'global' })
|
||||
.catch(() => new TrackedArray([]));
|
||||
if (model.isProject) {
|
||||
projects = await this.store.query('scope', { scope_id: model.scopeID });
|
||||
await this.store.query('scope', { scope_id: model.scopeID });
|
||||
}
|
||||
// Then pull out the "selected" scopes, if relevant
|
||||
let selectedOrg, selectedProject;
|
||||
@@ -70,16 +70,6 @@ export default class ScopesScopeRoute extends Route {
|
||||
// Update the scope service with the current scope(s);
|
||||
this.scope.org = selectedOrg;
|
||||
this.scope.project = selectedProject;
|
||||
this.scopes = { orgs, projects, selectedOrg, selectedProject };
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the scopes hash to the controller context (see `afterModel`).
|
||||
* @param {Controller} controller
|
||||
*/
|
||||
setupController(controller) {
|
||||
super.setupController(...arguments);
|
||||
const scopes = this.scopes;
|
||||
controller.setProperties({ scopes });
|
||||
this.scope.orgsList = orgs;
|
||||
}
|
||||
}
|
||||
+42
-113
@@ -24,34 +24,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This section enables scrolling within the sidebar columns separately,
|
||||
* rather than the whole viewport. This ensures the sidebar and application
|
||||
* header remain visible when scrolling.
|
||||
*/
|
||||
.rose-layout-global {
|
||||
max-height: 100vh;
|
||||
|
||||
.rose-layout-global-body {
|
||||
max-height: 100vh;
|
||||
overflow: auto;
|
||||
|
||||
main {
|
||||
/** This overrides the main defined within Rose.
|
||||
* HDS has this set to 1.5rem top/bottom 3rem left/right. HDS assumes the usage of breadcrumbs
|
||||
* but the DC have no breadcrumbs, so we will keep it at 3rem all around.
|
||||
*/
|
||||
padding: 3rem;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.rose-layout-sidebar-sidebar,
|
||||
.rose-layout-sidebar-body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.rose-nav-sidebar {
|
||||
margin-top: sizing.rems(xxl);
|
||||
|
||||
@@ -74,95 +46,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.rose-header {
|
||||
-webkit-app-region: drag;
|
||||
min-height: sizing.rems(l) * 2;
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
|
||||
.rose-header-brand,
|
||||
.rose-header-nav,
|
||||
.rose-header-utilities button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
&.header-cushion {
|
||||
padding-left: sizing.rems(l) * 3;
|
||||
}
|
||||
|
||||
.button-window-minimize,
|
||||
.button-window-fullscreen,
|
||||
.button-window-close {
|
||||
background: transparent;
|
||||
border: transparent;
|
||||
color: var(--white);
|
||||
margin: sizing.rems(xs);
|
||||
}
|
||||
|
||||
.button-window-close {
|
||||
&:hover {
|
||||
background: var(--failure);
|
||||
}
|
||||
}
|
||||
|
||||
.button-window-minimize,
|
||||
.button-window-fullscreen {
|
||||
&:hover {
|
||||
background: var(--white);
|
||||
color: var(--black);
|
||||
}
|
||||
}
|
||||
|
||||
.logotype {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
&::after {
|
||||
animation: gradient 1s linear infinite;
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
var(--subtle),
|
||||
var(--subtle),
|
||||
var(--info),
|
||||
var(--subtle),
|
||||
var(--subtle)
|
||||
);
|
||||
background-position: -100% 0;
|
||||
background-size: 200% auto;
|
||||
content: ' ';
|
||||
height: 3px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 100%;
|
||||
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[class*='session-status-'] {
|
||||
color: var(--ui-gray-subtler-2);
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.branded-card {
|
||||
border: 1px solid var(--ui-border-subtler-1);
|
||||
border-radius: var(--token-border-radius-x-small);
|
||||
margin: 0 auto;
|
||||
margin-top: sizing.rems(l) * 1.25;
|
||||
margin-top: sizing.rems(xl) * 1.5;
|
||||
padding: (sizing.rems(l) * 4) (sizing.rems(l) * 3) (sizing.rems(l) * 2)
|
||||
(sizing.rems(l) * 3);
|
||||
position: relative;
|
||||
@@ -424,3 +312,44 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-header {
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
|
||||
&.header-cushion {
|
||||
padding-left: sizing.rems(l) * 4;
|
||||
}
|
||||
|
||||
&__logo,
|
||||
&__global-actions,
|
||||
&__utility-actions,
|
||||
.hds-app-header__menu-button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.hds-app-header__utility-actions {
|
||||
.button-window-minimize,
|
||||
.button-window-fullscreen,
|
||||
.button-window-close {
|
||||
background: transparent;
|
||||
border: transparent;
|
||||
color: var(--white);
|
||||
margin: sizing.rems(xs);
|
||||
}
|
||||
|
||||
.button-window-close {
|
||||
&:hover {
|
||||
background: var(--failure);
|
||||
}
|
||||
}
|
||||
|
||||
.button-window-minimize,
|
||||
.button-window-fullscreen {
|
||||
&:hover {
|
||||
background: var(--white);
|
||||
color: var(--black);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,55 +5,76 @@
|
||||
|
||||
{{page-title (app-name)}}
|
||||
|
||||
<Rose::Layout::Global as |layout|>
|
||||
|
||||
<layout.header>
|
||||
<Rose::Header
|
||||
class='{{if (is-loading) " loading"}}
|
||||
{{if this.hasMacOSChrome " header-cushion"}}'
|
||||
as |header|
|
||||
<Hds::AppFrame @hasHeader={{true}} @hasSidebar={{this.showSideNav}} as |Frame|>
|
||||
<Frame.Header>
|
||||
<Hds::AppHeader
|
||||
class='app-header
|
||||
{{if this.hasMacOSChrome " header-cushion"}}
|
||||
app-header-dark-mode-overrides'
|
||||
@a11yRefocusRouteChangeValidator={{this.customRouteChangeValidator}}
|
||||
>
|
||||
<header.brand @logo='logo-app' @text={{(app-name)}} />
|
||||
<:logo>
|
||||
<Hds::AppHeader::HomeLink
|
||||
@icon='boundary'
|
||||
@color='var(--token-color-boundary-brand)'
|
||||
@text={{(app-name)}}
|
||||
@route='index'
|
||||
class='app-header__logo home-link-color-override'
|
||||
/>
|
||||
</:logo>
|
||||
|
||||
<header.nav>
|
||||
<div id='header-nav'></div>
|
||||
</header.nav>
|
||||
<:globalActions>
|
||||
{{#if this.session.isAuthenticated}}
|
||||
<Hds::Dropdown
|
||||
class='app-header__global-actions'
|
||||
@enableCollisionDetection={{true}}
|
||||
@listPosition='bottom-left'
|
||||
@height='20rem'
|
||||
data-test-header-scope-dropdown
|
||||
as |D|
|
||||
>
|
||||
{{#let this.currentScope as |scope|}}
|
||||
<D.ToggleButton
|
||||
@text={{scope.name}}
|
||||
@icon={{scope.icon}}
|
||||
class='dropdown-toggle-color-override'
|
||||
/>
|
||||
{{/let}}
|
||||
|
||||
<header.utilities>
|
||||
{{#if this.showWindowActions}}
|
||||
<Hds::Button
|
||||
{{on 'click' this.close}}
|
||||
class='button-window-close'
|
||||
title={{t 'actions.close'}}
|
||||
@text={{t 'actions.close'}}
|
||||
@icon='x'
|
||||
@isIconOnly={{true}}
|
||||
/>
|
||||
<Hds::Button
|
||||
{{on 'click' this.toggleFullScreen}}
|
||||
class='button-window-fullscreen'
|
||||
title={{t 'actions.fullscreen'}}
|
||||
@text={{t 'actions.fullscreen'}}
|
||||
@icon='square'
|
||||
@isIconOnly={{true}}
|
||||
@color='secondary'
|
||||
/>
|
||||
<Hds::Button
|
||||
{{on 'click' this.minimize}}
|
||||
class='button-window-minimize'
|
||||
title={{t 'actions.minimize'}}
|
||||
@text={{t 'actions.minimize'}}
|
||||
@icon='minus'
|
||||
@isIconOnly={{true}}
|
||||
@color='secondary'
|
||||
/>
|
||||
<D.Checkmark
|
||||
@icon='globe'
|
||||
@route='scopes.scope'
|
||||
@model='global'
|
||||
@selected={{this.scope.org.isGlobal}}
|
||||
>
|
||||
{{t 'titles.global'}}
|
||||
</D.Checkmark>
|
||||
|
||||
{{#if this.scope.orgsList}}
|
||||
<D.Separator />
|
||||
{{/if}}
|
||||
|
||||
{{#each this.scope.orgsList as |org|}}
|
||||
<D.Checkmark
|
||||
@icon='org'
|
||||
@route='scopes.scope'
|
||||
@model={{org.id}}
|
||||
@selected={{eq this.scope.org.id org.id}}
|
||||
>
|
||||
{{org.displayName}}
|
||||
</D.Checkmark>
|
||||
{{/each}}
|
||||
</Hds::Dropdown>
|
||||
{{/if}}
|
||||
</:globalActions>
|
||||
|
||||
<:utilityActions>
|
||||
{{#if this.session.username}}
|
||||
<Hds::Dropdown class='header-dropdown-button-override' as |dd|>
|
||||
<Hds::Dropdown class='app-header__utility-actions' as |dd|>
|
||||
<dd.ToggleButton
|
||||
@icon='user-circle'
|
||||
@text={{this.session.username}}
|
||||
class='dropdown-toggle-color-override'
|
||||
/>
|
||||
<dd.Interactive
|
||||
data-test-nav-signout-btn
|
||||
@@ -62,9 +83,13 @@
|
||||
{{t 'actions.deauthenticate'}}
|
||||
</dd.Interactive>
|
||||
</Hds::Dropdown>
|
||||
{{else}}
|
||||
<Hds::Dropdown class='header-dropdown-button-override' as |dd|>
|
||||
<dd.ToggleIcon @icon='user-circle' @text={{t 'titles.user-menu'}} />
|
||||
{{else if this.session.isAuthenticated}}
|
||||
<Hds::Dropdown as |dd|>
|
||||
<dd.ToggleIcon
|
||||
@icon='user-circle'
|
||||
@text={{t 'titles.user-menu'}}
|
||||
class='dropdown-toggle-color-override'
|
||||
/>
|
||||
<dd.Interactive
|
||||
data-test-nav-signout-btn
|
||||
{{on 'click' this.showModalOrLogout}}
|
||||
@@ -74,15 +99,49 @@
|
||||
</Hds::Dropdown>
|
||||
{{/if}}
|
||||
|
||||
</header.utilities>
|
||||
</Rose::Header>
|
||||
</layout.header>
|
||||
{{#if this.showWindowActions}}
|
||||
<Hds::Button
|
||||
{{on 'click' this.minimize}}
|
||||
class='app-header__utility-actions button-window-minimize'
|
||||
title={{t 'actions.minimize'}}
|
||||
@text={{t 'actions.minimize'}}
|
||||
@icon='minus'
|
||||
@isIconOnly={{true}}
|
||||
@color='secondary'
|
||||
/>
|
||||
<Hds::Button
|
||||
{{on 'click' this.toggleFullScreen}}
|
||||
class='app-header__utility-actions button-window-fullscreen'
|
||||
title={{t 'actions.fullscreen'}}
|
||||
@text={{t 'actions.fullscreen'}}
|
||||
@icon='square'
|
||||
@isIconOnly={{true}}
|
||||
@color='secondary'
|
||||
/>
|
||||
<Hds::Button
|
||||
{{on 'click' this.close}}
|
||||
class='app-header__utility-actions button-window-close'
|
||||
title={{t 'actions.close'}}
|
||||
@text={{t 'actions.close'}}
|
||||
@icon='x'
|
||||
@isIconOnly={{true}}
|
||||
/>
|
||||
{{/if}}
|
||||
</:utilityActions>
|
||||
|
||||
<layout.body>
|
||||
</Hds::AppHeader>
|
||||
</Frame.Header>
|
||||
|
||||
<Frame.Sidebar>
|
||||
<Hds::AppSideNav>
|
||||
<Hds::AppSideNav::Portal::Target />
|
||||
</Hds::AppSideNav>
|
||||
</Frame.Sidebar>
|
||||
|
||||
<Frame.Main>
|
||||
{{outlet}}
|
||||
</layout.body>
|
||||
|
||||
</Rose::Layout::Global>
|
||||
</Frame.Main>
|
||||
</Hds::AppFrame>
|
||||
|
||||
{{#if this.flashMessages.queue}}
|
||||
<div class='ember-notify-cn'>
|
||||
|
||||
@@ -3,41 +3,39 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
<main>
|
||||
<BrandedCard
|
||||
@title={{t 'titles.welcome-to-boundary'}}
|
||||
@description={{t 'descriptions.cluster-url-initialization'}}
|
||||
<BrandedCard
|
||||
@title={{t 'titles.welcome-to-boundary'}}
|
||||
@description={{t 'descriptions.cluster-url-initialization'}}
|
||||
>
|
||||
<Rose::Form
|
||||
class='full-width'
|
||||
@onSubmit={{fn this.setClusterUrl this.clusterUrl}}
|
||||
@cancel={{false}}
|
||||
@disabled={{(is-loading)}}
|
||||
as |form|
|
||||
>
|
||||
<Rose::Form
|
||||
class='full-width'
|
||||
@onSubmit={{fn this.setClusterUrl this.clusterUrl}}
|
||||
@cancel={{false}}
|
||||
@disabled={{(is-loading)}}
|
||||
as |form|
|
||||
|
||||
{{! template-lint-disable no-autofocus-attribute }}
|
||||
<Hds::Form::TextInput::Field
|
||||
name='host'
|
||||
@value={{this.clusterUrl}}
|
||||
autofocus
|
||||
{{on 'input' (set-from-event this 'clusterUrl')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.cluster-url.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.cluster-url.description'}}</F.HelperText>
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
{{! template-lint-disable no-autofocus-attribute }}
|
||||
<Hds::Form::TextInput::Field
|
||||
name='host'
|
||||
@value={{this.clusterUrl}}
|
||||
autofocus
|
||||
{{on 'input' (set-from-event this 'clusterUrl')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.cluster-url.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.cluster-url.description'}}</F.HelperText>
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
<form.actions>
|
||||
<:actions>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.submit'}}
|
||||
@isFullWidth={{true}}
|
||||
disabled={{form.disabled}}
|
||||
type='submit'
|
||||
/>
|
||||
</:actions>
|
||||
</form.actions>
|
||||
</Rose::Form>
|
||||
</BrandedCard>
|
||||
</main>
|
||||
<form.actions>
|
||||
<:actions>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.submit'}}
|
||||
@isFullWidth={{true}}
|
||||
disabled={{form.disabled}}
|
||||
type='submit'
|
||||
/>
|
||||
</:actions>
|
||||
</form.actions>
|
||||
</Rose::Form>
|
||||
</BrandedCard>
|
||||
@@ -5,18 +5,14 @@
|
||||
|
||||
{{page-title (t 'errors.generic.title')}}
|
||||
|
||||
<main>
|
||||
<Rose::Layout::Centered>
|
||||
<Error::Message @docLink={{doc-url 'support-page'}} />
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Error::Message @docLink={{doc-url 'support-page'}} />
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
<Rose::Layout::Centered>
|
||||
<Hds::Button
|
||||
@color='primary'
|
||||
@text={{t 'actions.disconnect'}}
|
||||
{{on 'click' this.appUtilities.disconnect}}
|
||||
/>
|
||||
</Rose::Layout::Centered>
|
||||
|
||||
</main>
|
||||
<Rose::Layout::Centered>
|
||||
<Hds::Button
|
||||
@color='primary'
|
||||
@text={{t 'actions.disconnect'}}
|
||||
{{on 'click' this.appUtilities.disconnect}}
|
||||
/>
|
||||
</Rose::Layout::Centered>
|
||||
@@ -3,31 +3,4 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
{{outlet}}
|
||||
|
||||
{{#if this.session.isAuthenticated}}
|
||||
<EmberWormhole @to='header-nav'>
|
||||
<Hds::Dropdown
|
||||
class='header-dropdown-button-override'
|
||||
@enableCollisionDetection={{true}}
|
||||
as |dd|
|
||||
>
|
||||
<dd.ToggleButton
|
||||
@text={{this.scopes.selectedOrg.displayName}}
|
||||
@icon={{if this.scopes.selectedOrg.isGlobal 'globe' 'org'}}
|
||||
@color='secondary'
|
||||
/>
|
||||
<dd.Interactive @route='scopes.scope' @model='global'>
|
||||
{{t 'titles.global'}}
|
||||
</dd.Interactive>
|
||||
{{#if this.scopes.orgs.length}}
|
||||
<dd.Separator />
|
||||
{{/if}}
|
||||
{{#each this.scopes.orgs as |scope|}}
|
||||
<dd.Interactive @route='scopes.scope' @model={{scope.id}}>
|
||||
{{scope.displayName}}
|
||||
</dd.Interactive>
|
||||
{{/each}}
|
||||
</Hds::Dropdown>
|
||||
</EmberWormhole>
|
||||
{{/if}}
|
||||
{{outlet}}
|
||||
@@ -5,76 +5,72 @@
|
||||
|
||||
{{page-title (t 'actions.authenticate')}}
|
||||
|
||||
<main>
|
||||
{{#if this.isOIDCRoute}}
|
||||
{{outlet}}
|
||||
{{else}}
|
||||
<BrandedCard
|
||||
@title={{t 'actions.authenticate'}}
|
||||
@description={{t
|
||||
'auth.descriptions.authenticating-with-org'
|
||||
name=@model.scope.displayName
|
||||
}}
|
||||
>
|
||||
{{#if this.isOIDCRoute}}
|
||||
{{outlet}}
|
||||
{{else}}
|
||||
<BrandedCard
|
||||
@title={{t 'actions.authenticate'}}
|
||||
@description={{t
|
||||
'auth.descriptions.authenticating-with-org'
|
||||
name=@model.scope.displayName
|
||||
}}
|
||||
>
|
||||
|
||||
<Hds::Dropdown @listPosition='bottom-left' as |dd|>
|
||||
<dd.ToggleButton
|
||||
@text={{t 'actions.choose-different-org'}}
|
||||
@icon='org'
|
||||
@color='secondary'
|
||||
/>
|
||||
<dd.Interactive {{on 'click' (fn this.selectScope 'global' dd.close)}}>
|
||||
{{t 'titles.global'}}
|
||||
<Hds::Dropdown @listPosition='bottom-left' as |dd|>
|
||||
<dd.ToggleButton
|
||||
@text={{t 'actions.choose-different-org'}}
|
||||
@icon='org'
|
||||
@color='secondary'
|
||||
/>
|
||||
<dd.Interactive {{on 'click' (fn this.selectScope 'global' dd.close)}}>
|
||||
{{t 'titles.global'}}
|
||||
</dd.Interactive>
|
||||
{{#each this.sortedScopes as |scope|}}
|
||||
<dd.Interactive {{on 'click' (fn this.selectScope scope.id dd.close)}}>
|
||||
{{scope.displayName}}
|
||||
</dd.Interactive>
|
||||
{{#each this.sortedScopes as |scope|}}
|
||||
<dd.Interactive
|
||||
{{on 'click' (fn this.selectScope scope.id dd.close)}}
|
||||
>
|
||||
{{scope.displayName}}
|
||||
</dd.Interactive>
|
||||
{{/each}}
|
||||
</Hds::Dropdown>
|
||||
{{/each}}
|
||||
</Hds::Dropdown>
|
||||
|
||||
<Rose::Nav::Tabs as |nav|>
|
||||
{{#each @model.authMethods as |authMethod|}}
|
||||
<nav.link
|
||||
@route='scopes.scope.authenticate.method'
|
||||
@model={{authMethod.id}}
|
||||
>
|
||||
{{#if authMethod.name}}
|
||||
{{authMethod.name}}
|
||||
{{else}}
|
||||
{{t (concat 'resources.auth-method.types.' authMethod.type)}}
|
||||
{{/if}}
|
||||
</nav.link>
|
||||
{{/each}}
|
||||
</Rose::Nav::Tabs>
|
||||
<Rose::Nav::Tabs as |nav|>
|
||||
{{#each @model.authMethods as |authMethod|}}
|
||||
<nav.link
|
||||
@route='scopes.scope.authenticate.method'
|
||||
@model={{authMethod.id}}
|
||||
>
|
||||
{{#if authMethod.name}}
|
||||
{{authMethod.name}}
|
||||
{{else}}
|
||||
{{t (concat 'resources.auth-method.types.' authMethod.type)}}
|
||||
{{/if}}
|
||||
</nav.link>
|
||||
{{/each}}
|
||||
</Rose::Nav::Tabs>
|
||||
|
||||
{{#if @model.authMethods}}
|
||||
{{outlet}}
|
||||
{{else}}
|
||||
<Rose::Layout::Centered>
|
||||
<Hds::ApplicationState data-test-no-auth-methods as |A|>
|
||||
<A.Header
|
||||
@icon='alert-circle'
|
||||
@title={{t 'resources.auth-method.messages.none.title'}}
|
||||
/>
|
||||
<A.Body
|
||||
@text={{t 'resources.auth-method.messages.none.description'}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
</Rose::Layout::Centered>
|
||||
{{/if}}
|
||||
<Hds::Text::Body @tag='p' class='change-origin'>
|
||||
{{t 'cluster-url.connected-to'}}:
|
||||
<Hds::Text::Code>
|
||||
{{this.clusterUrl}}
|
||||
</Hds::Text::Code>
|
||||
<br />
|
||||
<LinkTo @route='cluster-url'>
|
||||
{{t 'actions.change-cluster-url'}}
|
||||
</LinkTo>
|
||||
</Hds::Text::Body>
|
||||
</BrandedCard>
|
||||
{{/if}}
|
||||
</main>
|
||||
{{#if @model.authMethods}}
|
||||
{{outlet}}
|
||||
{{else}}
|
||||
<Rose::Layout::Centered>
|
||||
<Hds::ApplicationState data-test-no-auth-methods as |A|>
|
||||
<A.Header
|
||||
@icon='alert-circle'
|
||||
@title={{t 'resources.auth-method.messages.none.title'}}
|
||||
/>
|
||||
<A.Body
|
||||
@text={{t 'resources.auth-method.messages.none.description'}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
</Rose::Layout::Centered>
|
||||
{{/if}}
|
||||
<Hds::Text::Body @tag='p' class='change-origin'>
|
||||
{{t 'cluster-url.connected-to'}}:
|
||||
<Hds::Text::Code>
|
||||
{{this.clusterUrl}}
|
||||
</Hds::Text::Code>
|
||||
<br />
|
||||
<LinkTo @route='cluster-url'>
|
||||
{{t 'actions.change-cluster-url'}}
|
||||
</LinkTo>
|
||||
</Hds::Text::Body>
|
||||
</BrandedCard>
|
||||
{{/if}}
|
||||
@@ -3,28 +3,26 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
<Rose::Layout::Sidebar as |sidebarLayout|>
|
||||
<sidebarLayout.sidebar>
|
||||
<Rose::Nav::Sidebar as |nav|>
|
||||
<nav.link @route='scopes.scope.projects.targets'>
|
||||
<Hds::Icon @name='crosshair' @isInline={{true}} />
|
||||
{{t 'resources.target.title_plural'}}
|
||||
</nav.link>
|
||||
<Hds::AppSideNav::Portal
|
||||
@ariaLabel='Primary'
|
||||
class='side-nav-dark-mode-overrides'
|
||||
as |Nav|
|
||||
>
|
||||
<Nav.Link
|
||||
@icon='crosshair'
|
||||
@text={{t 'resources.target.title_plural'}}
|
||||
@route='scopes.scope.projects.targets'
|
||||
/>
|
||||
<Nav.Link
|
||||
@icon='entry-point'
|
||||
@text={{t 'resources.session.title_plural'}}
|
||||
@route='scopes.scope.projects.sessions'
|
||||
/>
|
||||
<Nav.Link
|
||||
@icon='settings'
|
||||
@text={{t 'titles.settings'}}
|
||||
@route='scopes.scope.projects.settings'
|
||||
/>
|
||||
</Hds::AppSideNav::Portal>
|
||||
|
||||
<nav.link @route='scopes.scope.projects.sessions'>
|
||||
<Hds::Icon @name='entry-point' @isInline={{true}} />
|
||||
{{t 'resources.session.title_plural'}}
|
||||
</nav.link>
|
||||
<nav.link @route='scopes.scope.projects.settings'>
|
||||
<Hds::Icon @name='settings' @isInline={{true}} />
|
||||
{{t 'titles.settings'}}
|
||||
</nav.link>
|
||||
</Rose::Nav::Sidebar>
|
||||
</sidebarLayout.sidebar>
|
||||
|
||||
<sidebarLayout.body>
|
||||
<main>
|
||||
{{outlet}}
|
||||
</main>
|
||||
</sidebarLayout.body>
|
||||
</Rose::Layout::Sidebar>
|
||||
{{outlet}}
|
||||
@@ -46,6 +46,7 @@
|
||||
"@xterm/addon-canvas": "^0.7.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"ember-a11y-refocus": "^5.0.0",
|
||||
"ember-inflector": "^6.0.0",
|
||||
"ember-named-blocks-polyfill": "^0.2.5",
|
||||
"lodash": "^4.17.23",
|
||||
|
||||
@@ -67,7 +67,7 @@ module('Acceptance | Application', function (hooks) {
|
||||
stubs.ipcService.withArgs('hasMacOSChrome').returns(true);
|
||||
await visit(urls.clusterUrl);
|
||||
assert.ok(
|
||||
find('.rose-header.header-cushion'),
|
||||
find('.app-header.header-cushion'),
|
||||
'Adds header padding around native window actions',
|
||||
);
|
||||
});
|
||||
@@ -77,7 +77,7 @@ module('Acceptance | Application', function (hooks) {
|
||||
stubs.ipcService.withArgs('hasMacOSChrome').returns(false);
|
||||
await visit(urls.clusterUrl);
|
||||
assert.notOk(
|
||||
find('.rose-header.header-cushion'),
|
||||
find('.app-header.header-cushion'),
|
||||
'Does not add header padding around native window actions',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -69,8 +69,7 @@ module('Acceptance | authentication', function (hooks) {
|
||||
const MODAL_CLOSE_SESSIONS = '[data-test-close-sessions-modal]';
|
||||
const MODAL_CONFIRM_BTN = '.hds-modal__footer .hds-button--color-primary';
|
||||
const MODAL_CANCEL_BTN = '.hds-modal__footer .hds-button--color-secondary';
|
||||
const HEADER_DROPDOWN_BTN =
|
||||
'.rose-header-utilities .header-dropdown-button-override button';
|
||||
const HEADER_DROPDOWN_BTN = '.app-header__utility-actions button';
|
||||
|
||||
const setDefaultClusterUrl = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
|
||||
@@ -542,8 +542,10 @@ module('Acceptance | projects | sessions | index', function (hooks) {
|
||||
.isVisible();
|
||||
|
||||
// change scope in app header
|
||||
await click('.rose-header-nav .hds-dropdown-toggle-button');
|
||||
await click('.rose-header-nav .hds-dropdown-list-item:nth-of-type(4) a');
|
||||
await click('[data-test-header-scope-dropdown] button');
|
||||
await click(
|
||||
`[data-test-header-scope-dropdown] a[href="${urls.scopes.org2}"]`,
|
||||
);
|
||||
// navigate to back sessions
|
||||
await click(`[href="${urls.sessions2}"]`);
|
||||
|
||||
|
||||
@@ -602,8 +602,10 @@ module('Acceptance | projects | targets | index', function (hooks) {
|
||||
.dom(`[data-test-target-project-id="${instances.scopes.project2.id}"]`)
|
||||
.exists();
|
||||
|
||||
await click('.rose-header-nav .hds-dropdown-toggle-button');
|
||||
await click('.rose-header-nav .hds-dropdown-list-item:nth-of-type(3) a');
|
||||
await click('[data-test-header-scope-dropdown] button');
|
||||
await click(
|
||||
`[data-test-header-scope-dropdown] a[href="${urls.scopes.org}"]`,
|
||||
);
|
||||
|
||||
assert
|
||||
.dom(`[data-test-target-project-id="${instances.scopes.project.id}"]`)
|
||||
|
||||
@@ -258,17 +258,23 @@ module('Acceptance | scopes', function (hooks) {
|
||||
);
|
||||
await visit(urls.targets);
|
||||
|
||||
await click('.rose-header-nav .hds-dropdown-toggle-button');
|
||||
|
||||
await click('.rose-header-nav .hds-dropdown-list-item:nth-of-type(3) a');
|
||||
await click('[data-test-header-scope-dropdown] button');
|
||||
await click(
|
||||
`[data-test-header-scope-dropdown] a[href="${urls.scopes.org}"]`,
|
||||
);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.targets);
|
||||
|
||||
await click('.rose-header-nav .hds-dropdown-list-item:nth-of-type(4) a');
|
||||
await click(
|
||||
`[data-test-header-scope-dropdown] a[href="${urls.scopes.org2}"]`,
|
||||
);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.org2Targets);
|
||||
|
||||
await click('.rose-header-nav .hds-dropdown-list-item:nth-of-type(1) a');
|
||||
await click('[data-test-header-scope-dropdown] button');
|
||||
await click(
|
||||
`[data-test-header-scope-dropdown] a[href="${urls.scopes.global}"]`,
|
||||
);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.globalTargets);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user