progress vertical menu

This commit is contained in:
lotte
2018-11-14 15:56:23 +01:00
parent 17239cd1be
commit 0c4784346b
36 changed files with 390 additions and 1584 deletions

View File

@@ -130,6 +130,7 @@
"devDependencies": { "devDependencies": {
"@angular/compiler": "^6.1.4", "@angular/compiler": "^6.1.4",
"@angular/compiler-cli": "^6.1.4", "@angular/compiler-cli": "^6.1.4",
"@fortawesome/fontawesome-free": "^5.5.0",
"@ngrx/entity": "^6.1.0", "@ngrx/entity": "^6.1.0",
"@ngrx/schematics": "^6.1.0", "@ngrx/schematics": "^6.1.0",
"@ngrx/store-devtools": "^6.1.0", "@ngrx/store-devtools": "^6.1.0",

View File

@@ -0,0 +1,61 @@
import { Action } from '@ngrx/store';
import { type } from '../../shared/ngrx/type';
/**
* For each action type in an action group, make a simple
* enum object for all of this group's action types.
*
* The 'type' utility function coerces strings into string
* literal types and runs a simple check to guarantee all
* action types in the application are unique.
*/
export const AdminSidebarSectionActionTypes = {
COLLAPSE: type('dspace/admin-sidebar-section/COLLAPSE'),
EXPAND: type('dspace/admin-sidebar-sectio/EXPAND'),
TOGGLE: type('dspace/admin-sidebar-sectio/TOGGLE'),
};
export class AdminSidebarSectionAction implements Action {
/**
* Name of the section the action is performed on, used to identify the section
*/
sectionName: string;
/**
* Type of action that will be performed
*/
type;
/**
* Initialize with the section's name
* @param {string} name of the section
*/
constructor(name: string) {
this.sectionName = name;
}
}
/* tslint:disable:max-classes-per-file */
/**
* Used to collapse a section
*/
export class AdminSidebarSectionCollapseAction extends AdminSidebarSectionAction {
type = AdminSidebarSectionActionTypes.COLLAPSE;
}
/**
* Used to expand a section
*/
export class AdminSidebarSectionExpandAction extends AdminSidebarSectionAction {
type = AdminSidebarSectionActionTypes.EXPAND;
}
/**
* Used to collapse a section when it's expanded and expand it when it's collapsed
*/
export class AdminSidebarSectionToggleAction extends AdminSidebarSectionAction {
type = AdminSidebarSectionActionTypes.TOGGLE;
}
/* tslint:enable:max-classes-per-file */

View File

@@ -1,112 +1,135 @@
<nav class="navbar navbar-dark bg-dark"> <nav class="navbar navbar-dark bg-dark p-0">
<ul class="navbar-nav sidebar-top-level-items"> <div class="sidebar-top-level-items">
<li class="admin-menu-header"> <ul class="navbar-nav">
<a class="shortcuts-tree" href="#"> <li class="admin-menu-header">
<div class="nav-icon-container"><img class="admin-logo" src="assets/images/dspace-logo-mini.svg"></div> <a class="shortcuts-tree navbar-brand" href="#">
<h4 class="nav-item-name">Admin</h4> <img class="admin-logo mr-2" src="assets/images/dspace-logo-mini.svg">
</a> <h4 class="nav-item-name">Admin</h4>
</li> </a>
<li> </li>
<a class="nav-item nav-link shortcuts-tree" href="#"> <li [ngClass]="{'active': (active('new') | async)}">
<i class="fa fa-plus-circle fa-fw"></i> <a class="nav-item nav-link shortcuts-tree" href="#"
New (click)="toggle($event, 'new')">
<i class="fa fa-chevron-right"></i> <i class="fas fa-plus-circle fa-fw"></i>
</a> New
<ul class="sidebar-sub-level-items"> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
<li><a class="nav-item nav-link" href="#">Community</a></li> [ngClass]="{'fa-rotate-90': (active('new') | async)}"></i>
<li><a class="nav-item nav-link" href="#">Collection</a></li> </a>
<li><a class="nav-item nav-link" href="#">Item</a></li> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('new') | async)">
<li><a class="nav-item nav-link" href="#">Item Version</a></li> <li><a class="nav-item nav-link" href="#">Community</a></li>
</ul> <li><a class="nav-item nav-link" href="#">Collection</a></li>
</li> <li><a class="nav-item nav-link" href="#">Item</a></li>
<li> <li><a class="nav-item nav-link" href="#">Item Version</a></li>
<a class="nav-item nav-link shortcuts-tree" href="#"> </ul>
<i class="fa fa-pencil fa-fw"></i> </li>
Edit <li [ngClass]="{'active': (active('edit') | async)}">
<i class="fa fa-chevron-right"></i> <a class="nav-item nav-link shortcuts-tree" href="#"
</a> (click)="toggle($event, 'edit')">
<ul class="sidebar-sub-level-items"> <i class="fas fa-pencil-alt fa-fw"></i>
<li><a class="nav-item nav-link" href="#">Community</a></li> Edit
<li><a class="nav-item nav-link" href="#">Collection</a></li> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
<li><a class="nav-item nav-link" href="#">Item</a></li> [ngClass]="{'fa-rotate-90': (active('edit') | async)}"></i>
</ul> </a>
</li> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('edit') | async)">
<li> <li><a class="nav-item nav-link" href="#">Community</a></li>
<a class="nav-item nav-link shortcuts-tree" href="#"> <li><a class="nav-item nav-link" href="#">Collection</a></li>
<i class="fa fa-arrow-circle-up fa-fw"></i> <li><a class="nav-item nav-link" href="#">Item</a></li>
Import </ul>
<i class="fa fa-chevron-right"></i> </li>
</a> <li [ngClass]="{'active': (active('import') | async)}">
<ul class="sidebar-sub-level-items"> <a class="nav-item nav-link shortcuts-tree" href="#"
<li><a class="nav-item nav-link" href="#">Metadata</a></li> (click)="toggle($event, 'import')">
<li><a class="nav-item nav-link" href="#">Batch Import (ZIP)</a></li> <i class="fas fa-arrow-circle-up fa-fw"></i>
</ul> Import
</li> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
<li> [ngClass]="{'fa-rotate-90': (active('import') | async)}"></i>
<a class="nav-item nav-link shortcuts-tree" href="#"> </a>
<i class="fa fa-arrow-circle-down fa-fw"></i> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('import') | async)">
Export <li><a class="nav-item nav-link" href="#">Metadata</a></li>
<i class="fa fa-chevron-right"></i> <li><a class="nav-item nav-link" href="#">Batch Import (ZIP)</a></li>
</a> </ul>
<ul class="sidebar-sub-level-items"> </li>
<li><a class="nav-item nav-link" href="#">Community</a></li> <li [ngClass]="{'active': (active('export') | async)}">
<li><a class="nav-item nav-link" href="#">Collection</a></li> <a class="nav-item nav-link shortcuts-tree" href="#"
<li><a class="nav-item nav-link" href="#">Item</a></li> (click)="toggle($event, 'export')">
<li><a class="nav-item nav-link" href="#">Metadata</a></li> <i class="fas fa-arrow-circle-down fa-fw"></i>
</ul> Export
</li> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
<li> [ngClass]="{'fa-rotate-90': (active('export') | async)}"></i>
<a class="nav-item nav-link shortcuts-tree" href="#"> </a>
<i class="fa fa-key fa-fw"></i> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('export') | async)">
Access Control <li><a class="nav-item nav-link" href="#">Community</a></li>
<i class="fa fa-chevron-right"></i> <li><a class="nav-item nav-link" href="#">Collection</a></li>
</a> <li><a class="nav-item nav-link" href="#">Item</a></li>
<ul class="sidebar-sub-level-items"> <li><a class="nav-item nav-link" href="#">Metadata</a></li>
<li><a class="nav-item nav-link" href="#">People</a></li> </ul>
<li><a class="nav-item nav-link" href="#">Groups</a></li> </li>
<li><a class="nav-item nav-link" href="#">Authorizations</a></li> <li [ngClass]="{'active': (active('access_control') | async)}">
</ul> <a class="nav-item nav-link shortcuts-tree" href="#"
</li> (click)="toggle($event, 'access_control')">
<li> <i class="fas fa-key fa-fw"></i>
<a class="nav-item nav-link shortcuts-tree" href="#"> Access Control
<i class="fa fa-search fa-fw"></i> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
Find [ngClass]="{'fa-rotate-90': (active('access_control') | async)}"></i>
<i class="fa fa-chevron-right"></i> </a>
</a> <ul class="sidebar-sub-level-items"
<ul class="sidebar-sub-level-items"> [ngbCollapse]="!(active('access_control') | async)">
<li><a class="nav-item nav-link" href="#">Items</a></li> <li><a class="nav-item nav-link" href="#">People</a></li>
<li><a class="nav-item nav-link" href="#">Withdrawn Items</a></li> <li><a class="nav-item nav-link" href="#">Groups</a></li>
<li><a class="nav-item nav-link" href="#">Private Items</a></li> <li><a class="nav-item nav-link" href="#">Authorizations</a></li>
</ul> </ul>
</li> </li>
<li> <li [ngClass]="{'active': (active('find') | async)}">
<a class="nav-item nav-link shortcuts-tree" href="#"> <a class="nav-item nav-link shortcuts-tree" href="#"
<i class="fa fa-list fa-fw"></i> (click)="toggle($event, 'find')">
Registries <i class="fas fa-search fa-fw"></i>
<i class="fa fa-chevron-right"></i> Find
</a> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
<ul class="sidebar-sub-level-items"> [ngClass]="{'fa-rotate-90': (active('find') | async)}"></i>
<li><a class="nav-item nav-link" href="#">Metadata</a></li> </a>
<li><a class="nav-item nav-link" href="#">Format</a></li> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('find') | async)">
</ul> <li><a class="nav-item nav-link" href="#">Items</a></li>
</li> <li><a class="nav-item nav-link" href="#">Withdrawn Items</a></li>
<li> <li><a class="nav-item nav-link" href="#">Private Items</a></li>
<a class="nav-item nav-link shortcuts-tree" href="#"> </ul>
<i class="fa fa-filter fa-fw"></i> </li>
Curation Tasks <li [ngClass]="{'active': (active('registries') | async)}">
</a> <a class="nav-item nav-link shortcuts-tree" href="#"
</li> (click)="toggle($event, 'registries')">
<li> <i class="fas fa-list fa-fw"></i>
<a class="nav-item nav-link shortcuts-tree" href="#"> Registries
<i class="fa fa-bar-chart fa-fw"></i> <i class="fas fa-chevron-right fa-pull-right fa-xxs"
Statistics [ngClass]="{'fa-rotate-90': (active('registries') | async)}"></i>
</a> </a>
</li> <ul class="sidebar-sub-level-items" [ngbCollapse]="!(active('registries') | async)">
<li> <li><a class="nav-item nav-link" href="#">Metadata</a></li>
<a class="nav-item nav-link shortcuts-tree" href="#"> <li><a class="nav-item nav-link" href="#">Format</a></li>
<i class="fa fa-cogs fa-fw"></i> </ul>
Control Panel </li>
</a> <li>
</li> <a class="nav-item nav-link shortcuts-tree" href="#">
</ul> <i class="fas fa-filter fa-fw"></i>
Curation Tasks
</a>
</li>
<li>
<a class="nav-item nav-link shortcuts-tree" href="#">
<i class="fas fa-chart-bar fa-fw"></i>
Statistics
</a>
</li>
<li>
<a class="nav-item nav-link shortcuts-tree" href="#">
<i class="fas fa-cogs fa-fw"></i>
Control Panel
</a>
</li>
</ul>
</div>
<div class="navbar-nav">
<a class="nav-item nav-link shortcuts-tree" href="#">
<i class="fas fa-fw fa-angle-double-right"></i>
Collapse
</a>
</div>
</nav> </nav>

View File

@@ -1,8 +1,41 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
:host { :host {
position: absolute; position: fixed;
.sidebar-sub-level-items { nav {
list-style: disc; height: 100vh;
color: $navbar-dark-color; flex-direction: column;
>div.sidebar-top-level-items {
flex: 1;
overflow: auto;
}
.navbar-nav {
min-width: $admin-sidebar-width;
> * {
padding: $spacer/2 $spacer;
&.active {
background-color: $admin-sidebar-dark;
}
}
.sidebar-sub-level-items {
list-style: disc;
color: $navbar-dark-color;
}
.fa-xxs {
font-size: 0.5rem;
line-height: 3;
}
.admin-menu-header {
background-color: $admin-sidebar-dark;
img {
height: 1em;
vertical-align: baseline;
}
h4 {
display: inline;
}
}
}
} }
} }

View File

@@ -1,10 +1,45 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
import { AdminSidebarSectionsState, AdminSidebarSectionState } from './admin-sidebar.reducer';
import { hasValue } from '../../shared/empty.util';
import { map } from 'rxjs/operators';
import { AdminSidebarSectionToggleAction } from './admin-sidebar.actions';
const sidebarSectionStateSelector = (state: AdminSidebarSectionsState) => state.adminSidebarSection;
const sectionByNameSelector = (name: string): MemoizedSelector<AdminSidebarSectionsState, AdminSidebarSectionState> => {
return keySelector<AdminSidebarSectionState>(name);
};
export function keySelector<T>(key: string): MemoizedSelector<AdminSidebarSectionsState, T> {
return createSelector(sidebarSectionStateSelector, (state: AdminSidebarSectionState) => {
if (hasValue(state)) {
return state[key];
} else {
return undefined;
}
});
}
@Component({ @Component({
selector: 'ds-admin-sidebar', selector: 'ds-admin-sidebar',
templateUrl: './admin-sidebar.component.html', templateUrl: './admin-sidebar.component.html',
styleUrls: ['./admin-sidebar.component.scss'], styleUrls: ['./admin-sidebar.component.scss'],
}) })
export class AdminSidebarComponent { export class AdminSidebarComponent {
constructor(private store: Store<AdminSidebarSectionsState>) {
} }
public active(name: string): Observable<boolean> {
return this.store.pipe(
select(sectionByNameSelector(name)),
map((state: AdminSidebarSectionState) => hasValue(state) ? !state.sectionCollapsed : false)
);
}
toggle(event: Event, name: string) {
event.preventDefault();
this.store.dispatch(new AdminSidebarSectionToggleAction(name));
}
}

View File

@@ -0,0 +1,60 @@
import { AdminSidebarSectionAction, AdminSidebarSectionActionTypes } from './admin-sidebar.actions';
import { hasValue } from '../../shared/empty.util';
/**
* Interface that represents the state for a single section
*/
export interface AdminSidebarSectionState {
sectionCollapsed: boolean,
}
/**
* Interface that represents the state for all available sections
*/
export interface AdminSidebarSectionsState {
[name: string]: AdminSidebarSectionState
}
const initialState: AdminSidebarSectionsState = Object.create(null);
const initiallyCollapsed = true;
/**
* Performs a search section action on the current state
* @param {AdminSidebarSectionsState} state The state before the action is performed
* @param {AdminSidebarSectionAction} action The action that should be performed
* @returns {AdminSidebarSectionsState} The state after the action is performed
*/
export function sidebarSectionReducer(state = initialState, action: AdminSidebarSectionAction): AdminSidebarSectionsState {
switch (action.type) {
case AdminSidebarSectionActionTypes.COLLAPSE: {
return Object.assign({}, state, {
[action.sectionName]: {
sectionCollapsed: true,
}
});
}
case AdminSidebarSectionActionTypes.EXPAND: {
return Object.assign({}, state, {
[action.sectionName]: {
sectionCollapsed: false,
}
});
}
case AdminSidebarSectionActionTypes.TOGGLE: {
const currentState = state[action.sectionName];
const collapsed = hasValue(currentState) ? currentState.sectionCollapsed : initiallyCollapsed;
return Object.assign({}, state, {
[action.sectionName]: {
sectionCollapsed: !collapsed,
}
});
}
default: {
return state;
}
}
}

View File

@@ -5,7 +5,7 @@ import { AdminRoutingModule } from './admin-routing.module';
@NgModule({ @NgModule({
imports: [ imports: [
AdminRegistriesModule, AdminRegistriesModule,
AdminRoutingModule AdminRoutingModule,
] ]
}) })
export class AdminModule { export class AdminModule {

View File

@@ -1,5 +1,5 @@
<div> <div>
<div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fa float-right" <div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fas float-right"
[ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div> [ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div>
<div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : collapsed}"> <div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : collapsed}">
<ds-search-facet-filter-wrapper [filterConfig]="filter"></ds-search-facet-filter-wrapper> <ds-search-facet-filter-wrapper [filterConfig]="filter"></ds-search-facet-filter-wrapper>

View File

@@ -26,7 +26,7 @@
<ds-view-mode-switch></ds-view-mode-switch> <ds-view-mode-switch></ds-view-mode-switch>
<button (click)="openSidebar()" aria-controls="#search-body" <button (click)="openSidebar()" aria-controls="#search-body"
class="btn btn-outline-primary float-right open-sidebar"><i class="btn btn-outline-primary float-right open-sidebar"><i
class="fa fa-sliders"></i> {{"search.sidebar.open" class="fas fa-sliders"></i> {{"search.sidebar.open"
| translate}} | translate}}
</button> </button>
</div> </div>

View File

@@ -4,7 +4,7 @@
<button (click)="toggleSidebar.emit()" <button (click)="toggleSidebar.emit()"
aria-controls="#search-body" aria-controls="#search-body"
class="btn btn-outline-primary float-right close-sidebar"><i class="btn btn-outline-primary float-right close-sidebar"><i
class="fa fa-arrow-right"></i> {{"search.sidebar.close" | translate}} class="fas fa-arrow-right"></i> {{"search.sidebar.close" | translate}}
</button> </button>
</div> </div>
<div id="search-sidebar-content"> <div id="search-sidebar-content">

View File

@@ -1,7 +1,7 @@
@import '../styles/variables.scss'; @import '../styles/variables.scss';
@import '../styles/font-awesome-imports.scss';
@import '../../node_modules/bootstrap/scss/bootstrap.scss'; @import '../../node_modules/bootstrap/scss/bootstrap.scss';
@import '../../node_modules/nouislider/distribute/nouislider.min.css'; @import '../../node_modules/nouislider/distribute/nouislider.min.css';
@import "../../node_modules/font-awesome/scss/font-awesome.scss";
html { html {
position: relative; position: relative;

View File

@@ -16,6 +16,10 @@ import {
} from './shared/notifications/notifications.reducers'; } from './shared/notifications/notifications.reducers';
import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer'; import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer';
import { navbarReducer, NavbarState } from './navbar/navbar.reducer'; import { navbarReducer, NavbarState } from './navbar/navbar.reducer';
import {
AdminSidebarSectionsState,
sidebarSectionReducer
} from './+admin/admin-sidebar/admin-sidebar.reducer';
export interface AppState { export interface AppState {
router: fromRouter.RouterReducerState; router: fromRouter.RouterReducerState;
@@ -26,6 +30,7 @@ export interface AppState {
searchSidebar: SearchSidebarState; searchSidebar: SearchSidebarState;
searchFilter: SearchFiltersState; searchFilter: SearchFiltersState;
truncatable: TruncatablesState; truncatable: TruncatablesState;
adminSidebarSection: AdminSidebarSectionsState;
} }
export const appReducers: ActionReducerMap<AppState> = { export const appReducers: ActionReducerMap<AppState> = {
@@ -36,7 +41,8 @@ export const appReducers: ActionReducerMap<AppState> = {
notifications: notificationsReducer, notifications: notificationsReducer,
searchSidebar: sidebarReducer, searchSidebar: sidebarReducer,
searchFilter: filterReducer, searchFilter: filterReducer,
truncatable: truncatableReducer truncatable: truncatableReducer,
adminSidebarSection: sidebarSectionReducer
}; };
export const routerStateSelector = (state: AppState) => state.router; export const routerStateSelector = (state: AppState) => state.router;

View File

@@ -1,10 +1,10 @@
import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core'; import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core';
import { createSelector, Store } from '@ngrx/store'; import { createSelector, select, Store } from '@ngrx/store';
import { AppState } from '../app.reducer'; import { AppState } from '../app.reducer';
import { Observable } from 'rxjs/Observable';
import { NavbarState } from '../navbar/navbar.reducer'; import { NavbarState } from '../navbar/navbar.reducer';
import { Subscription } from 'rxjs/Subscription';
import { hasValue } from '../shared/empty.util'; import { hasValue } from '../shared/empty.util';
import { Observable } from 'rxjs/internal/Observable';
import { Subscription } from 'rxjs/internal/Subscription';
const navbarStateSelector = (state: AppState) => state.navbar; const navbarStateSelector = (state: AppState) => state.navbar;
const navCollapsedSelector = createSelector(navbarStateSelector, (navbar: NavbarState) => navbar.navCollapsed); const navCollapsedSelector = createSelector(navbarStateSelector, (navbar: NavbarState) => navbar.navCollapsed);
@@ -24,7 +24,7 @@ export class HeaderNavbarWrapperComponent implements OnInit, OnDestroy {
} }
ngOnInit(): void { ngOnInit(): void {
this.isNavBarCollapsed = this.store.select(navCollapsedSelector); this.isNavBarCollapsed = this.store.pipe(select(navCollapsedSelector));
this.sub = this.isNavBarCollapsed.subscribe((isCollapsed) => this.isOpen = !isCollapsed) this.sub = this.isNavBarCollapsed.subscribe((isCollapsed) => this.isOpen = !isCollapsed)
} }

View File

@@ -10,7 +10,7 @@
<button class="navbar-toggler" type="button" (click)="toggle()" <button class="navbar-toggler" type="button" (click)="toggle()"
aria-controls="collapsingNav" aria-controls="collapsingNav"
aria-expanded="false" aria-label="Toggle navigation"> aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon fa fa-bars fa-fw" aria-hidden="true"></span> <span class="navbar-toggler-icon fas fa-bars fa-fw" aria-hidden="true"></span>
</button> </button>
</div> </div>
</nav> </nav>

View File

@@ -1,8 +1,8 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { NavbarToggleAction } from '../navbar/navbar.actions'; import { NavbarToggleAction } from '../navbar/navbar.actions';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '../app.reducer'; import { AppState } from '../app.reducer';
import { Observable } from 'rxjs/internal/Observable';
@Component({ @Component({
selector: 'ds-header', selector: 'ds-header',

View File

@@ -49,7 +49,7 @@ describe('NavbarComponent', () => {
comp = fixture.componentInstance; comp = fixture.componentInstance;
store = fixture.debugElement.injector.get(Store) as Store<HeaderState>; store = fixture.debugElement.injector.get(Store) as Store<NavbarState>;
spyOn(store, 'dispatch'); spyOn(store, 'dispatch');
}); });

View File

@@ -1,10 +1,10 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { AppState } from '../app.reducer'; import { AppState } from '../app.reducer';
import { slideMobileNav } from '../shared/animations/slide'; import { slideMobileNav } from '../shared/animations/slide';
import { HostWindowService } from '../shared/host-window.service'; import { HostWindowService } from '../shared/host-window.service';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { Observable } from 'rxjs/internal/Observable';
@Component({ @Component({
selector: 'ds-navbar', selector: 'ds-navbar',

View File

@@ -1,25 +1,25 @@
<ul class="navbar-nav" [ngClass]="{'mr-auto': (isXsOrSm$ | async)}"> <ul class="navbar-nav" [ngClass]="{'mr-auto': (isXsOrSm$ | async)}">
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item" (click)="$event.stopPropagation();"> <li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item" (click)="$event.stopPropagation();">
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut> <div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
<a href="#" id="dropdownLogin" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="caret"></span></a> <a href="#" id="dropdownLogin" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fas fa-sign-in-alt fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="caret"></span></a>
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin"> <div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
<ds-log-in></ds-log-in> <ds-log-in></ds-log-in>
</div> </div>
</div> </div>
</li> </li>
<li *ngIf="!(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item"> <li *ngIf="!(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
<a id="loginLink" class="nav-link" routerLink="/login" routerLinkActive="active"><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span></a> <a id="loginLink" class="nav-link" routerLink="/login" routerLinkActive="active"><i class="fas fa-sign-in-alt fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span></a>
</li> </li>
<li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"> <li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item">
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut> <div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
<a href="#" id="dropdownUser" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fa fa-user fa-fw" aria-hidden="true"></i>Hello {{(user | async).name}}<span class="caret"></span></a> <a href="#" id="dropdownUser" class="nav-link" (click)="$event.preventDefault()" ngbDropdownToggle><i class="fas fa-user fa-fw" aria-hidden="true"></i>Hello {{(user | async).name}}<span class="caret"></span></a>
<div id="logoutDropdownMenu" ngbDropdownMenu aria-labelledby="dropdownUser"> <div id="logoutDropdownMenu" ngbDropdownMenu aria-labelledby="dropdownUser">
<ds-log-out></ds-log-out> <ds-log-out></ds-log-out>
</div> </div>
</div> </div>
</li> </li>
<li *ngIf="(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item"> <li *ngIf="(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
<a id="logoutLink" class="nav-link" routerLink="/logout" routerLinkActive="active"><i class="fa fa-sign-out fa-fw" aria-hidden="true"></i> {{ 'nav.logout' | translate }}<span class="sr-only">(current)</span></a> <a id="logoutLink" class="nav-link" routerLink="/logout" routerLinkActive="active"><i class="fas fa-sign-out-alt fa-fw" aria-hidden="true"></i> {{ 'nav.logout' | translate }}<span class="sr-only">(current)</span></a>
</li> </li>
</ul> </ul>

View File

@@ -15,7 +15,7 @@
[ngbTooltip]="tipContent" [ngbTooltip]="tipContent"
triggers="manual" triggers="manual"
#t="ngbTooltip" #t="ngbTooltip"
class="fa {{icon.style}}" class="fas {{icon.style}}"
[class.mr-1]="!l" [class.mr-1]="!l"
[class.mr-2]="l" [class.mr-2]="l"
aria-hidden="true" aria-hidden="true"
@@ -23,7 +23,7 @@
(mouseover)="showTooltip(t, i, icon.metadata)" (mouseover)="showTooltip(t, i, icon.metadata)"
(mouseout)="t.close()"></i> (mouseout)="t.close()"></i>
</ng-container> </ng-container>
<p class="chip-label text-truncate d-table-cell">{{c.display}}</p><i class="fa fa-times ml-2" (click)="removeChips($event, i)"></i> <p class="chip-label text-truncate d-table-cell">{{c.display}}</p><i class="fas fa-times ml-2" (click)="removeChips($event, i)"></i>
</span> </span>
</a> </a>
</li> </li>

View File

@@ -34,14 +34,14 @@ describe('ChipsItem model test suite', () => {
}); });
it('should update icons', () => { it('should update icons', () => {
const icons: ChipsItemIcon[] = [{metadata: 'test', hasAuthority: false, style: 'fa fa-plus'}]; const icons: ChipsItemIcon[] = [{metadata: 'test', hasAuthority: false, style: 'fas fa-plus'}];
item.updateIcons(icons); item.updateIcons(icons);
expect(item.icons).toEqual(icons); expect(item.icons).toEqual(icons);
}); });
it('should return true if has icons', () => { it('should return true if has icons', () => {
const icons: ChipsItemIcon[] = [{metadata: 'test', hasAuthority: false, style: 'fa fa-plus'}]; const icons: ChipsItemIcon[] = [{metadata: 'test', hasAuthority: false, style: 'fas fa-plus'}];
item.updateIcons(icons); item.updateIcons(icons);
const hasIcons = item.hasIcons(); const hasIcons = item.hasIcons();

View File

@@ -27,7 +27,7 @@ export const DATE_TEST_MODEL_CONFIG = {
placeholder: 'Date', placeholder: 'Date',
readOnly: false, readOnly: false,
required: true, required: true,
toggleIcon: 'fa fa-calendar' toggleIcon: 'fas fa-calendar'
}; };
describe('DsDatePickerComponent test suite', () => { describe('DsDatePickerComponent test suite', () => {

View File

@@ -2,7 +2,7 @@
class="close position-relative" class="close position-relative"
ngbTooltip="{{'form.group-collapse-help' | translate}}" ngbTooltip="{{'form.group-collapse-help' | translate}}"
placement="left"> placement="left">
<span class="fa fa-angle-up fa-fw fa-2x" <span class="fas fa-angle-up fa-fw fa-2x"
aria-hidden="true" aria-hidden="true"
(click)="collapseForm()"></span> (click)="collapseForm()"></span>
</a> </a>
@@ -10,7 +10,7 @@
class="close position-relative" class="close position-relative"
ngbTooltip="{{'form.group-expand-help' | translate}}" ngbTooltip="{{'form.group-expand-help' | translate}}"
placement="left"> placement="left">
<span class="fa fa-angle-down fa-fw fa-2x" <span class="fas fa-angle-down fa-fw fa-2x"
aria-hidden="true" aria-hidden="true"
(click)="expandForm()"></span> (click)="expandForm()"></span>
</a> </a>
@@ -33,21 +33,21 @@
class="btn btn-link" class="btn btn-link"
[disabled]="isMandatoryFieldEmpty()" [disabled]="isMandatoryFieldEmpty()"
(click)="save()"> (click)="save()">
<i class="fa fa-save text-primary fa-2x" <i class="fas fa-save text-primary fa-2x"
aria-hidden="true"></i> aria-hidden="true"></i>
</button> </button>
<button type="button" <button type="button"
class="btn btn-link" class="btn btn-link"
[disabled]="!editMode" [disabled]="!editMode"
(click)="delete()"> (click)="delete()">
<i class="fa fa-trash text-danger fa-2x" <i class="fas fa-trash text-danger fa-2x"
aria-hidden="true"></i> aria-hidden="true"></i>
</button> </button>
<button type="button" <button type="button"
class="btn btn-link" class="btn btn-link"
[disabled]="isMandatoryFieldEmpty()" [disabled]="isMandatoryFieldEmpty()"
(click)="clear()"> (click)="clear()">
<i class="fa fa-undo fa-2x" <i class="fas fa-undo fa-2x"
aria-hidden="true"></i> aria-hidden="true"></i>
</button> </button>

View File

@@ -41,6 +41,6 @@
(keypress)="preventEventsPropagation($event)" (keypress)="preventEventsPropagation($event)"
(keydown)="preventEventsPropagation($event)" (keydown)="preventEventsPropagation($event)"
(keyup)="onKeyUp($event)"/> (keyup)="onKeyUp($event)"/>
<i *ngIf="searching" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw text-primary position-absolute mt-1 p-0" aria-hidden="true"></i> <i *ngIf="searching" class="fas fa-circle-o-notch fa-spin fa-2x fa-fw text-primary position-absolute mt-1 p-0" aria-hidden="true"></i>
</ds-chips> </ds-chips>

View File

@@ -2,7 +2,7 @@
{{ r.display}} {{ r.display}}
</ng-template> </ng-template>
<div class="position-relative right-addon"> <div class="position-relative right-addon">
<i *ngIf="searching" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw text-primary position-absolute mt-1 p-0" aria-hidden="true"></i> <i *ngIf="searching" class="fas fa-circle-o-notch fa-spin fa-2x fa-fw text-primary position-absolute mt-1 p-0" aria-hidden="true"></i>
<input class="form-control" <input class="form-control"
[attr.autoComplete]="model.autoComplete" [attr.autoComplete]="model.autoComplete"
[class.is-invalid]="showErrorMessages" [class.is-invalid]="showErrorMessages"

View File

@@ -11,7 +11,7 @@ export class DateFieldParser extends FieldParser {
let malformedDate = false; let malformedDate = false;
const inputDateModelConfig: DynamicDatePickerModelConfig = this.initModel(null, label); const inputDateModelConfig: DynamicDatePickerModelConfig = this.initModel(null, label);
inputDateModelConfig.toggleIcon = 'fa fa-calendar'; inputDateModelConfig.toggleIcon = 'fas fa-calendar';
this.setValues(inputDateModelConfig as any, fieldValue); this.setValues(inputDateModelConfig as any, fieldValue);
// Init Data and validity check // Init Data and validity check
if (isNotEmpty(inputDateModelConfig.value)) { if (isNotEmpty(inputDateModelConfig.value)) {

View File

@@ -20,12 +20,12 @@
<button type="button" class="btn btn-secondary" <button type="button" class="btn btn-secondary"
[disabled]="isItemReadOnly(context, index)" [disabled]="isItemReadOnly(context, index)"
(click)="insertItem($event, group.context, group.index + 1)"> (click)="insertItem($event, group.context, group.index + 1)">
<i class="fa fa-plus" aria-hidden="true"></i> <i class="fas fa-plus" aria-hidden="true"></i>
</button> </button>
<button type="button" class="btn btn-secondary" <button type="button" class="btn btn-secondary"
(click)="removeItem($event, context, index)" (click)="removeItem($event, context, index)"
[disabled]="group.context.groups.length === 1 || isItemReadOnly(context, index)"> [disabled]="group.context.groups.length === 1 || isItemReadOnly(context, index)">
<i class="fa fa-trash" aria-hidden="true"></i> <i class="fas fa-trash" aria-hidden="true"></i>
</button> </button>
</div> </div>
</div> </div>
@@ -37,7 +37,7 @@
<button type="button" class="btn btn-secondary" <button type="button" class="btn btn-secondary"
(click)="removeItem($event, context, index)" (click)="removeItem($event, context, index)"
[disabled]="group.context.groups.length === 1 || isItemReadOnly(context, index)"> [disabled]="group.context.groups.length === 1 || isItemReadOnly(context, index)">
<i class="fa fa-trash" aria-hidden="true"></i> <i class="fas fa-trash" aria-hidden="true"></i>
</button> </button>
</div> </div>
</div> </div>

View File

@@ -15,7 +15,7 @@
<div class="d-flex flex-row"> <div class="d-flex flex-row">
<div class="d-flex flex-column justify-content-center align-items-center"> <div class="d-flex flex-column justify-content-center align-items-center">
<div class="notification-icon d-flex justify-content-center"><i <div class="notification-icon d-flex justify-content-center"><i
[ngClass]="{'fa fa-2x': true, [ngClass]="{'fas fa-2x': true,
'fa-check': notification.type == 'alert-success', 'fa-check': notification.type == 'alert-success',
'fa-times-circle': notification.type == 'alert-danger', 'fa-times-circle': notification.type == 'alert-danger',
'fa-exclamation-triangle': notification.type == 'alert-warning', 'fa-exclamation-triangle': notification.type == 'alert-warning',

View File

@@ -7,12 +7,12 @@
</div> </div>
<div class="col"> <div class="col">
<div *ngIf="!hideGear" ngbDropdown #paginationControls="ngbDropdown" placement="bottom-right" class="d-inline-block float-right"> <div *ngIf="!hideGear" ngbDropdown #paginationControls="ngbDropdown" placement="bottom-right" class="d-inline-block float-right">
<button class="btn btn-outline-primary" id="paginationControls" ngbDropdownToggle><i class="fa fa-cog" aria-hidden="true"></i></button> <button class="btn btn-outline-primary" id="paginationControls" ngbDropdownToggle><i class="fas fa-cog" aria-hidden="true"></i></button>
<div id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" ngbDropdownMenu> <div id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" ngbDropdownMenu>
<h6 class="dropdown-header">{{ 'pagination.results-per-page' | translate}}</h6> <h6 class="dropdown-header">{{ 'pagination.results-per-page' | translate}}</h6>
<button class="dropdown-item" *ngFor="let item of pageSizeOptions" (click)="doPageSizeChange(item)"><i [ngClass]="{'invisible': item != pageSize}" class="fa fa-check" aria-hidden="true"></i> {{item}} </button> <button class="dropdown-item" *ngFor="let item of pageSizeOptions" (click)="doPageSizeChange(item)"><i [ngClass]="{'invisible': item != pageSize}" class="fas fa-check" aria-hidden="true"></i> {{item}} </button>
<h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6> <h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6>
<button class="dropdown-item" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== sortDirection}" class="fa fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button> <button class="dropdown-item" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== sortDirection}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -76,7 +76,6 @@ import { NumberPickerComponent } from './number-picker/number-picker.component';
import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component';
import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
import { MockAdminGuard } from './mocks/mock-admin-guard.service'; import { MockAdminGuard } from './mocks/mock-admin-guard.service';
import { BrowseByModule } from '../+browse-by/browse-by.module';
import { BrowseByComponent } from './browse-by/browse-by.component'; import { BrowseByComponent } from './browse-by/browse-by.component';
import { BrowseEntryListElementComponent } from './object-list/browse-entry-list-element/browse-entry-list-element.component'; import { BrowseEntryListElementComponent } from './object-list/browse-entry-list-element/browse-entry-list-element.component';
import { DebounceDirective } from './utils/debounce.directive'; import { DebounceDirective } from './utils/debounce.directive';

View File

@@ -19,7 +19,7 @@
(fileOver)="fileOverBase($event)" (fileOver)="fileOverBase($event)"
class="well ds-base-drop-zone mt-1 mb-3 text-muted"> class="well ds-base-drop-zone mt-1 mb-3 text-muted">
<p class="text-center m-0 pt-2" [hidden]="uploader?.queue?.length !== 0"> <p class="text-center m-0 pt-2" [hidden]="uploader?.queue?.length !== 0">
<span><i class="fa fa-cloud-upload" aria-hidden="true"></i> {{dropMsg | translate}} {{'uploader.or' | translate}} <span><i class="fas fa-cloud-upload" aria-hidden="true"></i> {{dropMsg | translate}} {{'uploader.or' | translate}}
<label class="btn btn-link m-0 p-0"> <label class="btn btn-link m-0 p-0">
<input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple /> <input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple />
{{'uploader.browse' | translate}} {{'uploader.browse' | translate}}
@@ -32,7 +32,7 @@
<span class="filename">{{'uploader.queue-lenght' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }}</span> <span class="filename">{{'uploader.queue-lenght' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }}</span>
<div class="btn-group btn-group-sm float-right" role="group"> <div class="btn-group btn-group-sm float-right" role="group">
<button type="button" class="btn btn-danger" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length"> <button type="button" class="btn btn-danger" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
<i class="fa fa-trash" aria-hidden="true"></i> <i class="fas fa-trash" aria-hidden="true"></i>
</button> </button>
</div> </div>
<span *ngIf="uploader.progress < 100" class="float-right mr-3">{{ uploader.progress }}%</span> <span *ngIf="uploader.progress < 100" class="float-right mr-3">{{ uploader.progress }}%</span>

View File

@@ -6,7 +6,7 @@
routerLinkActive="active" routerLinkActive="active"
[class.active]="currentMode === viewModeEnum.List" [class.active]="currentMode === viewModeEnum.List"
class="btn btn-secondary"> class="btn btn-secondary">
<i class="fa fa-list" title="{{'search.view-switch.show-list' | translate}}"></i> <i class="fas fa-list" title="{{'search.view-switch.show-list' | translate}}"></i>
</a> </a>
<a routerLink="." <a routerLink="."
[queryParams]="{view: 'grid'}" [queryParams]="{view: 'grid'}"
@@ -15,6 +15,6 @@
routerLinkActive="active" routerLinkActive="active"
[class.active]="currentMode !== viewModeEnum.List" [class.active]="currentMode !== viewModeEnum.List"
class="btn btn-secondary"> class="btn btn-secondary">
<i class="fa fa-th-large" title="{{'search.view-switch.show-grid' | translate}}"></i> <i class="fas fa-th-large" title="{{'search.view-switch.show-grid' | translate}}"></i>
</a> </a>
</div> </div>

View File

@@ -14,3 +14,6 @@ $nav-z-index: 10;
$sidebar-z-index: 20; $sidebar-z-index: 20;
$header-logo-height: 80px; $header-logo-height: 80px;
$admin-sidebar-dark: #0a1118;
$admin-sidebar-width: 250px;

View File

@@ -0,0 +1,5 @@
@import "../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/solid.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/brands.scss";
@import "../../node_modules/@fortawesome/fontawesome-free/scss/regular.scss";

View File

@@ -1,5 +1,4 @@
@import 'bootstrap_variables.scss'; @import 'bootstrap_variables.scss';
@import '../../node_modules/font-awesome/scss/variables.scss';
@import '../../node_modules/bootstrap/scss/functions.scss'; @import '../../node_modules/bootstrap/scss/functions.scss';
@import '../../node_modules/bootstrap/scss/variables.scss'; @import '../../node_modules/bootstrap/scss/variables.scss';
@import '_functions.scss'; @import '_functions.scss';

View File

@@ -90,7 +90,7 @@ module.exports = {
}, },
plugins: [ plugins: [
new CopyWebpackPlugin([{ new CopyWebpackPlugin([{
from: join(__dirname, '..', 'node_modules', 'font-awesome', 'fonts'), from: join(__dirname, '..', 'node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'),
to: join('assets', 'fonts') to: join('assets', 'fonts')
}, { }, {
from: join(__dirname, '..', 'resources', 'images'), from: join(__dirname, '..', 'resources', 'images'),

1427
yarn.lock

File diff suppressed because it is too large Load Diff