From c17a943d08b60f19f384f8c721c222c9f25c1fa6 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Tue, 12 May 2026 15:30:50 +0200 Subject: [PATCH 01/20] replaced jobs table with dynamic mat table --- .../jobs-dashboard-new.component.html | 25 +- .../jobs-dashboard-new.component.spec.ts | 125 +++++-- .../jobs-dashboard-new.component.ts | 320 ++++++++++++------ .../effects/user.effects.spec.ts | 1 + src/app/state-management/models/index.ts | 5 +- .../selectors/jobs.selectors.ts | 30 ++ src/app/state-management/state/user.store.ts | 1 + 7 files changed, 368 insertions(+), 139 deletions(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.html b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.html index 8cb997d2b3..aee744ff25 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.html +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.html @@ -1,7 +1,22 @@ - - + diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts index 92f0a07eee..0fcaf6bbb8 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts @@ -1,51 +1,85 @@ -import { NO_ERRORS_SCHEMA } from "@angular/compiler"; -import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; -import { ActivatedRoute, Router } from "@angular/router"; -import { AppConfigService } from "app-config.service"; import { - MockActivatedRoute, - MockAppConfigService, - MockAuthService, - MockHttp, - MockRouter, -} from "shared/MockStubs"; -import { ExportExcelService } from "shared/services/export-excel.service"; + ComponentFixture, + TestBed, + inject, + waitForAsync, +} from "@angular/core/testing"; + import { JobsDashboardNewComponent } from "./jobs-dashboard-new.component"; -import { SharedTableModule } from "shared/modules/shared-table/shared-table.module"; -import { SharedScicatFrontendModule } from "shared/shared.module"; -import { HttpClient } from "@angular/common/http"; -import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { InternalStorage } from "shared/services/auth/base.storage"; -import { AuthService } from "shared/services/auth/auth.service"; -import { provideLuxonDateAdapter } from "@angular/material-luxon-adapter"; +import { MockStore } from "shared/MockStubs"; +import { NO_ERRORS_SCHEMA } from "@angular/core"; +import { StoreModule, Store } from "@ngrx/store"; +import { Router } from "@angular/router"; +import { FlexLayoutModule } from "@ngbracket/ngx-layout"; +import { MatButtonModule } from "@angular/material/button"; +import { MatIconModule } from "@angular/material/icon"; +import { AppConfigService } from "app-config.service"; +import { ScicatDataService } from "shared/services/scicat-data-service"; +import { ExportExcelService } from "shared/services/export-excel.service"; +import { RowEventType } from "shared/modules/dynamic-material-table/models/table-row.model"; +import { provideMockStore } from "@ngrx/store/testing"; +import { selectJobsDashboardPageViewModel } from "state-management/selectors/jobs.selectors"; + +const getConfig = () => ({}); describe("JobsDashboardNewComponent", () => { let component: JobsDashboardNewComponent; let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - const appconfig = new MockAppConfigService(null); - const authService = new MockAuthService(); + const router = { + navigateByUrl: jasmine.createSpy("navigateByUrl"), + }; + let store: MockStore; + + const jobsVm = { + jobs: [], + count: 0, + currentPage: 0, + jobsPerPage: 5, + filters: { + skip: 0, + limit: 5, + sortField: "creationTime:desc", + mode: undefined, + }, + tableSettings: { columns: [] }, + }; + beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ schemas: [NO_ERRORS_SCHEMA], - declarations: [JobsDashboardNewComponent], imports: [ - SharedTableModule, - SharedScicatFrontendModule, - BrowserAnimationsModule, + FlexLayoutModule, + MatButtonModule, + MatIconModule, + StoreModule.forRoot({}), ], - providers: [ - { provide: ActivatedRoute, useClass: MockActivatedRoute }, - { provide: ExportExcelService, useValue: {} }, - { provide: Router, useClass: MockRouter }, - { provide: HttpClient, useClass: MockHttp }, - { provide: AppConfigService, useValue: appconfig }, - { provide: AuthService, useValue: authService }, - { provide: InternalStorage }, - provideLuxonDateAdapter(), - ], - }).compileComponents(); + declarations: [JobsDashboardNewComponent], + }); + + TestBed.overrideComponent(JobsDashboardNewComponent, { + set: { + providers: [ + { + provide: Router, + useValue: router, + }, + { + provide: AppConfigService, + useValue: { getConfig }, + }, + { provide: ScicatDataService, useValue: {} }, + { provide: ExportExcelService, useValue: {} }, + provideMockStore({ + selectors: [ + { selector: selectJobsDashboardPageViewModel, value: jobsVm }, + ], + }), + ], + }, + }); + + TestBed.compileComponents(); })); beforeEach(() => { @@ -54,6 +88,10 @@ describe("JobsDashboardNewComponent", () => { fixture.detectChanges(); }); + beforeEach(inject([Store], (mockStore: MockStore) => { + store = mockStore; + })); + afterEach(() => { fixture.destroy(); }); @@ -61,4 +99,19 @@ describe("JobsDashboardNewComponent", () => { it("should create", () => { expect(component).toBeTruthy(); }); + + describe("#onRowEvent", () => { + it("should navigate to a Job detail", () => { + const job = { id: "job-1" }; + const id = encodeURIComponent(job.id); + + component.onRowEvent({ + event: RowEventType.RowClick, + sender: { row: job }, + } as any); + + expect(router.navigateByUrl).toHaveBeenCalledTimes(1); + expect(router.navigateByUrl).toHaveBeenCalledWith("/user/jobs/" + id); + }); + }); }); diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts index 8a325b1046..86d69be42e 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts @@ -1,16 +1,29 @@ -import { - AfterViewChecked, - ChangeDetectorRef, - Component, - OnDestroy, -} from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { Router } from "@angular/router"; -import { SciCatDataSource } from "../../shared/services/scicat.datasource"; -import { ScicatDataService } from "../../shared/services/scicat-data-service"; -import { ExportExcelService } from "../../shared/services/export-excel.service"; -import { Column } from "shared/modules/shared-table/shared-table.module"; +import { Store } from "@ngrx/store"; +import { OutputJobV3Dto } from "@scicatproject/scicat-sdk-ts-angular"; +import { BehaviorSubject, Subscription, take, filter } from "rxjs"; import { AppConfigService } from "app-config.service"; -import { JobsTableData } from "jobs/jobs-dashboard/jobs-dashboard.component"; +import { ScicatDataService } from "shared/services/scicat-data-service"; +import { ExportExcelService } from "shared/services/export-excel.service"; +import { SciCatDataSource } from "shared/services/scicat.datasource"; +import { TableField } from "shared/modules/dynamic-material-table/models/table-field.model"; +import { + TablePagination, + TablePaginationMode, +} from "shared/modules/dynamic-material-table/models/table-pagination.model"; +import { + ITableSetting, + TableSettingEventType, +} from "shared/modules/dynamic-material-table/models/table-setting.model"; +import { actionMenu } from "shared/modules/dynamic-material-table/utilizes/default-table-settings"; +import { + IRowEvent, + RowEventType, +} from "shared/modules/dynamic-material-table/models/table-row.model"; +import { TableConfigService } from "shared/services/table-config.service"; +import { updateUserSettingsAction } from "state-management/actions/user.actions"; +import { selectJobsDashboardPageViewModel } from "state-management/selectors/jobs.selectors"; @Component({ selector: "app-jobs-new-dashboard", @@ -18,98 +31,92 @@ import { JobsTableData } from "jobs/jobs-dashboard/jobs-dashboard.component"; styleUrls: ["./jobs-dashboard-new.component.scss"], standalone: false, }) -export class JobsDashboardNewComponent implements OnDestroy, AfterViewChecked { - // not needed, date by default is shown in local time and using the locale of the browser (if installed, see app.module.ts) - // tz = Intl.DateTimeFormat().resolvedOptions().timeZone; - - columns: Column[] = [ - { - id: "id", - label: "ID", - canSort: true, - icon: "perm_device_information", - matchMode: "contains", - hideOrder: 0, - }, - { - id: "emailJobInitiator", - label: "Initiator", - icon: "person", - canSort: true, - matchMode: "contains", - hideOrder: 1, - }, - { - id: "type", - label: "Type", - icon: "unarchive", - canSort: true, - matchMode: "is", - hideOrder: 2, - }, - { - id: "creationTime", - icon: "schedule", - label: "Created at local time", - format: "date medium ", - canSort: true, - matchMode: "between", - hideOrder: 3, - sortDefault: "desc", - }, - { - id: "jobParams", - icon: "work", - label: "Parameters", - format: "json", - canSort: false, - matchMode: "contains", - hideOrder: 4, - }, - { - id: "jobStatusMessage", - icon: "traffic", - label: "Status", - format: "json", - canSort: true, - matchMode: "contains", - hideOrder: 5, - }, - { - id: "datasetList", - icon: "list", - label: "Datasets", - format: "json", - canSort: false, - matchMode: "contains", - hideOrder: 6, - }, - { - id: "jobResultObject", - icon: "work_outline", - label: "Result", - format: "json", - canSort: false, - matchMode: "contains", - hideOrder: 7, +export class JobsDashboardNewComponent implements OnInit, OnDestroy { + public vm$ = this.store.select(selectJobsDashboardPageViewModel); + + columns: TableField[] = []; + setting: ITableSetting = {}; + + tableName = "jobsTable"; + rowSelectionMode: "single" | "multi" | "none" = "none"; + paginationMode: TablePaginationMode = "server-side"; + pending = false; + globalTextSearch = ""; + + tableDefaultSettingsConfig: ITableSetting = { + visibleActionMenu: actionMenu, + settingList: [ + { + visibleActionMenu: actionMenu, + isDefaultSetting: true, + isCurrentSetting: true, + columnSetting: [ + { name: "jobId", header: "ID", index: 0 }, + { name: "emailJobInitiator", header: "Initiator", index: 1 }, + { name: "type", header: "Type", index: 2 }, + { + name: "creationTime", + header: "Created at local time", + index: 3, + type: "date", + format: "medium", + }, + { + name: "jobParams", + header: "Parameters", + index: 4, + customRender: (_, row) => JSON.stringify(row.jobParams), + }, + { name: "jobStatusMessage", header: "Status", index: 5 }, + { + name: "datasetList", + header: "Datasets", + index: 6, + customRender: (_, row) => JSON.stringify(row.datasetList), + }, + { + name: "jobResultObject", + header: "Result", + index: 7, + customRender: (_, row) => JSON.stringify(row.jobResultObject), + }, + ], + }, + ], + rowStyle: { + "border-bottom": "1px solid #d2d2d2", }, - ]; + }; + + pagination: TablePagination = { + pageSize: 5, + pageIndex: 0, + pageSizeOptions: [5, 10, 25, 100], + length: 0, + }; tableDefinition = { collection: "Jobs", columns: this.columns, }; - dataSource: SciCatDataSource; + dataSource: BehaviorSubject = new BehaviorSubject< + OutputJobV3Dto[] + >([]); + scicatDataSource: SciCatDataSource; + + subscriptions: Subscription[] = []; + currentFilters: any = {}; constructor( + private router: Router, + private store: Store, private appConfigService: AppConfigService, - private cdRef: ChangeDetectorRef, private dataService: ScicatDataService, private exportService: ExportExcelService, - private router: Router, + private tableConfigService: TableConfigService, ) { - this.dataSource = new SciCatDataSource( + this.scicatDataSource = new SciCatDataSource( this.appConfigService, this.dataService, this.exportService, @@ -117,16 +124,135 @@ export class JobsDashboardNewComponent implements OnDestroy, AfterViewChecked { ); } - ngAfterViewChecked() { - this.cdRef.detectChanges(); + ngOnInit() { + this.subscriptions.push( + this.vm$ + .pipe( + filter((vm) => vm.hasFetchedSettings), + take(1), + ) + .subscribe((vm) => { + this.currentFilters = vm.filters; + const { skip, limit } = vm.filters; + const pageIndex = skip / limit; + + this.loadData(vm.filters, pageIndex, limit); + + const tableSettingsConfig = + this.tableConfigService.getTableSettingsConfig( + this.tableName, + this.tableDefaultSettingsConfig, + vm.tableSettings?.columns || [], + ); + + const currentColumnSetting = tableSettingsConfig.settingList.find( + (s) => s.isCurrentSetting, + )?.columnSetting; + + this.columns = currentColumnSetting; + this.setting = tableSettingsConfig; + + this.pagination = { + ...this.pagination, + length: vm.count, + pageIndex, + pageSize: limit, + }; + }), + ); + + this.subscriptions.push( + this.scicatDataSource.connect().subscribe((data) => { + const mapped = data.map((job) => ({ + ...job, + jobId: job.id, + })); + this.dataSource.next(mapped); + }), + ); + + this.subscriptions.push( + this.scicatDataSource.count$.subscribe((count) => { + this.pagination = { ...this.pagination, length: count }; + }), + ); } - ngOnDestroy() { - this.dataSource.disconnectExportData(); + onRowEvent(event: IRowEvent) { + if (event?.event === RowEventType.RowClick) { + const id = encodeURIComponent(event.sender.row.id); + this.router.navigateByUrl("/user/jobs/" + id); + } + } + + onPaginationChange(pagination: TablePagination) { + const pageIndex = pagination.pageIndex; + const pageSize = pagination.pageSize; + const newFilters = { + ...this.currentFilters, + skip: pageIndex * pageSize, + limit: pageSize, + }; + + this.loadData(newFilters, pageIndex, pageSize); + } + + saveTableSettings(setting: ITableSetting) { + const columnsSetting = setting.columnSetting.map((column, index) => { + const { name, display, width } = column; + + return { name, display, order: index, width }; + }); + + this.store.dispatch( + updateUserSettingsAction({ + property: { fe_job_table_columns: columnsSetting }, + }), + ); } - onRowClick(job: JobsTableData) { - const id = encodeURIComponent(job.id); - this.router.navigateByUrl("/user/jobs/" + id); + onSettingChange(event: { + type: TableSettingEventType; + setting: ITableSetting; + }) { + if ( + event.type === TableSettingEventType.save || + event.type === TableSettingEventType.create + ) { + this.saveTableSettings(event.setting); + } + } + + loadData(filters: any, pageIndex: number, pageSize: number) { + const sortField = filters?.sortField; + const [field, direction] = sortField ? sortField.split(":") : ["", "asc"]; + + this.scicatDataSource.loadAllData( + filters, + field, + direction, + pageIndex, + pageSize, + ); + } + + onGlobalTextSearchChange(text: string) { + this.globalTextSearch = text; + } + + onGlobalTextSearchAction() { + const newFilters = { + ...this.currentFilters, + skip: 0, + limit: this.pagination.pageSize, + globalSearch: this.globalTextSearch || undefined, + }; + + this.loadData(newFilters, 0, this.pagination.pageSize); + this.currentFilters = newFilters; + } + + ngOnDestroy() { + this.subscriptions.forEach((sub) => sub.unsubscribe()); } } diff --git a/src/app/state-management/effects/user.effects.spec.ts b/src/app/state-management/effects/user.effects.spec.ts index 6e2df86840..e5d1555335 100644 --- a/src/app/state-management/effects/user.effects.spec.ts +++ b/src/app/state-management/effects/user.effects.spec.ts @@ -619,6 +619,7 @@ describe("UserEffects", () => { fe_sample_table_conditions: [], fe_instrument_table_columns: [], fe_file_table_columns: [], + fe_job_table_columns: [], }, } as unknown as UserSettings; const action = fromActions.fetchUserSettingsAction({ id }); diff --git a/src/app/state-management/models/index.ts b/src/app/state-management/models/index.ts index 16ce256ff8..7c99f62e1c 100644 --- a/src/app/state-management/models/index.ts +++ b/src/app/state-management/models/index.ts @@ -19,6 +19,7 @@ export interface Settings { fe_sample_table_conditions?: ConditionConfig[]; fe_instrument_table_columns?: TableColumn[]; fe_file_table_columns?: TableColumn[]; + fe_job_table_columns?: TableColumn[]; } export interface TableColumn { @@ -220,6 +221,7 @@ export const SETTINGS_CONFIG = [ configKey: "columns", }, { key: "fe_file_table_columns", scope: "file", configKey: "columns" }, + { key: "fe_job_table_columns", scope: "job", configKey: "columns" }, ]; export type SettingScope = @@ -227,7 +229,8 @@ export type SettingScope = | "proposal" | "sample" | "instrument" - | "file"; + | "file" + | "job"; export type SettingKind = "columns" | "filters" | "conditions"; export const getSettingKey = ( diff --git a/src/app/state-management/selectors/jobs.selectors.ts b/src/app/state-management/selectors/jobs.selectors.ts index 7d319b6322..448c7f878e 100644 --- a/src/app/state-management/selectors/jobs.selectors.ts +++ b/src/app/state-management/selectors/jobs.selectors.ts @@ -1,5 +1,6 @@ import { createFeatureSelector, createSelector } from "@ngrx/store"; import { JobsState } from "state-management/state/jobs.store"; +import { selectHasFetchedSettings, selectSettings } from "./user.selectors"; const selectJobState = createFeatureSelector("jobs"); @@ -48,3 +49,32 @@ export const selectQueryParams = createSelector(selectFilters, (filters) => { return { order: sortField, skip, limit }; } }); + +export const selectJobsDashboardPageViewModel = createSelector( + selectJobs, + selectJobsCount, + selectPage, + selectJobsPerPage, + selectFilters, + selectSettings, + selectHasFetchedSettings, + ( + jobs, + count, + currentPage, + jobsPerPage, + filters, + settings, + hasFetchedSettings, + ) => ({ + jobs, + count, + currentPage, + jobsPerPage, + filters, + hasFetchedSettings, + tableSettings: { + columns: settings.fe_job_table_columns, + }, + }), +); diff --git a/src/app/state-management/state/user.store.ts b/src/app/state-management/state/user.store.ts index 9e01a3c661..63ea8e3b0d 100644 --- a/src/app/state-management/state/user.store.ts +++ b/src/app/state-management/state/user.store.ts @@ -79,6 +79,7 @@ export const initialUserState: UserState = { fe_sample_table_conditions: [], fe_instrument_table_columns: [], fe_file_table_columns: [], + fe_job_table_columns: [], }, // TODO sync with server settings? message: undefined, From a366f2c4b1e75224fd2c6b5bff5a4fc348aab8f7 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Tue, 12 May 2026 15:50:07 +0200 Subject: [PATCH 02/20] sourcery changes --- .../jobs-dashboard-new.component.spec.ts | 63 ++++--------------- .../jobs-dashboard-new.component.ts | 2 + 2 files changed, 15 insertions(+), 50 deletions(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts index 0fcaf6bbb8..64127bba2f 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts @@ -1,18 +1,7 @@ -import { - ComponentFixture, - TestBed, - inject, - waitForAsync, -} from "@angular/core/testing"; - +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { JobsDashboardNewComponent } from "./jobs-dashboard-new.component"; -import { MockStore } from "shared/MockStubs"; import { NO_ERRORS_SCHEMA } from "@angular/core"; -import { StoreModule, Store } from "@ngrx/store"; import { Router } from "@angular/router"; -import { FlexLayoutModule } from "@ngbracket/ngx-layout"; -import { MatButtonModule } from "@angular/material/button"; -import { MatIconModule } from "@angular/material/icon"; import { AppConfigService } from "app-config.service"; import { ScicatDataService } from "shared/services/scicat-data-service"; import { ExportExcelService } from "shared/services/export-excel.service"; @@ -29,13 +18,10 @@ describe("JobsDashboardNewComponent", () => { const router = { navigateByUrl: jasmine.createSpy("navigateByUrl"), }; - let store: MockStore; const jobsVm = { jobs: [], count: 0, - currentPage: 0, - jobsPerPage: 5, filters: { skip: 0, limit: 5, @@ -48,38 +34,19 @@ describe("JobsDashboardNewComponent", () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ schemas: [NO_ERRORS_SCHEMA], - imports: [ - FlexLayoutModule, - MatButtonModule, - MatIconModule, - StoreModule.forRoot({}), - ], declarations: [JobsDashboardNewComponent], - }); - - TestBed.overrideComponent(JobsDashboardNewComponent, { - set: { - providers: [ - { - provide: Router, - useValue: router, - }, - { - provide: AppConfigService, - useValue: { getConfig }, - }, - { provide: ScicatDataService, useValue: {} }, - { provide: ExportExcelService, useValue: {} }, - provideMockStore({ - selectors: [ - { selector: selectJobsDashboardPageViewModel, value: jobsVm }, - ], - }), - ], - }, - }); - - TestBed.compileComponents(); + providers: [ + { provide: Router, useValue: router }, + { provide: AppConfigService, useValue: { getConfig } }, + { provide: ScicatDataService, useValue: {} }, + { provide: ExportExcelService, useValue: {} }, + provideMockStore({ + selectors: [ + { selector: selectJobsDashboardPageViewModel, value: jobsVm }, + ], + }), + ], + }).compileComponents(); })); beforeEach(() => { @@ -88,10 +55,6 @@ describe("JobsDashboardNewComponent", () => { fixture.detectChanges(); }); - beforeEach(inject([Store], (mockStore: MockStore) => { - store = mockStore; - })); - afterEach(() => { fixture.destroy(); }); diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts index 86d69be42e..b34e5916d1 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts @@ -194,6 +194,7 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { limit: pageSize, }; + this.currentFilters = newFilters; this.loadData(newFilters, pageIndex, pageSize); } @@ -253,6 +254,7 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { } ngOnDestroy() { + this.scicatDataSource.disconnectExportData(); this.subscriptions.forEach((sub) => sub.unsubscribe()); } } From 5fa850519cb751c275415ee9a10e2110edb78d40 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 18 May 2026 11:30:58 +0200 Subject: [PATCH 03/20] added a cypress file for jobs with cypress commands --- cypress/e2e/jobs/jobs-general.cy.js | 94 +++++++++++++++++++++++++++++ cypress/fixtures/testData.js | 14 ++++- cypress/support/commands.js | 73 ++++++++++++++++++++++ 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 cypress/e2e/jobs/jobs-general.cy.js diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js new file mode 100644 index 0000000000..09546e8c44 --- /dev/null +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -0,0 +1,94 @@ +import { testData } from "../../fixtures/testData"; + +describe("Jobs general", () => { + beforeEach(() => { + cy.login(Cypress.env("username"), Cypress.env("password")); + cy.createDataset({ + type: "raw", + dataFileSize: "small", + datasetName: "Jobs Dataset", + pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", + isPublished: true, + }); + }); + + afterEach(() => { + cy.removeJobs(); + cy.removeDatasets(); + }); + + describe("Jobs dynamic material table", () => { + it("should be able to search for job in the global search", () => { + cy.createJob(); + + cy.visit("/user/jobs"); + + cy.get('[data-cy="text-search"]').type("embargo_period"); + cy.get('[data-cy="search-button"]').click(); + + cy.get("mat-table mat-row").first().should("contain", "embargo_period"); + }); + + it("should be able to change page and page size in the job table", () => { + cy.createJob({ emailJobInitiator: "test1@example.com" }); + cy.createJob({ emailJobInitiator: "test2@example.com" }); + cy.createJob({ emailJobInitiator: "test3@example.com" }); + cy.createJob({ emailJobInitiator: "test4@example.com" }); + cy.createJob({ emailJobInitiator: "test5@example.com" }); + cy.createJob({ emailJobInitiator: "test6@example.com" }); + + cy.visit("/user/jobs"); + + cy.get("mat-paginator").first().find("mat-select").click({ force: true }); + cy.get("mat-option").contains("5").click({ force: true }); + + cy.get("mat-paginator .mat-mdc-paginator-range-actions").contains( + "1 – 5", + ); + + cy.get("mat-paginator").first().find("[aria-label='Next page']").click(); + + cy.get("mat-paginator .mat-mdc-paginator-range-actions").contains( + "6 – 6", + ); + }); + + it("should be able to change visible columns settings in the table", () => { + cy.createJob(); + + cy.visit("/user/jobs"); + + cy.get("dynamic-mat-table mat-header-row.header").should("exist"); + + cy.get("dynamic-mat-table table-menu button").click(); + cy.get('[role="menu"] button').contains("Default setting").click(); + cy.get("body").type("{esc}"); + + cy.get("dynamic-mat-table") + .scrollTo("right", { ensureScrollable: false }) + .get("mat-header-row") + .should("contain", "Initiator"); + + cy.get("dynamic-mat-table table-menu button").click(); + cy.get('[role="menu"] button').contains("Column setting").click(); + + cy.get('[role="menu"]') + .contains("Initiator") + .parent() + .find("input[type=checkbox]") + .uncheck(); + + cy.contains(".column-config-apply button.done-setting", "done").click(); + + cy.get("dynamic-mat-table table-menu button").click(); + cy.get('[role="menu"] button').contains("Save table setting").click(); + + cy.reload(); + + cy.get("dynamic-mat-table") + .scrollTo("right", { ensureScrollable: false }) + .get("mat-header-row") + .should("not.contain", "Initiator"); + }); + }); +}); diff --git a/cypress/fixtures/testData.js b/cypress/fixtures/testData.js index 12732c0811..f3987e9098 100644 --- a/cypress/fixtures/testData.js +++ b/cypress/fixtures/testData.js @@ -174,6 +174,16 @@ export const testData = { }, ], }, + job: { + emailJobInitiator: "user@example.com", + type: "embargo_period", + jobParams: { dataset: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532" }, + datasetList: [ + { pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", files: [] }, + ], + jobStatusMessage: "jobSubmitted", + jobResultObject: {}, + }, }; export const testConfig = { @@ -366,7 +376,7 @@ export const defaultDatasetsColumnsList = [ "Size", "Creation Time", "Image", - "Proposal Id" + "Proposal Id", ]; export const personalizedDatasetsColumnsList = [ @@ -377,5 +387,5 @@ export const personalizedDatasetsColumnsList = [ "Creation Time", "Proposal Id", "Start Time", - "End Time" + "End Time", ]; diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 363158e084..06e73f179c 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -244,6 +244,34 @@ Cypress.Commands.add("createSample", (sample) => { }); }); +Cypress.Commands.add("createJob", (overwrites = {}) => { + return cy.getCookie("user").then((userCookie) => { + const user = JSON.parse(decodeURIComponent(userCookie.value)); + + cy.getToken().then((token) => { + cy.log("Job: " + JSON.stringify(overwrites, null, 2)); + cy.log("User: " + JSON.stringify(user, null, 2)); + + const job = { + ...testData.job, + emailJobInitiator: user.email, + ...overwrites, + }; + + cy.request({ + method: "POST", + url: lbBaseUrl + "/jobs", + headers: { + Authorization: token, + Accept: "application/json", + "Content-Type": "application/json", + }, + body: job, + }); + }); + }); +}); + Cypress.Commands.add("updateProposal", (proposalId, updateProposalDto) => { return cy.getCookie("user").then((userCookie) => { const user = JSON.parse(decodeURIComponent(userCookie.value)); @@ -445,6 +473,51 @@ Cypress.Commands.add("removeSamples", () => { }); }); +Cypress.Commands.add("removeJobs", () => { + cy.login(Cypress.env("username"), Cypress.env("password")); + cy.getToken().then((token) => { + const fields = { type: "embargo_period" }; + const limits = { limit: 10, skip: 0, sort: { type: "asc" } }; + + cy.request({ + method: "GET", + url: + lbBaseUrl + + "/jobs/fullquery?fields=" + + encodeURIComponent(JSON.stringify(fields)) + + "&limits=" + + encodeURIComponent(JSON.stringify(limits)), + headers: { + Authorization: token, + Accept: "application/json", + "Content-Type": "application/json", + }, + }) + .its("body") + .as("jobs"); + + cy.login( + Cypress.env("secondaryUsername"), + Cypress.env("secondaryPassword"), + ); + cy.getToken().then((token) => { + cy.get("@jobs").then((jobs) => { + jobs.forEach((job) => { + cy.request({ + method: "DELETE", + url: lbBaseUrl + `/jobs/${encodeURIComponent(job.id)}`, + headers: { + Authorization: token, + Accept: "application/json", + "Content-Type": "application/json", + }, + }); + }); + }); + }); + }); +}); + Cypress.Commands.add("initializeElasticSearch", (index) => { cy.login(Cypress.env("username"), Cypress.env("password")); cy.getToken().then((token) => { From cb646d75e100b211a4b759fd78beb6f0c9ec8db2 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 18 May 2026 13:01:15 +0200 Subject: [PATCH 04/20] small fixes --- .../jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts | 4 ++-- src/app/jobs/jobs-detail/jobs-detail.component.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts index b34e5916d1..9db4902ca1 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts @@ -178,9 +178,9 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { ); } - onRowEvent(event: IRowEvent) { + onRowEvent(event: IRowEvent) { if (event?.event === RowEventType.RowClick) { - const id = encodeURIComponent(event.sender.row.id); + const id = encodeURIComponent(event.sender.row.jobId); this.router.navigateByUrl("/user/jobs/" + id); } } diff --git a/src/app/jobs/jobs-detail/jobs-detail.component.ts b/src/app/jobs/jobs-detail/jobs-detail.component.ts index 7f2c393549..277b07150f 100644 --- a/src/app/jobs/jobs-detail/jobs-detail.component.ts +++ b/src/app/jobs/jobs-detail/jobs-detail.component.ts @@ -35,7 +35,7 @@ export class JobsDetailComponent implements OnInit, OnDestroy { }); this.job$.subscribe((job) => { this.hasJobResultObject = - Object.keys(job.jobResultObject || {}).length > 0; + Object.keys(job?.jobResultObject || {}).length > 0; }); } From fc730e7b7a384b7dc43438111c7ae7484e8d327c Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 18 May 2026 13:06:52 +0200 Subject: [PATCH 05/20] fixed spec test --- .../jobs-dashboard-new/jobs-dashboard-new.component.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts index 64127bba2f..3028c8aab6 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.spec.ts @@ -65,8 +65,8 @@ describe("JobsDashboardNewComponent", () => { describe("#onRowEvent", () => { it("should navigate to a Job detail", () => { - const job = { id: "job-1" }; - const id = encodeURIComponent(job.id); + const job = { jobId: "job-1" }; + const id = encodeURIComponent(job.jobId); component.onRowEvent({ event: RowEventType.RowClick, From c0f22f702f6fd41dc676ecd236c20adae40c344b Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 10 Jun 2026 16:40:37 +0200 Subject: [PATCH 06/20] cypress fix: changed jobType to align with what has been configured in jobConfig.yaml --- cypress/e2e/jobs/jobs-general.cy.js | 6 +++--- cypress/fixtures/testData.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index 09546e8c44..c79729ae2b 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -18,15 +18,15 @@ describe("Jobs general", () => { }); describe("Jobs dynamic material table", () => { - it("should be able to search for job in the global search", () => { + it.only("should be able to search for job in the global search", () => { cy.createJob(); cy.visit("/user/jobs"); - cy.get('[data-cy="text-search"]').type("embargo_period"); + cy.get('[data-cy="text-search"]').type("all_access"); cy.get('[data-cy="search-button"]').click(); - cy.get("mat-table mat-row").first().should("contain", "embargo_period"); + cy.get("mat-table mat-row").first().should("contain", "all_access"); }); it("should be able to change page and page size in the job table", () => { diff --git a/cypress/fixtures/testData.js b/cypress/fixtures/testData.js index f3987e9098..6636ef5d58 100644 --- a/cypress/fixtures/testData.js +++ b/cypress/fixtures/testData.js @@ -176,7 +176,7 @@ export const testData = { }, job: { emailJobInitiator: "user@example.com", - type: "embargo_period", + type: "all_access", jobParams: { dataset: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532" }, datasetList: [ { pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", files: [] }, From 3c4a2b07cfccabdaa64b1a7c23bc4b9a0580da7e Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 10 Jun 2026 17:00:58 +0200 Subject: [PATCH 07/20] cypress fix: updated removeJobs and removed .only --- cypress/e2e/jobs/jobs-general.cy.js | 2 +- cypress/support/commands.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index c79729ae2b..64ec49e444 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -18,7 +18,7 @@ describe("Jobs general", () => { }); describe("Jobs dynamic material table", () => { - it.only("should be able to search for job in the global search", () => { + it("should be able to search for job in the global search", () => { cy.createJob(); cy.visit("/user/jobs"); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 06e73f179c..5963238d8b 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -476,7 +476,7 @@ Cypress.Commands.add("removeSamples", () => { Cypress.Commands.add("removeJobs", () => { cy.login(Cypress.env("username"), Cypress.env("password")); cy.getToken().then((token) => { - const fields = { type: "embargo_period" }; + const fields = { type: "all_access" }; const limits = { limit: 10, skip: 0, sort: { type: "asc" } }; cy.request({ From b00667bd1a822b264418bac5b0c57cc689ac5201 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 09:27:19 +0200 Subject: [PATCH 08/20] cypress fix: trying a different pid_prefix from env.backend.e2e --- cypress/e2e/jobs/jobs-general.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index 64ec49e444..3e1a21bbd8 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -7,7 +7,7 @@ describe("Jobs general", () => { type: "raw", dataFileSize: "small", datasetName: "Jobs Dataset", - pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", + pid: "20.500.12269/6ED35C17-EDD4-4CD4-B917-4E49698F7532", isPublished: true, }); }); From e7877ac6b2a5da24ed9278a614e06250422c9b9a Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 09:56:55 +0200 Subject: [PATCH 09/20] cypress fix: removed pid_prefix --- cypress/e2e/jobs/jobs-general.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index 3e1a21bbd8..299c0f0f30 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -7,7 +7,7 @@ describe("Jobs general", () => { type: "raw", dataFileSize: "small", datasetName: "Jobs Dataset", - pid: "20.500.12269/6ED35C17-EDD4-4CD4-B917-4E49698F7532", + pid: "6ED35C17-EDD4-4CD4-B917-4E49698F7532", isPublished: true, }); }); From 27260e8a66040d5108aec7d8b1671fb41028c6af Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 10:48:19 +0200 Subject: [PATCH 10/20] added jobConfig and mounted it to docker compose file --- CI/e2e/docker-compose.e2e.yaml | 1 + CI/e2e/jobconfig.e2e.yaml | 111 +++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 CI/e2e/jobconfig.e2e.yaml diff --git a/CI/e2e/docker-compose.e2e.yaml b/CI/e2e/docker-compose.e2e.yaml index b56cd346f1..63d91ea659 100644 --- a/CI/e2e/docker-compose.e2e.yaml +++ b/CI/e2e/docker-compose.e2e.yaml @@ -33,6 +33,7 @@ services: - "./CI/e2e/frontend.config.e2e.json:/home/node/app/dist/config/frontend.config.json" - "./CI/e2e/frontend.theme.e2e.json:/home/node/app/dist/config/frontend.theme.json" - "./CI/e2e/publishedDataConfig.e2e.json:/home/node/app/publishedDataConfig.json" + - "./CI/e2e/jobConfig.e2e.yaml:/home/node/app/jobConfig.yaml" environment: - DOI_USERNAME=${DOI_USERNAME} - DOI_PASSWORD=${DOI_PASSWORD} diff --git a/CI/e2e/jobconfig.e2e.yaml b/CI/e2e/jobconfig.e2e.yaml new file mode 100644 index 0000000000..089a1fa02d --- /dev/null +++ b/CI/e2e/jobconfig.e2e.yaml @@ -0,0 +1,111 @@ +configVersion: v1.0 2024-03-01 6f3f38 +jobs: + - jobType: all_access + create: + auth: "#all" + actions: + - actionType: log + update: + auth: "#all" + - jobType: public_access + create: + auth: "#datasetPublic" + update: + auth: "#all" + - jobType: authenticated_access + create: + auth: "#authenticated" + update: + auth: "#all" + - jobType: dataset_access + create: + auth: "#datasetAccess" + update: + auth: "#jobOwnerGroup" + - jobType: owner_access + create: + auth: "#datasetOwner" + update: + auth: "#jobOwnerUser" + - jobType: user_access + create: + auth: user5.1 + update: + auth: user5.1 + - jobType: group_access + create: + auth: "@group5" + update: + auth: "@group5" + - jobType: job_admin + create: + auth: "#jobAdmin" + update: + auth: "#jobAdmin" + - jobType: archive + create: + auth: "#all" + actions: + - actionType: validate + datasets: + datasetlifecycle.archivable: + const: true + update: + auth: "#all" + - jobType: retrieve + create: + auth: "#all" + actions: + - actionType: validate + datasets: + datasetlifecycle.retrievable: + const: true + update: + auth: "#all" + - jobType: public + create: + auth: "#all" + actions: + - actionType: validate + datasets: + isPublished: + const: true + update: + auth: "#all" + - jobType: validate + create: + auth: admin + actions: + - actionType: validate + request: + jobParams.requiredParam: + type: string + jobParams.arrayOfStrings: + type: array + items: + type: string + datasets: + datasetlifecycle.archivable: + const: true + update: + auth: admin + actions: + - actionType: validate + request: + $: + $schema: http://json-schema.org/draft-07/schema# + required: + - jobResultObject + properties: + jobResultObject: + type: object + required: + - requiredParam + - arrayOfStrings + properties: + requiredParam: + type: string + arrayOfStrings: + type: array + items: + type: string From 721a28bd3b9b310c7339868f4bffa1e58d0683d3 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 10:59:43 +0200 Subject: [PATCH 11/20] changed jobconfig file name --- CI/e2e/docker-compose.e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/e2e/docker-compose.e2e.yaml b/CI/e2e/docker-compose.e2e.yaml index 63d91ea659..7b55afa05b 100644 --- a/CI/e2e/docker-compose.e2e.yaml +++ b/CI/e2e/docker-compose.e2e.yaml @@ -33,7 +33,7 @@ services: - "./CI/e2e/frontend.config.e2e.json:/home/node/app/dist/config/frontend.config.json" - "./CI/e2e/frontend.theme.e2e.json:/home/node/app/dist/config/frontend.theme.json" - "./CI/e2e/publishedDataConfig.e2e.json:/home/node/app/publishedDataConfig.json" - - "./CI/e2e/jobConfig.e2e.yaml:/home/node/app/jobConfig.yaml" + - "./CI/e2e/jobconfig.e2e.yaml:/home/node/app/jobconfig.yaml" environment: - DOI_USERNAME=${DOI_USERNAME} - DOI_PASSWORD=${DOI_PASSWORD} From 80058a5f007a0cbe4d19d2f5a80888a226c4356b Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 12:53:24 +0200 Subject: [PATCH 12/20] wip: added env variable --- CI/e2e/docker-compose.e2e.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/CI/e2e/docker-compose.e2e.yaml b/CI/e2e/docker-compose.e2e.yaml index 7b55afa05b..3311b5ae81 100644 --- a/CI/e2e/docker-compose.e2e.yaml +++ b/CI/e2e/docker-compose.e2e.yaml @@ -37,6 +37,7 @@ services: environment: - DOI_USERNAME=${DOI_USERNAME} - DOI_PASSWORD=${DOI_PASSWORD} + - JOB_CONFIGURATION_FILE=/home/node/app/jobconfig.yaml depends_on: mongodb: condition: service_healthy From abce7b337789d1542f85437c893f91dd8f1427f3 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 13:04:47 +0200 Subject: [PATCH 13/20] resolved pid mismatch --- cypress/fixtures/testData.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/fixtures/testData.js b/cypress/fixtures/testData.js index cc5272850e..323bc20f8d 100644 --- a/cypress/fixtures/testData.js +++ b/cypress/fixtures/testData.js @@ -178,9 +178,9 @@ export const testData = { job: { emailJobInitiator: "user@example.com", type: "all_access", - jobParams: { dataset: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532" }, + jobParams: { dataset: "6ED35C17-EDD4-4CD4-B917-4E49698F7532" }, datasetList: [ - { pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", files: [] }, + { pid: "6ED35C17-EDD4-4CD4-B917-4E49698F7532", files: [] }, ], jobStatusMessage: "jobSubmitted", jobResultObject: {}, From 85c83c3ca8993ca2556a6fdf2eb546bc7e257b79 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 13:23:47 +0200 Subject: [PATCH 14/20] only testing jobs-general file and enabled cypress video --- .github/workflows/test.yml | 1 + cypress.config.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ba75a8162..d2744bbcdc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -133,6 +133,7 @@ jobs: config-file: cypress.config.ts browser: chrome install-command: npm install --omit peer + spec: cypress/e2e/jobs-general.cy.js - name: docker logs if: ${{ failure() }} diff --git a/cypress.config.ts b/cypress.config.ts index d2728dcc22..89b409c605 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -18,5 +18,6 @@ export default defineConfig({ viewportWidth: 1280, defaultCommandTimeout: 10000, retries: 1, + video: true, }, }); From 759b4103ff28def70164667e393c5adf455f9af6 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Mon, 15 Jun 2026 13:28:06 +0200 Subject: [PATCH 15/20] changed to the correct test path --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d2744bbcdc..5985973352 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -133,7 +133,7 @@ jobs: config-file: cypress.config.ts browser: chrome install-command: npm install --omit peer - spec: cypress/e2e/jobs-general.cy.js + spec: cypress/e2e/jobs/jobs-general.cy.js - name: docker logs if: ${{ failure() }} From b2eeb5e2400261301ce0b733e2a03feff05d772e Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 17 Jun 2026 09:18:51 +0200 Subject: [PATCH 16/20] wip: checking first cypress error msg --- cypress/e2e/jobs/jobs-general.cy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index 299c0f0f30..bc0f312315 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -7,7 +7,7 @@ describe("Jobs general", () => { type: "raw", dataFileSize: "small", datasetName: "Jobs Dataset", - pid: "6ED35C17-EDD4-4CD4-B917-4E49698F7532", + pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", isPublished: true, }); }); @@ -19,6 +19,7 @@ describe("Jobs general", () => { describe("Jobs dynamic material table", () => { it("should be able to search for job in the global search", () => { + cy.removeJobs(); cy.createJob(); cy.visit("/user/jobs"); From 1503471005efaaa4170343f60cea28b84105bc45 Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 17 Jun 2026 09:20:22 +0200 Subject: [PATCH 17/20] wip: removing local prefix --- cypress/e2e/jobs/jobs-general.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index bc0f312315..0fa07491cb 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -7,7 +7,7 @@ describe("Jobs general", () => { type: "raw", dataFileSize: "small", datasetName: "Jobs Dataset", - pid: "scicat_testing/6ED35C17-EDD4-4CD4-B917-4E49698F7532", + pid: "6ED35C17-EDD4-4CD4-B917-4E49698F7532", isPublished: true, }); }); From 37aa314742f4588b210fd17eb96e89051a40647a Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 17 Jun 2026 09:27:54 +0200 Subject: [PATCH 18/20] removed cypress video and single cypress test --- .github/workflows/test.yml | 1 - cypress.config.ts | 1 - cypress/e2e/jobs/jobs-general.cy.js | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5985973352..0ba75a8162 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -133,7 +133,6 @@ jobs: config-file: cypress.config.ts browser: chrome install-command: npm install --omit peer - spec: cypress/e2e/jobs/jobs-general.cy.js - name: docker logs if: ${{ failure() }} diff --git a/cypress.config.ts b/cypress.config.ts index 89b409c605..d2728dcc22 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -18,6 +18,5 @@ export default defineConfig({ viewportWidth: 1280, defaultCommandTimeout: 10000, retries: 1, - video: true, }, }); diff --git a/cypress/e2e/jobs/jobs-general.cy.js b/cypress/e2e/jobs/jobs-general.cy.js index 0fa07491cb..299c0f0f30 100644 --- a/cypress/e2e/jobs/jobs-general.cy.js +++ b/cypress/e2e/jobs/jobs-general.cy.js @@ -19,7 +19,6 @@ describe("Jobs general", () => { describe("Jobs dynamic material table", () => { it("should be able to search for job in the global search", () => { - cy.removeJobs(); cy.createJob(); cy.visit("/user/jobs"); From ca7c4e031e27d38daec6c860b6cf906b56f085ae Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 24 Jun 2026 15:17:37 +0200 Subject: [PATCH 19/20] copilot review suggestions added --- .../jobs-dashboard-new.component.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts index 9db4902ca1..dbcfb51dfc 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts @@ -95,9 +95,18 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { length: 0, }; + private scicatColumnsDef = + this.tableDefaultSettingsConfig.settingList[0]?.columnSetting?.map((c) => ({ + id: c.name, + label: c.header ?? c.name, + hideOrder: c.index ?? 0, + canSort: true, + matchMode: c.type === "date" ? "between" : "contains", + })) ?? []; + tableDefinition = { collection: "Jobs", - columns: this.columns, + columns: this.scicatColumnsDef, }; dataSource: BehaviorSubject = new BehaviorSubject< @@ -145,9 +154,9 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { vm.tableSettings?.columns || [], ); - const currentColumnSetting = tableSettingsConfig.settingList.find( - (s) => s.isCurrentSetting, - )?.columnSetting; + const currentColumnSetting = + tableSettingsConfig.settingList.find((s) => s.isCurrentSetting) + ?.columnSetting ?? []; this.columns = currentColumnSetting; this.setting = tableSettingsConfig; @@ -251,6 +260,7 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { this.loadData(newFilters, 0, this.pagination.pageSize); this.currentFilters = newFilters; + this.pagination = { ...this.pagination, pageIndex: 0 }; } ngOnDestroy() { From a73b6f9c680dcec92a921ca58b3dd8d74f3d405f Mon Sep 17 00:00:00 2001 From: Abdi Mo Date: Wed, 24 Jun 2026 15:20:18 +0200 Subject: [PATCH 20/20] eslint fix --- src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts index dbcfb51dfc..7054c36044 100644 --- a/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts +++ b/src/app/jobs/jobs-dashboard-new/jobs-dashboard-new.component.ts @@ -95,7 +95,7 @@ export class JobsDashboardNewComponent implements OnInit, OnDestroy { length: 0, }; - private scicatColumnsDef = + scicatColumnsDef = this.tableDefaultSettingsConfig.settingList[0]?.columnSetting?.map((c) => ({ id: c.name, label: c.header ?? c.name,