Merge branch 'w2p-111638_Process-admin-UI-redesign_Overview-page-tables_PR-feedback' into process-admin-ui-redesign-8.0.0-next

This commit is contained in:
Andreas Awouters
2024-02-07 11:18:28 +01:00
12 changed files with 157 additions and 173 deletions

View File

@@ -7,8 +7,7 @@ import { ControlContainer, NgForm } from '@angular/forms';
import { ScriptParameter } from '../scripts/script-parameter.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { RequestService } from '../../core/data/request.service';
import { Router } from '@angular/router';
import { Router, NavigationExtras } from '@angular/router';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { RemoteData } from '../../core/data/remote-data';
import { getProcessListRoute } from '../process-page-routing.paths';
@@ -57,7 +56,6 @@ export class ProcessFormComponent implements OnInit {
private scriptService: ScriptDataService,
private notificationsService: NotificationsService,
private translationService: TranslateService,
private requestService: RequestService,
private router: Router) {
}
@@ -91,7 +89,7 @@ export class ProcessFormComponent implements OnInit {
const title = this.translationService.get('process.new.notification.success.title');
const content = this.translationService.get('process.new.notification.success.content');
this.notificationsService.success(title, content);
this.sendBack();
this.sendBack(rd.payload);
} else {
const title = this.translationService.get('process.new.notification.error.title');
const content = this.translationService.get('process.new.notification.error.content');
@@ -143,11 +141,17 @@ export class ProcessFormComponent implements OnInit {
return this.missingParameters.length > 0;
}
private sendBack() {
this.requestService.removeByHrefSubstring('/processes');
/* should subscribe on the previous method to know the action is finished and then navigate,
will fix this when the removeByHrefSubstring changes are merged */
this.router.navigateByUrl(getProcessListRoute());
/**
* Redirect the user to the processes overview page with the new process' ID,
* so it can be highlighted in the overview table.
* @param newProcess The newly created process
* @private
*/
private sendBack(newProcess: Process) {
const extras: NavigationExtras = {
queryParams: { new_process_id: newProcess.processId },
};
void this.router.navigate([getProcessListRoute()], extras);
}
}

View File

@@ -2,18 +2,7 @@
<div class="d-flex">
<h1 class="flex-grow-1">{{'process.overview.title' | translate}}</h1>
</div>
<div class="d-flex justify-content-end mb-2">
<button *ngIf="processBulkDeleteService.hasSelected()" class="btn btn-primary mr-2"
(click)="processBulkDeleteService.clearAllProcesses()"><i
class="fas fa-undo pr-2"></i>{{'process.overview.delete.clear' | translate }}
</button>
<button *ngIf="processBulkDeleteService.hasSelected()" class="btn btn-danger mr-2"
(click)="openDeleteModal(deleteModal)"><i
class="fas fa-trash pr-2"></i>{{'process.overview.delete' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}
</button>
<button class="btn btn-success" routerLink="/processes/new"><i
class="fas fa-plus pr-2"></i>{{'process.overview.new' | translate}}</button>
</div>
<ng-container *ngTemplateOutlet="buttons"></ng-container>
<div class="sections">
<ds-process-overview-table
@@ -23,18 +12,37 @@
<ds-process-overview-table
[processStatus]="ProcessStatus.SCHEDULED"
[useAutoRefreshingSearchBy]="true"
[getInfoValueMethod]="processOverviewService.timeStarted"/>
[getInfoValueMethod]="processOverviewService.timeCreated"/>
<ds-process-overview-table
[processStatus]="ProcessStatus.COMPLETED"
[sortField]="ProcessSortField.endTime"
[useAutoRefreshingSearchBy]="true"
[getInfoValueMethod]="processOverviewService.timeCompleted"/>
<ds-process-overview-table
[processStatus]="ProcessStatus.FAILED"
[sortField]="ProcessSortField.endTime"
[useAutoRefreshingSearchBy]="true"
[getInfoValueMethod]="processOverviewService.timeCompleted"/>
</div>
<ng-container *ngTemplateOutlet="buttons"></ng-container>
</div>
<ng-template #buttons>
<div class="d-flex justify-content-end mb-2">
<button *ngIf="processBulkDeleteService.hasSelected()" class="btn btn-primary mr-2"
(click)="processBulkDeleteService.clearAllProcesses()"><i
class="fas fa-undo pr-2"></i>{{'process.overview.delete.clear' | translate }}
</button>
<button *ngIf="processBulkDeleteService.hasSelected()" class="btn btn-danger mr-2"
(click)="openDeleteModal(deleteModal)"><i
class="fas fa-trash pr-2"></i>{{'process.overview.delete' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}
</button>
<button class="btn btn-success" routerLink="/processes/new"><i
class="fas fa-plus pr-2"></i>{{'process.overview.new' | translate}}</button>
</div>
</ng-template>
<ng-template #deleteModal>
<div>

View File

@@ -3,86 +3,27 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NO_ERRORS_SCHEMA, TemplateRef } from '@angular/core';
import { ProcessDataService } from '../../core/data/processes/process-data.service';
import { Process } from '../processes/process.model';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { By } from '@angular/platform-browser';
import { ProcessStatus } from '../processes/process-status.model';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { DatePipe } from '@angular/common';
import { BehaviorSubject } from 'rxjs';
import { ProcessBulkDeleteService } from './process-bulk-delete.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ProcessOverviewService } from './process-overview.service';
describe('ProcessOverviewComponent', () => {
let component: ProcessOverviewComponent;
let fixture: ComponentFixture<ProcessOverviewComponent>;
let processService: ProcessDataService;
let ePersonService: EPersonDataService;
let paginationService;
let processes: Process[];
let ePerson: EPerson;
let processBulkDeleteService;
let modalService;
const pipe = new DatePipe('en-US');
function init() {
processes = [
Object.assign(new Process(), {
processId: 1,
scriptName: 'script-name',
startTime: '2020-03-19 00:30:00',
endTime: '2020-03-19 23:30:00',
processStatus: ProcessStatus.COMPLETED
}),
Object.assign(new Process(), {
processId: 2,
scriptName: 'script-name',
startTime: '2020-03-20 00:30:00',
endTime: '2020-03-20 23:30:00',
processStatus: ProcessStatus.FAILED
}),
Object.assign(new Process(), {
processId: 3,
scriptName: 'another-script-name',
startTime: '2020-03-21 00:30:00',
endTime: '2020-03-21 23:30:00',
processStatus: ProcessStatus.RUNNING
})
];
ePerson = Object.assign(new EPerson(), {
metadata: {
'eperson.firstname': [
{
value: 'John',
language: null
}
],
'eperson.lastname': [
{
value: 'Doe',
language: null
}
]
}
processService = jasmine.createSpyObj('processOverviewService', {
timeStarted: '2024-02-05 16:43:32',
});
processService = jasmine.createSpyObj('processService', {
findAll: createSuccessfulRemoteDataObject$(createPaginatedList(processes))
});
ePersonService = jasmine.createSpyObj('ePersonService', {
findById: createSuccessfulRemoteDataObject$(ePerson)
});
paginationService = new PaginationServiceStub();
processBulkDeleteService = jasmine.createSpyObj('processBulkDeleteService', {
clearAllProcesses: {},
@@ -96,11 +37,7 @@ describe('ProcessOverviewComponent', () => {
});
(processBulkDeleteService.isToBeDeleted as jasmine.Spy).and.callFake((id) => {
if (id === 2) {
return true;
} else {
return false;
}
return id === 2;
});
modalService = jasmine.createSpyObj('modalService', {
@@ -114,9 +51,7 @@ describe('ProcessOverviewComponent', () => {
declarations: [ProcessOverviewComponent, VarDirective],
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
providers: [
{ provide: ProcessDataService, useValue: processService },
{ provide: EPersonDataService, useValue: ePersonService },
{ provide: PaginationService, useValue: paginationService },
{ provide: ProcessOverviewService, useValue: processService },
{ provide: ProcessBulkDeleteService, useValue: processBulkDeleteService },
{ provide: NgbModal, useValue: modalService },
],
@@ -165,7 +100,7 @@ describe('ProcessOverviewComponent', () => {
describe('openDeleteModal', () => {
it('should open the modal', () => {
component.openDeleteModal({});
component.openDeleteModal({} as TemplateRef<any>);
expect(modalService.open).toHaveBeenCalledWith({});
});
});
@@ -173,13 +108,11 @@ describe('ProcessOverviewComponent', () => {
describe('deleteSelected', () => {
it('should call the deleteSelectedProcesses method on the processBulkDeleteService and close the modal when processing is done', () => {
spyOn(component, 'closeModal');
spyOn(component, 'setProcesses');
component.deleteSelected();
expect(processBulkDeleteService.deleteSelectedProcesses).toHaveBeenCalled();
expect(component.closeModal).toHaveBeenCalled();
expect(component.setProcesses).toHaveBeenCalled();
});
});
});

View File

@@ -1,19 +1,9 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { PaginatedList } from '../../core/data/paginated-list.model';
import { Process } from '../processes/process.model';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { switchMap } from 'rxjs/operators';
import { ProcessDataService } from '../../core/data/processes/process-data.service';
import { PaginationService } from '../../core/pagination/pagination.service';
import { FindListOptions } from '../../core/data/find-list-options.model';
import { Component, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { Subscription } from 'rxjs';
import { ProcessBulkDeleteService } from './process-bulk-delete.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { hasValue } from '../../shared/empty.util';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { ProcessOverviewService } from './process-overview.service';
import { ProcessOverviewService, ProcessSortField } from './process-overview.service';
import { ProcessStatus } from '../processes/process-status.model';
@Component({
@@ -25,64 +15,25 @@ import { ProcessStatus } from '../processes/process-status.model';
*/
export class ProcessOverviewComponent implements OnInit, OnDestroy {
// Enums are redeclared here so they can be used in the template
protected readonly ProcessStatus = ProcessStatus;
protected readonly ProcessSortField = ProcessSortField;
/**
* List of all processes
*/
processesRD$: Observable<RemoteData<PaginatedList<Process>>>;
/**
* The current pagination configuration for the page used by the FindAll method
*/
config: FindListOptions = Object.assign(new FindListOptions(), {
elementsPerPage: 20
});
/**
* The current pagination configuration for the page
*/
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'po',
pageSize: 20
});
/**
* Date format to use for start and end time of processes
*/
dateFormat = 'yyyy-MM-dd HH:mm:ss';
processesToDelete: string[] = [];
private modalRef: any;
isProcessingSub: Subscription;
constructor(protected processService: ProcessDataService,
protected processOverviewService: ProcessOverviewService,
protected paginationService: PaginationService,
protected ePersonService: EPersonDataService,
constructor(protected processOverviewService: ProcessOverviewService,
protected modalService: NgbModal,
public processBulkDeleteService: ProcessBulkDeleteService,
protected dsoNameService: DSONameService,
) {
}
ngOnInit(): void {
this.setProcesses();
this.processBulkDeleteService.clearAllProcesses();
}
/**
* Send a request to fetch all processes for the current page
*/
setProcesses() {
this.processesRD$ = this.paginationService.getFindListOptions(this.pageConfig.id, this.config).pipe(
switchMap((config) => this.processService.findAll(config, true, false))
);
}
ngOnDestroy(): void {
this.paginationService.clearPagination(this.pageConfig.id);
if (hasValue(this.isProcessingSub)) {
this.isProcessingSub.unsubscribe();
}
@@ -92,7 +43,7 @@ export class ProcessOverviewComponent implements OnInit, OnDestroy {
* Open a given modal.
* @param content - the modal content.
*/
openDeleteModal(content) {
openDeleteModal(content: TemplateRef<any>) {
this.modalRef = this.modalService.open(content);
}
@@ -118,7 +69,6 @@ export class ProcessOverviewComponent implements OnInit, OnDestroy {
.subscribe((isProcessing) => {
if (!isProcessing) {
this.closeModal();
this.setProcesses();
}
});
}

View File

@@ -9,6 +9,19 @@ import { RequestParam } from '../../core/cache/models/request-param.model';
import { ProcessStatus } from '../processes/process-status.model';
import { DatePipe } from '@angular/common';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortOptions, SortDirection } from '../../core/cache/models/sort-options.model';
import { hasValue } from '../../shared/empty.util';
/**
* The sortable fields for processes
* See [the endpoint documentation]{@link https://github.com/DSpace/RestContract/blob/main/processes-endpoint.md#search-processes-by-property}
* for details.
*/
export enum ProcessSortField {
creationTime = 'creationTime',
startTime = 'startTime',
endTime = 'endTime',
}
/**
* Service to manage the processes displayed in the
@@ -30,6 +43,7 @@ export class ProcessOverviewService {
datePipe = new DatePipe('en-US');
timeCreated = (process: Process) => this.datePipe.transform(process.creationTime, this.dateFormat, 'UTC');
timeCompleted = (process: Process) => this.datePipe.transform(process.endTime, this.dateFormat, 'UTC');
timeStarted = (process: Process) => this.datePipe.transform(process.startTime, this.dateFormat, 'UTC');
@@ -47,7 +61,7 @@ export class ProcessOverviewService {
elementsPerPage: 5,
}, findListOptions);
if (autoRefreshingIntervalInMs !== null && autoRefreshingIntervalInMs > 0) {
if (hasValue(autoRefreshingIntervalInMs) && autoRefreshingIntervalInMs > 0) {
return this.processDataService.autoRefreshingSearchBy('byProperty', options, autoRefreshingIntervalInMs);
} else {
return this.processDataService.searchBy('byProperty', options);
@@ -57,13 +71,16 @@ export class ProcessOverviewService {
/**
* Map the provided paginationOptions to FindListOptions
* @param paginationOptions the PaginationComponentOptions to map
* @param sortField the field on which the processes are sorted
*/
getFindListOptions(paginationOptions: PaginationComponentOptions): FindListOptions {
getFindListOptions(paginationOptions: PaginationComponentOptions, sortField: ProcessSortField): FindListOptions {
let sortOptions = new SortOptions(sortField, SortDirection.DESC);
return Object.assign(
new FindListOptions(),
{
currentPage: paginationOptions.currentPage,
elementsPerPage: paginationOptions.pageSize,
sort: sortOptions,
}
);
}

View File

@@ -12,7 +12,7 @@
</h2>
</div>
<div ngbCollapse #collapse="ngbCollapse">
<div ngbCollapse #collapse="ngbCollapse" [ngbCollapse]="isCollapsed">
<ng-container *ngVar="(processesRD$ | async) as processesRD">
<ds-themed-loading *ngIf="!processesRD || processesRD.isLoading"/>
@@ -27,7 +27,7 @@
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col" class="status-header">{{'process.overview.table.status' | translate}}</th>
<th scope="col" class="id-header">{{'process.overview.table.id' | translate}}</th>
<th scope="col" class="name-header">{{'process.overview.table.name' | translate}}</th>
<th scope="col" class="user-header">{{'process.overview.table.user' | translate}}</th>
<th scope="col" class="info-header">{{'process.overview.table.' + processStatus.toLowerCase() + '.info' | translate}}</th>
@@ -37,13 +37,14 @@
<tbody>
<tr *ngFor="let tableEntry of processesRD?.payload?.page"
[class.table-danger]="processBulkDeleteService.isToBeDeleted(tableEntry.process.processId)">
<td>{{tableEntry.process.processStatus}}</td>
[class]="getRowClass(tableEntry.process)">
<td><a [routerLink]="['/processes/', tableEntry.process.processId]">{{tableEntry.process.processId}}</a></td>
<td><a [routerLink]="['/processes/', tableEntry.process.processId]">{{tableEntry.process.scriptName}}</a></td>
<td>{{tableEntry.user}}</td>
<td>{{tableEntry.info}}</td>
<td>
<button [attr.aria-label]="'process.overview.delete-process' | translate"
aria-hidden="true"
(click)="processBulkDeleteService.toggleDelete(tableEntry.process.processId)"
class="btn btn-outline-danger">
<i class="fas fa-trash"></i>

View File

@@ -7,8 +7,8 @@
vertical-align: middle;
}
.status-header {
width: var(--ds-process-overview-table-status-column-width);
.id-header {
width: var(--ds-process-overview-table-id-column-width);
}
.name-header {

View File

@@ -19,6 +19,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { AuthService } from '../../../core/auth/auth.service';
import { AuthServiceMock } from '../../../shared/mocks/auth.service.mock';
import { RouteService } from '../../../core/services/route.service';
import { routeServiceStub } from '../../../shared/testing/route-service.stub';
describe('ProcessOverviewTableComponent', () => {
@@ -31,6 +33,7 @@ describe('ProcessOverviewTableComponent', () => {
let processBulkDeleteService: ProcessBulkDeleteService;
let modalService: NgbModal;
let authService; // : AuthService; Not typed as the mock does not fully implement AuthService
let routeService: RouteService;
let processes: Process[];
let ePerson: EPerson;
@@ -104,6 +107,7 @@ describe('ProcessOverviewTableComponent', () => {
});
authService = new AuthServiceMock();
routeService = routeServiceStub;
}
beforeEach(waitForAsync(() => {
@@ -119,6 +123,7 @@ describe('ProcessOverviewTableComponent', () => {
{ provide: ProcessBulkDeleteService, useValue: processBulkDeleteService },
{ provide: NgbModal, useValue: modalService },
{ provide: AuthService, useValue: authService },
{ provide: RouteService, useValue: routeService },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
@@ -143,10 +148,10 @@ describe('ProcessOverviewTableComponent', () => {
expect(rowElements.length).toEqual(3);
});
it('should display the process\' status in the first column', () => {
it('should display the process\' ID in the first column', () => {
rowElements.forEach((rowElement, index) => {
const el = rowElement.query(By.css('td:nth-child(1)')).nativeElement;
expect(el.textContent).toContain(processes[index].processStatus);
expect(el.textContent).toContain(processes[index].processId);
});
});

View File

@@ -1,22 +1,30 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, Inject, PLATFORM_ID } from '@angular/core';
import { ProcessStatus } from '../../processes/process-status.model';
import { Observable, mergeMap, from as observableFrom } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { Process } from '../../processes/process.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { ProcessOverviewService } from '../process-overview.service';
import { ProcessOverviewService, ProcessSortField } from '../process-overview.service';
import { ProcessBulkDeleteService } from '../process-bulk-delete.service';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
import { map, switchMap, toArray } from 'rxjs/operators';
import {
getFirstSucceededRemoteDataPayload,
getFirstCompletedRemoteData,
getAllCompletedRemoteData
} from '../../../core/shared/operators';
import { map, switchMap, toArray, take } from 'rxjs/operators';
import { EPerson } from '../../../core/eperson/models/eperson.model';
import { PaginationService } from 'src/app/core/pagination/pagination.service';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { redirectOn4xx } from '../../../core/shared/authorized.operators';
import { Router } from '@angular/router';
import { AuthService } from '../../../core/auth/auth.service';
import { isPlatformBrowser } from '@angular/common';
import { RouteService } from '../../../core/services/route.service';
const NEW_PROCESS_PARAM = 'new_process_id';
/**
* An interface to store a process and extra information related to the process
@@ -40,6 +48,13 @@ export class ProcessOverviewTableComponent implements OnInit {
*/
@Input() processStatus: ProcessStatus;
/**
* The field on which the processes in this table are sorted
* {@link ProcessSortField.creationTime} by default as every single process has a creation time,
* but not every process has a start or end time
*/
@Input() sortField: ProcessSortField = ProcessSortField.creationTime;
/**
* Whether to use auto refresh for the processes shown in this table.
*/
@@ -71,17 +86,38 @@ export class ProcessOverviewTableComponent implements OnInit {
*/
paginationOptions$: Observable<PaginationComponentOptions>;
/**
* Whether the table is collapsed
*/
isCollapsed = false;
/**
* The id of the process to highlight
*/
newProcessId: string;
constructor(protected processOverviewService: ProcessOverviewService,
protected processBulkDeleteService: ProcessBulkDeleteService,
protected ePersonDataService: EPersonDataService,
protected dsoNameService: DSONameService,
protected paginationService: PaginationService,
protected routeService: RouteService,
protected router: Router,
protected auth: AuthService,
@Inject(PLATFORM_ID) protected platformId: object,
) {
}
ngOnInit() {
// Only auto refresh on browsers
if (!isPlatformBrowser(this.platformId)) {
this.useAutoRefreshingSearchBy = false;
}
this.routeService.getQueryParameterValue(NEW_PROCESS_PARAM).pipe(take(1)).subscribe((id) => {
this.newProcessId = id;
});
// Creates an ID from the first 2 characters of the process status.
// Should two process status values ever start with the same substring,
// increase the number of characters until the ids are distinct.
@@ -113,7 +149,7 @@ export class ProcessOverviewTableComponent implements OnInit {
.pipe(
// Map the paginationOptions to findListOptions
map((paginationOptions: PaginationComponentOptions) =>
this.processOverviewService.getFindListOptions(paginationOptions)),
this.processOverviewService.getFindListOptions(paginationOptions, this.sortField)),
// Use the findListOptions to retrieve the relevant processes every interval
switchMap((findListOptions: FindListOptions) =>
this.processOverviewService.getProcessesByProcessStatus(
@@ -121,6 +157,7 @@ export class ProcessOverviewTableComponent implements OnInit {
),
// Redirect the user when he is logged out
redirectOn4xx(this.router, this.auth),
getAllCompletedRemoteData(),
// Map RemoteData<PaginatedList<Process>> to RemoteData<PaginatedList<ProcessOverviewTableEntry>>
switchMap((processesRD: RemoteData<PaginatedList<Process>>) => {
// Create observable emitting all processes one by one
@@ -152,6 +189,15 @@ export class ProcessOverviewTableComponent implements OnInit {
);
// Collapse this section when the number of processes is zero the first time processes are retrieved
this.processesRD$.pipe(getFirstCompletedRemoteData()).subscribe(
(processesRD: RemoteData<PaginatedList<ProcessOverviewTableEntry>>) => {
if (!(processesRD.payload.totalElements > 0)) {
this.isCollapsed = true;
}
}
);
}
/**
@@ -165,4 +211,18 @@ export class ProcessOverviewTableComponent implements OnInit {
);
}
/**
* Get the css class for a row depending on the state of the process
* @param process
*/
getRowClass(process: Process): string {
if (this.processBulkDeleteService.isToBeDeleted(process.processId)) {
return 'table-danger';
} else if (this.newProcessId === process.processId) {
return 'table-info';
} else {
return '';
}
}
}

View File

@@ -3,7 +3,7 @@ import { PROCESS_OUTPUT_TYPE } from '../../core/shared/process-output.resource-t
import { ProcessStatus } from './process-status.model';
import { ProcessParameter } from './process-parameter.model';
import { HALLink } from '../../core/shared/hal-link.model';
import { autoserialize, deserialize } from 'cerialize';
import { autoserialize, deserialize, autoserializeAs } from 'cerialize';
import { PROCESS } from './process.resource-type';
import { excludeFromEquals } from '../../core/utilities/equals.decorators';
import { ResourceType } from '../../core/shared/resource-type';
@@ -35,7 +35,7 @@ export class Process implements CacheableObject {
/**
* The identifier for this process
*/
@autoserialize
@autoserializeAs(String)
processId: string;
/**
@@ -44,6 +44,12 @@ export class Process implements CacheableObject {
@autoserialize
userId: string;
/**
* The creation time for this process
*/
@autoserialize
creationTime: string;
/**
* The start time for this process
*/

View File

@@ -3408,7 +3408,7 @@
"process.overview.table.completed.info": "Finish time (UTC)",
"process.overview.table.completed.title": "Completed processes",
"process.overview.table.completed.title": "Succeeded processes",
"process.overview.table.empty": "No matching processes found.",
@@ -3426,7 +3426,7 @@
"process.overview.table.running.title": "Running processes",
"process.overview.table.scheduled.info": "Start time (UTC)",
"process.overview.table.scheduled.info": "Creation time (UTC)",
"process.overview.table.scheduled.title": "Scheduled processes",

View File

@@ -107,7 +107,7 @@
--ds-comcol-logo-max-height: 500px;
--ds-process-overview-table-nb-processes-badge-size: 0.5em;
--ds-process-overview-table-status-column-width: 150px;
--ds-process-overview-table-id-column-width: 120px;
--ds-process-overview-table-name-column-width: auto;
--ds-process-overview-table-user-column-width: 200px;
--ds-process-overview-table-info-column-width: 250px;