mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
add tabulatable loader and related configuration
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="'logs'">
|
||||
<li [ngbNavItem]="'logs'" (click)="activateTableMode()">
|
||||
<a ngbNavLink>{{'admin-notify-dashboard.logs' | translate}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div id="logs">
|
||||
|
@@ -14,6 +14,8 @@ import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.compo
|
||||
import { AdminNotifySearchConfigurationService } from './config/admin-notify-search-configuration.service';
|
||||
import { AdminNotifySearchFilterService } from './config/admin-notify-filter-service';
|
||||
import { AdminNotifySearchFilterConfig } from './config/admin-notify-search-filter-config';
|
||||
import { ViewMode } from "../../core/shared/view-mode.model";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
export const FILTER_SEARCH: InjectionToken<SearchFilterService> = new InjectionToken<SearchFilterService>('searchFilterService');
|
||||
|
||||
@@ -45,7 +47,8 @@ export class AdminNotifyDashboardComponent implements OnInit{
|
||||
id: 'single-result-options',
|
||||
pageSize: 1
|
||||
});
|
||||
constructor(private searchService: SearchService) {}
|
||||
constructor(private searchService: SearchService,
|
||||
private router: Router) {}
|
||||
|
||||
ngOnInit() {
|
||||
const mertricsRowsConfigurations = this.metricsConfig
|
||||
@@ -99,4 +102,28 @@ export class AdminNotifyDashboardComponent implements OnInit{
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate Table view mode for search result rendering
|
||||
*/
|
||||
activateTableMode() {
|
||||
this.searchService.setViewMode(ViewMode.Table, this.getSearchLinkParts());
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
return this.searchService.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string[]} The base path to the search page, or the current page when inPlaceSearch is true, split in separate pieces
|
||||
*/
|
||||
public getSearchLinkParts(): string[] {
|
||||
if (this.searchService) {
|
||||
return [];
|
||||
}
|
||||
return this.getSearchLink().split('/');
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,34 @@
|
||||
<div class="d-flex bg-light w-100 align-items-center">
|
||||
<div class="p-2 text-truncate">{{indexableObject.queueTimeout ?? 'n/a'}}</div>
|
||||
<div class="p-2 text-truncate">{{indexableObject.source ?? 'n/a'}}</div>
|
||||
<div class="p-2 text-truncate">{{indexableObject.target ?? 'n/a'}}</div>
|
||||
<div class="p-2 text-truncate">{{indexableObject.coarNotifyType ?? 'n/a'}}</div>
|
||||
<div class="p-2 text-truncate">{{indexableObject.queueStatusLabel ?? 'n/a'}}</div>
|
||||
<div class="table-responsive">
|
||||
<table id="formats" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Timestamp</th>
|
||||
<th scope="col">Source</th>
|
||||
<th scope="col">Target</th>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let object of indexableObjects">
|
||||
<td>
|
||||
<div>{{object.queueTimeout}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{object.source}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{object.target}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{object.coarNotifyType}}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{object.queueStatusLabel}}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,24 +1,26 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {
|
||||
listableObjectComponent
|
||||
} from '../../../shared/object-collection/shared/listable-object/listable-object.decorator';
|
||||
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
|
||||
import { ViewMode } from '../../../core/shared/view-mode.model';
|
||||
import { Context } from '../../../core/shared/context.model';
|
||||
import {
|
||||
SearchResultListElementComponent
|
||||
} from '../../../shared/object-list/search-result-list-element/search-result-list-element.component';
|
||||
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
|
||||
import {
|
||||
tabulatableObjectsComponent
|
||||
} from "../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator";
|
||||
import {
|
||||
TabulatableResultListElementsComponent
|
||||
} from "../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component";
|
||||
import { PaginatedList } from "../../../core/data/paginated-list.model";
|
||||
|
||||
@listableObjectComponent(AdminNotifySearchResult, ViewMode.ListElement, Context.CoarNotify)
|
||||
@tabulatableObjectsComponent(AdminNotifySearchResult, ViewMode.Table, Context.CoarNotify)
|
||||
@Component({
|
||||
selector: 'ds-admin-notify-search-result',
|
||||
templateUrl: './admin-notify-search-result.component.html',
|
||||
styleUrls: ['./admin-notify-search-result.component.scss']
|
||||
})
|
||||
export class AdminNotifySearchResultComponent extends SearchResultListElementComponent<AdminNotifySearchResult, AdminNotifyMessage> implements OnInit{
|
||||
indexableObject: AdminNotifyMessage;
|
||||
export class AdminNotifySearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifyMessage>, AdminNotifyMessage> implements OnInit{
|
||||
public indexableObjects: AdminNotifyMessage[];
|
||||
ngOnInit() {
|
||||
this.indexableObject = this.object.indexableObject;
|
||||
this.indexableObjects = this.objects.page.map(object => object.indexableObject);
|
||||
console.log(this.objects.page)
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,12 @@ export class AdminNotifyMessage extends DSpaceObject {
|
||||
@autoserialize
|
||||
queueStatus: number;
|
||||
|
||||
/**
|
||||
* The status of the queue
|
||||
*/
|
||||
@autoserialize
|
||||
indexableObject: AdminNotifyMessage;
|
||||
|
||||
@deserialize
|
||||
_links: {
|
||||
self: {
|
||||
|
@@ -7,4 +7,5 @@ export enum ViewMode {
|
||||
GridElement = 'grid',
|
||||
DetailedListElement = 'detailed',
|
||||
StandalonePage = 'standalone',
|
||||
Table = 'table',
|
||||
}
|
||||
|
@@ -58,3 +58,20 @@
|
||||
</ds-object-detail>
|
||||
|
||||
|
||||
<ds-object-table
|
||||
[config]="config"
|
||||
[sortConfig]="sortConfig"
|
||||
[objects]="objects"
|
||||
[hideGear]="hideGear"
|
||||
[linkType]="linkType"
|
||||
[context]="context"
|
||||
[hidePaginationDetail]="hidePaginationDetail"
|
||||
[showPaginator]="showPaginator"
|
||||
[showThumbnails]="showThumbnails"
|
||||
(paginationChange)="onPaginationChange($event)"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||
(sortFieldChange)="onSortFieldChange($event)"
|
||||
*ngIf="(currentMode$ | async) === viewModeEnum.Table">
|
||||
</ds-object-table>
|
||||
|
@@ -154,7 +154,6 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
|
||||
}
|
||||
|
||||
private instantiateComponent(object: ListableObject, changes?: SimpleChanges): void {
|
||||
|
||||
const component = this.getComponent(object.getRenderTypes(), this.viewMode, this.context);
|
||||
|
||||
const viewContainerRef = this.listableObjectDirective.viewContainerRef;
|
||||
|
@@ -0,0 +1,194 @@
|
||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
import { hasNoValue, hasValue, isNotEmpty } from '../../../empty.util';
|
||||
import { GenericConstructor } from '../../../../core/shared/generic-constructor';
|
||||
import { ListableObject } from '../listable-object.model';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
import { ThemeConfig } from '../../../../../config/theme.config';
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
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();
|
||||
|
||||
/**
|
||||
* Decorator used for rendering a listable object
|
||||
* @param objectType The object type or entity type the component represents
|
||||
* @param viewMode The view mode the component represents
|
||||
* @param context The optional context the component represents
|
||||
* @param theme The optional theme for the component
|
||||
*/
|
||||
export function tabulatableObjectsComponent(objectsType: string | GenericConstructor<ListableObject>, viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme = DEFAULT_THEME) {
|
||||
return function decorator(component: any) {
|
||||
if (hasNoValue(objectsType)) {
|
||||
return;
|
||||
}
|
||||
if (hasNoValue(map.get(objectsType))) {
|
||||
map.set(objectsType, new Map());
|
||||
}
|
||||
if (hasNoValue(map.get(objectsType).get(viewMode))) {
|
||||
map.get(objectsType).set(viewMode, new Map());
|
||||
}
|
||||
if (hasNoValue(map.get(objectsType).get(viewMode).get(context))) {
|
||||
map.get(objectsType).get(viewMode).set(context, new Map());
|
||||
}
|
||||
map.get(objectsType).get(viewMode).get(context).set(theme, component);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter to retrieve the matching listable object component
|
||||
*
|
||||
* Looping over the provided types, it'll attempt to find the best match depending on the {@link MatchRelevancy} returned by getMatch()
|
||||
* The most relevant match between types is kept and eventually returned
|
||||
*
|
||||
* @param types The types of which one should match the listable component
|
||||
* @param viewMode The view mode that should match the components
|
||||
* @param context The context that should match the components
|
||||
* @param theme The theme that should match the components
|
||||
*/
|
||||
export function getTabulatableObjectsComponent(types: (string | GenericConstructor<ListableObject>)[], viewMode: ViewMode, context: Context = DEFAULT_CONTEXT, theme: string = DEFAULT_THEME) {
|
||||
let currentBestMatch: MatchRelevancy = null;
|
||||
for (const type of types) {
|
||||
const typeMap = map.get(type);
|
||||
if (hasValue(typeMap)) {
|
||||
const match = getMatch(typeMap, [viewMode, context, theme], [DEFAULT_VIEW_MODE, DEFAULT_CONTEXT, DEFAULT_THEME]);
|
||||
if (hasNoValue(currentBestMatch) || currentBestMatch.isLessRelevantThan(match)) {
|
||||
currentBestMatch = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasValue(currentBestMatch) ? currentBestMatch.match : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an object within a nested map, matching the provided keys as best as possible, falling back on defaults wherever
|
||||
* needed.
|
||||
*
|
||||
* Starting off with a Map, it loops over the provided keys, going deeper into the map until it finds a value
|
||||
* If at some point, no value is found, it'll attempt to use the default value for that index instead
|
||||
* If the default value exists, the index is stored in the "level"
|
||||
* If no default value exists, 1 is added to "relevancy"
|
||||
* See {@link MatchRelevancy} what these represent
|
||||
*
|
||||
* @param typeMap a multi-dimensional map
|
||||
* @param keys the keys of the multi-dimensional map to loop over. Each key represents a level within the map
|
||||
* @param defaults the default values to use for each level, in case no value is found for the key at that index
|
||||
* @returns matchAndLevel a {@link MatchRelevancy} object containing the match and its level of relevancy
|
||||
*/
|
||||
function getMatch(typeMap: Map<any, any>, keys: any[], defaults: any[]): MatchRelevancy {
|
||||
let currentMap = typeMap;
|
||||
let level = -1;
|
||||
let relevancy = 0;
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
// If we're currently checking the theme, resolve it first to take extended themes into account
|
||||
let currentMatch = defaults[i] === DEFAULT_THEME ? resolveTheme(currentMap, keys[i]) : currentMap.get(keys[i]);
|
||||
if (hasNoValue(currentMatch)) {
|
||||
currentMatch = currentMap.get(defaults[i]);
|
||||
if (level === -1) {
|
||||
level = i;
|
||||
}
|
||||
} else {
|
||||
relevancy++;
|
||||
}
|
||||
if (hasValue(currentMatch)) {
|
||||
if (currentMatch instanceof Map) {
|
||||
currentMap = currentMatch as Map<any, any>;
|
||||
} else {
|
||||
return new MatchRelevancy(currentMatch, level > -1 ? level : i + 1, relevancy);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@@ -0,0 +1,11 @@
|
||||
import { Directive, ViewContainerRef } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[dsTabulatableObjects]',
|
||||
})
|
||||
/**
|
||||
* Directive used as a hook to know where to inject the dynamic listable object component
|
||||
*/
|
||||
export class TabulatableObjectsDirective {
|
||||
constructor(public viewContainerRef: ViewContainerRef) { }
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import {
|
||||
AbstractTabulatableElementComponent
|
||||
} 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 { DSONameService } from "../../../../core/breadcrumbs/dso-name.service";
|
||||
import { APP_CONFIG, AppConfig } from "../../../../../config/app-config.interface";
|
||||
import { PaginatedList } from "../../../../core/data/paginated-list.model";
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-result-list-element',
|
||||
template: ``
|
||||
})
|
||||
export class TabulatableResultListElementsComponent<T extends PaginatedList<K>, K extends DSpaceObject> extends AbstractTabulatableElementComponent<T> {
|
||||
public constructor(protected truncatableService: TruncatableService,
|
||||
public dsoNameService: DSONameService,
|
||||
@Inject(APP_CONFIG) protected appConfig?: AppConfig) {
|
||||
super(dsoNameService);
|
||||
}
|
||||
|
||||
}
|
32
src/app/shared/object-table/object-table.component.html
Normal file
32
src/app/shared/object-table/object-table.component.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<ds-pagination
|
||||
[paginationOptions]="config"
|
||||
[pageInfoState]="objects?.payload"
|
||||
[collectionSize]="objects?.payload?.totalElements"
|
||||
[sortOptions]="sortConfig"
|
||||
[hideGear]="hideGear"
|
||||
[objects]="objects"
|
||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||
[hidePaginationDetail]="hidePaginationDetail"
|
||||
[showPaginator]="showPaginator"
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||
(sortFieldChange)="onSortFieldChange($event)"
|
||||
(paginationChange)="onPaginationChange($event)"
|
||||
(prev)="goPrev()"
|
||||
(next)="goNext()"
|
||||
>
|
||||
<div class="row" *ngIf="objects?.hasSucceeded">
|
||||
<div @fadeIn>
|
||||
<ds-tabulatable-objects-loader [objects]="objects.payload"
|
||||
[context]="context"
|
||||
[showThumbnails]="showThumbnails"
|
||||
[linkType]="linkType">
|
||||
</ds-tabulatable-objects-loader>
|
||||
</div>
|
||||
</div>
|
||||
<ds-error *ngIf="objects.hasFailed" message="{{'error.objects' | translate}}"></ds-error>
|
||||
<ds-themed-loading *ngIf="objects.isLoading" message="{{'loading.objects' | translate}}"></ds-themed-loading>
|
||||
</ds-pagination>
|
||||
|
||||
|
23
src/app/shared/object-table/object-table.component.spec.ts
Normal file
23
src/app/shared/object-table/object-table.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ObjectTableComponent } from './object-table.component';
|
||||
|
||||
describe('ObjectTableComponent', () => {
|
||||
let component: ObjectTableComponent;
|
||||
let fixture: ComponentFixture<ObjectTableComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ObjectTableComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ObjectTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
209
src/app/shared/object-table/object-table.component.ts
Normal file
209
src/app/shared/object-table/object-table.component.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
||||
import { ViewMode } from "../../core/shared/view-mode.model";
|
||||
import { PaginationComponentOptions } from "../pagination/pagination-component-options.model";
|
||||
import { SortDirection, SortOptions } from "../../core/cache/models/sort-options.model";
|
||||
import { CollectionElementLinkType } from "../object-collection/collection-element-link.type";
|
||||
import { Context } from "../../core/shared/context.model";
|
||||
import { BehaviorSubject} from "rxjs";
|
||||
import { RemoteData } from "../../core/data/remote-data";
|
||||
import { PaginatedList } from "../../core/data/paginated-list.model";
|
||||
import { ListableObject } from "../object-collection/shared/listable-object.model";
|
||||
import { fadeIn } from "../animations/fade";
|
||||
|
||||
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.Default,
|
||||
encapsulation: ViewEncapsulation.Emulated,
|
||||
selector: 'ds-object-table',
|
||||
templateUrl: './object-table.component.html',
|
||||
styleUrls: ['./object-table.component.scss'],
|
||||
animations: [fadeIn]
|
||||
})
|
||||
export class ObjectTableComponent {
|
||||
/**
|
||||
* The view mode of this component
|
||||
*/
|
||||
viewMode = ViewMode.Table;
|
||||
|
||||
/**
|
||||
* The current pagination configuration
|
||||
*/
|
||||
@Input() config: PaginationComponentOptions;
|
||||
|
||||
/**
|
||||
* The current sort configuration
|
||||
*/
|
||||
@Input() sortConfig: SortOptions;
|
||||
|
||||
/**
|
||||
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||
*/
|
||||
@Input() showPaginator = true;
|
||||
|
||||
/**
|
||||
* Whether to show the thumbnail preview
|
||||
*/
|
||||
@Input() showThumbnails;
|
||||
|
||||
/**
|
||||
* The whether or not the gear is hidden
|
||||
*/
|
||||
@Input() hideGear = false;
|
||||
|
||||
/**
|
||||
* Whether or not the pager is visible when there is only a single page of results
|
||||
*/
|
||||
@Input() hidePagerWhenSinglePage = true;
|
||||
|
||||
/**
|
||||
* The link type of the listable elements
|
||||
*/
|
||||
@Input() linkType: CollectionElementLinkType;
|
||||
|
||||
/**
|
||||
* The context of the listable elements
|
||||
*/
|
||||
@Input() context: Context;
|
||||
|
||||
/**
|
||||
* Option for hiding the pagination detail
|
||||
*/
|
||||
@Input() hidePaginationDetail = false;
|
||||
|
||||
/**
|
||||
* Behavior subject to output the current listable objects
|
||||
*/
|
||||
private _objects$: BehaviorSubject<RemoteData<PaginatedList<ListableObject>>>;
|
||||
|
||||
/**
|
||||
* Setter to make sure the observable is turned into an observable
|
||||
* @param objects The new objects to output
|
||||
*/
|
||||
@Input() set objects(objects: RemoteData<PaginatedList<ListableObject>>) {
|
||||
this._objects$.next(objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter to return the current objects
|
||||
*/
|
||||
get objects() {
|
||||
return this._objects$.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event fired when the page is changed.
|
||||
* Event's payload equals to the newly selected page.
|
||||
*/
|
||||
@Output() change: EventEmitter<{
|
||||
pagination: PaginationComponentOptions,
|
||||
sort: SortOptions
|
||||
}> = new EventEmitter<{
|
||||
pagination: PaginationComponentOptions,
|
||||
sort: SortOptions
|
||||
}>();
|
||||
|
||||
/**
|
||||
* An event fired when the page is changed.
|
||||
* Event's payload equals to the newly selected page.
|
||||
*/
|
||||
@Output() pageChange: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
/**
|
||||
* An event fired when the page wsize is changed.
|
||||
* Event's payload equals to the newly selected page size.
|
||||
*/
|
||||
@Output() pageSizeChange: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
/**
|
||||
* An event fired when the sort direction is changed.
|
||||
* Event's payload equals to the newly selected sort direction.
|
||||
*/
|
||||
@Output() sortDirectionChange: EventEmitter<SortDirection> = new EventEmitter<SortDirection>();
|
||||
|
||||
/**
|
||||
* An event fired when on of the pagination parameters changes
|
||||
*/
|
||||
@Output() paginationChange: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* An event fired when the sort field is changed.
|
||||
* Event's payload equals to the newly selected sort field.
|
||||
*/
|
||||
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* If showPaginator is set to true, emit when the previous button is clicked
|
||||
*/
|
||||
@Output() prev = new EventEmitter<boolean>();
|
||||
|
||||
/**
|
||||
* If showPaginator is set to true, emit when the next button is clicked
|
||||
*/
|
||||
@Output() next = new EventEmitter<boolean>();
|
||||
|
||||
data: any = {};
|
||||
|
||||
constructor() {
|
||||
this._objects$ = new BehaviorSubject(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the instance variables
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
console.log('table rendered')
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the current page when it changes
|
||||
* @param event The new page
|
||||
*/
|
||||
onPageChange(event) {
|
||||
this.pageChange.emit(event);
|
||||
}
|
||||
/**
|
||||
* Emits the current page size when it changes
|
||||
* @param event The new page size
|
||||
*/
|
||||
onPageSizeChange(event) {
|
||||
this.pageSizeChange.emit(event);
|
||||
}
|
||||
/**
|
||||
* Emits the current sort direction when it changes
|
||||
* @param event The new sort direction
|
||||
*/
|
||||
onSortDirectionChange(event) {
|
||||
this.sortDirectionChange.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the current sort field when it changes
|
||||
* @param event The new sort field
|
||||
*/
|
||||
onSortFieldChange(event) {
|
||||
this.sortFieldChange.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the current pagination when it changes
|
||||
* @param event The new pagination
|
||||
*/
|
||||
onPaginationChange(event) {
|
||||
this.paginationChange.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the previous page
|
||||
*/
|
||||
goPrev() {
|
||||
this.prev.emit(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next page
|
||||
*/
|
||||
goNext() {
|
||||
this.next.emit(true);
|
||||
}
|
||||
|
||||
}
|
@@ -286,6 +286,17 @@ import { SplitPipe } from './utils/split.pipe';
|
||||
import { ThemedUserMenuComponent } from './auth-nav-menu/user-menu/themed-user-menu.component';
|
||||
import { ThemedLangSwitchComponent } from './lang-switch/themed-lang-switch.component';
|
||||
import { NotificationBoxComponent } from './notification-box/notification-box.component';
|
||||
import { ObjectTableComponent } from './object-table/object-table.component';
|
||||
import { TabulatableObjectsLoaderComponent } from './object-collection/shared/tabulatable-objects/tabulatable-objects-loader.component';
|
||||
import {
|
||||
TabulatableObjectsDirective
|
||||
} from "./object-collection/shared/tabulatable-objects/tabulatable-objects.directive";
|
||||
import {
|
||||
AbstractTabulatableElementComponent
|
||||
} from "./object-collection/shared/objects-collection-tabulatable/objects-collection-tabulatable.component";
|
||||
import {
|
||||
TabulatableResultListElementsComponent
|
||||
} from "./object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component";
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
@@ -349,7 +360,9 @@ const COMPONENTS = [
|
||||
ThemedObjectListComponent,
|
||||
ObjectDetailComponent,
|
||||
ObjectGridComponent,
|
||||
ObjectTableComponent,
|
||||
AbstractListableElementComponent,
|
||||
AbstractTabulatableElementComponent,
|
||||
ObjectCollectionComponent,
|
||||
PaginationComponent,
|
||||
RSSComponent,
|
||||
@@ -415,6 +428,7 @@ const ENTRY_COMPONENTS = [
|
||||
CollectionListElementComponent,
|
||||
CommunityListElementComponent,
|
||||
SearchResultListElementComponent,
|
||||
TabulatableResultListElementsComponent,
|
||||
CommunitySearchResultListElementComponent,
|
||||
CollectionSearchResultListElementComponent,
|
||||
CollectionGridElementComponent,
|
||||
@@ -471,7 +485,8 @@ const ENTRY_COMPONENTS = [
|
||||
EpersonGroupListComponent,
|
||||
EpersonSearchBoxComponent,
|
||||
GroupSearchBoxComponent,
|
||||
NotificationBoxComponent
|
||||
NotificationBoxComponent,
|
||||
TabulatableObjectsLoaderComponent,
|
||||
];
|
||||
|
||||
const PROVIDERS = [
|
||||
@@ -490,6 +505,7 @@ const DIRECTIVES = [
|
||||
RoleDirective,
|
||||
MetadataRepresentationDirective,
|
||||
ListableObjectDirective,
|
||||
TabulatableObjectsDirective,
|
||||
ClaimedTaskActionsDirective,
|
||||
FileValueAccessorDirective,
|
||||
FileValidator,
|
||||
|
Reference in New Issue
Block a user