Skip to content

Commit

Permalink
Merge pull request #2676 from 4Science/DURACOM-195
Browse files Browse the repository at this point in the history
Header, navbar, and admin sidebar refactoring
  • Loading branch information
tdonohue authored Feb 29, 2024
2 parents 25955ae + 91f01ad commit ae15fe5
Show file tree
Hide file tree
Showing 79 changed files with 1,273 additions and 900 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/collection-edit.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('Edit Collection > Content Source tab', () => {
cy.get('#externalSourceCheck').check();

// Wait for the source controls to appear
cy.get('ds-collection-source-controls').should('be.visible');
// cy.get('ds-collection-source-controls').should('be.visible');

// Analyze entire page for accessibility issues
testA11y('ds-collection-source');
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/collection-statistics.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Collection Statistics Page', () => {

it('should load if you click on "Statistics" from a Collection page', () => {
cy.visit('/collections/'.concat(Cypress.env('DSPACE_TEST_COLLECTION')));
cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click();
cy.get('ds-navbar ds-link-menu-item a[data-test="link-menu-item.menu.section.statistics"]').click();
cy.location('pathname').should('eq', COLLECTIONSTATISTICSPAGE);
});

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/community-statistics.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Community Statistics Page', () => {

it('should load if you click on "Statistics" from a Community page', () => {
cy.visit('/communities/'.concat(Cypress.env('DSPACE_TEST_COMMUNITY')));
cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click();
cy.get('ds-navbar ds-link-menu-item a[data-test="link-menu-item.menu.section.statistics"]').click();
cy.location('pathname').should('eq', COMMUNITYSTATISTICSPAGE);
});

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/homepage-statistics.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import '../support/commands';
describe('Site Statistics Page', () => {
it('should load if you click on "Statistics" from homepage', () => {
cy.visit('/');
cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click();
cy.get('ds-navbar ds-link-menu-item a[data-test="link-menu-item.menu.section.statistics"]').click();
cy.location('pathname').should('eq', '/statistics');
});

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/item-statistics.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Item Statistics Page', () => {

it('should load if you click on "Statistics" from an Item/Entity page', () => {
cy.visit('/entities/publication/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')));
cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click();
cy.get('ds-navbar ds-link-menu-item a[data-test="link-menu-item.menu.section.statistics"]').click();
cy.location('pathname').should('eq', ITEMSTATISTICSPAGE);
});

Expand Down
26 changes: 13 additions & 13 deletions cypress/e2e/login-modal.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@ import { testA11y } from 'cypress/support/utils';
const page = {
openLoginMenu() {
// Click the "Log In" dropdown menu in header
cy.get('ds-themed-navbar [data-test="login-menu"]').click();
cy.get('ds-themed-header [data-test="login-menu"]').click();
},
openUserMenu() {
// Once logged in, click the User menu in header
cy.get('ds-themed-navbar [data-test="user-menu"]').click();
cy.get('ds-themed-header [data-test="user-menu"]').click();
},
submitLoginAndPasswordByPressingButton(email, password) {
// Enter email
cy.get('ds-themed-navbar [data-test="email"]').type(email);
cy.get('ds-themed-header [data-test="email"]').type(email);
// Enter password
cy.get('ds-themed-navbar [data-test="password"]').type(password);
cy.get('ds-themed-header [data-test="password"]').type(password);
// Click login button
cy.get('ds-themed-navbar [data-test="login-button"]').click();
cy.get('ds-themed-header [data-test="login-button"]').click();
},
submitLoginAndPasswordByPressingEnter(email, password) {
// In opened Login modal, fill out email & password, then click Enter
cy.get('ds-themed-navbar [data-test="email"]').type(email);
cy.get('ds-themed-navbar [data-test="password"]').type(password);
cy.get('ds-themed-navbar [data-test="password"]').type('{enter}');
cy.get('ds-themed-header [data-test="email"]').type(email);
cy.get('ds-themed-header [data-test="password"]').type(password);
cy.get('ds-themed-header [data-test="password"]').type('{enter}');
},
submitLogoutByPressingButton() {
// This is the POST command that will actually log us out
cy.intercept('POST', '/server/api/authn/logout').as('logout');
// Click logout button
cy.get('ds-themed-navbar [data-test="logout-button"]').click();
cy.get('ds-themed-header [data-test="logout-button"]').click();
// Wait until above POST command responds before continuing
// (This ensures next action waits until logout completes)
cy.wait('@logout');
Expand Down Expand Up @@ -102,10 +102,10 @@ describe('Login Modal', () => {
page.openLoginMenu();

// Registration link should be visible
cy.get('ds-themed-navbar [data-test="register"]').should('be.visible');
cy.get('ds-themed-header [data-test="register"]').should('be.visible');

// Click registration link & you should go to registration page
cy.get('ds-themed-navbar [data-test="register"]').click();
cy.get('ds-themed-header [data-test="register"]').click();
cy.location('pathname').should('eq', '/register');
cy.get('ds-register-email').should('exist');

Expand All @@ -119,10 +119,10 @@ describe('Login Modal', () => {
page.openLoginMenu();

// Forgot password link should be visible
cy.get('ds-themed-navbar [data-test="forgot"]').should('be.visible');
cy.get('ds-themed-header [data-test="forgot"]').should('be.visible');

// Click link & you should go to Forgot Password page
cy.get('ds-themed-navbar [data-test="forgot"]').click();
cy.get('ds-themed-header [data-test="forgot"]').click();
cy.location('pathname').should('eq', '/forgot');
cy.get('ds-forgot-email').should('exist');

Expand Down
8 changes: 4 additions & 4 deletions cypress/e2e/search-navbar.cy.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const page = {
fillOutQueryInNavBar(query) {
// Click the magnifying glass
cy.get('ds-themed-navbar [data-test="header-search-icon"]').click();
cy.get('ds-themed-header [data-test="header-search-icon"]').click();
// Fill out a query in input that appears
cy.get('ds-themed-navbar [data-test="header-search-box"]').type(query);
cy.get('ds-themed-header [data-test="header-search-box"]').type(query);
},
submitQueryByPressingEnter() {
cy.get('ds-themed-navbar [data-test="header-search-box"]').type('{enter}');
cy.get('ds-themed-header [data-test="header-search-box"]').type('{enter}');
},
submitQueryByPressingIcon() {
cy.get('ds-themed-navbar [data-test="header-search-icon"]').click();
cy.get('ds-themed-header [data-test="header-search-icon"]').click();
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
<div class="sidebar-section">
<a class="nav-item nav-link d-flex flex-row flex-nowrap"
[ngClass]="{ disabled: isDisabled }"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="'sidebarName-' + section.id"
[title]="('menu.section.icon.' + section.id) | translate"
[routerLink]="itemModel.link"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
href="javascript:void(0);"
>
<div class="shortcut-icon">
<i class="fas fa-{{section.icon}} fa-fw"></i>
<div>
<a class="sidebar-section-wrapper"
[ngClass]="{ disabled: isDisabled }"
role="menuitem"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="adminMenuSectionTitleId(section.id)"
[routerLink]="itemModel.link"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
href="javascript:void(0);"
>
<div class="sidebar-fixed-element-wrapper" data-test="sidebar-section-icon" aria-hidden="true">
<i class="fas fa-{{section.icon}} fa-fw"></i>
</div>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
<span [id]="adminMenuSectionTitleId(section.id)">{{itemModel.text | translate}}</span>
</div>
<div class="sidebar-collapsible">
<div class="toggle">
<span id="sidebarName-{{section.id}}" class="section-header-text">
{{itemModel.text | translate}}
</span>
</div>
</div>
</a>
</div>
</a>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('AdminSidebarSectionComponent', () => {
});

it('should set the right icon', () => {
const icon = fixture.debugElement.query(By.css('.shortcut-icon')).query(By.css('i.fas'));
const icon = fixture.debugElement.query(By.css('[data-test="sidebar-section-icon"]')).query(By.css('i.fas'));
expect(icon.nativeElement.getAttribute('class')).toContain('fa-' + iconString);
});
it('should not contain the disabled class', () => {
Expand Down Expand Up @@ -88,7 +88,7 @@ describe('AdminSidebarSectionComponent', () => {
});

it('should set the right icon', () => {
const icon = fixture.debugElement.query(By.css('.shortcut-icon')).query(By.css('i.fas'));
const icon = fixture.debugElement.query(By.css('[data-test="sidebar-section-icon"]')).query(By.css('i.fas'));
expect(icon.nativeElement.getAttribute('class')).toContain('fa-' + iconString);
});
it('should contain the disabled class', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,12 @@ export class AdminSidebarSectionComponent extends MenuSectionComponent implement
this.router.navigate(this.itemModel.link);
}
}

adminMenuSectionId(sectionId: string) {
return `admin-menu-section-${sectionId}`;
}

adminMenuSectionTitleId(sectionId: string) {
return `admin-menu-section-${sectionId}-title`;
}
}
99 changes: 54 additions & 45 deletions src/app/admin/admin-sidebar/admin-sidebar.component.html
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@
<nav class="navbar navbar-dark p-0"
[ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}"
<nav class="navbar navbar-dark p-0 vh-100"
id="admin-sidebar"
[attr.aria-label]="'menu.header.nav.description' | translate"
[ngClass]="{'expanded': sidebarOpen, 'collapsed': sidebarClosed, 'transitioning': sidebarTransitioning}"
[@slideSidebar]="{
value: (!(sidebarExpanded | async) ? 'collapsed' : 'expanded'),
params: {sidebarWidth: (sidebarWidth | async)}
params: { collapsedWidth: (collapsedSidebarWidth$ | async), expandedWidth: (expandedSidebarWidth$ | async) }
}" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)"
*ngIf="menuVisible | async"
(mouseenter)="handleMouseEnter($event)"
(mouseleave)="handleMouseLeave($event)"
role="navigation" [attr.aria-label]="'menu.header.admin.description' |translate">
<div class="sidebar-top-level-items">
<ul class="navbar-nav">
<li class="admin-menu-header">
<div class="sidebar-section">
<div href="javascript:void(0);" class="nav-item d-flex flex-row flex-nowrap py-0">
<div class="shortcut-icon navbar-brand logo-wrapper">
<img class="admin-logo" src="assets/images/dspace-logo-mini.svg"
[alt]="('menu.header.image.logo') | translate">
</div>
<div class="sidebar-collapsible navbar-brand">
<div class="mr-0">
<h4 class="section-header-text mb-0">{{ 'menu.header.admin' | translate }}</h4>
</div>
</div>
</div>
</div>
</li>
(mouseleave)="handleMouseLeave($event)">

<li *ngFor="let section of (sections | async)">
<ng-container
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
</li>
</ul>
</div>
<div class="navbar-nav">
<div class="sidebar-section" id="sidebar-collapse-toggle">
<button class="nav-item nav-link sidebar-section d-flex flex-row flex-nowrap border-0" type="button"
(click)="toggle($event)"
(keyup.space)="toggle($event)"
>
<span class="shortcut-icon">
<i *ngIf="(menuCollapsed | async)" class="fas fa-fw fa-angle-double-right"
[title]="'menu.section.icon.pin' | translate"></i>
<i *ngIf="!(menuCollapsed | async)" class="fas fa-fw fa-angle-double-left"
[title]="'menu.section.icon.unpin' | translate"></i>
</span>
<span class="sidebar-collapsible text-left">
<span *ngIf="menuCollapsed | async" class="section-header-text">{{'menu.section.pin' | translate }}</span>
<span *ngIf="!(menuCollapsed | async)" class="section-header-text">{{'menu.section.unpin' | translate }}</span>
</span>
</button>
<!-- HEADER -->

<div class="sidebar-full-width-container" id="sidebar-header-container" aria-hidden="true">
<div class="sidebar-section-wrapper">
<div class="sidebar-fixed-element-wrapper">
<img id="admin-sidebar-logo" src="assets/images/dspace-logo-mini.svg" [alt]="('menu.header.image.logo') | translate" aria-hidden="true">
</div>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
<h4 class="my-1">{{ 'menu.header.admin' | translate }}</h4>
</div>
</div>
</div>
</div>

<!-- ITEMS -->

<div class="sidebar-full-width-container" id="sidebar-top-level-items-container">
<div class="sidebar-full-width-container" id="sidebar-top-level-items" role="menubar"
[attr.aria-label]="'menu.header.admin.description' |translate">
<ng-container *ngFor="let section of (sections | async)">
<ng-container
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
</ng-container>
</div>
</div>

<!-- TOGGLER -->

<div class="sidebar-full-width-container" id="sidebar-collapse-toggle-container">
<a class="sidebar-section-wrapper sidebar-full-width-container"
id="sidebar-collapse-toggle"
href="javascript:void(0);"
(click)="toggle($event)"
(keyup.space)="toggle($event)"
>
<div class="sidebar-fixed-element-wrapper">
<i *ngIf="(menuCollapsed | async)" class="fas fa-fw fa-angle-double-right"
[title]="'menu.section.icon.pin' | translate"></i>
<i *ngIf="!(menuCollapsed | async)" class="fas fa-fw fa-angle-double-left"
[title]="'menu.section.icon.unpin' | translate"></i>
</div>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
{{ ((menuCollapsed | async) ? 'menu.section.pin' : 'menu.section.unpin' ) | translate }}
</div>
</div>
</a>
</div>

</nav>
Loading

0 comments on commit ae15fe5

Please sign in to comment.