CC-5545: Side Nav (#19342)

* Initial work for sidenav

* Use HDS::Text

* Add resolution for ember-element-helper

* WIP dc selector

* Update HCP Home link

* DC selector

* Hook up remaining selectors

* Fix settings and tutorial links

* Remove comments

* Remove skip-links

* Replace auth with new dropdown

* Use href-to helper for sidenav links

* Changelog

* Add description to NavSelector

* Wrap version in footer and role

* Fix login tests

* Add data-test selectors for namespaces

* Fix datacenter disclosure menu test

* Stop rendering auth dialog if acls are disabled

* Update disabled selector state and token selector

* Fix logic in ACL selector

* Fix HCP Home integration test

* Remove toggling the sidenav in tests

* Add sidenav to eng docs

* Re-add debug navigation for eng docs

* Remove ember-in-viewport

* Remove unused styles

* Upgrade @hashicorp/design-system-componentseee

* Add translations for side-nav

* Only show back to hcp link if url is present

* Disable responsive due to a11y-dialog issue
pull/19529/head
Tyler Wendlandt 2023-11-06 08:18:48 -07:00 committed by GitHub
parent 6baf695cd9
commit e5948e8eb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 986 additions and 1763 deletions

3
.changelog/19342.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
Replaces UI Side Nav with Helios Design System Side Nav. Adds dc/partition/namespace searching in Side Nav.
```

View File

@ -3,82 +3,54 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
<li {{#let @list as |SNL|}}
class="acls-separator" {{#if (can "use acls")}}
role="separator" <SNL.Title>{{t "components.hashicorp-consul.side-nav.acls.title"}}</SNL.Title>
> {{else}}
Access Controls <SNL.Title {{tooltip (t "components.hashicorp-consul.side-nav.acls.tooltip")}}>
{{#if (not (can "use acls"))}} {{t "components.hashicorp-consul.side-nav.acls.title"}}
<span </SNL.Title>
{{tooltip "ACLs are not currently enabled in this cluster"}} {{/if}}
></span>
{{/if}}
</li>
<li
data-test-main-nav-tokens
class={{if (is-href 'dc.acls.tokens' @dc.Name) 'is-active'}}
>
<a
href={{href-to 'dc.acls.tokens' @dc.Name}}
>
Tokens
</a>
</li>
{{#if (can "read acls")}}
<li
data-test-main-nav-policies
class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}
>
<a
href={{href-to 'dc.acls.policies' @dc.Name}}
>
Policies
</a>
</li>
<li
data-test-main-nav-roles
class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}
>
<a
href={{href-to 'dc.acls.roles' @dc.Name}}
>
Roles
</a>
</li>
<li
data-test-main-nav-auth-methods
class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}
>
<a
href={{href-to 'dc.acls.auth-methods' @dc.Name}}
>
Auth Methods
</a>
</li>
{{else if (not (can "use acls"))}}
<li
data-test-main-nav-policies
class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}
>
<span>
Policies
</span>
</li>
<li
data-test-main-nav-roles
class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}
>
<span>
Roles
</span>
</li>
<li
data-test-main-nav-auth-methods
class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}
>
<span>
Auth Methods
</span>
</li>
{{/if}}
<SNL.Link
@text={{t "components.hashicorp-consul.side-nav.acls.tokens"}}
@href={{href-to "dc.acls.tokens" @dc.Name}}
@isHrefExternal={{false}}
@isActive={{is-href "dc.acls.tokens" @dc.Name}}
data-test-main-nav-tokens
/>
{{#if (can "read acls")}}
<SNL.Link
@text={{t "components.hashicorp-consul.side-nav.acls.policies"}}
@href={{href-to "dc.acls.policies" @dc.Name}}
@isHrefExternal={{false}}
@isActive={{is-href "dc.acls.policies" @dc.Name}}
data-test-main-nav-policies
/>
<SNL.Link
@text={{t "components.hashicorp-consul.side-nav.acls.roles"}}
@href={{href-to "dc.acls.roles" @dc.Name}}
@isHrefExternal={{false}}
@isActive={{is-href "dc.acls.roles" @dc.Name}}
data-test-main-nav-roles
/>
<SNL.Link
@text={{t "components.hashicorp-consul.side-nav.acls.auth-methods"}}
@href={{href-to "dc.acls.auth-methods" @dc.Name}}
@isHrefExternal={{false}}
@isActive={{is-href "dc.acls.auth-methods" @dc.Name}}
data-test-main-nav-auth-methods
/>
{{else if (not (can "use acls"))}}
<SNL.Item class="consul-disabled-nav" data-test-main-nav-policies>
{{t "components.hashicorp-consul.side-nav.acls.policies"}}
</SNL.Item>
<SNL.Item class="consul-disabled-nav" data-test-main-nav-roles>
{{t "components.hashicorp-consul.side-nav.acls.roles"}}
</SNL.Item>
<SNL.Item class="consul-disabled-nav" data-test-main-nav-auth-methods>
{{t "components.hashicorp-consul.side-nav.acls.auth-methods"}}
</SNL.Item>
{{/if}}
{{/let}}

View File

@ -2,7 +2,7 @@
A self-contained component to allow the user to 'select' their token a.k.a. A self-contained component to allow the user to 'select' their token a.k.a.
log in. The component is mostly a wrapper around a composition of `<AuthDialog log in. The component is mostly a wrapper around a composition of `<AuthDialog
/>`, `<AuthForm />`, `<AuthProfile />` and `<ModalDialog />`. The majority of />`, `<AuthForm />`, and `<ModalDialog />`. The majority of
the functionality is contained in those other components. This composition the functionality is contained in those other components. This composition
mostly orchestrates the interactions between them i.e. wires them together. mostly orchestrates the interactions between them i.e. wires them together.

View File

@ -3,163 +3,162 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
{{#if (can 'use acls')}} {{#if (can "use acls")}}
<li data-test-main-nav-auth> <AuthDialog
@src={{uri "settings://consul:token"}}
@sink={{uri "settings://consul:token"}}
@onchange={{this.reauthorize}}
>
<:unauthorized as |authDialog|>
<AuthDialog <ModalDialog
@src={{uri 'settings://consul:token'}} @name="login-toggle"
@sink={{uri 'settings://consul:token'}} @onclose={{this.close}}
@onchange={{this.reauthorize}} @onopen={{this.open}}
> @aria={{hash label="Log in to Consul"}}
<:unauthorized as |authDialog|> as |modal|
<Portal @target="app-before-skip-links"> >
<Action <Ref @target={{this}} @name="modal" @value={{modal}} />
{{on "click" (optional this.modal.open)}} <BlockSlot @name="header">
<h2>
Log in to Consul
</h2>
</BlockSlot>
<BlockSlot @name="body">
<AuthForm
@dc={{@dc.Name}}
@partition={{@partition}}
@nspace={{@nspace}}
@onsubmit={{action authDialog.login value="data"}}
as |authForm|
> >
Login <Ref @target={{this}} @name="authForm" @value={{authForm}} />
</Action> {{#if (can "use SSO")}}
</Portal> <authForm.Method @matches="sso">
<Action <OidcSelect
@dc={{@dc.Name}}
@partition={{@partition}}
@nspace={{@nspace}}
@disabled={{authForm.disabled}}
@onchange={{authForm.submit}}
@onerror={{authForm.error}}
/>
</authForm.Method>
{{/if}}
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Hds::Button
@color="secondary"
@text="Continue without logging in"
{{on "click" modal.close}}
/>
</BlockSlot>
</ModalDialog>
<Hds::Dropdown
class="hds-side-nav__dropdown"
@listPosition="bottom-left"
as |dd|
>
<dd.ToggleIcon @icon="user" @text="Auth menu" data-test-auth-menu />
<dd.Interactive
@href={{href-to
"settings"
params=(hash nspace=undefined partition=undefined)
}}
@text={{t "components.hashicorp-consul.side-nav.user-menu.settings"}}
@isHrefExternal={{false}}
/>
<dd.Interactive
@text={{t "components.hashicorp-consul.side-nav.user-menu.log-in"}}
data-test-auth-menu-login
{{on "click" (optional this.modal.open)}} {{on "click" (optional this.modal.open)}}
> />
Log in </Hds::Dropdown>
</Action> </:unauthorized>
<ModalDialog <:authorized as |authDialog|>
@name="login-toggle"
@onclose={{this.close}}
@onopen={{this.open}}
@aria={{hash
label="Log in to Consul"
}}
as |modal|>
<Ref
@target={{this}}
@name="modal"
@value={{modal}}
/>
<BlockSlot @name="header">
<h2>
Log in to Consul
</h2>
</BlockSlot>
<BlockSlot @name="body">
<AuthForm
@dc={{@dc.Name}}
@partition={{@partition}}
@nspace={{@nspace}}
@onsubmit={{action authDialog.login value="data"}}
as |authForm|>
<Ref
@target={{this}}
@name="authForm"
@value={{authForm}}
/>
{{#if (can "use SSO")}}
<authForm.Method @matches="sso">
<OidcSelect
@dc={{@dc.Name}}
@partition={{@partition}}
@nspace={{@nspace}}
@disabled={{authForm.disabled}}
@onchange={{authForm.submit}}
@onerror={{authForm.error}}
/>
</authForm.Method>
{{/if}}
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Hds::Button
@color='secondary'
@text='Continue without logging in'
{{on 'click' modal.close}}
/>
</BlockSlot>
</ModalDialog>
</:unauthorized>
<:authorized as |authDialog|>
<ModalDialog
@name="login-toggle"
@onclose={{this.close}}
@onopen={{this.open}}
@aria={{hash
label="Log in with a different token"
}}
as |modal|>
<Ref
@target={{this}}
@name="modal"
@value={{modal}}
/>
<BlockSlot @name="header">
<h2>
Log in with a different token
</h2>
</BlockSlot>
<BlockSlot @name="body">
<AuthForm
@dc={{@dc.Name}}
@nspace={{@nspace}}
@partition={{@partition}}
@onsubmit={{action authDialog.login value="data"}}
as |authForm|>
<Ref
@target={{this}}
@name="authForm"
@value={{authForm}}
/>
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Hds::Button
@color='secondary'
@text='Continue without logging in'
{{on 'click' modal.close}}
/>
</BlockSlot>
</ModalDialog>
<Portal @target="app-before-skip-links">
<Action
{{on "click" (optional authDialog.logout)}}
>
Logout
</Action>
</Portal>
<DisclosureMenu as |disclosure|>
<disclosure.Action
{{on 'click' disclosure.toggle}}
>
Logout
</disclosure.Action>
<disclosure.Menu as |panel|>
{{#if authDialog.token.AccessorID}}
<AuthProfile
@item={{authDialog.token}}
/>
{{/if}}
<panel.Menu as |menu|>
<menu.Separator />
<menu.Item
class="dangerous"
>
<menu.Action
{{on 'click' (optional authDialog.logout)}}
>
Logout
</menu.Action>
</menu.Item>
</panel.Menu>
</disclosure.Menu>
</DisclosureMenu>
</:authorized>
</AuthDialog>
</li> <ModalDialog
{{yield @name="login-toggle"
(hash @onclose={{this.close}}
open=this.modal.open @onopen={{this.open}}
close=this.model.close @aria={{hash label="Log in with a different token"}}
) as |modal|
}} >
{{/if}} <Ref @target={{this}} @name="modal" @value={{modal}} />
<BlockSlot @name="header">
<h2>
Log in with a different token
</h2>
</BlockSlot>
<BlockSlot @name="body">
<AuthForm
@dc={{@dc.Name}}
@nspace={{@nspace}}
@partition={{@partition}}
@onsubmit={{action authDialog.login value="data"}}
as |authForm|
>
<Ref @target={{this}} @name="authForm" @value={{authForm}} />
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Hds::Button
@color="secondary"
@text="Continue without logging in"
{{on "click" modal.close}}
/>
</BlockSlot>
</ModalDialog>
<Hds::Dropdown
class="hds-side-nav__dropdown"
@listPosition="bottom-left"
as |dd|
>
<dd.ToggleIcon @icon="user" @text="Auth menu" data-test-auth-menu />
{{#if authDialog.token.AccessorID}}
<dd.Description
@text={{t
"components.consul.token.selector.logged-in"
token=(string-substring
authDialog.token.AccessorID
(sub authDialog.token.AccessorID.length 8)
)
htmlSafe=true
}}
/>
{{/if}}
<dd.Separator />
<dd.Interactive
@href={{href-to
"settings"
params=(hash nspace=undefined partition=undefined)
}}
@text={{t "components.hashicorp-consul.side-nav.user-menu.settings"}}
@isHrefExternal={{false}}
/>
<dd.Interactive
@text={{t "components.hashicorp-consul.side-nav.user-menu.log-out"}}
data-test-auth-menu-logout
{{on "click" (optional authDialog.logout)}}
/>
</Hds::Dropdown>
</:authorized>
</AuthDialog>
{{yield (hash open=this.modal.open close=this.model.close)}}
{{else}}
<Hds::Dropdown class="hds-side-nav__dropdown" @listPosition="bottom-left" as |dd|>
<dd.ToggleIcon @icon="user" @text="Auth menu" data-test-auth-menu />
<dd.Interactive
@href={{href-to
"settings"
params=(hash nspace=undefined partition=undefined)
}}
@text={{t "components.hashicorp-consul.side-nav.user-menu.settings"}}
@isHrefExternal={{false}}
/>
</Hds::Dropdown>
{{/if}}

View File

@ -3,11 +3,14 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
<div {{#let @list (env "CONSUL_HCP_URL") as |SNL hcpUrl|}}
class="consul-hcp-home" {{log hcpUrl}}
...attributes {{#if (and SNL hcpUrl)}}
> <SNL.BackLink
<a href={{env 'CONSUL_HCP_URL'}} data-native-href="true"> @text={{t "components.hashicorp-consul.side-nav.hcp"}}
Back to HCP @href={{hcpUrl}}
</a> @isHrefExternal={{true}}
</div> data-test-back-to-hcp
/>
{{/if}}
{{/let}}

View File

@ -1,16 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
.consul-hcp-home {
position: relative;
top: -22px;
}
.consul-hcp-home a::before {
content: '';
--icon-name: icon-arrow-left;
--icon-size: icon-300;
margin-right: 8px;
}

View File

@ -35,9 +35,46 @@ module('Integration | Component | consul hcp home', function(hooks) {
} }
); );
await render(hbs`<Consul::Hcp::Home />`); await render(hbs`
<Hds::SideNav::List as |SNL|>
<Consul::Hcp::Home @list={{SNL}} />
</Hds::SideNav::List>
`);
assert.dom('[data-test-back-to-hcp]').isVisible();
assert.dom('a').hasAttribute('href', 'http://hcp'); assert.dom('a').hasAttribute('href', 'http://hcp');
}); });
test('it does not output the Back to HCP link if CONSUL_HCP_URL is not present', async function(assert) {
// temporary registration until we are running as separate applications
this.owner.register(
'component:consul/hcp/home',
ConsulHcpHome
);
//
const Helper = this.owner.resolveRegistration('helper:env');
this.owner.register(
'helper:env',
class extends Helper {
compute([name, def]) {
switch(name) {
case 'CONSUL_HCP_URL':
return undefined;
}
return super.compute(...arguments);
}
}
);
await render(hbs`
<Hds::SideNav::List as |SNL|>
<Consul::Hcp::Home @list={{SNL}} />
</Hds::SideNav::List>
`);
assert.dom('[data-test-back-to-hcp]').doesNotExist();
assert.dom('a').doesNotExist();
});
}); });

View File

@ -3,93 +3,58 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
{{#if (can "use nspaces")}} {{#if (and (can "use nspaces") (can "choose nspaces"))}}
{{#if (can "choose nspaces")}} <DataSource
{{#let @src={{uri
(or @nspace 'default') "/${partition}/*/${dc}/namespaces"
(is-href 'dc.nspaces' @dc.Name) (hash partition=@partition dc=@dc.Name)
as |nspace isManaging|}} }}
<li @onchange={{fn (optional @onchange)}}
class="nspaces" />
data-test-nspace-menu {{#let
> @list
<DisclosureMenu (if @nspace (hash Name=@nspace) (hash Name="default"))
aria-label="Namespace" (is-href "dc.nspaces" @dc.Name)
@items={{append as |SNL nspace isManaging|
(hash }}
Name="Manage Namespaces" <SNL.Title class="consul-side-nav__selector-title">{{t "components.hashicorp-consul.side-nav.nspaces.title"}}</SNL.Title>
href=(href-to 'dc.nspaces' @dc.Name) <NavSelector
) @list={{@list}}
(reject-by 'DeletedAt' @nspaces) @items={{sort-by "Name:asc" (reject-by "DeletedAt" @nspaces)}}
}} @item={{nspace}}
as |disclosure|> @key="Name"
<disclosure.Action @icon="folder"
{{on 'click' disclosure.toggle}} @placeholder={{t "components.hashicorp-consul.side-nav.nspaces.placeholder"}}
> @footerLink={{href-to "dc.nspaces" @dc.Name}}
{{if isManaging 'Manage Namespaces' nspace}} @footerLinkText={{t "components.hashicorp-consul.side-nav.nspaces.footer"}}
</disclosure.Action> data-test-nspace-menu
<disclosure.Menu as |panel|> as |Dropdown item|
{{#if (gt @nspaces.length 0)}} >
<DataSource <Dropdown.Checkmark
@src={{uri @selected={{eq nspace.Name item.Name}}
'/${partition}/*/${dc}/namespaces' @href={{if
(hash isManaging
partition=@partition (href-to
dc=@dc.Name "dc.services.index"
) params=(hash
}} partition=(if (gt @partition.length 0) @partition undefined)
@onchange={{fn (optional @onchange)}} nspace=item.Name
/> dc=@dc.Name
{{else}} )
<DataSource )
@src={{uri (href-to
'/${partition}/*/${dc}/namespaces' "."
(hash params=(hash
partition=@partition partition=(if (gt @partition.length 0) @partition undefined)
dc=@dc.Name nspace=item.Name
) )
}} )
@onchange={{fn (optional @onchange)}} }}
/> @isHrefExternal={{false}}
{{/if}} data-test-nspace-item
<panel.Menu as |menu|> >
{{#each menu.items as |item|}} {{item.Name}}
</Dropdown.Checkmark>
<menu.Item </NavSelector>
data-test-main-nav-nspaces={{not-eq item.href undefined}} {{/let}}
aria-current={{if {{/if}}
(or
(and isManaging item.href)
(and (not isManaging) (eq nspace item.Name))
)
'true'
}}
>
<menu.Action
{{on 'click' disclosure.close}}
@href={{if item.href
item.href
(if isManaging
(href-to 'dc.services.index' params=(hash
partition=(if (gt @partition.length 0) @partition undefined)
nspace=item.Name
dc=@dc.Name
))
(href-to '.' params=(hash
partition=(if (gt @partition.length 0) @partition undefined)
nspace=item.Name
))
)
}}
>
{{item.Name}}
</menu.Action>
</menu.Item>
{{/each}}
</panel.Menu>
</disclosure.Menu>
</DisclosureMenu>
</li>
{{/let}}
{{/if}}
{{/if}}

View File

@ -4,71 +4,50 @@
}} }}
{{#let {{#let
(or @partition "default") @list
(if @partition (hash Name=@partition) (hash Name="default"))
(is-href "dc.partitions" @dc.Name) (is-href "dc.partitions" @dc.Name)
as |partition isManaging| (can "choose partitions" dc=@dc)
as |SNL partition isManaging canChoose|
}} }}
{{#if (can "choose partitions" dc=@dc)}} <DataSource
<li class="partitions" data-test-partition-menu> @src={{uri "/*/*/${dc}/partitions" (hash dc=@dc.Name)}}
<DisclosureMenu @onchange={{fn (optional @onchange)}}
aria-label="Admin Partition" />
@items={{append <SNL.Title class="consul-side-nav__selector-title">{{t "components.hashicorp-consul.side-nav.partitions.title"}}</SNL.Title>
(hash <NavSelector
Name="Manage Partitions" href=(href-to "dc.partitions" @dc.Name) @list={{@list}}
@items={{sort-by "Name:asc" (reject-by "DeletedAt" @partitions)}}
@item={{partition}}
@key="Name"
@icon="users"
@placeholder={{t "components.hashicorp-consul.side-nav.partitions.placeholder"}}
@footerLink={{href-to "dc.partitions" @dc.Name}}
@footerLinkText={{t "components.hashicorp-consul.side-nav.partitions.footer"}}
@disabled={{not canChoose}}
data-test-datacenter-disclosure-menu
as |Dropdown item|
>
{{#if canChoose}}
<Dropdown.Checkmark
@selected={{eq partition.Name item.Name}}
@href={{if
item.href
item.href
(if
isManaging
(href-to
"dc.services.index"
params=(hash partition=item.Name nspace=undefined dc=@dc.Name)
)
(href-to "." params=(hash partition=item.Name nspace=undefined))
) )
(reject-by "DeletedAt" @partitions)
}} }}
as |disclosure| @isHrefExternal={{false}}
data-test-partiton-item
> >
<disclosure.Action {{on "click" disclosure.toggle}}> {{item.Name}}
{{if isManaging "Manage Partition" partition}} </Dropdown.Checkmark>
</disclosure.Action> {{/if}}
<disclosure.Menu as |panel|> </NavSelector>
<DataSource
@src={{uri "/*/*/${dc}/partitions" (hash dc=@dc.Name)}}
@onchange={{fn (optional @onchange)}}
/>
<panel.Menu as |menu|>
{{#each menu.items as |item|}}
<menu.Item
aria-current={{if
(or
(and isManaging item.href)
(and (not isManaging) (eq partition item.Name))
)
"true"
}}
>
<menu.Action
{{on "click" disclosure.close}}
@href={{if
item.href
item.href
(if
isManaging
(href-to
"dc.services.index"
params=(hash
partition=item.Name nspace=undefined dc=@dc.Name
)
)
(href-to
"." params=(hash partition=item.Name nspace=undefined)
)
)
}}
>
{{item.Name}}
</menu.Action>
</menu.Item>
{{/each}}
</panel.Menu>
</disclosure.Menu>
</DisclosureMenu>
</li>
{{else}}
<li class="partition" aria-label="Admin Partition">
{{"default"}}
</li>
{{/if}}
{{/let}} {{/let}}

View File

@ -3,23 +3,14 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
<li {{#let @list as |SNL|}}
class="peers-separator" <SNL.Title ...attributes>{{t "components.hashicorp-consul.side-nav.organization.title"}}</SNL.Title>
role="separator" <SNL.Link
...attributes @text={{t "components.hashicorp-consul.side-nav.organization.peers"}}
> @route="dc.peers"
Organization @models={{array @dc.Name}}
</li> @query={{hash peer=undefined}}
<li @isActive={{is-href "dc.peers" @dc.Name}}
data-test-main-nav-peers data-test-main-nav-peers
class={{if (is-href 'dc.peers' @dc.Name) 'is-active'}} />
> {{/let}}
<a
href={{href-to 'dc.peers' @dc.Name
params=(hash peer=undefined)
}}
>
Peers
</a>
</li>

View File

@ -3,102 +3,19 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
{{#let (hash {{#let (hash main=(concat guid '-main') Notification=(component 'app/notification')) as |exported|}}
main=(concat guid '-main')
Notification=(component 'app/notification')
) as |exported|}}
<div <div class='app' ...attributes>
class="app" <ModalLayer />
...attributes
>
<div {{yield exported to='side-nav'}}
class="skip-links" <main id={{concat guid '-main'}}>
{{on "click" this.focus}} <div class='notifications'>
> {{yield exported to='notifications'}}
<PortalTarget <PortalTarget @name='app-notifications' @multiple={{true}} />
@name="app-before-skip-links" </div>
@multiple={{true}} {{yield exported to='main'}}
></PortalTarget> </main>
<a href={{concat '#' exported.main}}>{{t 'components.app.skip_to_content'}}</a>
{{!--
In order to add further skip links from within other templates use:
<Portal @target="app-skip-links">
<a href="#sub-content">Skip to subcontent</a>
</Portal>
from within your template
--}}
<PortalTarget
@name="app-after-skip-links"
@multiple={{true}}
></PortalTarget>
</div> </div>
<ModalLayer />
<input
type="checkbox"
id={{concat guid "-main-nav-toggle"}}
/>
<header
role="banner"
>
<label
tabindex="0"
for={{concat guid "-main-nav-toggle"}}
aria-label={{t 'components.app.toggle_menu'}}
{{on "keypress" this.keypressClick}}
{{on "mouseup" this.unfocus}}
></label>
{{yield exported to="home-nav"}}
<div
data-test-navigation
>
{{!--
The viewport tolerances here give us a 10 pixel buffer to make sure the menu
is marked as out of the viewport, we use all sides so we don't need to change
this should any CSS change
--}}
<nav
aria-label={{t 'components.app.main'}}
class={{if this.navInViewport 'in-viewport'}}
{{in-viewport
onEnter=(set this 'navInViewport' true)
onExit=(set this 'navInViewport' false)
viewportTolerance=(hash top=-10 bottom =-10 left=-10 right=-10)
}}
>
{{yield exported to="main-nav"}}
</nav>
{{!--
Whilst this has a role of navigation, it is 'complementary navigation' we
don't want to change the navigation role here, but we do want to label it as
'complementary' to the main content. The phrase 'complementary navigation' as
read by a screenreader should convey the meaning we are after here.
--}}
<nav aria-label={{t 'components.app.complementary'}}>
{{yield exported to="complementary-nav"}}
</nav>
</div>
</header>
<main id={{concat guid '-main'}}>
<div class="notifications">
{{yield exported to="notifications"}}
<PortalTarget
@name="app-notifications"
@multiple={{true}}
></PortalTarget>
</div>
{{yield exported to="main"}}
</main>
<footer
role="contentinfo"
data-test-footer
>
{{yield exported to="content-info"}}
</footer>
</div>
{{/let}} {{/let}}

View File

@ -3,9 +3,6 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
.app .skip-links {
@extend %skip-links;
}
.app .notifications { .app .notifications {
@extend %app-notifications; @extend %app-notifications;
} }
@ -28,125 +25,3 @@
max-width: 80%; max-width: 80%;
pointer-events: auto; pointer-events: auto;
} }
[role='contentinfo'] {
@extend %footer;
}
[role='banner'] {
@extend %main-header-horizontal;
}
[role='banner'] > label {
@extend %main-nav-horizontal-toggle-button;
}
.app > input[id] {
@extend %main-nav-horizontal-toggle;
}
%main-header-horizontal > div {
@extend %main-nav-horizontal-panel;
}
%main-header-horizontal nav:first-of-type {
@extend %main-nav-vertical, %main-nav-sidebar;
}
%main-header-horizontal nav:last-of-type {
@extend %main-nav-horizontal;
margin-left: auto;
}
%main-nav-vertical-hoisted {
top: 18px;
}
%main-nav-vertical-hoisted [aria-label]::before {
display: none !important;
}
%main-nav-horizontal [aria-haspopup='menu'] ~ * {
position: absolute;
right: 0;
min-width: 192px;
}
%main-nav-horizontal [aria-expanded],
%main-nav-vertical-hoisted [aria-expanded] {
@extend %main-nav-horizontal-popover-menu-trigger;
@extend %main-nav-horizontal-action;
}
%main-nav-horizontal-popover-menu-trigger {
@extend %main-nav-horizontal-action-active;
}
%footer,
%main-nav-sidebar,
%main-notifications,
main {
@extend %transition-pushover;
}
%footer {
@extend %body-100-regular;
position: fixed;
z-index: 50;
color: var(--token-color-foreground-disabled);
width: 250px;
padding-left: 25px;
}
%footer {
top: calc(100vh - 42px);
top: calc(max(100vh, 460px) - 42px);
}
html.has-partitions.has-nspaces .app [role='contentinfo'] {
top: calc(100vh - 42px);
top: calc(max(100vh, 640px) - 42px);
}
%main-nav-sidebar {
z-index: 10;
}
%footer,
%main-nav-sidebar {
transition-property: left;
}
%app-notifications,
main {
margin-top: var(--chrome-height, 64px);
transition-property: margin-left;
}
%app-notifications {
transition-property: margin-left, width;
}
@media #{$--sidebar-open} {
%main-nav-horizontal-toggle ~ main .notifications {
width: calc(100% - var(--chrome-width));
}
%main-nav-horizontal-toggle:checked ~ main .notifications {
width: 100%;
}
%main-nav-horizontal-toggle ~ footer,
%main-nav-horizontal-toggle + header > div > nav:first-of-type {
left: 0;
}
%main-nav-horizontal-toggle:checked ~ footer,
%main-nav-horizontal-toggle:checked + header > div > nav:first-of-type {
left: calc(var(--chrome-width, 280px) * -1);
}
%main-nav-horizontal-toggle ~ main {
margin-left: var(--chrome-width, 280px);
}
%main-nav-horizontal-toggle:checked ~ main .notifications,
%main-nav-horizontal-toggle:checked ~ main {
margin-left: 0;
}
}
@media #{$--lt-sidebar-open} {
%main-nav-horizontal-toggle ~ main .notifications {
width: 100%;
}
%main-nav-horizontal-toggle:checked ~ footer,
%main-nav-horizontal-toggle:checked + header > div > nav:first-of-type {
left: 0;
}
%main-nav-horizontal-toggle ~ footer,
%main-nav-horizontal-toggle + header > div > nav:first-of-type {
left: calc(var(--chrome-width, 280px) * -1);
}
%main-nav-horizontal-toggle ~ main .notifications,
%main-nav-horizontal-toggle ~ main {
margin-left: 0;
}
}

View File

@ -14,9 +14,6 @@ A component to help orchestrate a login/logout flow.
/> />
</:unauthorized> </:unauthorized>
<:authorized as |api|> <:authorized as |api|>
<AuthProfile
@item={{api.token}}
/>
<button <button
{{on 'click' (fn api.logout)}} {{on 'click' (fn api.logout)}}
> >

View File

@ -1,24 +0,0 @@
# AuthProfile
A straightforward partial-like component for rendering a user profile.
Only the last 8 characters are shown.
```hbs preview-template
<AuthProfile
@item={{hash AccessorID='123456-1234567-123456'}}
/>
```
## Arguments
| Argument | Type | Default | Description |
| --- | --- | --- | --- |
| `item` | `Token` | | A token object (currently only requires an AccessorID property to be set |
## See
- [Component Source Code](./index.js)
- [Template Source Code](./index.hbs)
---

View File

@ -1,17 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<dl
class="auth-profile"
...attributes
>
<dt>
<span>My ACL Token</span><br />
AccessorID
</dt>
<dd>
{{string-substring @item.AccessorID (sub @item.AccessorID.length 8)}}
</dd>
</dl>

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
.auth-profile {
padding: 0.9em 1em;
}
.auth-profile {
@extend %body-100-regular;
}
.auth-profile dt span {
font-weight: var(--token-typography-font-weight-regular);
}
.auth-profile dt {
font-weight: var(--token-typography-font-weight-bold);
}
.auth-profile dt,
.auth-profile dd {
color: var(--token-color-paletter-neutral-300);
}
.auth-profile dt span {
color: var(--token-color-foreground-faint);
}

View File

@ -3,67 +3,56 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
<li class='dcs' data-test-datacenter-menu> {{#let @list as |SNL|}}
{{#if (gt @dcs.length 1)}} {{#if (gt @dcs.length 1)}}
<DisclosureMenu <SNL.Title class='consul-side-nav__selector-title'>{{t "components.hashicorp-consul.side-nav.datacenters.title"}}</SNL.Title>
aria-label='Datacenter' <NavSelector
@list={{SNL}}
@items={{sort-by 'Primary:desc' 'Local:desc' 'Name:asc' @dcs}} @items={{sort-by 'Primary:desc' 'Local:desc' 'Name:asc' @dcs}}
data-test-datacenter-disclosure-menu @item={{@dc}}
as |disclosure| @key='Name'
@icon='server-cluster'
@placeholder={{t "components.hashicorp-consul.side-nav.datacenters.placeholder"}}
@description={{t "components.hashicorp-consul.side-nav.datacenters.description"}}
class='consul-datacenter-selector'
data-test-datacenter-menu
as |Dropdown item|
> >
<disclosure.Action {{on 'click' disclosure.toggle}}> <Dropdown.Checkmark
{{@dc.Name}} @selected={{eq @dc.Name item.Name}}
</disclosure.Action> @href={{href-to
<disclosure.Menu as |panel|> '.'
<DataSource params=(hash
@src={{uri '/*/*/*/datacenters'}} dc=item.Name partition=undefined nspace=(if (gt @nspace.length 0) @nspace undefined)
@onchange={{action (mut @dcs) value='data'}} )
/> }}
<p class='dcs-message'> @isHrefExternal={{false}}
Datacenters shown in this dropdown are available through WAN Federation. class='consul-datacenter-selector__item'
</p> data-test-dc-item
<panel.Menu as |menu|> >
<menu.Separator> <span class='consul-datacenter-selector__dc-name'>
DATACENTERS {{item.Name}}
</menu.Separator>
{{#each menu.items as |item|}} {{#if (or item.Local item.Primary)}}
<menu.Item <span class='consul-datacenter-selector__badges'>
data-test-dc-item {{#if item.Primary}}
aria-current={{if (eq @dc.Name item.Name) 'true'}} <Hds::Badge @text='Primary' />
class={{class-map (array 'is-local' item.Local) (array 'is-primary' item.Primary)}} {{/if}}
> {{#if item.Local}}
<menu.Action <Hds::Badge @text='Local' />
{{on 'click' disclosure.close}} {{/if}}
@href={{href-to </span>
'.' {{/if}}
params=(hash </span>
dc=item.Name </Dropdown.Checkmark>
partition=undefined </NavSelector>
nspace=(if (gt @nspace.length 0) @nspace undefined)
)
}}
>
{{item.Name}}
{{#if item.Primary}}
<span>Primary</span>
{{/if}}
{{#if item.Local}}
<span>Local</span>
{{/if}}
</menu.Action>
</menu.Item>
{{/each}}
</panel.Menu>
</disclosure.Menu>
</DisclosureMenu>
{{else}} {{else}}
<div class='dc-name' data-test-datacenter-single> <SNL.Item class='consul-side-nav__datacenter' data-test-datacenter-single>
{{@dcs.firstObject.Name}} <FlightIcon
{{#let (env 'CONSUL_HCP_MANAGED_RUNTIME') as |managedRuntime|}} @name='server-cluster'
{{#if managedRuntime}} @color='var(--token-form-control-disabled-foreground-color)'
<span>{{capitalize managedRuntime}}</span> />
{{/if}} <Hds::Text::Display @size='200' @color='disabled'>{{@dc.Name}}</Hds::Text::Display>
{{/let}} </SNL.Item>
</div>
{{/if}} {{/if}}
</li> {{/let}}

View File

@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class DatacenterSelectorComponent extends Component {
@tracked search = '';
get filteredItems() {
const lowerCaseSearch = this.search.toLowerCase();
return this.args.dcs.filter((dc) => dc.Name.toLowerCase().includes(lowerCaseSearch));
}
@action
onSearchInput(e) {
this.search = e.target.value;
}
}

View File

@ -3,6 +3,6 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
}} }}
<li> {{#let @dropdown as |DD|}}
<a href={{href-to 'docs'}} target="_blank">Eng Docs</a> <DD.Interactive @href={{href-to "docs"}} @isHrefExternal={{true}} @text={{t "components.hashicorp-consul.side-nav.support-menu.eng-docs" }} />
</li> {{/let}}

View File

@ -15,20 +15,21 @@
<Hds::Toast <Hds::Toast
@color={{if (eq status 'error') 'critical' status}} @color={{if (eq status 'error') 'critical' status}}
data-notification data-notification
as |T|> as |T|
>
<T.Title>{{capitalize status}}!</T.Title> <T.Title>{{capitalize status}}!</T.Title>
<T.Description> <T.Description>
{{#if (eq type 'logout')}} {{#if (eq type 'logout')}}
{{#if (eq status 'success')}} {{#if (eq status 'success')}}
You are now logged out. {{t "components.hashicorp-consul.notifications.logged-out"}}
{{else}} {{else}}
There was an error logging out. {{t "components.hashicorp-consul.notifications.logged-out-error"}}
{{/if}} {{/if}}
{{else if (eq type 'authorize')}} {{else if (eq type 'authorize')}}
{{#if (eq status 'success')}} {{#if (eq status 'success')}}
You are now logged in. {{t "components.hashicorp-consul.notifications.logged-in"}}
{{else}} {{else}}
There was an error, please check your SecretID/Token {{t "components.hashicorp-consul.notifications.logged-in-error"}}
{{/if}} {{/if}}
{{else}} {{else}}
{{#if (or (eq type 'use') (eq flash.model 'token'))}} {{#if (or (eq type 'use') (eq flash.model 'token'))}}
@ -71,137 +72,162 @@
</:notifications> </:notifications>
<:home-nav> <:side-nav>
<a class='w-8 h-8' href={{href-to 'index' params=(hash peer=undefined)}}> <Hds::SideNav @isResponsive={{false}} class='consul-side-nav' data-test-navigation>
<FlightIcon @size='24' @name='consul-color' @stretched={{true}} /> <:header>
</a> <Hds::SideNav::Header>
</:home-nav> <:logo>
<Hds::SideNav::Header::HomeLink
@icon='consul-color'
@ariaLabel='Consul'
@route='index'
@query={{hash peer=undefined}}
/>
</:logo>
<:actions>
<Hds::Dropdown class='hds-side-nav__dropdown' @listPosition='bottom-left' as |dd|>
<dd.ToggleIcon @icon='help' @text='Help & Support menu' />
<Debug::Navigation @dropdown={{dd}} />
<dd.Interactive
@href={{env 'CONSUL_DOCS_URL'}}
@isHrefExternal={{true}}
@text={{t "components.hashicorp-consul.side-nav.support-menu.docs"}}
/>
<dd.Interactive
@href={{concat (env 'CONSUL_DOCS_LEARN_URL') '/consul'}}
@isHrefExternal={{true}}
@text={{t "components.hashicorp-consul.side-nav.support-menu.tutorials"}}
/>
<dd.Interactive
@href={{env 'CONSUL_REPO_ISSUES_URL'}}
@isHrefExternal={{true}}
@text={{t "components.hashicorp-consul.side-nav.support-menu.feedback"}}
/>
</Hds::Dropdown>
<:main-nav> <Consul::Token::Selector
<Consul::Hcp::Home /> @dc={{@dc}}
<ul> @partition={{@partition}}
<Consul::Datacenter::Selector @nspace={{@nspace}}
@dc={{@dc}} @onchange={{@onchange}}
@partition={{@partition}} as |selector|
@nspace={{@nspace}} >
@dcs={{@dcs}} <Ref @target={{this}} @name='tokenSelector' @value={{selector}} />
/> </Consul::Token::Selector>
<Consul::Partition::Selector </:actions>
@dc={{@dc}} </Hds::SideNav::Header>
@partition={{@partition}} </:header>
@nspace={{@nspace}} <:body>
@partitions={{this.partitions}} <Hds::SideNav::List
@onchange={{action (mut this.partitions) value='data'}} class='hds-side-nav-hide-when-minimized consul-side-nav__selector-group'
/> as |SNL|
<Consul::Nspace::Selector
@dc={{@dc}}
@partition={{@partition}}
@nspace={{@nspace}}
@nspaces={{this.nspaces}}
@onchange={{action (mut this.nspaces) value='data'}}
/>
{{#if (can 'access overview')}}
<li
data-test-main-nav-overview
class={{class-map (array 'is-active' (is-href 'dc.show' @dc.Name))}}
> >
<Action @href={{href-to 'dc.show' @dc.Name params=(hash peer=undefined)}}> <Consul::Hcp::Home @list={{SNL}} />
Overview <Consul::Datacenter::Selector
</Action> @list={{SNL}}
</li> @dc={{@dc}}
{{/if}} @partition={{@partition}}
{{#if (can 'read services')}} @nspace={{@nspace}}
<li data-test-main-nav-services class={{if (is-href 'dc.services' @dc.Name) 'is-active'}}> @dcs={{@dcs}}
<a href={{href-to 'dc.services' @dc.Name params=(hash peer=undefined)}}>Services</a> />
</li>
{{/if}}
{{#if (can 'read nodes')}}
<li data-test-main-nav-nodes class={{if (is-href 'dc.nodes' @dc.Name) 'is-active'}}>
<a href={{href-to 'dc.nodes' @dc.Name params=(hash peer=undefined)}}>Nodes</a>
</li>
{{/if}}
{{#if (can 'read kv')}}
<li data-test-main-nav-kvs class={{if (is-href 'dc.kv' @dc.Name) 'is-active'}}>
<a href={{href-to 'dc.kv' @dc.Name params=(hash peer=undefined)}}>Key/Value</a>
</li>
{{/if}}
{{#if (can 'read intentions')}}
<li
data-test-main-nav-intentions
class={{if (is-href 'dc.intentions' @dc.Name) 'is-active'}}
>
<a href={{href-to 'dc.intentions' @dc.Name params=(hash peer=undefined)}}>Intentions</a>
</li>
{{/if}}
<Consul::Acl::Selector @dc={{@dc}} @partition={{@partition}} @nspace={{@nspace}} />
<Consul::Peer::Selector @dc={{@dc}} @partition={{@partition}} @nspace={{@nspace}} />
</ul>
</:main-nav>
<:complementary-nav> <Consul::Partition::Selector
<ul> @dc={{@dc}}
<Debug::Navigation /> @partition={{@partition}}
<li data-test-main-nav-help> @nspace={{@nspace}}
<DisclosureMenu as |disclosure|> @partitions={{this.partitions}}
<disclosure.Action {{on 'click' disclosure.toggle}}> @list={{SNL}}
Help @onchange={{action (mut this.partitions) value='data'}}
</disclosure.Action> />
<disclosure.Menu as |panel|> <Consul::Nspace::Selector
<panel.Menu as |menu|> @list={{SNL}}
<menu.Separator> @dc={{@dc}}
Consul v{{env 'CONSUL_VERSION'}} @partition={{@partition}}
</menu.Separator> @nspace={{@nspace}}
<menu.Item class='docs-link'> @nspaces={{this.nspaces}}
<menu.Action @href={{env 'CONSUL_DOCS_URL'}} @external={{true}}> @onchange={{action (mut this.nspaces) value='data'}}
Documentation />
</menu.Action> </Hds::SideNav::List>
</menu.Item> <Hds::SideNav::List class='hds-side-nav-hide-when-minimized' as |SNL|>
<menu.Item class='learn-link'> {{#if (can 'access overview')}}
<menu.Action <SNL.Link
@href={{concat (env 'CONSUL_DOCS_LEARN_URL') '/consul'}} @text={{t "components.hashicorp-consul.side-nav.overview"}}
@external={{true}} @route='dc.show'
> @models={{array @dc.Name}}
HashiCorp Learn @query={{hash peer=undefined}}
</menu.Action> @isActive={{is-href 'dc.show' @dc.Name}}
</menu.Item> data-test-main-nav-overview
<menu.Separator /> />
<menu.Item class='feedback-link'> {{/if}}
<menu.Action @href={{env 'CONSUL_REPO_ISSUES_URL'}} @external={{true}}> {{#if (can 'read services')}}
Provide Feedback <SNL.Link
</menu.Action> @text={{t "components.hashicorp-consul.side-nav.services"}}
</menu.Item> @href={{href-to 'dc.services' @dc.Name params=(hash peer=undefined)}}
</panel.Menu> @isHrefExternal={{false}}
</disclosure.Menu> @isActive={{is-href 'dc.services' @dc.Name}}
</DisclosureMenu> data-test-main-nav-services
</li> />
<li data-test-main-nav-settings class={{if (is-href 'settings') 'is-active'}}> {{/if}}
<a href={{href-to 'settings' params=(hash nspace=undefined partition=undefined)}}> {{#if (can 'read nodes')}}
Settings <SNL.Link
</a> @text={{t "components.hashicorp-consul.side-nav.nodes"}}
</li> @href={{href-to 'dc.nodes' @dc.Name params=(hash peer=undefined)}}
<Consul::Token::Selector @isHrefExternal={{false}}
@dc={{@dc}} @isActive={{is-href 'dc.nodes' @dc.Name}}
@partition={{@partition}} data-test-main-nav-nodes
@nspace={{@nspace}} />
@onchange={{@onchange}} {{/if}}
as |selector| {{#if (can 'read kv')}}
> <SNL.Link
<Ref @target={{this}} @name='tokenSelector' @value={{selector}} /> @text={{t "components.hashicorp-consul.side-nav.kv"}}
</Consul::Token::Selector> @href={{href-to 'dc.kv' @dc.Name params=(hash peer=undefined)}}
</ul> @isHrefExternal={{false}}
</:complementary-nav> @isActive={{is-href 'dc.kv' @dc.Name}}
data-test-main-nav-kv
/>
{{/if}}
{{#if (can 'read intentions')}}
<SNL.Link
@text={{t "components.hashicorp-consul.side-nav.intentions"}}
@href={{href-to 'dc.intentions' @dc.Name params=(hash peer=undefined)}}
@isHrefExternal={{false}}
@isActive={{is-href 'dc.intentions' @dc.Name}}
data-test-main-nav-intentions
/>
{{/if}}
<Consul::Acl::Selector
@dc={{@dc}}
@partition={{@partition}}
@nspace={{@nspace}}
@list={{SNL}}
/>
<Consul::Peer::Selector
@dc={{@dc}}
@partition={{@partition}}
@nspace={{@nspace}}
@list={{SNL}}
/>
</Hds::SideNav::List>
</:body>
<:footer>
<footer role='contentinfo' data-test-footer>
<Hds::Text::Display
class='hds-side-nav-hide-when-minimized'
@size='100'
@color='disabled'
>
{{t "components.hashicorp-consul.side-nav.footer" version=(env 'CONSUL_VERSION')}}
</Hds::Text::Display>
{{{concat '<!-- ' (env 'CONSUL_GIT_SHA') '-->'}}}
</footer>
</:footer>
</Hds::SideNav>
</:side-nav>
<:main> <:main>
{{yield {{yield
(hash login=(if this.tokenSelector this.tokenSelector (hash open=undefined close=undefined))) (hash login=(if this.tokenSelector this.tokenSelector (hash open=undefined close=undefined)))
}} }}
</:main> </:main>
</App>
<:content-info>
<p>
Consul v{{env 'CONSUL_VERSION'}}
</p>
{{{concat '<!-- ' (env 'CONSUL_GIT_SHA') '-->'}}}
</:content-info>
</App>

View File

@ -4,71 +4,71 @@
*/ */
%hashicorp-consul { %hashicorp-consul {
nav .dcs { .consul-side-nav {
@extend %main-nav-vertical-hoisted; li.consul-disabled-nav {
left: 100px; width: 100%;
min-height: var(--token-side-nav-body-list-item-height);
padding: var(--token-side-nav-body-list-item-padding-vertical)
var(--token-side-nav-body-list-item-padding-horizontal);
color: var(--token-color-foreground-disabled);
}
.dcs-message { li.consul-side-nav__selector {
padding: 8px 12px; .consul-side-nav__selector-toggle {
border-bottom: 1px solid var(--token-color-foreground-disabled); min-width: 15.5rem;
max-width: fit-content;
background-color: var(--token-color-hashicorp-brand); &:disabled {
color: var(--token-color-palette-neutral-300); color: var(--token-color-foreground-disabled);
border-color: var(--token-color-border-primary);
&:hover {
background-color: transparent;
}
}
}
.hds-dropdown__content {
min-width: 15.5rem;
max-height: 500px;
}
}
.hds-side-nav__wrapper-body {
overflow-y: unset;
overflow-x: unset;
}
li.consul-side-nav__datacenter {
display: flex;
gap: 0.5rem;
align-items: center;
padding-left: 0.5rem;
}
.consul-side-nav__selector-group {
margin-bottom: 1.5rem;
}
.consul-datacenter-selector__dc-name {
display: flex;
align-items: center;
gap: 0.5rem;
.consul-datacenter-selector__badges {
display: flex;
gap: 0.25rem;
}
}
.consul-side-nav__selector-title {
margin-top: 0.5rem;
}
.consul-side-nav__selector-description {
padding-top: 0.5rem;
} }
} }
nav .dcs li.is-primary span,
nav .dcs li.is-local span {
@extend %menu-panel-badge;
}
nav .dcs .dc-name {
color: var(--token-color-foreground-faint);
padding: 3.25px 0px;
font-weight: var(--token-typography-font-weight-semibold);
}
nav .dcs .dc-name span {
@extend %pill-200;
margin-left: 1rem;
background-color: var(--token-color-palette-neutral-300);
color: var(--token-color-hashicorp-brand);
}
nav li.partitions,
nav li.nspaces {
@extend %main-nav-vertical-popover-menu;
}
nav li.dcs [aria-expanded] ~ * {
min-width: 250px;
}
nav li.dcs [aria-expanded] ~ * {
max-height: 560px;
--paged-row-height: 43px;
}
nav li.partitions [aria-expanded] ~ *,
nav li.nspaces [aria-expanded] ~ * {
max-height: 360px;
--paged-row-height: 43px;
}
[role='banner'] a svg {
fill: var(--token-color-consul-brand);
}
.docs-link a::after {
@extend %with-docs-mask, %as-pseudo;
}
.learn-link a::after {
@extend %with-learn-mask, %as-pseudo;
}
.feedback-link a::after {
@extend %with-logo-github-monochrome-mask, %as-pseudo;
}
.acls-separator span {
@extend %led-icon;
color: var(--token-color-foreground-critical);
display: inline-block;
position: relative;
top: 2px;
margin-left: 2px;
}
} }
.hashicorp-consul { .hashicorp-consul {
@extend %hashicorp-consul; @extend %hashicorp-consul;
} }

View File

@ -42,16 +42,19 @@ export default (collection, clickable, attribute, is, authForm, emptyState) => (
status: attribute('data-test-status', '[data-test-status]'), status: attribute('data-test-status', '[data-test-status]'),
}, },
}; };
page.navigation.login = clickable('[data-test-main-nav-auth] button'); page.navigation.authMenu = clickable('[data-test-auth-menu]');
page.navigation.login = clickable('[data-test-auth-menu-login]');
page.navigation.dc = clickable('[data-test-datacenter-menu] button'); page.navigation.dc = clickable('[data-test-datacenter-menu] button');
page.navigation.nspace = clickable('[data-test-nspace-menu] button'); page.navigation.nspace = clickable('[data-test-nspace-menu] button');
page.navigation.manageNspaces = clickable('[data-test-main-nav-nspaces] a'); page.navigation.manageNspaces = clickable(
'[data-test-nspace-menu] [data-test-nav-selector-footer-link]'
);
page.navigation.manageNspacesIsVisible = is( page.navigation.manageNspacesIsVisible = is(
':checked', ':checked',
'[data-test-nspace-menu] > input[type="checkbox"]' '[data-test-nspace-menu] > input[type="checkbox"]'
); );
page.navigation.dcs = collection('[data-test-datacenter-menu] [data-test-dc-item]', { page.navigation.dcs = collection('[data-test-datacenter-menu] [data-test-dc-item]', {
name: clickable('a'), name: clickable(),
}); });
return page; return page;
}; };

View File

@ -1,7 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './skin.scss';
@import './layout.scss';

View File

@ -1,32 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-header-horizontal {
display: flex;
position: fixed;
z-index: 50;
left: 0;
padding: 0 25px;
width: calc(100% - 50px);
}
%main-header-horizontal,
%main-header-horizontal::before {
height: var(--chrome-height);
}
%main-header-horizontal {
align-items: center;
}
%main-header-horizontal::before {
content: '';
position: absolute;
z-index: -1;
left: 0;
width: 100vw;
}
%main-header-horizontal > a {
display: block;
line-height: 0;
font-size: 0;
}

View File

@ -1,8 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-header-horizontal::before {
background-color: var(--token-color-hashicorp-brand);
}

View File

@ -1,36 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './skin';
@import './layout';
/* things that should look like nav buttons */
%main-nav-horizontal > ul > li > a,
%main-nav-horizontal > ul > li > span,
%main-nav-horizontal > ul > li > button,
%main-nav-horizontal-popover-menu-trigger,
%main-nav-horizontal > ul > li > .popover-menu > label > button {
@extend %main-nav-horizontal-action;
}
%main-nav-horizontal .popover-menu [type='checkbox']:checked + label > *,
%main-nav-horizontal > ul > li.is-active > a,
%main-nav-horizontal > ul > li.is-active > button {
@extend %main-nav-horizontal-action-active;
}
/* Whilst we want spans to look the same as actions */
/* we don't want them to act the same */
%main-nav-horizontal-action:not(span):hover,
%main-nav-horizontal-action:not(span):focus {
@extend %main-nav-horizontal-action-intent;
}
%main-nav-horizontal > ul > li > span {
cursor: default;
}
/**/
/* menu-panels in the main navigation are treated slightly differently */
%main-nav-horizontal .disclosure-menu button + * {
@extend %main-nav-horizontal-menu-panel;
}

View File

@ -1,48 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-nav-horizontal > ul,
%main-nav-horizontal-panel {
display: flex;
}
%main-nav-horizontal-toggle-button {
display: flex;
align-items: center;
height: 100%;
padding: 0 1rem;
padding-left: 5px;
}
%main-nav-horizontal-panel {
justify-content: space-between;
flex-grow: 1;
}
%main-nav-horizontal-menu-panel {
z-index: 400;
/* TODO: We should probably make menu-panel default to left hand side*/
top: 28px !important;
}
%main-nav-horizontal-action {
display: block;
padding: 5px 12px;
white-space: nowrap;
}
%main-nav-horizontal .popover-menu > label {
/* Usually there is no space between buttons which is */
/* fine as the button only highlights when its selected */
/* therefore no two siblings are highlighted at the same time */
/* which means you don't notice there is no space between the */
/* buttons. popover-menu triggers on the other hand can be */
/* at the same time as a sibling, therefore they need a little */
/* space between it and its sibling - this is a property of */
/* the main nav not the popover-menu */
padding-right: 5px;
}
%main-nav-horizontal .popover-menu > label > * {
/* less space as the chevron adds space */
padding-right: 4px !important;
}
%main-nav-horizontal .popover-menu > label > button::after {
top: 2px;
}

View File

@ -1,45 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-nav-horizontal-action {
border-radius: var(--decor-radius-200);
cursor: pointer;
}
%main-nav-horizontal-action > a {
color: inherit;
}
%main-nav-horizontal-popover-menu-trigger::after {
--icon-name: icon-chevron-down;
content: '';
}
%main-nav-horizontal-popover-menu-trigger[aria-expanded='true']::after {
transform: scaleY(-100%);
}
%main-nav-horizontal-menu-panel,
%main-nav-horizontal-menu-panel > ul[role='menu'],
%main-nav-horizontal-menu-panel > ul[role='menu'] > li > [role='menuitem'] {
background-color: var(--token-color-hashicorp-brand);
color: var(--token-color-palette-neutral-300);
}
%main-nav-horizontal-menu-panel > ul[role='menu'] > li > [role='menuitem']:hover {
background-color: var(--token-color-palette-neutral-600);
}
%main-nav-horizontal-toggle {
display: none;
}
%main-nav-horizontal-toggle-button::before {
--icon-name: icon-menu;
--icon-color: var(--token-color-palette-neutral-300);
content: '';
cursor: pointer;
}
%main-nav-horizontal-action,
%main-nav-horizontal-action-intent,
%main-nav-horizontal-action-active {
color: var(--token-color-palette-neutral-300);
}

View File

@ -1,71 +0,0 @@
---
class: css
---
# MainNavVertical
Used for styles of vertically orientated main application menus/navigation.
Menu item active state is applied on `.is-active` `<li>` elements. Additionally you can use the following placeholders for setting certin states manually:
- `%menu-nav-vertical-action-active` The 'active' or currently selected state.
- `%menu-nav-vertical-action-intent` The highlighted state, usually for `:hover`
and `:focus`.
`%menu-nav-vertical-hoisted` will 'hoist' an `<li>` element to the top of the
containing block, the containing block defaults to the current viewport. If
you need to define a different ancestor for a containing block you can use
`transform` (see below).
```hbs preview-template
<div class="wrapper">
<nav class="main-nav-vertical in-viewport">
<ul>
<li role="separator">Title</li>
<li>
<a href="">One</a>
</li>
<li class="is-active">
<a href="">Two (is-active)</a>
</li>
<li class="with-intent">
<a href="">Three (with-intent)</a>
</li>
<li class="hoisted">
<a href="">Four (hoisted)</a>
</li>
<li role="separator">Title</li>
<li class="custom-active">
<a href="">One (custom-active)</a>
</li>
<li>
<a href="">Two</a>
</li>
<li>
<a href="">Three</a>
</li>
</ul>
</nav>
</div>
```
```css preview-template
.main-nav-vertical {
@extend %main-nav-vertical;
}
.main-nav-vertical li.hoisted {
@extend %main-nav-vertical-hoisted;
}
.main-nav-vertical .with-intent > * {
@extend %main-nav-vertical-action-intent;
}
.main-nav-vertical .custom-active > * {
@extend %main-nav-vertical-action-active;
}
.wrapper {
/* a transform is required to mark this element as the containing block */
/* for hoisting, otherwise the viewport is the containing block */
transform: translate(0, 0);
background-color: var(--token-color-foreground-faint);
padding-top: 64px;
}
```

View File

@ -1,34 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
#docfy-demo-preview-main-nav-vertical {
.main-nav-vertical {
@extend %main-nav-vertical;
}
.main-nav-vertical li.hoisted {
@extend %main-nav-vertical-hoisted;
}
.main-nav-vertical .with-intent > * {
@extend %main-nav-vertical-action-intent;
}
.main-nav-vertical .custom-active > * {
@extend %main-nav-vertical-action-active;
}
.wrapper {
/* a transform is required to mark this element as the containing block */
/* for hoisting, otherwise the viewport is the containing block */
transform: translate(0, 0);
background-color: var(--token-color-foreground-faint);
padding-top: 64px;
}
// TODO: Reduce the need for these debug overrides
.main-nav-vertical {
position: static;
height: auto;
}
.main-nav-vertical ul {
margin-bottom: 0 !important;
}
}

View File

@ -1,45 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './skin';
@import './layout';
/* things that should look like nav buttons */
/* items are single things that look like button */
/* but aren't clickable */
%main-nav-vertical > ul > li[aria-label] {
@extend %main-nav-vertical-item;
}
/**/
/* actual clickable button-y things plus states */
%main-nav-vertical a {
@extend %main-nav-vertical-action;
}
%main-nav-vertical > ul > li.is-active > a {
@extend %main-nav-vertical-action-active;
}
%main-nav-vertical-action-active:hover:not(:active),
%main-nav-vertical-action-active:focus:not(:active) {
@extend %main-nav-vertical-action-active-intent;
}
%main-nav-vertical-action:hover,
%main-nav-vertical-action:focus {
@extend %main-nav-vertical-action-intent;
}
%main-nav-vertical > ul > li > label {
@extend %main-nav-vertical-action;
}
/* menu-panels in the main navigation are treated slightly differently */
%main-nav-vertical-popover-menu .disclosure-menu button + * {
@extend %main-nav-vertical-menu-panel;
}
/**/
%main-nav-vertical-popover-menu .disclosure-menu > button {
@extend %main-nav-vertical-popover-menu-trigger;
@extend %internal-button;
}

View File

@ -1,68 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-nav-vertical {
position: absolute;
left: 0;
top: var(--chrome-height, 47px);
width: var(--chrome-width, 280px);
height: calc(100vh - var(--chrome-height, 47px) - 35px);
padding-top: 35px;
overflow: auto;
}
// disable tabbing when not visible
%main-nav-vertical:not(.in-viewport) {
visibility: hidden;
}
%main-nav-vertical li.partition,
%main-nav-vertical li.partitions,
%main-nav-vertical li.nspaces {
margin-bottom: 25px;
padding: 0 26px;
}
%main-nav-vertical li.dcs {
padding: 0 18px;
}
// TODO: We no longer have the rule that menu-panel buttons only contain two
// items, left and right aligned. We should remove this and look to use
// align-self for anything that needs right aligning instead.
%main-nav-vertical [role='menuitem'] {
justify-content: flex-start !important;
}
%main-nav-vertical [role='menuitem'] span {
margin-left: 0.5rem;
}
%main-nav-vertical-action,
%main-nav-vertical li:not([role='separator']) > span,
%main-nav-vertical [role='separator'] {
display: block;
padding: 7px 25px;
}
%main-nav-vertical > ul > [role='separator'] {
margin-top: 0.7rem;
padding-bottom: 0;
}
%main-nav-vertical-popover-menu .disclosure {
position: relative;
}
%main-nav-vertical-popover-menu-trigger {
width: 100%;
text-align: left;
padding: 10px;
}
%main-nav-vertical-popover-menu-trigger::after {
float: right;
}
%main-nav-vertical-menu-panel {
position: absolute;
z-index: 1;
width: calc(100% - 2px);
}
%main-nav-vertical-hoisted {
visibility: visible;
position: fixed;
z-index: 10;
}

View File

@ -1,114 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%main-nav-vertical-action {
@extend %body-200-medium;
cursor: pointer;
border-right: var(--decor-border-400);
border-color: transparent;
}
%main-nav-vertical-action > a {
color: inherit;
font-size: inherit;
}
%main-nav-vertical [role='separator'] {
@extend %body-100-medium;
text-transform: uppercase;
}
%main-nav-vertical-action-intent {
text-decoration: underline;
}
%main-nav-vertical-action-active-intent {
text-decoration: none;
}
%main-nav-vertical {
background-color: var(--token-color-foreground-strong);
color: var(--token-color-foreground-faint);
}
%main-nav-vertical li:not([role='separator']) > span {
color: var(--token-color-palette-neutral-300);
}
%main-nav-vertical [role='separator'],
%main-nav-vertical-hoisted [role='separator'] {
color: var(--token-color-palette-neutral-400);
background-color: var(--token-color-foreground-strong);
}
%main-nav-vertical-action {
color: var(--token-color-palette-neutral-300);
}
%main-nav-vertical-item,
%main-nav-vertical-action-intent,
%main-nav-vertical-action-active {
color: var(--token-color-palette-neutral-0);
}
%main-nav-vertical-action-active {
background-color: var(--token-color-palette-neutral-500);
border-color: var(--token-color-palette-neutral-0);
}
%main-nav-vertical [aria-label]::before {
color: var(--token-color-palette-neutral-400);
content: attr(aria-label);
display: block;
margin-top: -0.5rem;
margin-bottom: 0.5rem;
}
%main-nav-vertical-popover-menu-trigger {
border: var(--decor-border-100);
border-color: var(--token-color-foreground-faint);
border-radius: var(--decor-radius-100);
font-weight: inherit;
background-color: var(--token-color-foreground-strong);
color: var(--token-color-palette-neutral-200);
}
%main-nav-vertical-popover-menu-trigger:hover,
%main-nav-vertical-popover-menu-trigger:focus {
color: var(--token-color-palette-neutral-300);
background-color: var(--token-color-foreground-strong);
}
%main-nav-vertical ul[role='menu'] li a[role='menuitem'] {
color: var(--token-color-palette-neutral-300);
background-color: var(--token-color-foreground-strong);
}
%main-nav-vertical ul[role='menu']li a[role='menuitem']:hover {
background-color: var(--token-color-palette-neutral-600);
}
%main-nav-vertical-popover-menu-trigger[aria-expanded='true'] {
border-bottom-left-radius: var(--decor-radius-000);
border-bottom-right-radius: var(--decor-radius-000);
}
%main-nav-horizontal %panel,
%main-nav-horizontal %panel-separator,
%main-nav-vertical %panel,
%main-nav-vertical %panel-separator {
border-color: var(--token-color-foreground-faint);
}
%main-nav-vertical-popover-menu-trigger::after {
@extend %with-chevron-down-mask, %as-pseudo;
width: 16px;
height: 16px;
position: relative;
}
%main-nav-vertical-popover-menu-trigger[aria-expanded='true']::after {
@extend %with-chevron-up-mask;
}
%main-nav-vertical-menu-panel {
border-top-left-radius: var(--decor-radius-000);
border-top-right-radius: var(--decor-radius-000);
border-top: var(--decor-border-000);
color: var(--token-color-palette-neutral-300);
background-color: var(--token-color-foreground-strong);
}
%main-nav-vertical-hoisted ul[role='menu'] {
background-color: var(--token-color-hashicorp-brand);
}

View File

@ -0,0 +1,58 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{#let @list as |SNL|}}
<SNL.Item class='consul-side-nav__selector'>
<Hds::Dropdown
@listPosition='bottom-left'
@width='15.5rem'
class='hds-side-nav__dropdown'
@isInline={{true}}
...attributes
as |DD|
>
<DD.ToggleButton
class='consul-side-nav__selector-toggle'
@icon={{@icon}}
@text={{get @item @key}}
disabled={{eq @disabled true}}
/>
<DD.Header @hasDivider={{true}}>
{{#if @description}}
<div class='consul-side-nav__selector-description'>
<Hds::Text::Body @size='100' @color='faint'>{{@description}}</Hds::Text::Body>
</div>
{{/if}}
<Hds::Form::TextInput::Base
@type='search'
@value={{this.search}}
placeholder={{@placeholder}}
aria-label={{@placeholder}}
{{on 'input' this.onSearchInput}}
/>
</DD.Header>
{{#if (eq this.filteredItems.length 0)}}
<DD.Description @text='No results' />
{{else}}
{{#each this.filteredItems as |item|}}
{{yield DD item}}
{{/each}}
{{/if}}
{{#if @footerLink}}
<DD.Footer @hasDivider={{true}}>
<Hds::Link::Standalone
@href={{@footerLink}}
@isHrefExternal={{false}}
@text={{@footerLinkText}}
@iconPosition='trailing'
@icon='arrow-right'
@color='secondary'
data-test-nav-selector-footer-link
/>
</DD.Footer>
{{/if}}
</Hds::Dropdown>
</SNL.Item>
{{/let}}

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class NavSelectorComponent extends Component {
@tracked search = '';
get filteredItems() {
const lowerCaseSearch = this.search.toLowerCase();
if (lowerCaseSearch) {
return this.args.items.filter((item) =>
item[this.args.key].toLowerCase().includes(lowerCaseSearch)
);
} else {
return this.args.items;
}
}
@action
onSearchInput(e) {
this.search = e.target.value;
}
}

View File

@ -1,7 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './skin';
@import './layout';

View File

@ -1,26 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%skip-links {
display: flex;
flex-direction: column;
position: absolute;
z-index: 10;
left: 50%;
padding: 20px;
top: -100px;
transform: translateX(-50%);
}
%skip-links div,
%skip-links button,
%skip-links a {
display: block;
width: 100%;
text-align: center;
box-sizing: border-box;
}
%skip-links:focus-within {
top: 0px;
}

View File

@ -1,14 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
%skip-links {
outline: 1px solid var(--token-color-surface-primary);
color: var(--token-color-surface-primary);
background-color: var(--token-color-foreground-action);
}
%skip-links button,
%skip-links a {
color: inherit;
}

View File

@ -75,8 +75,7 @@ export default CollectionComponent.extend(Slotted, {
if ($appContent) { if ($appContent) {
const border = 1; const border = 1;
const rect = $tbody.getBoundingClientRect(); const rect = $tbody.getBoundingClientRect();
const $footer = this.dom.element('footer[role="contentinfo"]'); const space = rect.top + border;
const space = rect.top + $footer.clientHeight + border;
const height = e.target.innerHeight - space; const height = e.target.innerHeight - space;
this.set('maxHeight', Math.max(0, height)); this.set('maxHeight', Math.max(0, height));
// TODO: The row height should auto calculate properly from the CSS // TODO: The row height should auto calculate properly from the CSS

View File

@ -254,6 +254,10 @@ export default class FSMWithOptionalLocation {
* performs an ember transition/refresh and browser location update using that * performs an ember transition/refresh and browser location update using that
*/ */
transitionTo(url) { transitionTo(url) {
if (typeof this.router === 'undefined') {
this.router = this.container.lookup('router:main');
}
if (this.router.currentRouteName.startsWith('docs') && url.startsWith('console://')) { if (this.router.currentRouteName.startsWith('docs') && url.startsWith('console://')) {
console.info(`location.transitionTo: ${url.substr(10)}`); console.info(`location.transitionTo: ${url.substr(10)}`);
return true; return true;

View File

@ -25,7 +25,8 @@
/* more semantically (for our project) named icons */ /* more semantically (for our project) named icons */
@import 'icons'; @import 'icons';
/* global control of themeable components */ /* global control of themeable components */
@import 'themes'; @import './base/color/index';
/* debug only, this is empty during a production build */ /* debug only, this is empty during a production build */
/* but uses the contents of ./debug.scss during dev */ /* but uses the contents of ./debug.scss during dev */
@import '_debug'; @import '_debug';

View File

@ -3,5 +3,5 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
@import './ui/index';
@import './semantic-variables'; @import './semantic-variables';
@import './ui/frame-placeholders.scss';

View File

@ -1,6 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './frame-placeholders';

View File

@ -8,7 +8,6 @@
@import 'consul-ui/components/anchors'; @import 'consul-ui/components/anchors';
@import 'consul-ui/components/auth-form'; @import 'consul-ui/components/auth-form';
@import 'consul-ui/components/auth-modal'; @import 'consul-ui/components/auth-modal';
@import 'consul-ui/components/auth-profile';
@import 'consul-ui/components/breadcrumbs'; @import 'consul-ui/components/breadcrumbs';
@import 'consul-ui/components/buttons'; @import 'consul-ui/components/buttons';
@import 'consul-ui/components/card'; @import 'consul-ui/components/card';
@ -53,12 +52,8 @@
@import 'consul-ui/components/route/title'; @import 'consul-ui/components/route/title';
@import 'consul-ui/components/app-view'; @import 'consul-ui/components/app-view';
@import 'consul-ui/components/brand-loader'; @import 'consul-ui/components/brand-loader';
@import 'consul-ui/components/skip-links';
@import 'consul-ui/components/app'; @import 'consul-ui/components/app';
/* app chrome */ /* app chrome */
@import 'consul-ui/components/main-header-horizontal';
@import 'consul-ui/components/main-nav-horizontal';
@import 'consul-ui/components/main-nav-vertical';
@import 'consul-ui/components/hashicorp-consul'; @import 'consul-ui/components/hashicorp-consul';
/**/ /**/
@import 'consul-ui/components/menu-panel'; @import 'consul-ui/components/menu-panel';
@ -113,5 +108,4 @@
@import 'consul-ui/components/consul/node/peer-info'; @import 'consul-ui/components/consul/node/peer-info';
@import 'consul-ui/components/consul/peer/info'; @import 'consul-ui/components/consul/peer/info';
@import 'consul-ui/components/consul/peer/form'; @import 'consul-ui/components/consul/peer/form';
@import 'consul-ui/components/consul/hcp/home';
@import 'consul-ui/components/consul/node/agentless-notice'; @import 'consul-ui/components/consul/node/agentless-notice';

View File

@ -6,7 +6,6 @@
@import 'prism-coldark-dark'; @import 'prism-coldark-dark';
// temporary component debugging setup // temporary component debugging setup
@import 'consul-ui/components/main-nav-vertical/debug';
@import 'consul-ui/components/badge/debug'; @import 'consul-ui/components/badge/debug';
@import 'consul-ui/components/panel/debug'; @import 'consul-ui/components/panel/debug';
@import 'consul-ui/components/tile/debug'; @import 'consul-ui/components/tile/debug';

View File

@ -103,9 +103,10 @@ html:not(.has-partitions) [class*='partition-'] {
@extend %viewport-container; @extend %viewport-container;
display: flex; display: flex;
min-height: 100vh; min-height: 100vh;
flex-direction: column;
} }
main { main {
padding: 0 48px;
position: relative; position: relative;
flex: 1; flex: 1;
} }

View File

@ -6,7 +6,7 @@
// workaround bulma's sweeping box-sizing // workaround bulma's sweeping box-sizing
%viewport-container { %viewport-container {
box-sizing: content-box; box-sizing: border-box;
} }
%modal-dialog > *, %modal-dialog > *,
%content-container > * { %content-container > * {
@ -15,10 +15,6 @@
%content-container-restricted { %content-container-restricted {
max-width: 1260px; max-width: 1260px;
} }
%viewport-container {
padding-left: 48px;
padding-right: 48px;
}
fieldset [role='group'] { fieldset [role='group'] {
display: flex; display: flex;

View File

@ -1,16 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@import './base/color/ui/index';
%main-nav-horizontal .dangerous button:hover,
%main-nav-horizontal .dangerous button:focus {
color: var(--token-color-surface-primary) !important;
}
%main-nav-vertical .menu-panel a:hover,
%main-nav-vertical .menu-panel a:focus {
background-color: var(--token-color-foreground-action);
}

View File

@ -15,9 +15,6 @@ fieldset > header,
%form-element > span { %form-element > span {
@extend %display-100-semibold; @extend %display-100-semibold;
} }
%main-nav-horizontal-action {
@extend %body-200-medium;
}
%definition-table dt { %definition-table dt {
line-height: var(--token-typography-body-300-line-height); line-height: var(--token-typography-body-300-line-height);
} }
@ -45,7 +42,6 @@ fieldset > header,
%empty-state-anchor, %empty-state-anchor,
%form-element-label, %form-element-label,
%stats-card header a span, %stats-card header a span,
%footer,
%app-view h1 span.kind-proxy { %app-view h1 span.kind-proxy {
@extend %body-100-regular; @extend %body-100-regular;
} }

View File

@ -5,18 +5,18 @@
{{page-title 'Engineering Docs - Consul' separator=' - '}} {{page-title 'Engineering Docs - Consul' separator=' - '}}
{{document-attrs class="is-debug" }} {{document-attrs class='is-debug'}}
{{! Tell CSS what we have enabled }} {{! Tell CSS what we have enabled }}
{{#if (can "use acls")}} {{#if (can 'use acls')}}
{{document-attrs class="has-acls" }} {{document-attrs class='has-acls'}}
{{/if}} {{/if}}
{{#if (can "use nspaces")}} {{#if (can 'use nspaces')}}
{{document-attrs class="has-nspaces" }} {{document-attrs class='has-nspaces'}}
{{/if}} {{/if}}
{{#if (can "use partitions")}} {{#if (can 'use partitions')}}
{{document-attrs class="has-partitions" }} {{document-attrs class='has-partitions'}}
{{/if}} {{/if}}
<App class="docs" id="wrapper"> <App class='docs' id='wrapper'>
<:notifications as |app|> <:notifications as |app|>
{{#each flashMessages.queue as |flash|}} {{#each flashMessages.queue as |flash|}}
@ -31,71 +31,71 @@
{{/each}} {{/each}}
</:notifications> </:notifications>
<:main-nav> <:side-nav>
<Hds::SideNav @isResponsive={{true}} class='consul-side-nav'>
<:header>
<Hds::SideNav::Header>
<:logo>
<Hds::SideNav::Header::HomeLink
@icon='consul-color'
@ariaLabel='Consul'
@route='index'
@query={{hash peer=undefined}}
/>
</:logo>
</Hds::SideNav::Header>
</:header>
<:body>
<DocfyOutput as |node|>
<Hds::SideNav::List class='hds-side-nav-hide-when-minimized' as |SNL|>
<SNL.Title>Docs</SNL.Title>
<DocfyOutput as |node|> {{#each node.children as |child|}}
<ul> {{#each child.pages as |child|}}
<SNL.Link
@href={{concat '/ui' child.url}}
@isHrefExternal={{false}}
@isActive={{is-href (to-route child.url)}}
@text={{classify child.title}}
/>
{{/each}}
{{!hardcode in docs first}} {{!hardcode in styles next}}
<li role="separator">Docs</li> {{#let (find-by 'label' 'styles' child.children) as |section|}}
{{#each node.children as |child|}} <SNL.Title>{{section.label}}</SNL.Title>
{{#each child.pages as |child|}} {{#each (flatten-property section 'pages') as |child|}}
<li <SNL.Link
class={{if (is-href (to-route child.url)) 'is-active'}} @href={{concat '/ui' child.url}}
> @text={{classify child.title}}
<DocfyLink @to={{child.url}}> @isHrefExternal={{false}}
{{classify child.title}} @isActive={{is-href (to-route child.url)}}
</DocfyLink> />
</li> {{/each}}
{{/each}} {{/let}}
{{!hardcode in styles next}} {{!print out the rest}}
{{#let (find-by 'label' 'styles' child.children) as |section|}} {{#each child.children as |section|}}
<li role="separator">{{section.label}}</li> {{#if (not-eq section.label 'styles')}}
{{#each (flatten-property section 'pages') as |child|}} <SNL.Title>{{section.label}}</SNL.Title>
<li {{#each (flatten-property section 'pages') as |child|}}
class={{concat <SNL.Link
(slugify section.label) ' ' @href={{concat '/ui' child.url}}
(if (is-href (to-route child.url)) 'is-active') @text={{classify child.title}}
}} @isHrefExternal={{false}}
> @isActive={{is-href (to-route child.url)}}
<DocfyLink @to={{child.url}}> />
{{classify child.title}} {{/each}}
</DocfyLink> {{/if}}
</li> {{/each}}
{{/each}} {{/each}}
{{/let}} </Hds::SideNav::List>
</DocfyOutput>
{{!print out the rest}} </:body>
{{#each child.children as |section|}} </Hds::SideNav>
{{#if (not-eq section.label 'styles')}} </:side-nav>
<li role="separator">{{section.label}}</li>
{{#each (flatten-property section 'pages') as |child|}}
<li
class={{concat
(slugify section.label) ' '
(if (eq child.frontmatter.class 'ember') 'ember-component') ' '
(if (eq child.frontmatter.class 'css') 'css-component') ' '
(if (is-href (to-route child.url)) 'is-active')
}}
>
<DocfyLink @to={{child.url}}>
{{classify child.title}}
</DocfyLink>
</li>
{{/each}}
{{/if}}
{{/each}}
{{/each}}
</ul>
</DocfyOutput>
</:main-nav>
<:main> <:main>
<DocfyOutput @fromCurrentURL={{true}} as |page|> <DocfyOutput @fromCurrentURL={{true}} as |page|>
{{outlet}} {{outlet}}
</DocfyOutput> </DocfyOutput>
</:main> </:main>
</App> </App>

View File

@ -69,10 +69,10 @@
"@ember/test-helpers": "^2.6.0", "@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4", "@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4", "@glimmer/tracking": "^1.0.4",
"@hashicorp/design-system-components": "^2.14.1", "@hashicorp/design-system-components": "^3.0.2",
"@hashicorp/design-system-tokens": "^1.9.0", "@hashicorp/design-system-tokens": "^1.9.0",
"@hashicorp/ember-cli-api-double": "^4.0.0", "@hashicorp/ember-cli-api-double": "^4.0.0",
"@hashicorp/ember-flight-icons": "^3.1.3", "@hashicorp/ember-flight-icons": "^4.0.1",
"@html-next/vertical-collection": "^4.0.0", "@html-next/vertical-collection": "^4.0.0",
"@lit/reactive-element": "^1.2.1", "@lit/reactive-element": "^1.2.1",
"@xstate/fsm": "^1.4.0", "@xstate/fsm": "^1.4.0",
@ -134,7 +134,6 @@
"ember-decorators": "^6.1.1", "ember-decorators": "^6.1.1",
"ember-exam": "^6.1.0", "ember-exam": "^6.1.0",
"ember-export-application-global": "^2.0.1", "ember-export-application-global": "^2.0.1",
"ember-in-viewport": "^4.0.0",
"ember-inflector": "^4.0.1", "ember-inflector": "^4.0.1",
"ember-intl": "^5.7.0", "ember-intl": "^5.7.0",
"ember-load-initializers": "^2.1.2", "ember-load-initializers": "^2.1.2",
@ -217,6 +216,7 @@
"node": "18" "node": "18"
}, },
"dependencies": { "dependencies": {
"doctoc": "^2.0.0" "doctoc": "^2.0.0",
"ember-element-helper": "0.6.1"
} }
} }

View File

@ -8,6 +8,7 @@ Feature: login
dc: dc-1 dc: dc-1
--- ---
Then the url should be /dc-1/acls/tokens Then the url should be /dc-1/acls/tokens
And I click authMenu on the navigation
And I click login on the navigation And I click login on the navigation
And I fill in the auth form with yaml And I fill in the auth form with yaml
--- ---
@ -39,6 +40,7 @@ Feature: login
state: state-123456789/abcdefghijklmnopqrstuvwxyz state: state-123456789/abcdefghijklmnopqrstuvwxyz
code: code-abcdefghijklmnopqrstuvwxyz/123456789 code: code-abcdefghijklmnopqrstuvwxyz/123456789
--- ---
And I click authMenu on the navigation
And I click login on the navigation And I click login on the navigation
And I click "[data-test-tab=tab_sso] button" And I click "[data-test-tab=tab_sso] button"
Then the "[name='partition']" input should have the value "default" Then the "[name='partition']" input should have the value "default"

View File

@ -24,6 +24,7 @@ Feature: token-header
dc: dc1 dc: dc1
--- ---
Then the url should be /dc1/acls/tokens Then the url should be /dc1/acls/tokens
And I click authMenu on the navigation
And I click login on the navigation And I click login on the navigation
And I fill in the auth form with yaml And I fill in the auth form with yaml
--- ---

View File

@ -1,29 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | auth-profile', 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) { ... });
await render(hbs`<AuthProfile />`);
assert.notStrictEqual(this.element.textContent.indexOf('AccessorID'), -1);
// Template block usage:
await render(hbs`
<AuthProfile></AuthProfile>
`);
assert.notStrictEqual(this.element.textContent.indexOf('AccessorID'), -1);
});
});

View File

@ -20,10 +20,14 @@ module('Integration | Component | consul datacenter selector', function (hooks)
this.set('dcs', dcs); this.set('dcs', dcs);
this.set('dc', dcs[0]); this.set('dc', dcs[0]);
await render(hbs`<Consul::Datacenter::Selector @dcs={{this.dcs}} @dc={{this.dc}} />`); await render(hbs`
<Hds::SideNav::List as |SNL|>
<Consul::Datacenter::Selector @list={{SNL}} @dcs={{this.dcs}} @dc={{this.dc}} />
</Hds::SideNav::List>
`);
assert assert
.dom('[data-test-datacenter-disclosure-menu]') .dom('[data-test-datacenter-menu]')
.doesNotExist('datacenter dropdown is not displayed in nav'); .doesNotExist('datacenter dropdown is not displayed in nav');
assert assert
@ -43,12 +47,16 @@ module('Integration | Component | consul datacenter selector', function (hooks)
this.set('dcs', dcs); this.set('dcs', dcs);
this.set('dc', dcs[0]); this.set('dc', dcs[0]);
await render(hbs`<Consul::Datacenter::Selector @dcs={{this.dcs}} @dc={{this.dc}} />`); await render(hbs`
<Hds::SideNav::List as |SNL|>
<Consul::Datacenter::Selector @list={{SNL}} @dcs={{this.dcs}} @dc={{this.dc}} />
</Hds::SideNav::List>
`);
assert assert
.dom('[data-test-datacenter-single]') .dom('[data-test-datacenter-single]')
.doesNotExist('we are displaying more than just the name of the first dc'); .doesNotExist('we are displaying more than just the name of the first dc');
assert.dom('[data-test-datacenter-disclosure-menu]').exists('datacenter dropdown is displayed'); assert.dom('[data-test-datacenter-menu]').exists('datacenter dropdown is displayed');
}); });
}); });

View File

@ -70,6 +70,8 @@ acl:
management: Management management: Management
client: Client client: Client
token: token:
selector:
logged-in: "Logged in with ACL Token'<br><'b class=consul-side-nav__acl-logged-in'>'{token}'<'/b'>'"
search-bar: search-bar:
kind: kind:
name: Type name: Type

View File

@ -0,0 +1,47 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
notifications:
logged-out: You are now logged out.
logged-out-error: There was an error logging out.
logged-in: You are now logged in.
logged-in-error: There was an error, please check your SecretID/Token
side-nav:
support-menu:
eng-docs: Eng docs
docs: Documentation
tutorials: Tutorials
feedback: Give feedback
user-menu:
settings: Settings
log-in: Log in
Log out: Log out
hcp: Back to HCP
datacenters:
title: Datacenter
placeholder: Search datacenters
description: WAN federated datacenters
partitions:
title: Admin partition
placeholder: Search partitions
footer: View all partitions
nspaces:
title: Namespace
placeholder: Search namespaces
footer: View all namespaces
overview: Overview
services: Services
nodes: Nodes
kv: Key/Value
intentions: Intentions
acls:
title: Access Controls
tooltip: ACLs are not currently enabled in this cluster
tokens: Tokens
policies: Policies
roles: Roles
auth-methods: Auth Methods
organization:
title: Organization
peers: Peers
footer: Consul v{version}

View File

@ -1311,6 +1311,14 @@
ember-cli-version-checker "^5.1.2" ember-cli-version-checker "^5.1.2"
semver "^7.3.5" semver "^7.3.5"
"@embroider/addon-shim@1.8.3":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@embroider/addon-shim/-/addon-shim-1.8.3.tgz#2368510b8ce42d50d02cb3289c32e260dfa34bd9"
integrity sha512-7pyHwzT6ESXc3nZsB8rfnirLkUhQWdvj6CkYH+0MUPN74mX4rslf7pnBqZE/KZkW3uBIaBYvU8fxi0hcKC/Paw==
dependencies:
"@embroider/shared-internals" "^1.8.3"
semver "^7.3.5"
"@embroider/addon-shim@^1.0.0", "@embroider/addon-shim@^1.2.0", "@embroider/addon-shim@^1.8.4": "@embroider/addon-shim@^1.0.0", "@embroider/addon-shim@^1.2.0", "@embroider/addon-shim@^1.8.4":
version "1.8.4" version "1.8.4"
resolved "https://registry.npmjs.org/@embroider/addon-shim/-/addon-shim-1.8.4.tgz" resolved "https://registry.npmjs.org/@embroider/addon-shim/-/addon-shim-1.8.4.tgz"
@ -1411,7 +1419,21 @@
resolve "^1.20.0" resolve "^1.20.0"
semver "^7.3.2" semver "^7.3.2"
"@embroider/macros@^0.50.0 || ^1.0.0", "@embroider/macros@^1.0.0", "@embroider/macros@^1.10.0", "@embroider/macros@^1.2.0", "@embroider/macros@^1.8.1", "@embroider/macros@^1.8.3": "@embroider/macros@^0.50.0 || ^1.0.0", "@embroider/macros@^1.13.0", "@embroider/macros@^1.2.0":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-1.13.2.tgz#07dda11313a2539f403404881b729e622a80ca17"
integrity sha512-AUgJ71xG8kjuTx8XB1AQNBiebJuXRfhcHr318dCwnQz9VRXdYSnEEqf38XRvGYIoCvIyn/3c72LrSwzaJqknOA==
dependencies:
"@embroider/shared-internals" "2.5.0"
assert-never "^1.2.1"
babel-import-util "^2.0.0"
ember-cli-babel "^7.26.6"
find-up "^5.0.0"
lodash "^4.17.21"
resolve "^1.20.0"
semver "^7.3.2"
"@embroider/macros@^1.0.0", "@embroider/macros@^1.10.0":
version "1.10.0" version "1.10.0"
resolved "https://registry.npmjs.org/@embroider/macros/-/macros-1.10.0.tgz" resolved "https://registry.npmjs.org/@embroider/macros/-/macros-1.10.0.tgz"
integrity sha512-LMbfQGk/a+f6xtvAv5fq/wf2LRxETnbgSCLUf/z6ebzmuskOUxrke+uP55chF/loWrARi9g6erFQ7RDOUoBMSg== integrity sha512-LMbfQGk/a+f6xtvAv5fq/wf2LRxETnbgSCLUf/z6ebzmuskOUxrke+uP55chF/loWrARi9g6erFQ7RDOUoBMSg==
@ -1478,7 +1500,22 @@
semver "^7.3.5" semver "^7.3.5"
typescript-memoize "^1.0.1" typescript-memoize "^1.0.1"
"@embroider/shared-internals@^1.0.0": "@embroider/shared-internals@2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-2.5.0.tgz#4a0b5127c589718fae60fc22f81374ed558b944a"
integrity sha512-7qzrb7GVIyNqeY0umxoeIvjDC+ay1b+wb2yCVuYTUYrFfLAkLEy9FNI3iWCi3RdQ9OFjgcAxAnwsAiPIMZZ3pQ==
dependencies:
babel-import-util "^2.0.0"
debug "^4.3.2"
ember-rfc176-data "^0.3.17"
fs-extra "^9.1.0"
js-string-escape "^1.0.1"
lodash "^4.17.21"
resolve-package-path "^4.0.1"
semver "^7.3.5"
typescript-memoize "^1.0.1"
"@embroider/shared-internals@^1.0.0", "@embroider/shared-internals@^1.8.3":
version "1.8.3" version "1.8.3"
resolved "https://registry.npmjs.org/@embroider/shared-internals/-/shared-internals-1.8.3.tgz" resolved "https://registry.npmjs.org/@embroider/shared-internals/-/shared-internals-1.8.3.tgz"
integrity sha512-N5Gho6Qk8z5u+mxLCcMYAoQMbN4MmH+z2jXwQHVs859bxuZTxwF6kKtsybDAASCtd2YGxEmzcc1Ja/wM28824w== integrity sha512-N5Gho6Qk8z5u+mxLCcMYAoQMbN4MmH+z2jXwQHVs859bxuZTxwF6kKtsybDAASCtd2YGxEmzcc1Ja/wM28824w==
@ -1501,6 +1538,15 @@
broccoli-funnel "^3.0.5" broccoli-funnel "^3.0.5"
ember-cli-babel "^7.23.1" ember-cli-babel "^7.23.1"
"@embroider/util@^0.39.1 || ^0.40.0 || ^0.41.0 || ^1.0.0", "@embroider/util@^1.0.0":
version "1.12.0"
resolved "https://registry.yarnpkg.com/@embroider/util/-/util-1.12.0.tgz#4b7828650b55f8498f1e78bb63e27e77835e926f"
integrity sha512-P4M1QADEH9ceIYC9mwHeV+6DDgEIQQYFfZi728nVKqTAxakXoiLgu/BCyQmEGyow9fYEPYaC1boDCZxW2JQAXg==
dependencies:
"@embroider/macros" "^1.13.0"
broccoli-funnel "^3.0.5"
ember-cli-babel "^7.26.11"
"@embroider/util@^0.47.0": "@embroider/util@^0.47.0":
version "0.47.2" version "0.47.2"
resolved "https://registry.npmjs.org/@embroider/util/-/util-0.47.2.tgz" resolved "https://registry.npmjs.org/@embroider/util/-/util-0.47.2.tgz"
@ -1814,24 +1860,24 @@
faker "^4.1.0" faker "^4.1.0"
js-yaml "^3.13.1" js-yaml "^3.13.1"
"@hashicorp/design-system-components@^2.14.1": "@hashicorp/design-system-components@^3.0.2":
version "2.14.1" version "3.0.2"
resolved "https://registry.npmjs.org/@hashicorp/design-system-components/-/design-system-components-2.14.1.tgz" resolved "https://registry.yarnpkg.com/@hashicorp/design-system-components/-/design-system-components-3.0.2.tgz#f9bf18f0f20f6396d4afc2ed138056c27dff8a38"
integrity sha512-EgUpKUAQlTXKnJfv98RHFz1rqcb3xWE8CiLgiEcjN8RuX5P05D0llHKMlbdhsuzqe0D72c//wesk9Mlbb9tngw== integrity sha512-Pt3dgCxzutIJ3LDtVgT0NSU5oTV8OFzgK9Nx1tTzIpMOfbCRzZuBmJB06ZPCdyP9Vs7lQVrn/kKzZaKJejrXiQ==
dependencies: dependencies:
"@ember/render-modifiers" "^2.0.5" "@ember/render-modifiers" "^2.0.5"
"@ember/test-waiters" "^3.0.2" "@ember/test-waiters" "^3.0.2"
"@hashicorp/design-system-tokens" "^1.9.0" "@hashicorp/design-system-tokens" "^1.9.0"
"@hashicorp/ember-flight-icons" "^3.1.3" "@hashicorp/ember-flight-icons" "^4.0.1"
dialog-polyfill "^0.5.6" dialog-polyfill "^0.5.6"
ember-a11y-refocus "^3.0.2" ember-a11y-refocus "^3.0.2"
ember-auto-import "^2.6.3" ember-auto-import "^2.6.3"
ember-cached-decorator-polyfill "^0.1.4" ember-cached-decorator-polyfill "^0.1.4"
ember-cli-babel "^7.26.11" ember-cli-babel "^7.26.11"
ember-cli-clipboard "^1.0.0"
ember-cli-htmlbars "^6.2.0" ember-cli-htmlbars "^6.2.0"
ember-cli-sass "^10.0.1" ember-cli-sass "^10.0.1"
ember-composable-helpers "^4.5.0" ember-composable-helpers "^4.5.0"
ember-element-helper "^0.8.5"
ember-focus-trap "^1.0.2" ember-focus-trap "^1.0.2"
ember-keyboard "^8.2.0" ember-keyboard "^8.2.0"
ember-stargate "^0.4.3" ember-stargate "^0.4.3"
@ -1860,15 +1906,16 @@
pretender "^3.2.0" pretender "^3.2.0"
recursive-readdir-sync "^1.0.6" recursive-readdir-sync "^1.0.6"
"@hashicorp/ember-flight-icons@^3.1.3": "@hashicorp/ember-flight-icons@^4.0.1":
version "3.1.3" version "4.0.1"
resolved "https://registry.npmjs.org/@hashicorp/ember-flight-icons/-/ember-flight-icons-3.1.3.tgz" resolved "https://registry.yarnpkg.com/@hashicorp/ember-flight-icons/-/ember-flight-icons-4.0.1.tgz#08499f495f8f9ff9eb9eb6c439f1861f8411c047"
integrity sha512-Cy/zD6aKqwN1Q+jnF1wJ2QzRx4/6XIVM4x3qO0poi2RHBSzZS/jxwAIqyDXdKiqJha7i/vWP3aGQmDEBqoGKjA== integrity sha512-8xkU+2ATX/a5pofmwO51YXgwHamG6YUpxOXxcPbA+9/TKNn1HFbrk3TWJBuDIwz2kdk9hXRZBri2XIR18BFrTA==
dependencies: dependencies:
"@hashicorp/flight-icons" "^2.20.0" "@hashicorp/flight-icons" "^2.20.0"
ember-auto-import "^2.6.3" ember-auto-import "^2.6.3"
ember-cli-babel "^7.26.11" ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.2.0" ember-cli-htmlbars "^6.2.0"
ember-get-config "^2.1.1"
"@hashicorp/flight-icons@^2.20.0": "@hashicorp/flight-icons@^2.20.0":
version "2.20.0" version "2.20.0"
@ -5680,7 +5727,7 @@ debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4" version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -6044,18 +6091,6 @@ ember-a11y-refocus@^3.0.2:
ember-cli-babel "^7.26.11" ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.0.1" ember-cli-htmlbars "^6.0.1"
ember-arg-types@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/ember-arg-types/-/ember-arg-types-1.1.0.tgz"
integrity sha512-hWpUz0eiNkWzi3FgHW5QU6LyCDyUlTWwuIROHluEKZoa9m6LJVXbb/EVFgIG3FkAib6a5Ie00WvkXEZFXxh3+A==
dependencies:
"@embroider/macros" "^1.8.1"
ember-auto-import "^2.4.2"
ember-cli-babel "^7.26.11"
ember-cli-typescript "^5.1.1"
ember-get-config "^2.1.1"
prop-types "^15.8.1"
ember-array-fns@^1.4.0: ember-array-fns@^1.4.0:
version "1.4.2" version "1.4.2"
resolved "https://registry.npmjs.org/ember-array-fns/-/ember-array-fns-1.4.2.tgz" resolved "https://registry.npmjs.org/ember-array-fns/-/ember-array-fns-1.4.2.tgz"
@ -6317,20 +6352,6 @@ ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.10.0, ember-c
rimraf "^3.0.1" rimraf "^3.0.1"
semver "^5.5.0" semver "^5.5.0"
ember-cli-clipboard@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/ember-cli-clipboard/-/ember-cli-clipboard-1.1.0.tgz"
integrity sha512-gqFMeLCMe7OKP8rtZluV3BsP03bnjqD/f1QQLdOB9gAbdiHzMIAbwIA/RhccGtGQgy5AlnxkkQ+7j/h6UDluPQ==
dependencies:
"@embroider/macros" "^1.10.0"
clipboard "^2.0.11"
ember-arg-types "^1.0.0"
ember-auto-import "^2.4.2"
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.1.0"
ember-modifier "^3.2.7 || ^4.1.0"
prop-types "^15.8.1"
ember-cli-code-coverage@^1.0.0-beta.4: ember-cli-code-coverage@^1.0.0-beta.4:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/ember-cli-code-coverage/-/ember-cli-code-coverage-1.0.3.tgz" resolved "https://registry.npmjs.org/ember-cli-code-coverage/-/ember-cli-code-coverage-1.0.3.tgz"
@ -6433,7 +6454,7 @@ ember-cli-htmlbars@^5.0.0, ember-cli-htmlbars@^5.1.0, ember-cli-htmlbars@^5.1.2,
strip-bom "^4.0.0" strip-bom "^4.0.0"
walk-sync "^2.2.0" walk-sync "^2.2.0"
ember-cli-htmlbars@^6.0.0, ember-cli-htmlbars@^6.0.1, ember-cli-htmlbars@^6.1.0, ember-cli-htmlbars@^6.1.1, ember-cli-htmlbars@^6.2.0: ember-cli-htmlbars@^6.0.0, ember-cli-htmlbars@^6.0.1, ember-cli-htmlbars@^6.1.1, ember-cli-htmlbars@^6.2.0:
version "6.2.0" version "6.2.0"
resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-6.2.0.tgz" resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-6.2.0.tgz"
integrity sha512-j5EGixjGau23HrqRiW/JjoAovg5UBHfjbyN7wX5ekE90knIEqUUj1z/Mo/cTx/J2VepQ2lE6HdXW9LWQ/WdMtw== integrity sha512-j5EGixjGau23HrqRiW/JjoAovg5UBHfjbyN7wX5ekE90knIEqUUj1z/Mo/cTx/J2VepQ2lE6HdXW9LWQ/WdMtw==
@ -6671,7 +6692,7 @@ ember-cli-typescript@^4.0.0, ember-cli-typescript@^4.1.0, ember-cli-typescript@^
stagehand "^1.0.0" stagehand "^1.0.0"
walk-sync "^2.2.0" walk-sync "^2.2.0"
ember-cli-typescript@^5.0.0, ember-cli-typescript@^5.1.0, ember-cli-typescript@^5.1.1: ember-cli-typescript@^5.0.0, ember-cli-typescript@^5.1.0:
version "5.2.1" version "5.2.1"
resolved "https://registry.npmjs.org/ember-cli-typescript/-/ember-cli-typescript-5.2.1.tgz" resolved "https://registry.npmjs.org/ember-cli-typescript/-/ember-cli-typescript-5.2.1.tgz"
integrity sha512-qqp5TAIuPHxHiGXJKL+78Euyhy0zSKQMovPh8sJpN/ZBYx0H90pONufHR3anaMcp1snVfx4B+mb9+7ijOik8ZA== integrity sha512-qqp5TAIuPHxHiGXJKL+78Euyhy0zSKQMovPh8sJpN/ZBYx0H90pONufHR3anaMcp1snVfx4B+mb9+7ijOik8ZA==
@ -6954,6 +6975,15 @@ ember-destroyable-polyfill@^2.0.2, ember-destroyable-polyfill@^2.0.3:
ember-cli-version-checker "^5.1.1" ember-cli-version-checker "^5.1.1"
ember-compatibility-helpers "^1.2.1" ember-compatibility-helpers "^1.2.1"
ember-element-helper@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/ember-element-helper/-/ember-element-helper-0.6.1.tgz#a6fbc5be5f875b5c864ae61bf5c5f81d6de6d936"
integrity sha512-YiOdAMlzYul4ulkIoNp8z7iHDfbT1fbut/9xGFRfxDwU/FmF8HtAUB2f1veu/w50HTeZNopa1OV2PCloZ76XlQ==
dependencies:
"@embroider/util" "^0.39.1 || ^0.40.0 || ^0.41.0 || ^1.0.0"
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.0.1"
ember-element-helper@^0.5.5: ember-element-helper@^0.5.5:
version "0.5.5" version "0.5.5"
resolved "https://registry.npmjs.org/ember-element-helper/-/ember-element-helper-0.5.5.tgz" resolved "https://registry.npmjs.org/ember-element-helper/-/ember-element-helper-0.5.5.tgz"
@ -6963,6 +6993,14 @@ ember-element-helper@^0.5.5:
ember-cli-babel "^7.17.2" ember-cli-babel "^7.17.2"
ember-cli-htmlbars "^5.1.0" ember-cli-htmlbars "^5.1.0"
ember-element-helper@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/ember-element-helper/-/ember-element-helper-0.8.5.tgz#5a53d4e3aa8379694c2002a3097269aeb7c2621b"
integrity sha512-yZYzuasn6ZC8Nwv0MpaLYGtm68ZxIBSNSe/CYxNWkDdgcuAb2lAG1gx37XkwBIiwPQET0W2agwq7++/HwdMF8g==
dependencies:
"@embroider/addon-shim" "1.8.3"
"@embroider/util" "^1.0.0"
ember-exam@^6.1.0: ember-exam@^6.1.0:
version "6.1.0" version "6.1.0"
resolved "https://registry.npmjs.org/ember-exam/-/ember-exam-6.1.0.tgz" resolved "https://registry.npmjs.org/ember-exam/-/ember-exam-6.1.0.tgz"
@ -7037,20 +7075,6 @@ ember-in-element-polyfill@^1.0.0:
ember-cli-htmlbars "^5.3.1" ember-cli-htmlbars "^5.3.1"
ember-cli-version-checker "^5.1.2" ember-cli-version-checker "^5.1.2"
ember-in-viewport@^4.0.0:
version "4.1.0"
resolved "https://registry.npmjs.org/ember-in-viewport/-/ember-in-viewport-4.1.0.tgz"
integrity sha512-3y6qWXuJPPc6vX2GfxWgtr+sDjb+bdZF9babstr0lTd8t8c1b42gJ13GaJqlylZIyZz2dEXFCimX9WAeudPv9g==
dependencies:
"@embroider/macros" "^1.8.3"
ember-auto-import "^2.2.3"
ember-cli-babel "^7.26.6"
ember-destroyable-polyfill "^2.0.3"
ember-modifier "^2.1.2 || ^3.0.0 || ^4.0.0"
fast-deep-equal "^2.0.1"
intersection-observer-admin "~0.3.2"
raf-pool "~0.1.4"
ember-inflector@^4.0.1, ember-inflector@^4.0.2: ember-inflector@^4.0.1, ember-inflector@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-4.0.2.tgz" resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-4.0.2.tgz"
@ -7156,7 +7180,7 @@ ember-modifier@^2.1.0:
ember-destroyable-polyfill "^2.0.2" ember-destroyable-polyfill "^2.0.2"
ember-modifier-manager-polyfill "^1.2.0" ember-modifier-manager-polyfill "^1.2.0"
"ember-modifier@^2.1.2 || ^3.0.0 || ^4.0.0", "ember-modifier@^2.1.2 || ^3.1.0 || ^4.0.0", "ember-modifier@^3.2.7 || ^4.0.0", "ember-modifier@^3.2.7 || ^4.1.0", ember-modifier@^4.1.0: "ember-modifier@^2.1.2 || ^3.1.0 || ^4.0.0", "ember-modifier@^3.2.7 || ^4.0.0", ember-modifier@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.npmjs.org/ember-modifier/-/ember-modifier-4.1.0.tgz" resolved "https://registry.npmjs.org/ember-modifier/-/ember-modifier-4.1.0.tgz"
integrity sha512-YFCNpEYj6jdyy3EjslRb2ehNiDvaOrXTilR9+ngq+iUqSHYto2zKV0rleiA1XJQ27ELM1q8RihT29U6Lq5EyqQ== integrity sha512-YFCNpEYj6jdyy3EjslRb2ehNiDvaOrXTilR9+ngq+iUqSHYto2zKV0rleiA1XJQ27ELM1q8RihT29U6Lq5EyqQ==
@ -8194,11 +8218,6 @@ faker@^5.5.3:
resolved "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz" resolved "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz"
integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz"
integrity sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
@ -9637,11 +9656,6 @@ internmap@^1.0.0:
resolved "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz" resolved "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz"
integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==
intersection-observer-admin@~0.3.2:
version "0.3.3"
resolved "https://registry.npmjs.org/intersection-observer-admin/-/intersection-observer-admin-0.3.3.tgz"
integrity sha512-aKMJPw/8cxybcgYTbnwGn87VgSFbSNNqeChRJahD+ai+jtwlCOdIcEvtuBd2BWO9bPuylVgeQVmGGfX2aS1NIg==
intl-messageformat-parser@^6.0.5: intl-messageformat-parser@^6.0.5:
version "6.4.4" version "6.4.4"
resolved "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-6.4.4.tgz" resolved "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-6.4.4.tgz"
@ -10808,7 +10822,7 @@ longest-streak@^2.0.0:
resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz" resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz"
integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==
loose-envify@^1.0.0, loose-envify@^1.4.0: loose-envify@^1.0.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -12502,15 +12516,6 @@ promise.hash.helper@^1.0.7:
resolved "https://registry.npmjs.org/promise.hash.helper/-/promise.hash.helper-1.0.8.tgz" resolved "https://registry.npmjs.org/promise.hash.helper/-/promise.hash.helper-1.0.8.tgz"
integrity sha512-KYcnXctWUWyVD3W3Ye0ZDuA1N8Szrh85cVCxpG6xYrOk/0CttRtYCmU30nWsUch0NuExQQ63QXvzRE6FLimZmg== integrity sha512-KYcnXctWUWyVD3W3Ye0ZDuA1N8Szrh85cVCxpG6xYrOk/0CttRtYCmU30nWsUch0NuExQQ63QXvzRE6FLimZmg==
prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.13.1"
property-information@^5.0.0: property-information@^5.0.0:
version "5.6.0" version "5.6.0"
resolved "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz" resolved "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz"
@ -12648,11 +12653,6 @@ qunit@^2.16.0, qunit@^2.17.2:
node-watch "0.7.3" node-watch "0.7.3"
tiny-glob "0.2.9" tiny-glob "0.2.9"
raf-pool@~0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/raf-pool/-/raf-pool-0.1.4.tgz"
integrity sha512-BBPamTVuSprPq7CUmgxc+ycbsYUtUYnQtJYEfMHXMaostPaNpQzipLfSa/rwjmlgjBPiD7G+I+8W340sLOPu6g==
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
@ -12701,11 +12701,6 @@ raw-body@~1.1.0:
bytes "1" bytes "1"
string_decoder "0.10" string_decoder "0.10"
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^17.0.1: react-is@^17.0.1:
version "17.0.2" version "17.0.2"
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"