mirror of https://github.com/rancher/ui.git
Active links (rancher/rancher#13481)
This commit is contained in:
parent
0952d58b50
commit
ce4d300604
|
|
@ -2,121 +2,92 @@
|
|||
<a class="nav-logo logo-{{app.mode}} btn bg-transparent"><span class="sr-only">{{settings.appName}}</span></a>
|
||||
|
||||
<ul class="nav-main nav-list no-inline-space">
|
||||
{{page-header-environment
|
||||
pageScope=pageScope
|
||||
}}
|
||||
{{page-header-environment pageScope=pageScope}}
|
||||
|
||||
{{#each navTree as |item|}}
|
||||
|
||||
{{#if item.submenu.length}}
|
||||
|
||||
{{! Has a submenu }}
|
||||
{{#basic-dropdown
|
||||
tagName="li"
|
||||
class="nav-item"
|
||||
as |dd|}}
|
||||
|
||||
{{#dd.trigger
|
||||
onMouseDown=(action "prevent")
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
}}
|
||||
|
||||
{{#if (or (not item.resource) (rbac-allows resource=item.resource scope=item.resourceScope))}}
|
||||
|
||||
{{#if item.route}}
|
||||
|
||||
{{#link-to-as-attrs
|
||||
item.route
|
||||
models=item.ctx
|
||||
qp=item.qp
|
||||
onlyCurrentWhen=item.onlyCurrentWhen
|
||||
activeParent=true
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
}}
|
||||
{{maybe-t item.localizedLabel item.label}}
|
||||
<span class="icon icon-chevron-down"/>
|
||||
{{/link-to-as-attrs}}
|
||||
|
||||
{{else}}
|
||||
|
||||
<a role="button" aria-haspopup="true" aria-label={{maybe-t item.localizedLabel item.label}}>
|
||||
{{maybe-t item.localizedLabel item.label}}
|
||||
<span class="icon icon-chevron-down"/>
|
||||
</a>
|
||||
|
||||
{{/if}}
|
||||
|
||||
tagName="li"
|
||||
class="nav-item"
|
||||
as |dd|
|
||||
}}
|
||||
{{#dd.trigger
|
||||
onMouseDown=(action "prevent")
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
}}
|
||||
{{#if (or (not item.resource) (rbac-allows resource=item.resource scope=item.resourceScope))}}
|
||||
{{#if item.route}}
|
||||
{{#link-to-as-attrs
|
||||
item.route
|
||||
models=item.ctx
|
||||
qp=item.qp
|
||||
currentWhen=item.currentWhen
|
||||
activeParent="LI"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
}}
|
||||
{{maybe-t item.localizedLabel item.label}}
|
||||
<span class="icon icon-chevron-down"/>
|
||||
{{/link-to-as-attrs}}
|
||||
{{else}}
|
||||
<a role="button" aria-haspopup="true" aria-label={{maybe-t item.localizedLabel item.label}}>
|
||||
{{maybe-t item.localizedLabel item.label}}
|
||||
<span class="icon icon-chevron-down"/>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/dd.trigger}}
|
||||
|
||||
{{/dd.trigger}}
|
||||
|
||||
{{#dd.content
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
tagName="ul"
|
||||
}}
|
||||
|
||||
{{#each item.submenu as |subitem|}}
|
||||
|
||||
{{#if subitem.route}}
|
||||
|
||||
{{#if (or (not subitem.resource) (rbac-allows resource=subitem.resource scope=subitem.resourceScope))}}
|
||||
|
||||
<li>
|
||||
{{#link-to-as-attrs
|
||||
subitem.route
|
||||
models=subitem.ctx
|
||||
qp=subitem.qp
|
||||
activeParent=true
|
||||
onlyCurrentWhen=subitem.onlyCurrentWhen
|
||||
submenuItem=true
|
||||
}}
|
||||
<i class="{{subitem.icon}}"/> {{maybe-t subitem.localizedLabel subitem.label}}
|
||||
{{/link-to-as-attrs}}
|
||||
</li>
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{else if subitem.divider}}
|
||||
|
||||
<li class="divider"></li>
|
||||
|
||||
{{else}}
|
||||
|
||||
{{! Just a label }}
|
||||
<li class="dropdown-header">
|
||||
<i class="{{subitem.icon}}"/> {{maybe-t subitem.localizedLabel subitem.label}}
|
||||
{{#dd.content
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
tagName="ul"
|
||||
}}
|
||||
{{#each item.submenu as |subitem|}}
|
||||
{{#if subitem.route}}
|
||||
{{#if (or (not subitem.resource) (rbac-allows resource=subitem.resource scope=subitem.resourceScope))}}
|
||||
<li>
|
||||
{{#link-to-as-attrs
|
||||
subitem.route
|
||||
models=subitem.ctx
|
||||
qp=subitem.qp
|
||||
activeParent="LI"
|
||||
}}
|
||||
<i class="{{subitem.icon}}"/> {{maybe-t subitem.localizedLabel subitem.label}}
|
||||
{{/link-to-as-attrs}}
|
||||
</li>
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{/each}}
|
||||
|
||||
{{/dd.content}}
|
||||
|
||||
{{else if subitem.divider}}
|
||||
<li class="divider"></li>
|
||||
{{else}}
|
||||
{{! Just a label }}
|
||||
<li class="dropdown-header">
|
||||
<i class="{{subitem.icon}}"/> {{maybe-t subitem.localizedLabel subitem.label}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{/dd.content}}
|
||||
{{/basic-dropdown}}
|
||||
|
||||
{{else if item.route}}
|
||||
|
||||
{{#if (or (not item.resource) (rbac-allows resource=item.resource scope=item.resourceScope))}}
|
||||
|
||||
{{! No submenu }}
|
||||
<li class="nav-item">
|
||||
{{#link-to-as-attrs
|
||||
item.route
|
||||
models=item.ctx
|
||||
qp=item.qp
|
||||
activeParent=true
|
||||
onlyCurrentWhen=item.onlyCurrentWhen
|
||||
activeParent="LI"
|
||||
currentWhen=item.currentWhen
|
||||
class="nav-link"
|
||||
}}
|
||||
{{maybe-t item.localizedLabel item.label}}
|
||||
{{/link-to-as-attrs}}
|
||||
</li>
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
|
|
@ -127,25 +98,23 @@
|
|||
</li>
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{/each}}
|
||||
|
||||
</ul>
|
||||
|
||||
{{#basic-dropdown
|
||||
tagName="ul"
|
||||
class="nav-user"
|
||||
horizontalPosition="right"
|
||||
delay=250
|
||||
as |dd|
|
||||
tagName="ul"
|
||||
class="nav-user"
|
||||
horizontalPosition="right"
|
||||
delay=250
|
||||
as |dd|
|
||||
}}
|
||||
{{!-- <ul class="nav-user"> --}}
|
||||
{{#dd.trigger
|
||||
class="btn"
|
||||
ariaLabel=(t 'nav.user.label' username=session.user)
|
||||
onMouseDown=(action "prevent")
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
class="btn"
|
||||
ariaLabel=(t 'nav.user.label' username=session.user)
|
||||
onMouseDown=(action "prevent")
|
||||
onMouseEnter=(action "open")
|
||||
onMouseLeave=(action "closeLater")
|
||||
}}
|
||||
{{#if accessEnabled}}
|
||||
{{identity-avatar link=false identity=access.principal}}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,47 @@
|
|||
import LinkComponent from '@ember/routing/link-component';
|
||||
import { get } from '@ember/object'
|
||||
|
||||
export function initialize(/*application */) {
|
||||
LinkComponent.reopen({
|
||||
attributeBindings: ['tooltip', 'data-placement'],
|
||||
|
||||
// Set activeParent=true on a {{link-to}} to automatically propagate the active
|
||||
// class to the parent element (like <li>{{link-to}}</li>)
|
||||
activeParent: false,
|
||||
// Set activeParent=LI on a {{link-to}} to automatically propagate the active
|
||||
// class to the parent element of that tag name (like <li>{{link-to}}</li>)
|
||||
activeParent: null,
|
||||
|
||||
addActiveObserver: function () {
|
||||
if (this.get('activeParent')) {
|
||||
if ( this.get('activeParent') ) {
|
||||
this.addObserver('active', this, 'activeChanged');
|
||||
this.addObserver('application.currentRouteName', this, 'activeChanged');
|
||||
this.activeChanged();
|
||||
}
|
||||
}.on('didInsertElement'),
|
||||
|
||||
isOnlyCurrentWhen() {
|
||||
if (!this.get('onlyCurrentWhen')) {
|
||||
return false;
|
||||
}
|
||||
let currentRouteName = this.get('application.currentRouteName');
|
||||
return !this.get('onlyCurrentWhen').some(r => currentRouteName.startsWith(r));
|
||||
},
|
||||
|
||||
activeChanged() {
|
||||
if (this.isDestroyed || this.isDestroying) {
|
||||
if ( this.isDestroyed || this.isDestroying ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need to mark the parent drop down as active as well
|
||||
if (!!this.get('active')) {
|
||||
if (this.get('submenuItem')) {
|
||||
if (!this.$().closest('li.dropdown.active').length) {
|
||||
var $dropdown = this.$().closest('li.dropdown');
|
||||
$dropdown.addClass('active');
|
||||
$dropdown.siblings('li.active').removeClass('active');
|
||||
}
|
||||
} else {
|
||||
if (this.$().parent().siblings('li.dropdown.active').length) {
|
||||
this.$().parent().siblings('li.dropdown.active').removeClass('active');
|
||||
const parent = this.$().closest(get(this, 'activeParent'));
|
||||
if ( !parent || !parent.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let active = !!get(this, 'active');
|
||||
let more = get(this, 'currentWhen');
|
||||
if ( !active && more && more.length) {
|
||||
const currentRouteName = get(this, 'application.currentRouteName');
|
||||
for ( let i = 0 ; i < get(more, 'length') ; i++ ) {
|
||||
const entry = more.objectAt(i);
|
||||
|
||||
if ( currentRouteName === entry || currentRouteName.startsWith(`${entry}.`) ) {
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.get('active') && !this.isOnlyCurrentWhen()) {
|
||||
this.$().parent().toggleClass('active', true);
|
||||
} else {
|
||||
this.$().parent().toggleClass('active', false);
|
||||
}
|
||||
parent.toggleClass('active', active);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,15 @@ const rootNav = [
|
|||
localizedLabel: 'nav.containers.tab',
|
||||
route: 'authenticated.project.index',
|
||||
ctx: [getProjectId],
|
||||
onlyCurrentWhen: ['containers','ingresses','authenticated.project.dns','volumes', 'authenticated.project.pipeline'],
|
||||
resource: ["workload", "ingress", "dnsrecord"],
|
||||
resourceScope: 'project',
|
||||
moreCurrentWhen: [
|
||||
'containers','workload',
|
||||
'ingresses',
|
||||
'authenticated.project.dns',
|
||||
'volumes',
|
||||
'authenticated.project.pipeline'
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
|
|
@ -99,7 +105,7 @@ const rootNav = [
|
|||
id: 'project-security-roles',
|
||||
localizedLabel: 'nav.infra.members',
|
||||
icon: 'icon icon-users',
|
||||
route: 'authenticated.project.security.members.index',
|
||||
route: 'authenticated.project.security.members',
|
||||
resource: ['projectroletemplatebinding'],
|
||||
resourceScope: 'global',
|
||||
ctx: [getProjectId],
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ $nav-spacing: 4px;
|
|||
display: inline-block;
|
||||
|
||||
&.active {
|
||||
> .ember-basic-dropdown-trigger > a,
|
||||
> a {
|
||||
color: $info;
|
||||
border-bottom: solid $nav-spacing mix($user-btn, black, 50%);
|
||||
|
|
@ -47,6 +48,7 @@ $nav-spacing: 4px;
|
|||
}
|
||||
}
|
||||
|
||||
> .ember-basic-dropdown-trigger > a,
|
||||
> a {
|
||||
color: $header-link;
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const headers = [
|
|||
name: 'created',
|
||||
sort: ['created'],
|
||||
classNames: 'text-right pr-20',
|
||||
width: 200,
|
||||
width: 250,
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -33,33 +33,50 @@ const navTree = [
|
|||
|
||||
export function addItem(opt) {
|
||||
navTree.pushObject(opt);
|
||||
syncCurrentWhen();
|
||||
}
|
||||
|
||||
export function bulkAdd(opts) {
|
||||
navTree.addObjects(opts);
|
||||
syncCurrentWhen();
|
||||
}
|
||||
|
||||
export function removeId(id) {
|
||||
for ( let i = navTree.length-1 ; i >= 0 ; i-- )
|
||||
{
|
||||
// These go backwards so that entries aren't skipped if multiple are deleted
|
||||
for ( let i = navTree.length-1 ; i >= 0 ; i-- ) {
|
||||
if ( navTree[i].id === id ) {
|
||||
navTree.removeAt(i);
|
||||
} else if ( navTree[i].submenu && isArray(navTree[i].submenu) ) {
|
||||
let sub = navTree[i].submenu;
|
||||
for ( var j = sub.length-1 ; j >= 0 ; j-- )
|
||||
{
|
||||
for ( var j = sub.length-1 ; j >= 0 ; j-- ) {
|
||||
if ( sub[j].id === id ) {
|
||||
sub.removeAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncCurrentWhen();
|
||||
}
|
||||
|
||||
export function get() {
|
||||
return EmberCopy(navTree,true);
|
||||
}
|
||||
|
||||
function syncCurrentWhen() {
|
||||
for ( let i = 0 ; i < navTree.length ; i++ ) {
|
||||
let when = (navTree[i].moreCurrentWhen||[]).slice();
|
||||
|
||||
let sub = navTree[i].submenu;
|
||||
if ( sub ) {
|
||||
when.addObjects(sub.map(x => x.route));
|
||||
when = when.filter(x => !!x && x.length);
|
||||
}
|
||||
|
||||
navTree[i].currentWhen = when;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
get: get,
|
||||
removeId: removeId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue