mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-10 11:33:04 +00:00
57053: intermediate commit active issue
This commit is contained in:
@@ -213,71 +213,37 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"section": {
|
"section": {
|
||||||
"new": {
|
"new": "New",
|
||||||
"header": "New",
|
"new_community": "Community",
|
||||||
"subsections": {
|
"new_collection": "Collection",
|
||||||
"community": "Community",
|
"new_item": "Item",
|
||||||
"collection": "Collection",
|
"new_item_version": "Item Version",
|
||||||
"item": "Item",
|
"edit": "Edit",
|
||||||
"item_version": "Item Version"
|
"edit_community": "Community",
|
||||||
}
|
"edit_collection": "Collection",
|
||||||
},
|
"edit_item": "Item",
|
||||||
"edit": {
|
"import": "Import",
|
||||||
"header": "Edit",
|
"import_metadata": "Metadata",
|
||||||
"subsections": {
|
"import_batch": "Batch Import (ZIP)",
|
||||||
"community": "Community",
|
"export": "Export",
|
||||||
"collection": "Collection",
|
"export_community": "Community",
|
||||||
"item": "Item"
|
"export_collection": "Collection",
|
||||||
}
|
"export_item": "Item",
|
||||||
},
|
"export_metadata": "Metadata",
|
||||||
"import": {
|
"access_control": "Access Control",
|
||||||
"header": "Import",
|
"access_control_people": "People",
|
||||||
"subsections": {
|
"access_control_groups": "Groups",
|
||||||
"metadata": "Metadata",
|
"access_control_authorizations": "Authorizations",
|
||||||
"batch_import": "Batch Import (ZIP)"
|
"find": "Find",
|
||||||
}
|
"find_items": "Items",
|
||||||
},
|
"find_withdrawn_items": "Withdrawn Items",
|
||||||
"export": {
|
"find_private_items": "Private Items",
|
||||||
"header": "Export",
|
"registries": "Registries",
|
||||||
"subsections": {
|
"registries_metadata": "Metadata",
|
||||||
"community": "Community",
|
"registries_format": "Format",
|
||||||
"collection": "Collection",
|
"curation_task": "Curation Task",
|
||||||
"item": "Item",
|
"statistics": "Statistics Task",
|
||||||
"metadata": "Metadata"
|
"control_panel": "Control Panel"
|
||||||
}
|
|
||||||
},
|
|
||||||
"access_control": {
|
|
||||||
"header": "Access Control",
|
|
||||||
"subsections": {
|
|
||||||
"people": "People",
|
|
||||||
"groups": "Groups",
|
|
||||||
"authorizations": "Authorizations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"find": {
|
|
||||||
"header": "Find",
|
|
||||||
"subsections": {
|
|
||||||
"items": "Items",
|
|
||||||
"withdrawn_items": "Withdrawn Items",
|
|
||||||
"private_items": "Private Items"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"registries": {
|
|
||||||
"header": "Registries",
|
|
||||||
"subsections": {
|
|
||||||
"metadata": "Metadata",
|
|
||||||
"format": "Format"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"curation_task": {
|
|
||||||
"header": "Curation Task"
|
|
||||||
},
|
|
||||||
"statistics": {
|
|
||||||
"header": "Statistics Task"
|
|
||||||
},
|
|
||||||
"control_panel": {
|
|
||||||
"header": "Control Panel"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
<li class="sidebar-section">
|
<li class="sidebar-section">
|
||||||
<a class="nav-item nav-link shortcut-icon" [href]="link">
|
<a class="nav-item nav-link shortcut-icon">
|
||||||
<i class="fas fa-{{icon}} fa-fw"></i>
|
<i class="fas fa-{{section.icon}} fa-fw"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="sidebar-collapsible">
|
<div class="sidebar-collapsible">
|
||||||
<a class="nav-item nav-link" [href]="link">
|
<span class="section-header-text">
|
||||||
<span class="section-header-text"> {{('admin.sidebar.section.' + name + '.header') | translate}}</span>
|
<ng-container
|
||||||
</a>
|
*ngComponentOutlet="getMenuItemComponent(); injector: getItemModelInjector();"></ng-container>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
@@ -1,4 +1,8 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Inject, Injector, Input, OnInit } from '@angular/core';
|
||||||
|
import { MenuSectionComponent } from '../../../shared/menu/menu-section/menu-section.component';
|
||||||
|
import { MenuID } from '../../../shared/menu/initial-menus-state';
|
||||||
|
import { rendersSectionForMenu } from '../../../shared/menu/menu.decorator';
|
||||||
|
import { MenuService } from '../../../shared/menu/menu.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-admin-sidebar-section',
|
selector: 'ds-admin-sidebar-section',
|
||||||
@@ -6,8 +10,15 @@ import { Component, Input } from '@angular/core';
|
|||||||
styleUrls: ['./admin-sidebar-section.component.scss'],
|
styleUrls: ['./admin-sidebar-section.component.scss'],
|
||||||
|
|
||||||
})
|
})
|
||||||
export class AdminSidebarSectionComponent {
|
@rendersSectionForMenu(MenuID.ADMIN, false)
|
||||||
@Input() name: string;
|
export class AdminSidebarSectionComponent extends MenuSectionComponent implements OnInit {
|
||||||
@Input() link: string;
|
menuID: MenuID = MenuID.ADMIN;
|
||||||
@Input() icon: string;
|
|
||||||
|
constructor(@Inject('sectionDataProvider') menuSection, protected menuService: MenuService, protected injector: Injector,) {
|
||||||
|
super(menuSection, menuService, injector);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
super.ngOnInit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,98 +0,0 @@
|
|||||||
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 AdminSidebarActionTypes = {
|
|
||||||
SECTION_COLLAPSE: type('dspace/admin-sidebar/SECTION_COLLAPSE'),
|
|
||||||
SECTION_COLLAPSE_ALL: type('dspace/admin-sidebar/SECTION_COLLAPSE_ALL'),
|
|
||||||
SECTION_EXPAND: type('dspace/admin-sidebar/SECTION_EXPAND'),
|
|
||||||
SECTION_TOGGLE: type('dspace/admin-sidebar/SECTION_TOGGLE'),
|
|
||||||
COLLAPSE: type('dspace/admin-sidebar/COLLAPSE'),
|
|
||||||
EXPAND: type('dspace/admin-sidebar/EXPAND'),
|
|
||||||
TOGGLE: type('dspace/admin-sidebar/TOGGLE'),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
|
||||||
export class AdminSidebarAction implements Action {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of action that will be performed
|
|
||||||
*/
|
|
||||||
type;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminSidebarSectionAction extends AdminSidebarAction {
|
|
||||||
/**
|
|
||||||
* Name of the section the action is performed on, used to identify the section
|
|
||||||
*/
|
|
||||||
sectionName: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize with the section's name
|
|
||||||
* @param {string} name of the section
|
|
||||||
*/
|
|
||||||
constructor(name: string) {
|
|
||||||
super();
|
|
||||||
this.sectionName = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
|
||||||
/**
|
|
||||||
* Used to collapse the sidebar
|
|
||||||
*/
|
|
||||||
export class AdminSidebarCollapseAction extends AdminSidebarAction {
|
|
||||||
type = AdminSidebarActionTypes.COLLAPSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to expand the sidebar
|
|
||||||
*/
|
|
||||||
export class AdminSidebarExpandAction extends AdminSidebarAction {
|
|
||||||
type = AdminSidebarActionTypes.EXPAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to collapse the sidebar when it's expanded and expand it when it's collapsed
|
|
||||||
*/
|
|
||||||
export class AdminSidebarToggleAction extends AdminSidebarAction {
|
|
||||||
type = AdminSidebarActionTypes.TOGGLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to collapse a section
|
|
||||||
*/
|
|
||||||
export class AdminSidebarSectionCollapseAction extends AdminSidebarSectionAction {
|
|
||||||
type = AdminSidebarActionTypes.SECTION_COLLAPSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to collapse a section
|
|
||||||
*/
|
|
||||||
export class AdminSidebarSectionCollapseAllAction extends AdminSidebarAction {
|
|
||||||
type = AdminSidebarActionTypes.SECTION_COLLAPSE_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to expand a section
|
|
||||||
*/
|
|
||||||
export class AdminSidebarSectionExpandAction extends AdminSidebarSectionAction {
|
|
||||||
type = AdminSidebarActionTypes.SECTION_EXPAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to collapse a section when it's expanded and expand it when it's collapsed
|
|
||||||
*/
|
|
||||||
export class AdminSidebarSectionToggleAction extends AdminSidebarSectionAction {
|
|
||||||
type = AdminSidebarActionTypes.SECTION_TOGGLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tslint:enable:max-classes-per-file */
|
|
@@ -1,7 +1,7 @@
|
|||||||
<nav class="navbar navbar-dark bg-dark p-0"
|
<nav class="navbar navbar-dark bg-dark p-0"
|
||||||
[ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}"
|
[ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}"
|
||||||
[@slideSidebar]="{
|
[@slideSidebar]="{
|
||||||
value: ((sidebarCollapsed | async) ? 'collapsed' : 'expanded'),
|
value: ((menuCollapsed | async) ? 'collapsed' : 'expanded'),
|
||||||
params: {sidebarWidth: (sidebarWidth | async)}
|
params: {sidebarWidth: (sidebarWidth | async)}
|
||||||
}" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)">
|
}" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)">
|
||||||
<div class="sidebar-top-level-items">
|
<div class="sidebar-top-level-items">
|
||||||
@@ -18,47 +18,10 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<ds-expandable-admin-sidebar-section name="new" icon="plus-circle" [subSections]="[
|
<li *ngFor="let section of (sections | async)">
|
||||||
{name: 'Community', link: '#'},
|
<ng-container
|
||||||
{name: 'Collection', link: '#'},
|
*ngComponentOutlet="(getSectionComponent(section) | async); injector: getSectionDataInjector(section);"></ng-container>
|
||||||
{name: 'Item', link: '#'},
|
</li>
|
||||||
{name: 'Item Version', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="edit" icon="pencil-alt" [subSections]="[
|
|
||||||
{name: 'Community', link: '#'},
|
|
||||||
{name: 'Collection', link: '#'},
|
|
||||||
{name: 'Item', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="import" icon="sign-in-alt" [subSections]="[
|
|
||||||
{name: 'Metadata', link: '#'},
|
|
||||||
{name: 'Batch Import (ZIP)', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="export" icon="sign-out-alt" [subSections]="[
|
|
||||||
{name: 'Community', link: '#'},
|
|
||||||
{name: 'Collection', link: '#'},
|
|
||||||
{name: 'Item', link: '#'},
|
|
||||||
{name: 'Metadata', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="access_control" icon="key" [subSections]="[
|
|
||||||
{name: 'People', link: '#'},
|
|
||||||
{name: 'Groups', link: '#'},
|
|
||||||
{name: 'Authorizations', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="find" icon="search" [subSections]="[
|
|
||||||
{name: 'Items', link: '#'},
|
|
||||||
{name: 'Withdrawn Items', link: '#'},
|
|
||||||
{name: 'Private Items', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-expandable-admin-sidebar-section name="registries" icon="list" [subSections]="[
|
|
||||||
{name: 'Metadata', link: '#'},
|
|
||||||
{name: 'Format', link: '#'}
|
|
||||||
]"></ds-expandable-admin-sidebar-section>
|
|
||||||
<ds-admin-sidebar-section name="curation_task" icon="filter"
|
|
||||||
link="#"></ds-admin-sidebar-section>
|
|
||||||
<ds-admin-sidebar-section name="statistics" icon="chart-bar"
|
|
||||||
link="#"></ds-admin-sidebar-section>
|
|
||||||
<ds-admin-sidebar-section name="control_panel" icon="cogs"
|
|
||||||
link="#"></ds-admin-sidebar-section>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-nav">
|
<div class="navbar-nav">
|
||||||
@@ -67,7 +30,7 @@
|
|||||||
href="#"
|
href="#"
|
||||||
(click)="toggle($event)">
|
(click)="toggle($event)">
|
||||||
<i class="fas fa-fw fa-angle-double-right"
|
<i class="fas fa-fw fa-angle-double-right"
|
||||||
[ngClass]="{'fa-angle-double-right': (sidebarCollapsed | async), 'fa-angle-double-left': !(sidebarCollapsed | async)}"></i>
|
[ngClass]="{'fa-angle-double-right': (menuCollapsed | async), 'fa-angle-double-left': !(menuCollapsed | async)}"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="sidebar-collapsible">
|
<div class="sidebar-collapsible">
|
||||||
<a class="nav-item nav-link sidebar-section"
|
<a class="nav-item nav-link sidebar-section"
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, Injector, OnInit } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { slideSidebar } from '../../shared/animations/slide';
|
import { slideSidebar } from '../../shared/animations/slide';
|
||||||
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
||||||
import { AdminSidebarService } from './admin-sidebar.service';
|
import { MenuService } from '../../shared/menu/menu.service';
|
||||||
|
import { MenuID, SectionType } from '../../shared/menu/initial-menus-state';
|
||||||
|
import { MenuComponent } from '../../shared/menu/menu.component';
|
||||||
|
import { TextSectionTypeModel } from '../../shared/menu/models/section-types/text.model';
|
||||||
|
import { LinkSectionTypeModel } from '../../shared/menu/models/section-types/link.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-admin-sidebar',
|
selector: 'ds-admin-sidebar',
|
||||||
@@ -10,28 +14,264 @@ import { AdminSidebarService } from './admin-sidebar.service';
|
|||||||
styleUrls: ['./admin-sidebar.component.scss'],
|
styleUrls: ['./admin-sidebar.component.scss'],
|
||||||
animations: [slideSidebar]
|
animations: [slideSidebar]
|
||||||
})
|
})
|
||||||
export class AdminSidebarComponent implements OnInit {
|
export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||||
sidebarCollapsed: Observable<boolean>;
|
menuID = MenuID.ADMIN;
|
||||||
sidebarWidth: Observable<string>;
|
sidebarWidth: Observable<string>;
|
||||||
sidebarOpen = true;
|
sidebarOpen = true;
|
||||||
sidebarClosed = !this.sidebarOpen;
|
sidebarClosed = !this.sidebarOpen;
|
||||||
|
|
||||||
constructor(private sidebarService: AdminSidebarService,
|
constructor(protected menuService: MenuService,
|
||||||
|
protected injector: Injector,
|
||||||
private variableService: CSSVariableService) {
|
private variableService: CSSVariableService) {
|
||||||
|
super(menuService, injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
super.ngOnInit();
|
||||||
this.sidebarWidth = this.variableService.getVariable('adminSidebarWidth');
|
this.sidebarWidth = this.variableService.getVariable('adminSidebarWidth');
|
||||||
this.sidebarCollapsed = this.sidebarService.isSidebarCollapsed();
|
this.createMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(event: Event) {
|
createMenu() {
|
||||||
event.preventDefault();
|
const menuList = [
|
||||||
// Is sidebar closing?
|
/* News */
|
||||||
if (this.sidebarOpen) {
|
{
|
||||||
this.sidebarService.collapseAllSections();
|
id: 'new',
|
||||||
}
|
active: false,
|
||||||
this.sidebarService.toggleSidebar();
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.new' } as TextSectionTypeModel,
|
||||||
|
icon: 'plus-circle'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'new_community',
|
||||||
|
parentID: 'new',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_community', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'new_collection',
|
||||||
|
parentID: 'new',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_collection', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'new_item',
|
||||||
|
parentID: 'new',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_item', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'new_item_version',
|
||||||
|
parentID: 'new',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_item_version', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Edit */
|
||||||
|
{
|
||||||
|
id: 'edit',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.edit' } as TextSectionTypeModel,
|
||||||
|
icon: 'pencil-alt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'edit_community',
|
||||||
|
parentID: 'edit',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_community', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'edit_collection',
|
||||||
|
parentID: 'edit',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_collection', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'edit_item',
|
||||||
|
parentID: 'edit',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_item', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Import */
|
||||||
|
{
|
||||||
|
id: 'import',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.import' } as TextSectionTypeModel,
|
||||||
|
icon: 'sign-in-alt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'import_metadata',
|
||||||
|
parentID: 'import',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.import_metadata', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'import_batch',
|
||||||
|
parentID: 'import',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.import_batch', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Export */
|
||||||
|
{
|
||||||
|
id: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.export' } as TextSectionTypeModel,
|
||||||
|
icon: 'sign-out-alt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'export_community',
|
||||||
|
parentID: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_community', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'export_collection',
|
||||||
|
parentID: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_collection', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'export_item',
|
||||||
|
parentID: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_item', link: '#' } as LinkSectionTypeModel,
|
||||||
|
}, {
|
||||||
|
id: 'export_metadata',
|
||||||
|
parentID: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_metadata', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Access Control */
|
||||||
|
{
|
||||||
|
id: 'access_control',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.access_control' } as TextSectionTypeModel,
|
||||||
|
icon: 'key'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'access_control_people',
|
||||||
|
parentID: 'access_control',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_people', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'access_control_groups',
|
||||||
|
parentID: 'access_control',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_groups', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'access_control_authorizations',
|
||||||
|
parentID: 'access_control',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_authorizations', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Search */
|
||||||
|
{
|
||||||
|
id: 'find',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.find' } as TextSectionTypeModel,
|
||||||
|
icon: 'search'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'find_items',
|
||||||
|
parentID: 'find',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_items', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'find_withdrawn_items',
|
||||||
|
parentID: 'find',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_withdrawn_items', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'find_private_items',
|
||||||
|
parentID: 'find',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_private_items', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Registries */
|
||||||
|
{
|
||||||
|
id: 'registries',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.TEXT, text: 'admin.sidebar.section.registries' } as TextSectionTypeModel,
|
||||||
|
icon: 'list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'registries_metadata',
|
||||||
|
parentID: 'registries',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.registries_metadata', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'registries_format',
|
||||||
|
parentID: 'registries',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.registries_format', link: '#' } as LinkSectionTypeModel,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Curation tasks */
|
||||||
|
{
|
||||||
|
id: 'curation_tasks',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.curation_task', link: '#' } as LinkSectionTypeModel,
|
||||||
|
icon: 'filter'
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Statistics */
|
||||||
|
{
|
||||||
|
id: 'statistics',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.statistics', link: '#' } as LinkSectionTypeModel,
|
||||||
|
icon: 'chart-bar'
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Control Panel */
|
||||||
|
{
|
||||||
|
id: 'control_panel',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: { type: SectionType.LINK, text: 'admin.sidebar.section.control_panel', link: '#' } as LinkSectionTypeModel,
|
||||||
|
icon: 'cogs'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, menuSection));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,114 +0,0 @@
|
|||||||
import {
|
|
||||||
AdminSidebarAction,
|
|
||||||
AdminSidebarSectionAction,
|
|
||||||
AdminSidebarActionTypes
|
|
||||||
} from './admin-sidebar.actions';
|
|
||||||
import { hasValue } from '../../shared/empty.util';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface that represents the state for a single sidebar section
|
|
||||||
*/
|
|
||||||
export interface AdminSidebarSectionState {
|
|
||||||
sectionCollapsed: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminSidebarSectionsState {
|
|
||||||
[name: string]: AdminSidebarSectionState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface that represents the state of the admin sidebar and its sections
|
|
||||||
*/
|
|
||||||
export interface AdminSidebarState {
|
|
||||||
sections: AdminSidebarSectionsState,
|
|
||||||
collapsed: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: AdminSidebarState = Object.create(null);
|
|
||||||
const initiallySectionCollapsed = true;
|
|
||||||
const initiallyCollapsed = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a sidebar action on the current state
|
|
||||||
* @param {AdminSidebarState} state The state before the action is performed
|
|
||||||
* @param {AdminSidebarAction} action The action that should be performed
|
|
||||||
* @returns {AdminSidebarState} The state after the action is performed
|
|
||||||
*/
|
|
||||||
export function adminSidebarReducer(state = initialState, action: AdminSidebarAction): AdminSidebarState {
|
|
||||||
|
|
||||||
if (action instanceof AdminSidebarSectionAction) {
|
|
||||||
return reduceSectionAction(state, action);
|
|
||||||
} else {
|
|
||||||
switch (action.type) {
|
|
||||||
case AdminSidebarActionTypes.COLLAPSE: {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
collapsed: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
case AdminSidebarActionTypes.EXPAND: {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
collapsed: false
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
case AdminSidebarActionTypes.TOGGLE: {
|
|
||||||
const currentState = state.collapsed;
|
|
||||||
const collapsed = hasValue(currentState) ? currentState : initiallyCollapsed;
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
collapsed: !collapsed
|
|
||||||
});
|
|
||||||
}
|
|
||||||
case AdminSidebarActionTypes.SECTION_COLLAPSE_ALL: {
|
|
||||||
const newSectionState: AdminSidebarSectionState = Object.create(null);
|
|
||||||
if (hasValue(state.sections)) {
|
|
||||||
Object.keys(state.sections).forEach((section) =>
|
|
||||||
newSectionState[section] = {
|
|
||||||
sectionCollapsed: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Object.assign({}, state, { sections: newSectionState });
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function reduceSectionAction(state: AdminSidebarState, action: AdminSidebarSectionAction): AdminSidebarState {
|
|
||||||
switch (action.type) {
|
|
||||||
case AdminSidebarActionTypes.SECTION_COLLAPSE: {
|
|
||||||
const sections = Object.assign({}, state.sections, {
|
|
||||||
[action.sectionName]: {
|
|
||||||
sectionCollapsed: true,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Object.assign({}, state, { sections });
|
|
||||||
}
|
|
||||||
|
|
||||||
case AdminSidebarActionTypes.SECTION_EXPAND: {
|
|
||||||
const sections = Object.assign({}, state.sections, {
|
|
||||||
[action.sectionName]: {
|
|
||||||
sectionCollapsed: false,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Object.assign({}, state, { sections });
|
|
||||||
|
|
||||||
}
|
|
||||||
case AdminSidebarActionTypes.SECTION_TOGGLE: {
|
|
||||||
const currentState = state.sections;
|
|
||||||
const collapsed = (hasValue(currentState) && currentState[action.sectionName]) ? currentState[action.sectionName].sectionCollapsed : initiallySectionCollapsed;
|
|
||||||
const sections = Object.assign({}, state.sections, {
|
|
||||||
[action.sectionName]: {
|
|
||||||
sectionCollapsed: !collapsed,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Object.assign({}, state, { sections });
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,55 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { AppState, keySelector } from '../../app.reducer';
|
|
||||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
|
||||||
import { AdminSidebarSectionState, AdminSidebarState } from './admin-sidebar.reducer';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
|
||||||
import { hasValue } from '../../shared/empty.util';
|
|
||||||
import {
|
|
||||||
AdminSidebarSectionCollapseAllAction,
|
|
||||||
AdminSidebarSectionToggleAction,
|
|
||||||
AdminSidebarToggleAction
|
|
||||||
} from './admin-sidebar.actions';
|
|
||||||
|
|
||||||
const sidebarStateSelector = (state) => state.adminSidebar;
|
|
||||||
const sidebarSectionStateSelector = (state: AppState) => state.adminSidebar.sections;
|
|
||||||
|
|
||||||
const sectionByNameSelector = (name: string): MemoizedSelector<AppState, AdminSidebarSectionState> => {
|
|
||||||
return keySelector<AdminSidebarSectionState>(name, sidebarSectionStateSelector);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service that performs all actions that have to do with search the admin sidebar
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class AdminSidebarService {
|
|
||||||
|
|
||||||
constructor(private store: Store<AdminSidebarState>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
isSidebarCollapsed(): Observable<boolean> {
|
|
||||||
return this.store.pipe(
|
|
||||||
select(sidebarStateSelector),
|
|
||||||
map((state: AdminSidebarState) => state.collapsed)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSidebar(): void {
|
|
||||||
this.store.dispatch(new AdminSidebarToggleAction());
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSection(name: string): void {
|
|
||||||
this.store.dispatch(new AdminSidebarSectionToggleAction(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
collapseAllSections(): void {
|
|
||||||
this.store.dispatch(new AdminSidebarSectionCollapseAllAction());
|
|
||||||
}
|
|
||||||
|
|
||||||
isSectionCollapsed(name: string): Observable<boolean> {
|
|
||||||
return this.store.pipe(
|
|
||||||
select(sectionByNameSelector(name)),
|
|
||||||
map((state: AdminSidebarSectionState) => hasValue(state) ? state.sectionCollapsed : true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,22 +1,24 @@
|
|||||||
<li class="sidebar-section" [ngClass]="{'active': !(collapsed | async)}"
|
<li class="sidebar-section" [ngClass]="{'active': (active | async)}"
|
||||||
[@bgColor]="{
|
[@bgColor]="{
|
||||||
value: ((collapsed | async) ? 'startBackground' : 'endBackground'),
|
value: ((active | async) ? 'endBackground' : 'startBackground'),
|
||||||
params: {endColor: (sidebarActiveBg | async)}}">
|
params: {endColor: (sidebarActiveBg | async)}}">
|
||||||
<div class="icon-wrapper">
|
<div class="icon-wrapper">
|
||||||
<a class="nav-item nav-link shortcut-icon" (click)="toggleSection($event)" href="#">
|
<a class="nav-item nav-link shortcut-icon" (click)="toggleSection($event)" href="#">
|
||||||
<i class="fas fa-{{icon}} fa-fw"></i>
|
<i class="fas fa-{{section.icon}} fa-fw"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-collapsible">
|
<div class="sidebar-collapsible">
|
||||||
<a class="nav-item nav-link" href="#"
|
<a class="nav-item nav-link" href="#"
|
||||||
(click)="toggleSection($event)">
|
(click)="toggleSection($event)">
|
||||||
<span class="section-header-text">{{('admin.sidebar.section.' + name + '.header') | translate}}</span>
|
<span class="section-header-text">{{count | async}}<ng-container
|
||||||
|
*ngComponentOutlet="getMenuItemComponent(); injector: getItemModelInjector();"></ng-container></span>
|
||||||
<i class="fas fa-chevron-right fa-pull-right"
|
<i class="fas fa-chevron-right fa-pull-right"
|
||||||
[@rotate]="(collapsed | async) ? 'collapsed' : 'expanded'"></i>
|
[@rotate]="(active | async) ? 'expanded' : 'collapsed'"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul class="sidebar-sub-level-items list-unstyled" @slide *ngIf="!(collapsed | async)">
|
<ul class="sidebar-sub-level-items list-unstyled" @slide *ngIf="(active | async)">
|
||||||
<li *ngFor="let section of subSections">
|
<li class="nav-item nav-link" *ngFor="let subSection of (subSections | async)">
|
||||||
<a class="nav-item nav-link" [href]="section.link">{{section.name}}</a>
|
<ng-container
|
||||||
|
*ngComponentOutlet="getMenuItemComponent(subSection.model); injector: getItemModelInjector(subSection.model);"></ng-container>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,19 +1,21 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
@import '../../../../styles/variables.scss';
|
||||||
|
|
||||||
.fa-chevron-right {
|
::ng-deep {
|
||||||
|
.fa-chevron-right {
|
||||||
padding-left: $spacer/2;
|
padding-left: $spacer/2;
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
line-height: 3;
|
line-height: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-sub-level-items {
|
.sidebar-sub-level-items {
|
||||||
list-style: disc;
|
list-style: disc;
|
||||||
color: $navbar-dark-color;
|
color: $navbar-dark-color;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-collapsible {
|
.sidebar-collapsible {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,12 +1,15 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Inject, Injector, OnInit } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
|
||||||
import { first } from 'rxjs/operators';
|
|
||||||
import { rotate } from '../../../shared/animations/rotate';
|
import { rotate } from '../../../shared/animations/rotate';
|
||||||
import { AdminSidebarSectionComponent } from '../admin-sidebar-section/admin-sidebar-section.component';
|
import { AdminSidebarSectionComponent } from '../admin-sidebar-section/admin-sidebar-section.component';
|
||||||
import { slide } from '../../../shared/animations/slide';
|
import { slide } from '../../../shared/animations/slide';
|
||||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
||||||
import { bgColor } from '../../../shared/animations/bgColor';
|
import { bgColor } from '../../../shared/animations/bgColor';
|
||||||
import { AdminSidebarService } from '../admin-sidebar.service';
|
import { MenuID } from '../../../shared/menu/initial-menus-state';
|
||||||
|
import { rendersSectionForMenu } from '../../../shared/menu/menu.decorator';
|
||||||
|
import { MenuService } from '../../../shared/menu/menu.service';
|
||||||
|
import { MenuSection } from '../../../shared/menu/menu.reducer';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-expandable-admin-sidebar-section',
|
selector: 'ds-expandable-admin-sidebar-section',
|
||||||
@@ -15,32 +18,27 @@ import { AdminSidebarService } from '../admin-sidebar.service';
|
|||||||
animations: [rotate, slide, bgColor]
|
animations: [rotate, slide, bgColor]
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@rendersSectionForMenu(MenuID.ADMIN, true)
|
||||||
export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionComponent implements OnInit {
|
export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionComponent implements OnInit {
|
||||||
@Input() subSections;
|
subSections: Observable<MenuSection[]>;
|
||||||
|
menuID = MenuID.ADMIN;
|
||||||
link = '#';
|
link = '#';
|
||||||
sidebarActiveBg;
|
sidebarActiveBg;
|
||||||
collapsed: Observable<boolean>;
|
|
||||||
sidebarCollapsed: Observable<boolean>;
|
sidebarCollapsed: Observable<boolean>;
|
||||||
|
c = 0;
|
||||||
|
count = new BehaviorSubject<number>(0);
|
||||||
|
|
||||||
constructor(private sidebarService: AdminSidebarService,
|
constructor(@Inject('sectionDataProvider') menuSection, protected menuService: MenuService,
|
||||||
private variableService: CSSVariableService) {
|
private variableService: CSSVariableService, protected injector: Injector,) {
|
||||||
super();
|
super(menuSection, menuService, injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
super.ngOnInit();
|
||||||
|
this.subSections = this.menuService.getSubSectionsByParentID(this.menuID, this.section.id);
|
||||||
|
// this.active.subscribe((t) => console.log('section: ', this.section.id, this.c, t));
|
||||||
|
// this.active.subscribe((t) => this.count.next(++this.c));
|
||||||
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
|
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
|
||||||
this.collapsed = this.sidebarService.isSectionCollapsed(this.name);
|
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
|
||||||
this.sidebarCollapsed = this.sidebarService.isSidebarCollapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSection(event: Event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.sidebarCollapsed.pipe(first())
|
|
||||||
.subscribe((sidebarCollapsed) => {
|
|
||||||
if (sidebarCollapsed) {
|
|
||||||
this.sidebarService.toggleSidebar();
|
|
||||||
}
|
|
||||||
this.sidebarService.toggleSection(this.name);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
import { StoreEffects } from './store.effects';
|
import { StoreEffects } from './store.effects';
|
||||||
import { NotificationsEffects } from './shared/notifications/notifications.effects';
|
import { NotificationsEffects } from './shared/notifications/notifications.effects';
|
||||||
import { NavbarEffects } from './navbar/navbar.effects';
|
import { NavbarEffects } from './navbar/navbar.effects';
|
||||||
|
import { MenuEffects } from './shared/menu/menu.effects';
|
||||||
|
|
||||||
export const appEffects = [
|
export const appEffects = [
|
||||||
StoreEffects,
|
StoreEffects,
|
||||||
NavbarEffects,
|
NavbarEffects,
|
||||||
NotificationsEffects
|
NotificationsEffects,
|
||||||
|
MenuEffects
|
||||||
];
|
];
|
||||||
|
@@ -120,6 +120,11 @@ const EXPORTS = [
|
|||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
...EXPORTS
|
...EXPORTS
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AdminSidebarComponent,
|
||||||
|
AdminSidebarSectionComponent,
|
||||||
|
ExpandableAdminSidebarSectionComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
@@ -16,12 +16,9 @@ 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 {
|
|
||||||
adminSidebarReducer,
|
|
||||||
AdminSidebarState
|
|
||||||
} from './+admin/admin-sidebar/admin-sidebar.reducer';
|
|
||||||
import { hasValue } from './shared/empty.util';
|
import { hasValue } from './shared/empty.util';
|
||||||
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
||||||
|
import { menusReducer, MenusState } from './shared/menu/menu.reducer';
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
router: fromRouter.RouterReducerState;
|
router: fromRouter.RouterReducerState;
|
||||||
@@ -32,8 +29,8 @@ export interface AppState {
|
|||||||
searchSidebar: SearchSidebarState;
|
searchSidebar: SearchSidebarState;
|
||||||
searchFilter: SearchFiltersState;
|
searchFilter: SearchFiltersState;
|
||||||
truncatable: TruncatablesState;
|
truncatable: TruncatablesState;
|
||||||
adminSidebar: AdminSidebarState;
|
|
||||||
cssVariables: CSSVariablesState;
|
cssVariables: CSSVariablesState;
|
||||||
|
menus: MenusState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appReducers: ActionReducerMap<AppState> = {
|
export const appReducers: ActionReducerMap<AppState> = {
|
||||||
@@ -45,8 +42,8 @@ export const appReducers: ActionReducerMap<AppState> = {
|
|||||||
searchSidebar: sidebarReducer,
|
searchSidebar: sidebarReducer,
|
||||||
searchFilter: filterReducer,
|
searchFilter: filterReducer,
|
||||||
truncatable: truncatableReducer,
|
truncatable: truncatableReducer,
|
||||||
adminSidebar: adminSidebarReducer,
|
|
||||||
cssVariables: cssVariablesReducer,
|
cssVariables: cssVariablesReducer,
|
||||||
|
menus: menusReducer,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const routerStateSelector = (state: AppState) => state.router;
|
export const routerStateSelector = (state: AppState) => state.router;
|
||||||
|
@@ -65,7 +65,7 @@ import { UploaderService } from '../shared/uploader/uploader.service';
|
|||||||
import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
|
import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
|
||||||
import { DSpaceObjectDataService } from './data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from './data/dspace-object-data.service';
|
||||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
||||||
import { AdminSidebarService } from '../+admin/admin-sidebar/admin-sidebar.service';
|
import { MenuService } from '../shared/menu/menu.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -131,7 +131,7 @@ const PROVIDERS = [
|
|||||||
UUIDService,
|
UUIDService,
|
||||||
DSpaceObjectDataService,
|
DSpaceObjectDataService,
|
||||||
CSSVariableService,
|
CSSVariableService,
|
||||||
AdminSidebarService,
|
MenuService,
|
||||||
// register AuthInterceptor as HttpInterceptor
|
// register AuthInterceptor as HttpInterceptor
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
import { filter, map } from 'rxjs/operators';
|
import { filter, map, tap } from 'rxjs/operators';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Effect, Actions, ofType } from '@ngrx/effects';
|
import { Actions, Effect, ofType } from '@ngrx/effects';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ObjectCacheActionTypes, AddToObjectCacheAction,
|
AddToObjectCacheAction,
|
||||||
|
ObjectCacheActionTypes,
|
||||||
RemoveFromObjectCacheAction
|
RemoveFromObjectCacheAction
|
||||||
} from '../cache/object-cache.actions';
|
} from '../cache/object-cache.actions';
|
||||||
import { RequestActionTypes, RequestConfigureAction } from '../data/request.actions';
|
import { RequestActionTypes, RequestConfigureAction } from '../data/request.actions';
|
||||||
@@ -11,6 +12,11 @@ import { RestRequestMethod } from '../data/request.models';
|
|||||||
import { AddToIndexAction, RemoveFromIndexByValueAction } from './index.actions';
|
import { AddToIndexAction, RemoveFromIndexByValueAction } from './index.actions';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import { IndexName } from './index.reducer';
|
import { IndexName } from './index.reducer';
|
||||||
|
import {
|
||||||
|
AddMenuSectionAction,
|
||||||
|
MenuActionTypes,
|
||||||
|
RemoveMenuSectionAction
|
||||||
|
} from '../../shared/menu/menu.actions';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UUIDIndexEffects {
|
export class UUIDIndexEffects {
|
||||||
@@ -52,17 +58,6 @@ export class UUIDIndexEffects {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// @Effect() removeRequest$ = this.actions$
|
|
||||||
// .pipe(
|
|
||||||
// ofType(ObjectCacheActionTypes.REMOVE),
|
|
||||||
// map((action: RemoveFromObjectCacheAction) => {
|
|
||||||
// return new RemoveFromIndexByValueAction(
|
|
||||||
// IndexName.OBJECT,
|
|
||||||
// action.payload
|
|
||||||
// );
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
|
|
||||||
constructor(private actions$: Actions) {
|
constructor(private actions$: Actions) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -7,13 +7,11 @@ import {
|
|||||||
|
|
||||||
export enum IndexName {
|
export enum IndexName {
|
||||||
OBJECT = 'object/uuid-to-self-link',
|
OBJECT = 'object/uuid-to-self-link',
|
||||||
REQUEST = 'get-request/href-to-uuid'
|
REQUEST = 'get-request/href-to-uuid',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndexState {
|
export type IndexState = {
|
||||||
// TODO this should be `[name in IndexName]: {` but that's currently broken,
|
[name in IndexName]: {
|
||||||
// see https://github.com/Microsoft/TypeScript/issues/13042
|
|
||||||
[name: string]: {
|
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,8 +11,8 @@ import {
|
|||||||
export const slide = trigger('slide', [
|
export const slide = trigger('slide', [
|
||||||
state('void', style({ height: 0 })),
|
state('void', style({ height: 0 })),
|
||||||
state('*', style({ height: '*' })),
|
state('*', style({ height: '*' })),
|
||||||
transition(':enter', [animate('200ms')]),
|
transition(':enter', [animate('2000ms')]),
|
||||||
transition(':leave', [animate('200ms')])
|
transition(':leave', [animate('2000ms')])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const slideMobileNav = trigger('slideMobileNav', [
|
export const slideMobileNav = trigger('slideMobileNav', [
|
||||||
|
29
src/app/shared/menu/initial-menus-state.ts
Normal file
29
src/app/shared/menu/initial-menus-state.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { MenusState } from './menu.reducer';
|
||||||
|
|
||||||
|
export enum MenuID {
|
||||||
|
ADMIN = 'admin-sidebar',
|
||||||
|
PUBLIC = 'public'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SectionType {
|
||||||
|
TEXT, LINK, ALTMETRIC, SEARCH
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialMenusState: MenusState = {
|
||||||
|
[MenuID.ADMIN]:
|
||||||
|
{
|
||||||
|
id: MenuID.ADMIN,
|
||||||
|
collapsed: false,
|
||||||
|
visible: false,
|
||||||
|
sections: {},
|
||||||
|
sectionToSubsectionIndex: {}
|
||||||
|
},
|
||||||
|
[MenuID.PUBLIC]:
|
||||||
|
{
|
||||||
|
id: MenuID.PUBLIC,
|
||||||
|
collapsed: true,
|
||||||
|
visible: true,
|
||||||
|
sections: {},
|
||||||
|
sectionToSubsectionIndex: {}
|
||||||
|
}
|
||||||
|
};
|
16
src/app/shared/menu/menu-section.decorator.ts
Normal file
16
src/app/shared/menu/menu-section.decorator.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { SectionType } from './initial-menus-state';
|
||||||
|
|
||||||
|
const menuSectionTypeComponentMap = new Map();
|
||||||
|
|
||||||
|
export function rendersSectionForType(type: SectionType) {
|
||||||
|
return function decorator(sectionComponent: any) {
|
||||||
|
if (!sectionComponent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
menuSectionTypeComponentMap.set(type, sectionComponent);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getComponentForSectionType(type: SectionType) {
|
||||||
|
return menuSectionTypeComponentMap.get(type);
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MenuSectionComponent } from './menu-section.component';
|
||||||
|
|
||||||
|
describe('MenuSectionComponent', () => {
|
||||||
|
let component: MenuSectionComponent;
|
||||||
|
let fixture: ComponentFixture<MenuSectionComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MenuSectionComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MenuSectionComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
48
src/app/shared/menu/menu-section/menu-section.component.ts
Normal file
48
src/app/shared/menu/menu-section/menu-section.component.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Component, Injector, Input } from '@angular/core';
|
||||||
|
import { MenuService } from '../menu.service';
|
||||||
|
import { MenuSection } from '../menu.reducer';
|
||||||
|
import { getComponentForSectionType } from '../menu-section.decorator';
|
||||||
|
import { MenuID, SectionType } from '../initial-menus-state';
|
||||||
|
import { hasNoValue, hasValue } from '../../empty.util';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { SectionTypeModel } from '../models/section-types/section-type.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-menu-section',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class MenuSectionComponent {
|
||||||
|
active: Observable<boolean>;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(protected section: MenuSection, protected menuService: MenuService, protected injector: Injector) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.active = this.menuService.isSectionActive(this.menuID, this.section.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSection(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.menuService.toggleActiveSection(this.menuID, this.section.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenuItemComponent(itemModel?: SectionTypeModel) {
|
||||||
|
if (hasNoValue(itemModel)) {
|
||||||
|
itemModel = this.section.model;
|
||||||
|
}
|
||||||
|
const type: SectionType = itemModel.type;
|
||||||
|
return getComponentForSectionType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemModelInjector(itemModel?: SectionTypeModel) {
|
||||||
|
if (hasNoValue(itemModel)) {
|
||||||
|
itemModel = this.section.model;
|
||||||
|
}
|
||||||
|
return Injector.create({
|
||||||
|
providers: [{ provide: 'itemModelProvider', useFactory: () => (itemModel), deps: [] }],
|
||||||
|
parent: this.injector
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
159
src/app/shared/menu/menu.actions.ts
Normal file
159
src/app/shared/menu/menu.actions.ts
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
import { MenuID } from './initial-menus-state';
|
||||||
|
import { type } from '../ngrx/type';
|
||||||
|
import { MenuSection } from './menu.reducer';
|
||||||
|
|
||||||
|
export const MenuActionTypes = {
|
||||||
|
COLLAPSE_MENU: type('dspace/menu/COLLAPSE_MENU'),
|
||||||
|
TOGGLE_MENU: type('dspace/menu/TOGGLE_MENU'),
|
||||||
|
EXPAND_MENU: type('dspace/menu/EXPAND_MENU'),
|
||||||
|
SHOW_MENU: type('dspace/menu/SHOW_MENU'),
|
||||||
|
HIDE_MENU: type('dspace/menu/HIDE_MENU'),
|
||||||
|
ADD_SECTION: type('dspace/menu-section/ADD_SECTION'),
|
||||||
|
REMOVE_SECTION: type('dspace/menu-section/REMOVE_SECTION'),
|
||||||
|
SHOW_SECTION: type('dspace/menu-section/SHOW_SECTION'),
|
||||||
|
HIDE_SECTION: type('dspace/menu-section/HIDE_SECTION'),
|
||||||
|
ACTIVATE_SECTION: type('dspace/menu-section/ACTIVATE_SECTION'),
|
||||||
|
DEACTIVATE_SECTION: type('dspace/menu-section/DEACTIVATE_SECTION'),
|
||||||
|
TOGGLE_ACTIVE_SECTION: type('dspace/menu-section/TOGGLE_ACTIVE_SECTION'),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
|
// MENU STATE ACTIONS
|
||||||
|
export class CollapseMenuAction implements Action {
|
||||||
|
type = MenuActionTypes.COLLAPSE_MENU;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExpandMenuAction implements Action {
|
||||||
|
type = MenuActionTypes.EXPAND_MENU;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ToggleMenuAction implements Action {
|
||||||
|
type = MenuActionTypes.TOGGLE_MENU;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ShowMenuAction implements Action {
|
||||||
|
type = MenuActionTypes.SHOW_MENU;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HideMenuAction implements Action {
|
||||||
|
type = MenuActionTypes.HIDE_MENU;
|
||||||
|
menuID: MenuID;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MENU STRUCTURING ACTIONS
|
||||||
|
export abstract class MenuSectionAction implements Action {
|
||||||
|
type;
|
||||||
|
menuID: MenuID;
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
this.menuID = menuID;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AddMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.ADD_SECTION;
|
||||||
|
section: MenuSection;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, section: MenuSection) {
|
||||||
|
super(menuID, section.id);
|
||||||
|
this.section = section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoveMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.REMOVE_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HideMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.HIDE_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to expand a section
|
||||||
|
*/
|
||||||
|
export class ShowMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.SHOW_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ActivateMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.ACTIVATE_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to expand a section
|
||||||
|
*/
|
||||||
|
export class DeactivateMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.DEACTIVATE_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ToggleActiveMenuSectionAction extends MenuSectionAction {
|
||||||
|
type = MenuActionTypes.TOGGLE_ACTIVE_SECTION;
|
||||||
|
|
||||||
|
constructor(menuID: MenuID, id: string) {
|
||||||
|
super(menuID, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MenuAction =
|
||||||
|
CollapseMenuAction
|
||||||
|
| ExpandMenuAction
|
||||||
|
| ToggleMenuAction
|
||||||
|
| ShowMenuAction
|
||||||
|
| HideMenuAction
|
||||||
|
| AddMenuSectionAction
|
||||||
|
| RemoveMenuSectionAction
|
||||||
|
| ShowMenuSectionAction
|
||||||
|
| HideMenuSectionAction
|
||||||
|
| ActivateMenuSectionAction
|
||||||
|
| DeactivateMenuSectionAction
|
||||||
|
| ToggleActiveMenuSectionAction
|
||||||
|
/* tslint:enable:max-classes-per-file */
|
48
src/app/shared/menu/menu.component.ts
Normal file
48
src/app/shared/menu/menu.component.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Component, Injector, OnInit } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { MenuService } from '../../shared/menu/menu.service';
|
||||||
|
import { MenuID } from '../../shared/menu/initial-menus-state';
|
||||||
|
import { MenuSection } from '../../shared/menu/menu.reducer';
|
||||||
|
import { map, tap } from 'rxjs/operators';
|
||||||
|
import { getComponentForMenu } from './menu.decorator';
|
||||||
|
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
||||||
|
import { MenuSectionComponent } from './menu-section/menu-section.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-menu',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class MenuComponent implements OnInit {
|
||||||
|
menuID: MenuID;
|
||||||
|
menuCollapsed: Observable<boolean>;
|
||||||
|
sections: Observable<MenuSection[]>;
|
||||||
|
|
||||||
|
constructor(protected menuService: MenuService, protected injector: Injector) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.menuCollapsed = this.menuService.isMenuCollapsed(this.menuID);
|
||||||
|
this.sections = this.menuService.getMenuTopSections(this.menuID);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.menuService.toggleMenu(this.menuID);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSectionComponent(section: MenuSection): Observable<GenericConstructor<MenuSectionComponent>> {
|
||||||
|
return this.menuService.hasSubSections(this.menuID, section.id).pipe(
|
||||||
|
map((expandable: boolean) => {
|
||||||
|
return getComponentForMenu(this.menuID, expandable);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSectionDataInjector(section: MenuSection) {
|
||||||
|
return Injector.create({
|
||||||
|
providers: [{ provide: 'sectionDataProvider', useFactory: () => (section), deps: [] }],
|
||||||
|
parent: this.injector
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
src/app/shared/menu/menu.decorator.ts
Normal file
19
src/app/shared/menu/menu.decorator.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { MenuID } from './initial-menus-state';
|
||||||
|
|
||||||
|
const menuComponentMap = new Map();
|
||||||
|
|
||||||
|
export function rendersSectionForMenu(menuID: MenuID, expandable: boolean) {
|
||||||
|
return function decorator(menuSectionWrapperComponent: any) {
|
||||||
|
if (!menuSectionWrapperComponent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!menuComponentMap.get(menuID)) {
|
||||||
|
menuComponentMap.set(menuID, new Map());
|
||||||
|
}
|
||||||
|
menuComponentMap.get(menuID).set(expandable, menuSectionWrapperComponent);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getComponentForMenu(menuID: MenuID, expandable: boolean) {
|
||||||
|
return menuComponentMap.get(menuID).get(expandable);
|
||||||
|
}
|
63
src/app/shared/menu/menu.effects.ts
Normal file
63
src/app/shared/menu/menu.effects.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { Actions, Effect, ofType } from '@ngrx/effects';
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs/index';
|
||||||
|
import { filter, first, map, switchMap } from 'rxjs/operators';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
ActivateMenuSectionAction,
|
||||||
|
CollapseMenuAction,
|
||||||
|
DeactivateMenuSectionAction,
|
||||||
|
ExpandMenuAction,
|
||||||
|
MenuActionTypes,
|
||||||
|
ToggleActiveMenuSectionAction,
|
||||||
|
ToggleMenuAction,
|
||||||
|
} from './menu.actions';
|
||||||
|
import { MenuState } from './menu.reducer';
|
||||||
|
import { MenuService } from './menu.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MenuEffects {
|
||||||
|
|
||||||
|
@Effect()
|
||||||
|
public collapseSectionsOnCollapseMenu$: Observable<Action> = this.actions$.pipe(
|
||||||
|
ofType(MenuActionTypes.COLLAPSE_MENU, MenuActionTypes.TOGGLE_MENU),
|
||||||
|
switchMap((action: CollapseMenuAction | ToggleMenuAction) => {
|
||||||
|
return this.menuService.getMenu(action.menuID).pipe(
|
||||||
|
first(),
|
||||||
|
switchMap((menu: MenuState) => {
|
||||||
|
if (menu.collapsed) {
|
||||||
|
const sections = menu.sections;
|
||||||
|
return Object.keys(sections)
|
||||||
|
.map((id) => {
|
||||||
|
return new DeactivateMenuSectionAction(action.menuID, id);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return [{ type: 'NO_ACTION' }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
@Effect()
|
||||||
|
public onExpandSectionMenuExpandMenu: Observable<Action> = this.actions$.pipe(
|
||||||
|
ofType(MenuActionTypes.ACTIVATE_SECTION, MenuActionTypes.TOGGLE_ACTIVE_SECTION),
|
||||||
|
switchMap((action: ActivateMenuSectionAction | ToggleActiveMenuSectionAction) => {
|
||||||
|
return this.menuService.getMenu(action.menuID).pipe(
|
||||||
|
first(),
|
||||||
|
map((menu: MenuState) => {
|
||||||
|
if (menu.collapsed) {
|
||||||
|
return new ExpandMenuAction(menu.id)
|
||||||
|
} else {
|
||||||
|
return { type: 'NO_ACTION' };
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(private actions$: Actions,
|
||||||
|
private menuService: MenuService) {
|
||||||
|
}
|
||||||
|
}
|
13
src/app/shared/menu/menu.reducer.spec.ts
Normal file
13
src/app/shared/menu/menu.reducer.spec.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// import { initialState, reducer } from './menu.reducer';
|
||||||
|
//
|
||||||
|
// describe('Menu Reducer', () => {
|
||||||
|
// describe('unknown action', () => {
|
||||||
|
// it('should return the initial state', () => {
|
||||||
|
// const action = {} as any;
|
||||||
|
//
|
||||||
|
// const result = reducer(initialState, action);
|
||||||
|
//
|
||||||
|
// expect(result).toBe(initialState);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
188
src/app/shared/menu/menu.reducer.ts
Normal file
188
src/app/shared/menu/menu.reducer.ts
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
import {
|
||||||
|
ActivateMenuSectionAction,
|
||||||
|
AddMenuSectionAction, DeactivateMenuSectionAction,
|
||||||
|
HideMenuSectionAction,
|
||||||
|
MenuAction,
|
||||||
|
MenuActionTypes,
|
||||||
|
MenuSectionAction,
|
||||||
|
RemoveMenuSectionAction,
|
||||||
|
ShowMenuSectionAction, ToggleActiveMenuSectionAction
|
||||||
|
} from './menu.actions';
|
||||||
|
import { initialMenusState, MenuID, SectionType } from './initial-menus-state';
|
||||||
|
import { hasValue } from '../empty.util';
|
||||||
|
import { SectionTypeModel } from './models/section-types/section-type.model';
|
||||||
|
|
||||||
|
export type MenusState = {
|
||||||
|
[id in MenuID]: MenuState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuState {
|
||||||
|
id: MenuID;
|
||||||
|
collapsed: boolean;
|
||||||
|
visible: boolean;
|
||||||
|
sections: MenuSections
|
||||||
|
sectionToSubsectionIndex: MenuSectionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuSectionIndex {
|
||||||
|
[id: string]: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuSections {
|
||||||
|
[id: string]: MenuSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MenuSection {
|
||||||
|
id: string;
|
||||||
|
parentID?: string;
|
||||||
|
visible: boolean;
|
||||||
|
active: boolean;
|
||||||
|
model: SectionTypeModel;
|
||||||
|
index?: number;
|
||||||
|
icon?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function menusReducer(state: MenusState = initialMenusState, action: MenuAction): MenusState {
|
||||||
|
const menuState: MenuState = state[action.menuID];
|
||||||
|
switch (action.type) {
|
||||||
|
case MenuActionTypes.COLLAPSE_MENU: {
|
||||||
|
const newMenuState = Object.assign({}, menuState, { collapsed: true });
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
case MenuActionTypes.EXPAND_MENU: {
|
||||||
|
const newMenuState = Object.assign({}, menuState, { collapsed: false });
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
case MenuActionTypes.TOGGLE_MENU: {
|
||||||
|
const newMenuState = Object.assign({}, menuState, { collapsed: !menuState.collapsed });
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
case MenuActionTypes.SHOW_MENU: {
|
||||||
|
const newMenuState = Object.assign({}, menuState, { visible: true });
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
case MenuActionTypes.HIDE_MENU: {
|
||||||
|
const newMenuState = Object.assign({}, menuState, { visible: false });
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
case MenuActionTypes.ADD_SECTION: {
|
||||||
|
return addSection(state, action as AddMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.REMOVE_SECTION: {
|
||||||
|
return removeSection(state, action as RemoveMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.ACTIVATE_SECTION: {
|
||||||
|
return activateSection(state, action as ActivateMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.DEACTIVATE_SECTION: {
|
||||||
|
return deactivateSection(state, action as DeactivateMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.TOGGLE_ACTIVE_SECTION: {
|
||||||
|
return toggleActiveSection(state, action as ToggleActiveMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.HIDE_SECTION: {
|
||||||
|
return hideSection(state, action as HideMenuSectionAction);
|
||||||
|
}
|
||||||
|
case MenuActionTypes.SHOW_SECTION: {
|
||||||
|
return showSection(state, action as ShowMenuSectionAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSection(state: MenusState, action: AddMenuSectionAction) {
|
||||||
|
const newState = addToIndex(state, action.section, action.menuID);
|
||||||
|
return putSectionState(newState, action, action.section);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToIndex(state: MenusState, section: MenuSection, menuID: MenuID) {
|
||||||
|
const sectionID = section.id;
|
||||||
|
const parentID = section.parentID;
|
||||||
|
if (hasValue(parentID)) {
|
||||||
|
const menuState: MenuState = state[menuID];
|
||||||
|
const index = menuState.sectionToSubsectionIndex;
|
||||||
|
const parentIndex = hasValue(index[parentID]) ? index[parentID] : [];
|
||||||
|
const newIndex = Object.assign({}, index, { [parentID]: [...parentIndex, sectionID] });
|
||||||
|
const newMenuState = Object.assign({}, menuState, { sectionToSubsectionIndex: newIndex });
|
||||||
|
return Object.assign({}, state, { [menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSection(state: MenusState, action: RemoveMenuSectionAction) {
|
||||||
|
const menuState: MenuState = state[action.menuID];
|
||||||
|
const id = action.id;
|
||||||
|
const newMenuState = Object.assign({}, menuState);
|
||||||
|
delete newMenuState[id];
|
||||||
|
const newState = removeFromIndex(state, menuState.sections[action.id], action.menuID);
|
||||||
|
return Object.assign({}, newState, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFromIndex(state: MenusState, section: MenuSection, menuID: MenuID) {
|
||||||
|
const sectionID = section.id;
|
||||||
|
const parentID = section.parentID;
|
||||||
|
if (hasValue(parentID)) {
|
||||||
|
const menuState: MenuState = state[menuID];
|
||||||
|
const index = menuState.sectionToSubsectionIndex;
|
||||||
|
const parentIndex = hasValue(index[parentID]) ? index[parentID] : [];
|
||||||
|
const newIndex = Object.assign({}, index, { [parentID]: parentIndex.filter((id) => id === sectionID) });
|
||||||
|
const newMenuState = Object.assign({}, menuState, { sectionToSubsectionIndex: newIndex });
|
||||||
|
return Object.assign({}, state, { [menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSection(state: MenusState, action: HideMenuSectionAction) {
|
||||||
|
return updateSectionState(state, action, { visible: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSection(state: MenusState, action: ShowMenuSectionAction) {
|
||||||
|
return updateSectionState(state, action, { visible: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function deactivateSection(state: MenusState, action: DeactivateMenuSectionAction) {
|
||||||
|
const sectionState: MenuSection = state[action.menuID].sections[action.id];
|
||||||
|
if (hasValue(sectionState)) {
|
||||||
|
return updateSectionState(state, action, { active: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateSection(state: MenusState, action: ActivateMenuSectionAction) {
|
||||||
|
const sectionState: MenuSection = state[action.menuID].sections[action.id];
|
||||||
|
if (hasValue(sectionState)) {
|
||||||
|
return updateSectionState(state, action, { active: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleActiveSection(state: MenusState, action: ToggleActiveMenuSectionAction) {
|
||||||
|
const sectionState: MenuSection = state[action.menuID].sections[action.id];
|
||||||
|
if (hasValue(sectionState)) {
|
||||||
|
return updateSectionState(state, action, { active: !sectionState.active });
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function putSectionState(state: MenusState, action: MenuAction, section: MenuSection): MenusState {
|
||||||
|
const menuState: MenuState = state[action.menuID];
|
||||||
|
const newTopSections = Object.assign({}, menuState.sections, {
|
||||||
|
[section.id]: section
|
||||||
|
});
|
||||||
|
const newMenuState = Object.assign({}, menuState, {
|
||||||
|
sections: newTopSections
|
||||||
|
});
|
||||||
|
return Object.assign({}, state, { [action.menuID]: newMenuState });
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSectionState(state: MenusState, action: MenuSectionAction, update: any): MenusState {
|
||||||
|
const menuState: MenuState = state[action.menuID];
|
||||||
|
const sectionState = menuState.sections[action.id];
|
||||||
|
if (hasValue(sectionState)) {
|
||||||
|
const newTopSection = Object.assign({}, sectionState, update);
|
||||||
|
return putSectionState(state, action, newTopSection);
|
||||||
|
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
114
src/app/shared/menu/menu.service.ts
Normal file
114
src/app/shared/menu/menu.service.ts
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
||||||
|
import { MenuSection, MenuSectionIndex, MenuSections, MenusState, MenuState } from './menu.reducer';
|
||||||
|
import { AppState, keySelector } from '../../app.reducer';
|
||||||
|
import { MenuID } from './initial-menus-state';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
|
||||||
|
import {
|
||||||
|
AddMenuSectionAction,
|
||||||
|
RemoveMenuSectionAction,
|
||||||
|
ToggleActiveMenuSectionAction,
|
||||||
|
ToggleMenuAction,
|
||||||
|
} from './menu.actions';
|
||||||
|
import { hasNoValue, isNotEmpty } from '../empty.util';
|
||||||
|
import { combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
|
|
||||||
|
const menusStateSelector = (state) => state.menus;
|
||||||
|
|
||||||
|
const menuByIDSelector = (menuID: MenuID): MemoizedSelector<AppState, MenuState> => {
|
||||||
|
return keySelector<MenuState>(menuID, menusStateSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuSectionStateSelector = (state: MenuState) => state.sections;
|
||||||
|
|
||||||
|
const menuSectionByIDSelector = (id: string): MemoizedSelector<AppState, MenuSection> => {
|
||||||
|
return keySelector<MenuSection>(id, menuSectionStateSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuSectionIndexStateSelector = (state: MenuState) => state.sectionToSubsectionIndex;
|
||||||
|
|
||||||
|
const getSubSectionsFromSectionSelector = (id: string): MemoizedSelector<AppState, MenuSectionIndex> => {
|
||||||
|
return keySelector<MenuSectionIndex>(id, menuSectionIndexStateSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MenuService {
|
||||||
|
|
||||||
|
constructor(private store: Store<MenusState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenu(id: MenuID): Observable<MenuState> {
|
||||||
|
return this.store.pipe(select(menuByIDSelector(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenuTopSections(menuID: MenuID): Observable<MenuSection[]> {
|
||||||
|
return this.store.pipe(
|
||||||
|
select(menuByIDSelector(menuID)),
|
||||||
|
select(menuSectionStateSelector),
|
||||||
|
map((sections: MenuSections) => {
|
||||||
|
return Object.values(sections).filter((section: MenuSection) => hasNoValue(section.parentID))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubSectionsByParentID(menuID: MenuID, parentID: string): Observable<MenuSection[]> {
|
||||||
|
return this.store.pipe(
|
||||||
|
select(menuByIDSelector(menuID)),
|
||||||
|
select(getSubSectionsFromSectionSelector(parentID)),
|
||||||
|
map((ids: string[]) => isNotEmpty(ids) ? ids : []),
|
||||||
|
switchMap((ids: string[]) => observableCombineLatest(ids.map((id: string) => this.getMenuSection(menuID, id)))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSubSections(menuID: MenuID, parentID: string): Observable<boolean> {
|
||||||
|
return this.store.pipe(
|
||||||
|
select(menuByIDSelector(menuID)),
|
||||||
|
select(getSubSectionsFromSectionSelector(parentID)),
|
||||||
|
map((ids: string[]) => isNotEmpty(ids))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenuSection(menuID: MenuID, sectionId: string): Observable<MenuSection> {
|
||||||
|
return this.store.pipe(
|
||||||
|
select(menuByIDSelector(menuID)),
|
||||||
|
select(menuSectionByIDSelector(sectionId)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSection(menuID: MenuID, section: MenuSection) {
|
||||||
|
this.store.dispatch(new AddMenuSectionAction(menuID, section));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSection(menuID: MenuID, sectionID: string) {
|
||||||
|
this.store.dispatch(new RemoveMenuSectionAction(menuID, sectionID));
|
||||||
|
}
|
||||||
|
|
||||||
|
isMenuCollapsed(menuID: MenuID): Observable<boolean> {
|
||||||
|
return this.getMenu(menuID).pipe(
|
||||||
|
map((state: MenuState) => state.collapsed)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMenu(menuID: MenuID): void {
|
||||||
|
this.store.dispatch(new ToggleMenuAction(menuID));
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleActiveSection(menuID: MenuID, id: string): void {
|
||||||
|
this.store.dispatch(new ToggleActiveMenuSectionAction(menuID, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
isSectionActive(menuID: MenuID, id: string): Observable<boolean> {
|
||||||
|
return this.getMenuSection(menuID, id).pipe(tap((section) => console.log(section.id)), map((section) => section.active),
|
||||||
|
distinctUntilChanged((a, b) => {
|
||||||
|
console.log('DISTINCT', a, b);
|
||||||
|
return a === b
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
isSectionVisible(menuID: MenuID, id: string): Observable<boolean> {
|
||||||
|
return this.getMenuSection(menuID, id).pipe(map((section) => section.visible));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
import { SectionType } from '../../initial-menus-state';
|
||||||
|
import { SectionTypeModel } from './section-type.model';
|
||||||
|
|
||||||
|
export class AltmetricSectionTypeModel implements SectionTypeModel {
|
||||||
|
type = SectionType.ALTMETRIC;
|
||||||
|
url: string;
|
||||||
|
}
|
8
src/app/shared/menu/models/section-types/link.model.ts
Normal file
8
src/app/shared/menu/models/section-types/link.model.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { SectionTypeModel } from './section-type.model';
|
||||||
|
import { SectionType } from '../../initial-menus-state';
|
||||||
|
|
||||||
|
export class LinkSectionTypeModel implements SectionTypeModel {
|
||||||
|
type = SectionType.LINK;
|
||||||
|
text: string;
|
||||||
|
link: string;
|
||||||
|
}
|
8
src/app/shared/menu/models/section-types/search.model.ts
Normal file
8
src/app/shared/menu/models/section-types/search.model.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { SectionTypeModel } from './section-type.model';
|
||||||
|
import { SectionType } from '../../initial-menus-state';
|
||||||
|
|
||||||
|
export class SearchSectionTypeModel implements SectionTypeModel {
|
||||||
|
type = SectionType.SEARCH;
|
||||||
|
placeholder: string;
|
||||||
|
action: string;
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
import { SectionType } from '../../initial-menus-state';
|
||||||
|
|
||||||
|
export interface SectionTypeModel {
|
||||||
|
type: SectionType;
|
||||||
|
}
|
7
src/app/shared/menu/models/section-types/text.model.ts
Normal file
7
src/app/shared/menu/models/section-types/text.model.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { SectionTypeModel } from './section-type.model';
|
||||||
|
import { SectionType } from '../../initial-menus-state';
|
||||||
|
|
||||||
|
export class TextSectionTypeModel implements SectionTypeModel {
|
||||||
|
type = SectionType.TEXT;
|
||||||
|
text: string;
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
<a class="nav-item nav-link" [href]="item.link">{{item.text | translate}}</a>
|
16
src/app/shared/menu/type-components/link-type.component.ts
Normal file
16
src/app/shared/menu/type-components/link-type.component.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Component, Inject, Input } from '@angular/core';
|
||||||
|
import { LinkSectionTypeModel } from '../models/section-types/link.model';
|
||||||
|
import { SectionType } from '../initial-menus-state';
|
||||||
|
import { rendersSectionForType } from '../menu-section.decorator';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-link-type-menu-item',
|
||||||
|
templateUrl: './link-type.component.html'
|
||||||
|
})
|
||||||
|
@rendersSectionForType(SectionType.LINK)
|
||||||
|
export class LinkTypeMenuItemComponent {
|
||||||
|
@Input() item: LinkSectionTypeModel;
|
||||||
|
constructor(@Inject('itemModelProvider') item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
<span>{{item.text | translate}}</span>
|
16
src/app/shared/menu/type-components/text-type.component.ts
Normal file
16
src/app/shared/menu/type-components/text-type.component.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Component, Inject, Input } from '@angular/core';
|
||||||
|
import { TextSectionTypeModel } from '../models/section-types/text.model';
|
||||||
|
import { SectionType } from '../initial-menus-state';
|
||||||
|
import { rendersSectionForType } from '../menu-section.decorator';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-text-type-menu-item',
|
||||||
|
templateUrl: './text-type.component.html',
|
||||||
|
})
|
||||||
|
@rendersSectionForType(SectionType.TEXT)
|
||||||
|
export class TextTypeMenuItemComponent {
|
||||||
|
@Input() item: TextSectionTypeModel;
|
||||||
|
constructor(@Inject('itemModelProvider') item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
}
|
@@ -85,6 +85,10 @@ import { InputSuggestionsComponent } from './input-suggestions/input-suggestions
|
|||||||
import { CapitalizePipe } from './utils/capitalize.pipe';
|
import { CapitalizePipe } from './utils/capitalize.pipe';
|
||||||
import { ObjectKeysPipe } from './utils/object-keys-pipe';
|
import { ObjectKeysPipe } from './utils/object-keys-pipe';
|
||||||
import { MomentModule } from 'ngx-moment';
|
import { MomentModule } from 'ngx-moment';
|
||||||
|
import { MenuSectionComponent } from './menu/menu-section/menu-section.component';
|
||||||
|
import { MenuComponent } from './menu/menu.component';
|
||||||
|
import { LinkTypeMenuItemComponent } from './menu/type-components/link-type.component';
|
||||||
|
import { TextTypeMenuItemComponent } from './menu/type-components/text-type.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -158,7 +162,11 @@ const COMPONENTS = [
|
|||||||
TruncatableComponent,
|
TruncatableComponent,
|
||||||
TruncatablePartComponent,
|
TruncatablePartComponent,
|
||||||
BrowseByComponent,
|
BrowseByComponent,
|
||||||
InputSuggestionsComponent
|
InputSuggestionsComponent,
|
||||||
|
MenuSectionComponent,
|
||||||
|
MenuComponent,
|
||||||
|
LinkTypeMenuItemComponent,
|
||||||
|
TextTypeMenuItemComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
@@ -171,7 +179,9 @@ const ENTRY_COMPONENTS = [
|
|||||||
CollectionGridElementComponent,
|
CollectionGridElementComponent,
|
||||||
CommunityGridElementComponent,
|
CommunityGridElementComponent,
|
||||||
SearchResultGridElementComponent,
|
SearchResultGridElementComponent,
|
||||||
BrowseEntryListElementComponent
|
BrowseEntryListElementComponent,
|
||||||
|
LinkTypeMenuItemComponent,
|
||||||
|
TextTypeMenuItemComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
@@ -195,7 +205,6 @@ const DIRECTIVES = [
|
|||||||
...COMPONENTS,
|
...COMPONENTS,
|
||||||
...DIRECTIVES,
|
...DIRECTIVES,
|
||||||
...ENTRY_COMPONENTS,
|
...ENTRY_COMPONENTS,
|
||||||
...DIRECTIVES
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
...PROVIDERS
|
...PROVIDERS
|
||||||
|
Reference in New Issue
Block a user