mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
add modal, refine table,refactor, fix lint
This commit is contained in:
@@ -12,6 +12,7 @@ import { AdminNotifySearchResultComponent } from './admin-notify-search-result/a
|
|||||||
import {
|
import {
|
||||||
AdminNotifyOutgoingComponent
|
AdminNotifyOutgoingComponent
|
||||||
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
|
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
|
||||||
|
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal/admin-notify-detail-modal.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -28,7 +29,8 @@ import {
|
|||||||
AdminNotifyMetricsComponent,
|
AdminNotifyMetricsComponent,
|
||||||
AdminNotifyIncomingComponent,
|
AdminNotifyIncomingComponent,
|
||||||
AdminNotifyOutgoingComponent,
|
AdminNotifyOutgoingComponent,
|
||||||
AdminNotifySearchResultComponent
|
AdminNotifySearchResultComponent,
|
||||||
|
AdminNotifyDetailModalComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AdminNotifyDashboardModule {
|
export class AdminNotifyDashboardModule {
|
||||||
|
@@ -0,0 +1,14 @@
|
|||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">Message Detail</h4>
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex modal-body flex-column p-4">
|
||||||
|
<div *ngFor="let key of notifyMessageKeys">
|
||||||
|
<div class="d-flex w-100 justify-content-between mb-4">
|
||||||
|
<div class="font-weight-bold mr-5">{{ key }}</div>
|
||||||
|
<div class="text-nowrap text-truncate">{{ notifyMessage[key] }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal.component';
|
||||||
|
|
||||||
|
describe('AdminNotifyDetailModalComponent', () => {
|
||||||
|
let component: AdminNotifyDetailModalComponent;
|
||||||
|
let fixture: ComponentFixture<AdminNotifyDetailModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AdminNotifyDetailModalComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AdminNotifyDetailModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,32 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
|
||||||
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-admin-notify-detail-modal',
|
||||||
|
templateUrl: './admin-notify-detail-modal.component.html',
|
||||||
|
styleUrls: ['./admin-notify-detail-modal.component.scss']
|
||||||
|
})
|
||||||
|
export class AdminNotifyDetailModalComponent {
|
||||||
|
@Input() notifyMessage: AdminNotifyMessage;
|
||||||
|
@Input() notifyMessageKeys: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event fired when the modal is closed
|
||||||
|
*/
|
||||||
|
@Output()
|
||||||
|
response = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
|
||||||
|
constructor(protected activeModal: NgbActiveModal) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the modal and set the response to true so RootComponent knows the modal was closed
|
||||||
|
*/
|
||||||
|
closeModal() {
|
||||||
|
this.activeModal.close();
|
||||||
|
this.response.emit(true);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,22 +1,22 @@
|
|||||||
<div class="w-100">
|
<div class="table-responsive mt-2">
|
||||||
<div class="table-responsive">
|
<table class="table table-striped table-hover">
|
||||||
<table id="formats" class="table table-striped table-hover">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Timestamp</th>
|
<th scope="col">Timestamp</th>
|
||||||
<th scope="col">Source</th>
|
<th scope="col">Origin</th>
|
||||||
<th scope="col">Target</th>
|
<th scope="col">Target</th>
|
||||||
<th scope="col">Type</th>
|
<th scope="col">Type</th>
|
||||||
<th scope="col">Status</th>
|
<th scope="col">Status</th>
|
||||||
|
<th scope="col">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let message of notifyMessages">
|
<tr *ngFor="let message of notifyMessages">
|
||||||
<td>
|
<td>
|
||||||
<div>{{message.queueTimeout}}</div>
|
<div class="text-nowrap">{{message.queueTimeout}}</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div>{{message.source}}</div>
|
<div>{{message.origin}}</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div>{{message.target}}</div>
|
<div>{{message.target}}</div>
|
||||||
@@ -27,8 +27,13 @@
|
|||||||
<td>
|
<td>
|
||||||
<div>{{message.queueStatusLabel}}</div>
|
<div>{{message.queueStatusLabel}}</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<button class="btn mb-2 btn-dark" (click)="openDetailModal(message)">Detail</button>
|
||||||
|
<button class="btn btn-warning">Reprocess</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
|
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
|
||||||
import { ViewMode } from '../../../core/shared/view-mode.model';
|
import { ViewMode } from '../../../core/shared/view-mode.model';
|
||||||
import { Context } from '../../../core/shared/context.model';
|
import { Context } from '../../../core/shared/context.model';
|
||||||
@@ -10,16 +10,60 @@ import {
|
|||||||
TabulatableResultListElementsComponent
|
TabulatableResultListElementsComponent
|
||||||
} from '../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
|
} from '../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { TruncatableService } from '../../../shared/truncatable/truncatable.service';
|
||||||
|
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
|
||||||
|
import { APP_CONFIG, AppConfig } from '../../../../config/app-config.interface';
|
||||||
|
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
|
||||||
|
|
||||||
@tabulatableObjectsComponent(AdminNotifySearchResult, ViewMode.Table, Context.CoarNotify)
|
@tabulatableObjectsComponent(PaginatedList<AdminNotifySearchResult>, ViewMode.Table, Context.CoarNotify)
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-admin-notify-search-result',
|
selector: 'ds-admin-notify-search-result',
|
||||||
templateUrl: './admin-notify-search-result.component.html',
|
templateUrl: './admin-notify-search-result.component.html',
|
||||||
styleUrls: ['./admin-notify-search-result.component.scss']
|
styleUrls: ['./admin-notify-search-result.component.scss']
|
||||||
})
|
})
|
||||||
export class AdminNotifySearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifyMessage>, AdminNotifyMessage> implements OnInit{
|
export class AdminNotifySearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifySearchResult>, AdminNotifySearchResult> implements OnInit{
|
||||||
public notifyMessages: AdminNotifyMessage[];
|
public notifyMessages: AdminNotifyMessage[];
|
||||||
ngOnInit() {
|
|
||||||
this.notifyMessages = this.objects.page.map(object => object.indexableObject);
|
private queueStatusMap = {
|
||||||
|
QUEUE_STATUS_PROCESSED: 'Processed',
|
||||||
|
QUEUE_STATUS_FAILED: 'Failed',
|
||||||
|
QUEUE_STATUS_UNMAPPED_ACTION: 'Unmapped action',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(private modalService: NgbModal,
|
||||||
|
protected truncatableService: TruncatableService,
|
||||||
|
public dsoNameService: DSONameService,
|
||||||
|
@Inject(APP_CONFIG) protected appConfig?: AppConfig) {
|
||||||
|
super(truncatableService, dsoNameService, appConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map messages on init for readable representation
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.notifyMessages = this.objects.page.map(object => {
|
||||||
|
const indexableObject = object.indexableObject;
|
||||||
|
indexableObject.coarNotifyType = indexableObject.coarNotifyType.split(':')[1];
|
||||||
|
indexableObject.queueStatusLabel = this.queueStatusMap[indexableObject.queueStatusLabel];
|
||||||
|
return indexableObject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal for details visualization
|
||||||
|
* @param message the message to be displayed
|
||||||
|
*/
|
||||||
|
openDetailModal(message: AdminNotifyMessage) {
|
||||||
|
const modalRef = this.modalService.open(AdminNotifyDetailModalComponent);
|
||||||
|
const messageKeys = Object.keys(message);
|
||||||
|
const keysToRead = [];
|
||||||
|
messageKeys.forEach((key) => {
|
||||||
|
if (typeof message[key] !== 'object') {
|
||||||
|
keysToRead.push(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
modalRef.componentInstance.notifyMessage = message;
|
||||||
|
modalRef.componentInstance.notifyMessageKeys = keysToRead;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,11 +26,35 @@ export class AdminNotifyMessage extends DSpaceObject {
|
|||||||
@autoserialize
|
@autoserialize
|
||||||
coarNotifyType: string;
|
coarNotifyType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the activity
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
activityStreamType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object the message reply to
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
inReplyTo: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attempts of the queue
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
queueAttempts: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp of the last queue attempt
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
queueLastStartTime: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the activity stream
|
* The type of the activity stream
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
source: number;
|
origin: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the activity stream
|
* The type of the activity stream
|
||||||
@@ -56,11 +80,6 @@ export class AdminNotifyMessage extends DSpaceObject {
|
|||||||
@autoserialize
|
@autoserialize
|
||||||
queueStatus: number;
|
queueStatus: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* The status of the queue
|
|
||||||
*/
|
|
||||||
@autoserialize
|
|
||||||
indexableObject: AdminNotifyMessage;
|
|
||||||
|
|
||||||
@deserialize
|
@deserialize
|
||||||
_links: {
|
_links: {
|
||||||
|
@@ -58,20 +58,19 @@
|
|||||||
</ds-object-detail>
|
</ds-object-detail>
|
||||||
|
|
||||||
|
|
||||||
<ds-object-table
|
<ds-object-table [config]="config"
|
||||||
[config]="config"
|
[sortConfig]="sortConfig"
|
||||||
[sortConfig]="sortConfig"
|
[objects]="objects"
|
||||||
[objects]="objects"
|
[hideGear]="hideGear"
|
||||||
[hideGear]="hideGear"
|
[linkType]="linkType"
|
||||||
[linkType]="linkType"
|
[context]="context"
|
||||||
[context]="context"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[showPaginator]="showPaginator"
|
||||||
[showPaginator]="showPaginator"
|
[showThumbnails]="showThumbnails"
|
||||||
[showThumbnails]="showThumbnails"
|
(paginationChange)="onPaginationChange($event)"
|
||||||
(paginationChange)="onPaginationChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
(sortFieldChange)="onSortFieldChange($event)"
|
||||||
(sortFieldChange)="onSortFieldChange($event)"
|
*ngIf="(currentMode$ | async) === viewModeEnum.Table">
|
||||||
*ngIf="(currentMode$ | async) === viewModeEnum.Table">
|
|
||||||
</ds-object-table>
|
</ds-object-table>
|
||||||
|
@@ -34,7 +34,7 @@ export const DEFAULT_THEME = '*';
|
|||||||
* - { level: 1, relevancy: 1 } is less relevant than { level: 2, relevancy: 0 }
|
* - { level: 1, relevancy: 1 } is less relevant than { level: 2, relevancy: 0 }
|
||||||
* - { level: 1, relevancy: 1 } is more relevant than null
|
* - { level: 1, relevancy: 1 } is more relevant than null
|
||||||
*/
|
*/
|
||||||
class MatchRelevancy {
|
export class MatchRelevancy {
|
||||||
constructor(public match: any,
|
constructor(public match: any,
|
||||||
public level: number,
|
public level: number,
|
||||||
public relevancy: number) {
|
public relevancy: number) {
|
||||||
|
@@ -1,70 +1,16 @@
|
|||||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||||
import { Context } from '../../../../core/shared/context.model';
|
import { Context } from '../../../../core/shared/context.model';
|
||||||
import { hasNoValue, hasValue, isNotEmpty } from '../../../empty.util';
|
import { hasNoValue, hasValue } from '../../../empty.util';
|
||||||
import { GenericConstructor } from '../../../../core/shared/generic-constructor';
|
import { GenericConstructor } from '../../../../core/shared/generic-constructor';
|
||||||
import { ListableObject } from '../listable-object.model';
|
import { ListableObject } from '../listable-object.model';
|
||||||
import { environment } from '../../../../../environments/environment';
|
import {
|
||||||
import { ThemeConfig } from '../../../../../config/theme.config';
|
DEFAULT_CONTEXT,
|
||||||
import { InjectionToken } from '@angular/core';
|
DEFAULT_THEME,
|
||||||
|
DEFAULT_VIEW_MODE,
|
||||||
|
MatchRelevancy, resolveTheme
|
||||||
|
} from '../listable-object/listable-object.decorator';
|
||||||
|
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
||||||
|
|
||||||
export const DEFAULT_VIEW_MODE = ViewMode.ListElement;
|
|
||||||
export const DEFAULT_CONTEXT = Context.Any;
|
|
||||||
export const DEFAULT_THEME = '*';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class used to compare two matches and their relevancy to determine which of the two gains priority over the other
|
|
||||||
*
|
|
||||||
* "level" represents the index of the first default value that was used to find the match with:
|
|
||||||
* ViewMode being index 0, Context index 1 and theme index 2. Examples:
|
|
||||||
* - If a default value was used for context, but not view-mode and theme, the "level" will be 1
|
|
||||||
* - If a default value was used for view-mode and context, but not for theme, the "level" will be 0
|
|
||||||
* - If no default value was used for any of the fields, the "level" will be 3
|
|
||||||
*
|
|
||||||
* "relevancy" represents the amount of values that didn't require a default value to fall back on. Examples:
|
|
||||||
* - If a default value was used for theme, but not view-mode and context, the "relevancy" will be 2
|
|
||||||
* - If a default value was used for view-mode and context, but not for theme, the "relevancy" will be 1
|
|
||||||
* - If a default value was used for all fields, the "relevancy" will be 0
|
|
||||||
* - If no default value was used for any of the fields, the "relevancy" will be 3
|
|
||||||
*
|
|
||||||
* To determine which of two MatchRelevancies is the most relevant, we compare "level" and "relevancy" in that order.
|
|
||||||
* If any of the two is higher than the other, that match is most relevant. Examples:
|
|
||||||
* - { level: 1, relevancy: 1 } is more relevant than { level: 0, relevancy: 2 }
|
|
||||||
* - { level: 1, relevancy: 1 } is less relevant than { level: 1, relevancy: 2 }
|
|
||||||
* - { level: 1, relevancy: 1 } is more relevant than { level: 1, relevancy: 0 }
|
|
||||||
* - { level: 1, relevancy: 1 } is less relevant than { level: 2, relevancy: 0 }
|
|
||||||
* - { level: 1, relevancy: 1 } is more relevant than null
|
|
||||||
*/
|
|
||||||
class MatchRelevancy {
|
|
||||||
constructor(public match: any,
|
|
||||||
public level: number,
|
|
||||||
public relevancy: number) {
|
|
||||||
}
|
|
||||||
|
|
||||||
isMoreRelevantThan(otherMatch: MatchRelevancy): boolean {
|
|
||||||
if (hasNoValue(otherMatch)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (otherMatch.level > this.level) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (otherMatch.level === this.level && otherMatch.relevancy > this.relevancy) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLessRelevantThan(otherMatch: MatchRelevancy): boolean {
|
|
||||||
return !this.isMoreRelevantThan(otherMatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory to allow us to inject getThemeConfigFor so we can mock it in tests
|
|
||||||
*/
|
|
||||||
export const GET_THEME_CONFIG_FOR_FACTORY = new InjectionToken<(str) => ThemeConfig>('getThemeConfigFor', {
|
|
||||||
providedIn: 'root',
|
|
||||||
factory: () => getThemeConfigFor
|
|
||||||
});
|
|
||||||
|
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
|
|
||||||
@@ -75,7 +21,7 @@ const map = new Map();
|
|||||||
* @param context The optional context the component represents
|
* @param context The optional context the component represents
|
||||||
* @param theme The optional theme for the component
|
* @param theme The optional theme for the component
|
||||||
*/
|
*/
|
||||||
export function tabulatableObjectsComponent(objectsType: string | GenericConstructor<ListableObject>, viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme = DEFAULT_THEME) {
|
export function tabulatableObjectsComponent(objectsType: string | GenericConstructor<PaginatedList<ListableObject>>, viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme = DEFAULT_THEME) {
|
||||||
return function decorator(component: any) {
|
return function decorator(component: any) {
|
||||||
if (hasNoValue(objectsType)) {
|
if (hasNoValue(objectsType)) {
|
||||||
return;
|
return;
|
||||||
@@ -107,7 +53,7 @@ export function tabulatableObjectsComponent(objectsType: string | GenericConstru
|
|||||||
export function getTabulatableObjectsComponent(types: (string | GenericConstructor<ListableObject>)[], viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme: string = DEFAULT_THEME) {
|
export function getTabulatableObjectsComponent(types: (string | GenericConstructor<ListableObject>)[], viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme: string = DEFAULT_THEME) {
|
||||||
let currentBestMatch: MatchRelevancy = null;
|
let currentBestMatch: MatchRelevancy = null;
|
||||||
for (const type of types) {
|
for (const type of types) {
|
||||||
const typeMap = map.get(type);
|
const typeMap = map.get(PaginatedList<typeof type>);
|
||||||
if (hasValue(typeMap)) {
|
if (hasValue(typeMap)) {
|
||||||
const match = getMatch(typeMap, [viewMode, context, theme], [DEFAULT_VIEW_MODE, DEFAULT_CONTEXT, DEFAULT_THEME]);
|
const match = getMatch(typeMap, [viewMode, context, theme], [DEFAULT_VIEW_MODE, DEFAULT_CONTEXT, DEFAULT_THEME]);
|
||||||
if (hasNoValue(currentBestMatch) || currentBestMatch.isLessRelevantThan(match)) {
|
if (hasNoValue(currentBestMatch) || currentBestMatch.isLessRelevantThan(match)) {
|
||||||
@@ -160,35 +106,3 @@ function getMatch(typeMap: Map<any, any>, keys: any[], defaults: any[]): MatchRe
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for a ThemeConfig by its name;
|
|
||||||
*/
|
|
||||||
export const getThemeConfigFor = (themeName: string): ThemeConfig => {
|
|
||||||
return environment.themes.find(theme => theme.name === themeName);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a match in the given map for the given theme name, taking theme extension into account
|
|
||||||
*
|
|
||||||
* @param contextMap A map of theme names to components
|
|
||||||
* @param themeName The name of the theme to check
|
|
||||||
* @param checkedThemeNames The list of theme names that are already checked
|
|
||||||
*/
|
|
||||||
export const resolveTheme = (contextMap: Map<any, any>, themeName: string, checkedThemeNames: string[] = []): any => {
|
|
||||||
const match = contextMap.get(themeName);
|
|
||||||
if (hasValue(match)) {
|
|
||||||
return match;
|
|
||||||
} else {
|
|
||||||
const cfg = getThemeConfigFor(themeName);
|
|
||||||
if (hasValue(cfg) && isNotEmpty(cfg.extends)) {
|
|
||||||
const nextTheme = cfg.extends;
|
|
||||||
const nextCheckedThemeNames = [...checkedThemeNames, themeName];
|
|
||||||
if (checkedThemeNames.includes(nextTheme)) {
|
|
||||||
throw new Error('Theme extension cycle detected: ' + [...nextCheckedThemeNames, nextTheme].join(' -> '));
|
|
||||||
} else {
|
|
||||||
return resolveTheme(contextMap, nextTheme, nextCheckedThemeNames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@@ -2,17 +2,17 @@ import { Component, Inject } from '@angular/core';
|
|||||||
import {
|
import {
|
||||||
AbstractTabulatableElementComponent
|
AbstractTabulatableElementComponent
|
||||||
} from '../../../object-collection/shared/objects-collection-tabulatable/objects-collection-tabulatable.component';
|
} from '../../../object-collection/shared/objects-collection-tabulatable/objects-collection-tabulatable.component';
|
||||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
|
||||||
import { TruncatableService } from '../../../truncatable/truncatable.service';
|
import { TruncatableService } from '../../../truncatable/truncatable.service';
|
||||||
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
||||||
import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
|
import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
||||||
|
import { SearchResult } from '../../../search/models/search-result.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-result-list-element',
|
selector: 'ds-search-result-list-element',
|
||||||
template: ``
|
template: ``
|
||||||
})
|
})
|
||||||
export class TabulatableResultListElementsComponent<T extends PaginatedList<K>, K extends DSpaceObject> extends AbstractTabulatableElementComponent<T> {
|
export class TabulatableResultListElementsComponent<T extends PaginatedList<K>, K extends SearchResult<any>> extends AbstractTabulatableElementComponent<T> {
|
||||||
public constructor(protected truncatableService: TruncatableService,
|
public constructor(protected truncatableService: TruncatableService,
|
||||||
public dsoNameService: DSONameService,
|
public dsoNameService: DSONameService,
|
||||||
@Inject(APP_CONFIG) protected appConfig?: AppConfig) {
|
@Inject(APP_CONFIG) protected appConfig?: AppConfig) {
|
||||||
|
@@ -15,9 +15,10 @@
|
|||||||
(paginationChange)="onPaginationChange($event)"
|
(paginationChange)="onPaginationChange($event)"
|
||||||
(prev)="goPrev()"
|
(prev)="goPrev()"
|
||||||
(next)="goNext()"
|
(next)="goNext()"
|
||||||
|
[retainScrollPosition]="true"
|
||||||
>
|
>
|
||||||
<div class="row" *ngIf="objects?.hasSucceeded">
|
<div class="row" *ngIf="objects?.hasSucceeded">
|
||||||
<div @fadeIn>
|
<div @fadeIn>
|
||||||
<ds-tabulatable-objects-loader [objects]="objects.payload"
|
<ds-tabulatable-objects-loader [objects]="objects.payload"
|
||||||
[context]="context"
|
[context]="context"
|
||||||
[showThumbnails]="showThumbnails"
|
[showThumbnails]="showThumbnails"
|
||||||
|
@@ -147,13 +147,6 @@ export class ObjectTableComponent {
|
|||||||
this._objects$ = new BehaviorSubject(undefined);
|
this._objects$ = new BehaviorSubject(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the instance variables
|
|
||||||
*/
|
|
||||||
ngOnInit(): void {
|
|
||||||
console.log('table rendered');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits the current page when it changes
|
* Emits the current page when it changes
|
||||||
* @param event The new page
|
* @param event The new page
|
||||||
@@ -205,5 +198,4 @@ export class ObjectTableComponent {
|
|||||||
goNext() {
|
goNext() {
|
||||||
this.next.emit(true);
|
this.next.emit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user