diff --git a/package-lock.json b/package-lock.json index b31689c0cf..41a1f2fa6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,9 @@ "@ngx-translate/core": "^17.0.0", "@ngxmc/datetime-picker": "^19.3.1", "@scicatproject/scicat-sdk-ts-angular": "^4.27.0", + "ajv": "^8.18.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", "autolinker": "^4.0.0", "deep-equal": "^2.0.5", "exceljs": "^4.4.0", @@ -7697,7 +7700,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -7715,7 +7717,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" diff --git a/package.json b/package.json index a8d838fb1d..8c8786fbd0 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,9 @@ "@ngx-translate/core": "^17.0.0", "@ngxmc/datetime-picker": "^19.3.1", "@scicatproject/scicat-sdk-ts-angular": "^4.27.0", + "ajv": "^8.18.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", "autolinker": "^4.0.0", "deep-equal": "^2.0.5", "exceljs": "^4.4.0", diff --git a/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.ts b/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.ts index 050c03ba6a..47b67b8b6c 100644 --- a/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.ts +++ b/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.ts @@ -45,7 +45,7 @@ import { OutputDatasetObsoleteDto, ProposalClass, ReturnedUserDto, - SampleClass, + OutputSampleDto, } from "@scicatproject/scicat-sdk-ts-angular"; import { AttachmentService } from "shared/services/attachment.service"; @@ -80,7 +80,7 @@ export class DatasetDetailComponent implements OnInit, OnDestroy { loading$ = this.store.select(selectIsLoading); instrument: Instrument | undefined; proposal: ProposalClass | undefined; - sample: SampleClass | undefined; + sample: OutputSampleDto | undefined; user: ReturnedUserDto | undefined; editingAllowed = false; editEnabled = false; diff --git a/src/app/datasets/publish/publish.component.html b/src/app/datasets/publish/publish.component.html index 32431a9b18..b2b9e509c0 100644 --- a/src/app/datasets/publish/publish.component.html +++ b/src/app/datasets/publish/publish.component.html @@ -49,6 +49,7 @@ [schema]="schema" [uischema]="uiSchema" [renderers]="renderers" + [ajv]="ajv" (errors)="onErrors($event)" (dataChange)="onMetadataChange($event)" > @@ -69,9 +70,7 @@ class="save-and-continue" mat-raised-button color="primary" - [disabled]=" - !formIsValid() || (panelOpenState() && !metadataIsValid()) - " + [disabled]="!formIsValid()" > Save and Continue diff --git a/src/app/datasets/publish/publish.component.spec.ts b/src/app/datasets/publish/publish.component.spec.ts index f893172116..2a4dac6a69 100644 --- a/src/app/datasets/publish/publish.component.spec.ts +++ b/src/app/datasets/publish/publish.component.spec.ts @@ -24,7 +24,9 @@ import { MatInputModule } from "@angular/material/input"; import { MatSelectModule } from "@angular/material/select"; import { MatButtonModule } from "@angular/material/button"; import { AppConfigService } from "app-config.service"; -import { PublishedDataService } from "@scicatproject/scicat-sdk-ts-angular"; +import { PublishedDataV4Service } from "@scicatproject/scicat-sdk-ts-angular"; +import { AjvService } from "shared/services/ajv.service"; +import { SharedScicatFrontendModule } from "shared/shared.module"; const getConfig = () => ({ facility: "test", @@ -49,6 +51,7 @@ describe("PublishComponent", () => { MatInputModule, MatSelectModule, ReactiveFormsModule, + SharedScicatFrontendModule, ], providers: [ provideMockStore({ @@ -65,7 +68,7 @@ describe("PublishComponent", () => { { provide: ActivatedRoute, useClass: MockActivatedRoute }, { provide: ActionsSubject, useValue: of({}) }, { provide: AppConfigService, useValue: { getConfig } }, - { provide: PublishedDataService, useClass: MockPublishedDataApi }, + { provide: PublishedDataV4Service, useClass: MockPublishedDataApi }, { provide: Router, useClass: MockRouter }, { provide: Store, useClass: MockStore }, ], diff --git a/src/app/datasets/publish/publish.component.ts b/src/app/datasets/publish/publish.component.ts index 8966122c34..ef2ccaf1c3 100644 --- a/src/app/datasets/publish/publish.component.ts +++ b/src/app/datasets/publish/publish.component.ts @@ -20,7 +20,7 @@ import { angularMaterialRenderers } from "@jsonforms/angular-material"; import { CreatePublishedDataV4Dto, PublishedData, - PublishedDataService, + PublishedDataV4Service, } from "@scicatproject/scicat-sdk-ts-angular"; import { AppConfigService } from "app-config.service"; import { EditableComponent } from "app-routing/pending-changes.guard"; @@ -31,6 +31,8 @@ import { accordionArrayLayoutRendererTester, } from "shared/modules/jsonforms-custom-renderers/expand-panel-renderer/accordion-array-layout-renderer.component"; import { selectPublishedDataConfig } from "state-management/selectors/published-data.selectors"; +import Ajv2019 from "ajv/dist/2019"; +import { AjvService } from "shared/services/ajv.service"; @Component({ selector: "publish", @@ -47,6 +49,7 @@ export class PublishComponent implements OnInit, OnDestroy, EditableComponent { private beforeUnloadSubscription: Subscription; readonly panelOpenState = signal(false); + ajv: Ajv2019; appConfig = this.appConfigService.getConfig(); renderers = [ ...angularMaterialRenderers, @@ -76,10 +79,13 @@ export class PublishComponent implements OnInit, OnDestroy, EditableComponent { constructor( private appConfigService: AppConfigService, private store: Store, - private publishedDataApi: PublishedDataService, + private publishedDataApi: PublishedDataV4Service, private actionsSubj: ActionsSubject, private router: Router, - ) {} + private ajvService: AjvService, + ) { + this.ajv = this.ajvService.newInstance(); + } public formIsValid() { if (!Object.values(this.form).includes(undefined)) { @@ -127,14 +133,10 @@ export class PublishComponent implements OnInit, OnDestroy, EditableComponent { this.publishedDataConfigSubscription = this.publishedDataConfig$.subscribe( (publishedDataConfig) => { if (!isEmpty(publishedDataConfig)) { - this.schema = publishedDataConfig.metadataSchema; - // NOTE: We set the publicationYear by the system, so we remove it from the required fields in the frontend - this.schema?.required.splice( - this.schema.required.indexOf("publicationYear"), - 1, + this.schema = this.ajvService.cleanupSchema( + publishedDataConfig.metadataSchema, ); this.uiSchema = publishedDataConfig.uiSchema; - this.metadata = cloneDeep(publishedDataConfig.defaultValues) ?? {}; } }, ); @@ -146,10 +148,11 @@ export class PublishComponent implements OnInit, OnDestroy, EditableComponent { }); this.publishedDataApi - .publishedDataControllerFormPopulateV3(this.form.datasetPids[0]) + .publishedDataV4ControllerFormPopulateV4(this.form.datasetPids) .subscribe((result) => { this.form.abstract = result.abstract; this.form.title = result.title; + this.metadata = result.metadata; }); this.actionSubjectSubscription = this.actionsSubj.subscribe((data) => { diff --git a/src/app/datasets/sample-edit/sample-edit.component.spec.ts b/src/app/datasets/sample-edit/sample-edit.component.spec.ts index 94613e2dc6..561b1f034f 100644 --- a/src/app/datasets/sample-edit/sample-edit.component.spec.ts +++ b/src/app/datasets/sample-edit/sample-edit.component.spec.ts @@ -31,7 +31,7 @@ import { } from "state-management/actions/samples.actions"; import { SampleEditComponent } from "./sample-edit.component"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; describe("SampleEditComponent", () => { let component: SampleEditComponent; @@ -162,7 +162,7 @@ describe("SampleEditComponent", () => { it("should return false if sample in form has same id as current sample", () => { const sampleId = "abc123"; - const sample = createMock({ + const sample = createMock({ sampleId, owner: "test", description: "test", @@ -187,7 +187,7 @@ describe("SampleEditComponent", () => { it("should return true if form is valid", () => { const sampleId = "abc123"; - const sample = createMock({ + const sample = createMock({ sampleId: "123abc", owner: "test", description: "test", @@ -224,7 +224,7 @@ describe("SampleEditComponent", () => { it("should close the dialog and emit data", () => { const dialogCloseSpy = spyOn(component.dialogRef, "close"); - const sample = createMock({ + const sample = createMock({ sampleId: "123abc", owner: "test", description: "test", diff --git a/src/app/datasets/sample-edit/sample-edit.component.ts b/src/app/datasets/sample-edit/sample-edit.component.ts index 0c875ff3ba..fe33e5ed4e 100644 --- a/src/app/datasets/sample-edit/sample-edit.component.ts +++ b/src/app/datasets/sample-edit/sample-edit.component.ts @@ -21,7 +21,7 @@ import { PageChangeEvent, SortChangeEvent, } from "shared/modules/table/table.component"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; import { changePageAction, fetchSamplesAction, @@ -58,7 +58,7 @@ export class SampleEditComponent implements OnInit, OnDestroy { ); samplesSubscription: Subscription = new Subscription(); - samples: SampleClass[] = []; + samples: OutputSampleDto[] = []; selectedSampleId = ""; displayedColumns = [ @@ -70,7 +70,7 @@ export class SampleEditComponent implements OnInit, OnDestroy { ]; form = new FormGroup({ - sample: new FormControl(null, [ + sample: new FormControl(null, [ Validators.required, this.sampleValidator(), ]), @@ -129,7 +129,7 @@ export class SampleEditComponent implements OnInit, OnDestroy { sortByColumnAction({ column: event.active, direction: event.direction }), ); - onRowClick = (sample: SampleClass): void => { + onRowClick = (sample: OutputSampleDto): void => { this.selectedSampleId = sample.sampleId; this.sample?.setValue(sample); }; diff --git a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.html b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.html index c69d3bc518..0cb2088b4e 100644 --- a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.html +++ b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.html @@ -55,6 +55,7 @@ [schema]="schema" [uischema]="uiSchema" [renderers]="renderers" + [ajv]="ajv" (errors)="onErrors($event)" (dataChange)="onMetadataChange($event)" > @@ -73,9 +74,7 @@ color="primary" class="save-and-continue" (click)="onPublishedDataUpdate(true)" - [disabled]=" - !form.valid || (panelOpenState() && !metadataDataIsValid()) - " + [disabled]="!form.valid" > Save and continue diff --git a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.spec.ts b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.spec.ts index f3dd30d5e2..159620dc30 100644 --- a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.spec.ts +++ b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.spec.ts @@ -26,6 +26,7 @@ import { MatButtonModule } from "@angular/material/button"; import { FlexLayoutModule } from "@ngbracket/ngx-layout"; import { PublishedDataService } from "@scicatproject/scicat-sdk-ts-angular"; import { AppConfigService } from "app-config.service"; +import { SharedScicatFrontendModule } from "shared/shared.module"; describe("PublisheddataEditComponent", () => { let component: PublisheddataEditComponent; @@ -51,6 +52,7 @@ describe("PublisheddataEditComponent", () => { MatOptionModule, MatSelectModule, ReactiveFormsModule, + SharedScicatFrontendModule, ], providers: [ provideMockStore({ diff --git a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.ts b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.ts index 32264111d1..7360212f34 100644 --- a/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.ts +++ b/src/app/publisheddata/publisheddata-edit/publisheddata-edit.component.ts @@ -20,12 +20,15 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { fromEvent, Observable, Subscription } from "rxjs"; import { angularMaterialRenderers } from "@jsonforms/angular-material"; import { EditableComponent } from "app-routing/pending-changes.guard"; -import { isEmpty } from "lodash-es"; +import { cloneDeep, isEmpty } from "lodash-es"; import { AppConfigService } from "app-config.service"; import { AccordionArrayLayoutRendererComponent, accordionArrayLayoutRendererTester, } from "shared/modules/jsonforms-custom-renderers/expand-panel-renderer/accordion-array-layout-renderer.component"; +import Ajv2019 from "ajv/dist/2019"; +import { PublishComponent } from "datasets/publish/publish.component"; +import { AjvService } from "shared/services/ajv.service"; @Component({ selector: "publisheddata-edit", @@ -38,6 +41,7 @@ export class PublisheddataEditComponent { private _hasUnsavedChanges = false; private publishedDataConfig$ = this.store.select(selectPublishedDataConfig); + ajv: Ajv2019; renderers = [ ...angularMaterialRenderers, { @@ -74,7 +78,10 @@ export class PublisheddataEditComponent private router: Router, private store: Store, private appConfigService: AppConfigService, - ) {} + private ajvService: AjvService, + ) { + this.ajv = this.ajvService.newInstance(); + } public onPublishedDataUpdate(shouldRedirect = false) { if (this.form.valid) { @@ -143,11 +150,8 @@ export class PublisheddataEditComponent this.publishedDataConfigSubscription = this.publishedDataConfig$.subscribe( (publishedDataConfig) => { if (!isEmpty(publishedDataConfig)) { - this.schema = publishedDataConfig.metadataSchema; - // NOTE: We set the publicationYear by the system, so we remove it from the required fields in the frontend - this.schema?.required.splice( - this.schema.required.indexOf("publicationYear"), - 1, + this.schema = this.ajvService.cleanupSchema( + publishedDataConfig.metadataSchema, ); this.uiSchema = publishedDataConfig.uiSchema; } diff --git a/src/app/samples/sample-dashboard/sample-dashboard.component.ts b/src/app/samples/sample-dashboard/sample-dashboard.component.ts index a37d3caf5f..326bbde27b 100644 --- a/src/app/samples/sample-dashboard/sample-dashboard.component.ts +++ b/src/app/samples/sample-dashboard/sample-dashboard.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, OnDestroy, ViewChild } from "@angular/core"; import { Store } from "@ngrx/store"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; import { changePageAction, fetchSamplesAction, @@ -125,8 +125,8 @@ export class SampleDashboardComponent implements OnInit, OnDestroy { paginationMode: TablePaginationMode = "server-side"; - dataSource: BehaviorSubject = new BehaviorSubject< - SampleClass[] + dataSource: BehaviorSubject = new BehaviorSubject< + OutputSampleDto[] >([]); pagination: TablePagination = {}; @@ -228,7 +228,7 @@ export class SampleDashboardComponent implements OnInit, OnDestroy { ); }; - formatTableData(samples: SampleClass[]): any { + formatTableData(samples: OutputSampleDto[]): any { if (samples) { return samples.map((sample) => ({ sampleId: sample.sampleId, @@ -363,7 +363,7 @@ export class SampleDashboardComponent implements OnInit, OnDestroy { } } - onRowClick(event: IRowEvent) { + onRowClick(event: IRowEvent) { if (event.event === RowEventType.RowClick) { const id = encodeURIComponent(event.sender.row.sampleId); this.router.navigateByUrl("/samples/" + id); diff --git a/src/app/samples/sample-detail/sample-detail.component.ts b/src/app/samples/sample-detail/sample-detail.component.ts index 7c749aaaf3..c73c583b94 100644 --- a/src/app/samples/sample-detail/sample-detail.component.ts +++ b/src/app/samples/sample-detail/sample-detail.component.ts @@ -31,7 +31,7 @@ import { OutputAttachmentV3Dto, OutputDatasetObsoleteDto, ReturnedUserDto, - SampleClass, + OutputSampleDto, } from "@scicatproject/scicat-sdk-ts-angular"; export interface TableData { @@ -58,7 +58,7 @@ export class SampleDetailComponent appConfig = this.appConfigService.getConfig(); - sample: SampleClass; + sample: OutputSampleDto; user: ReturnedUserDto; attachment: CreateAttachmentV3Dto; attachments: OutputAttachmentV3Dto[] = []; diff --git a/src/app/samples/sample-dialog/sample-dialog.component.ts b/src/app/samples/sample-dialog/sample-dialog.component.ts index 6f2e712966..ce2f831b52 100644 --- a/src/app/samples/sample-dialog/sample-dialog.component.ts +++ b/src/app/samples/sample-dialog/sample-dialog.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, OnInit, OnDestroy } from "@angular/core"; import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; import { Store } from "@ngrx/store"; import { addSampleAction, @@ -23,7 +23,7 @@ export class SampleDialogComponent implements OnInit, OnDestroy { private vm$ = this.store.select(selectSampleDialogPageViewModel); public form: FormGroup; description: string; - sample: SampleClass; + sample: OutputSampleDto; username = ""; userGroups: string[] | undefined; @@ -34,7 +34,7 @@ export class SampleDialogComponent implements OnInit, OnDestroy { private fb: FormBuilder, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) - { description, sampleCharacteristics, ownerGroup }: SampleClass, + { description, sampleCharacteristics, ownerGroup }: OutputSampleDto, ) { this.description = description; diff --git a/src/app/shared/MockStubs.ts b/src/app/shared/MockStubs.ts index 49951bc7e1..fd668f791a 100644 --- a/src/app/shared/MockStubs.ts +++ b/src/app/shared/MockStubs.ts @@ -15,7 +15,7 @@ import { OutputDatasetObsoleteDto, ProposalClass, PublishedData, - SampleClass, + OutputSampleDto, Logbook, Policy, ReturnedUserDto, @@ -250,7 +250,7 @@ export class MockPublishedDataApi { ]); } - publishedDataControllerFormPopulateV3() { + publishedDataV4ControllerFormPopulateV4() { return of({}); } } @@ -339,7 +339,7 @@ export function createMock(data?: Partial): T { export const mockDataset = createMock({}); export const mockAttachment = createMock({}); -export const mockSample = createMock({}); +export const mockSample = createMock({}); export const mockProposal = createMock({}); export const mockInstrument = createMock({}); export const mockOrigDatablock = createMock({}); diff --git a/src/app/shared/services/ajv.service.spec.ts b/src/app/shared/services/ajv.service.spec.ts new file mode 100644 index 0000000000..c2238b43cc --- /dev/null +++ b/src/app/shared/services/ajv.service.spec.ts @@ -0,0 +1,96 @@ +import { TestBed } from "@angular/core/testing"; + +import { AjvService } from "./ajv.service"; +import { omit } from "lodash-es"; + +describe("AjvService", () => { + let service: AjvService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AjvService], + }); + service = TestBed.inject(AjvService); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); + + it('should remove top level "dynamicDefaults"', () => { + const schema = { + type: "object", + dynamicDefaults: { + ts: "datetime", + }, + properties: { + ts: { + type: "string", + format: "date-time", + }, + }, + }; + + const cleanedupSchema = service.cleanupSchema(schema); + expect(cleanedupSchema).toEqual(omit(schema, "dynamicDefaults")); + }); + + it('should remove top level "dynamicDefaults" in an "allOf"', () => { + const schema = { + type: "object", + allOf: [ + { + dynamicDefaults: { + ts: "datetime", + }, + }, + { + properties: { + ts: { + type: "string", + }, + }, + }, + ], + }; + const cleanedupSchema = service.cleanupSchema(schema); + expect(cleanedupSchema).toEqual(omit(schema, "allOf[0].dynamicDefaults")); + }); + + it('should remove "dynamicDefaults" from nested objects and within "allOf" structures', () => { + const schema = { + type: "object", + dynamicDefaults: { userId: "uuid" }, + properties: { + metadata: { + type: "object", + dynamicDefaults: { createdAt: "datetime" }, + properties: { + createdAt: { type: "string" }, + }, + }, + profile: { + allOf: [ + { + dynamicDefaults: { lastLogin: "datetime" }, + properties: { lastLogin: { type: "string" } }, + }, + { + type: "object", + properties: { username: { type: "string" } }, + }, + ], + }, + }, + }; + + const cleanedupSchema = service.cleanupSchema(schema); + expect(cleanedupSchema).toEqual( + omit(schema, [ + "dynamicDefaults", + "properties.metadata.dynamicDefaults", + "properties.profile.allOf[0].dynamicDefaults", + ]), + ); + }); +}); diff --git a/src/app/shared/services/ajv.service.ts b/src/app/shared/services/ajv.service.ts new file mode 100644 index 0000000000..e103764778 --- /dev/null +++ b/src/app/shared/services/ajv.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from "@angular/core"; +import Ajv2019 from "ajv/dist/2019"; +import addFormats from "ajv-formats"; +import addKeywords from "ajv-keywords"; +import { cloneDeep } from "lodash-es"; + +@Injectable() +export class AjvService { + private static deleteDynamicDefaults(schema: any): void { + if (Array.isArray(schema)) { + schema.forEach((entry) => AjvService.deleteDynamicDefaults(entry)); + } else if (typeof schema === "object" && schema !== null) { + if (Object.prototype.hasOwnProperty.call(schema, "dynamicDefaults")) { + delete schema["dynamicDefaults"]; + } + + for (const key in schema) { + if (Object.prototype.hasOwnProperty.call(schema, key)) { + AjvService.deleteDynamicDefaults(schema[key]); + } + } + } + } + + constructor() { } + + newInstance() { + const ajv = new Ajv2019({ + strict: false, + useDefaults: "empty", + allErrors: true, + }); + addFormats(ajv); + addKeywords(ajv); + + return ajv; + } + + cleanupSchema(schema: any) { + const cleanSchema = cloneDeep(schema); + AjvService.deleteDynamicDefaults(cleanSchema); + return cleanSchema; + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index f44ccd75d1..fc9e3c0436 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -30,6 +30,7 @@ import { JsonformsAccordionRendererService } from "./services/jsonforms-accordio import { TranslateModule } from "@ngx-translate/core"; import { JsonPreviewDialogModule } from "./modules/json-preview-dialog/json-preview-dialog.module"; import { DatasetsListService } from "./services/datasets-list.service"; +import { AjvService } from "./services/ajv.service"; @NgModule({ imports: [ BreadcrumbModule, @@ -67,6 +68,7 @@ import { DatasetsListService } from "./services/datasets-list.service"; AttachmentService, JsonformsAccordionRendererService, DatasetsListService, + AjvService, ], exports: [ BreadcrumbModule, diff --git a/src/app/state-management/actions/samples.actions.ts b/src/app/state-management/actions/samples.actions.ts index 392ed83e6b..d11bbb6464 100644 --- a/src/app/state-management/actions/samples.actions.ts +++ b/src/app/state-management/actions/samples.actions.ts @@ -3,14 +3,14 @@ import { CreateAttachmentV3Dto, OutputAttachmentV3Dto, OutputDatasetObsoleteDto, - SampleClass, + OutputSampleDto, } from "@scicatproject/scicat-sdk-ts-angular"; import { SampleFilters, ScientificCondition } from "state-management/models"; export const fetchSamplesAction = createAction("[Sample] Fetch Samples"); export const fetchSamplesCompleteAction = createAction( "[Sample] Fetch Samples Complete", - props<{ samples: SampleClass[] }>(), + props<{ samples: OutputSampleDto[] }>(), ); export const fetchSamplesFailedAction = createAction( "[Sample] Fetch Samples Failed", @@ -44,7 +44,7 @@ export const fetchSampleAction = createAction( ); export const fetchSampleCompleteAction = createAction( "[Sample] Fetch Sample Complete", - props<{ sample: SampleClass }>(), + props<{ sample: OutputSampleDto }>(), ); export const fetchSampleFailedAction = createAction( "[Sample] Fetch Sample Failed", @@ -90,11 +90,11 @@ export const fetchSampleDatasetsCountFailedAction = createAction( export const addSampleAction = createAction( "[Sample] Add Sample", - props<{ sample: SampleClass }>(), + props<{ sample: OutputSampleDto }>(), ); export const addSampleCompleteAction = createAction( "[Sample] Add Sample Complete", - props<{ sample: SampleClass }>(), + props<{ sample: OutputSampleDto }>(), ); export const addSampleFailedAction = createAction("[Sample] Add Sample Failed"); @@ -104,7 +104,7 @@ export const saveCharacteristicsAction = createAction( ); export const saveCharacteristicsCompleteAction = createAction( "[Sample] Save Characteristics Complete", - props<{ sample: SampleClass }>(), + props<{ sample: OutputSampleDto }>(), ); export const saveCharacteristicsFailedAction = createAction( "[Sample] Save Characteristics Failed", diff --git a/src/app/state-management/effects/datasets.effects.ts b/src/app/state-management/effects/datasets.effects.ts index b901da6bbb..66b7aa17a9 100644 --- a/src/app/state-management/effects/datasets.effects.ts +++ b/src/app/state-management/effects/datasets.effects.ts @@ -227,7 +227,7 @@ export class DatasetEffects { }; } return this.datasetsService - .datasetsControllerFindAllV3(JSON.stringify(queryFilter)) + .datasetsControllerFindAllV3(queryFilter) .pipe( map((relatedDatasets) => fromActions.fetchRelatedDatasetsCompleteAction({ diff --git a/src/app/state-management/effects/jobs.effects.ts b/src/app/state-management/effects/jobs.effects.ts index f69093ff4f..1694550fda 100644 --- a/src/app/state-management/effects/jobs.effects.ts +++ b/src/app/state-management/effects/jobs.effects.ts @@ -30,7 +30,7 @@ export class JobEffects { concatLatestFrom(() => this.queryParams$), map(([action, params]) => params), switchMap((params) => - this.jobsService.jobsControllerFindAllV3(JSON.stringify(params)).pipe( + this.jobsService.jobsControllerFindAllV3(params).pipe( switchMap((jobs) => [ fromActions.fetchJobsCompleteAction({ jobs }), fromActions.fetchCountAction(), diff --git a/src/app/state-management/effects/proposals.effects.ts b/src/app/state-management/effects/proposals.effects.ts index 4910cb3367..0b9a5d0226 100644 --- a/src/app/state-management/effects/proposals.effects.ts +++ b/src/app/state-management/effects/proposals.effects.ts @@ -117,7 +117,7 @@ export class ProposalEffects { mergeMap(({ skip, limit, sortColumn, sortDirection, proposalId }) => { return this.datasetsService .datasetsControllerFindAllV3( - JSON.stringify({ + { where: { proposalId }, limits: { skip: skip, @@ -126,7 +126,7 @@ export class ProposalEffects { ? `${sortColumn}:${sortDirection}` : undefined, }, - }), + }, ) .pipe( mergeMap((datasets) => [ diff --git a/src/app/state-management/effects/published-data.effects.ts b/src/app/state-management/effects/published-data.effects.ts index b4d6c90048..06c01bdb85 100644 --- a/src/app/state-management/effects/published-data.effects.ts +++ b/src/app/state-management/effects/published-data.effects.ts @@ -376,9 +376,9 @@ export class PublishedDataEffects { switchMap(({ datasetPids, publishedDataDoi }) => this.datasetsV4Service .datasetsV4ControllerFindAllV4( - JSON.stringify({ + { where: { pid: { $in: datasetPids } }, - }), + }, ) .pipe( mergeMap((datasets) => [ diff --git a/src/app/state-management/effects/samples.effects.spec.ts b/src/app/state-management/effects/samples.effects.spec.ts index b34aac15ab..61c1d5a6b4 100644 --- a/src/app/state-management/effects/samples.effects.spec.ts +++ b/src/app/state-management/effects/samples.effects.spec.ts @@ -16,7 +16,7 @@ import { import { Type } from "@angular/core"; import { DatasetsService, - SampleClass, + OutputSampleDto, SamplesService, } from "@scicatproject/scicat-sdk-ts-angular"; import { TestObservable } from "jasmine-marbles/src/test-observables"; @@ -26,7 +26,7 @@ import { mockAttachment as attachment, } from "shared/MockStubs"; -const sample = createMock({ +const sample = createMock({ sampleId: "testId", ownerGroup: "testGroup", createdBy: "", diff --git a/src/app/state-management/effects/samples.effects.ts b/src/app/state-management/effects/samples.effects.ts index 03a63e233d..96c6b95de1 100644 --- a/src/app/state-management/effects/samples.effects.ts +++ b/src/app/state-management/effects/samples.effects.ts @@ -132,12 +132,12 @@ export class SampleEffects { mergeMap(([{ sampleId }, { order, skip, limit }]) => this.datasetApi .datasetsControllerFindAllV3( - JSON.stringify({ + { where: { sampleId }, order, skip, limit, - }), + }, ) .pipe( mergeMap((datasets) => [ @@ -155,7 +155,7 @@ export class SampleEffects { ofType(fromActions.fetchSampleDatasetsCountAction), switchMap(({ sampleId }) => this.datasetApi - .datasetsControllerFindAllV3(JSON.stringify({ where: { sampleId } })) + .datasetsControllerFindAllV3({ where: { sampleId } }) .pipe( map((datasets) => fromActions.fetchSampleDatasetsCountCompleteAction({ diff --git a/src/app/state-management/reducers/samples.reducer.spec.ts b/src/app/state-management/reducers/samples.reducer.spec.ts index 0aa7c3c9ed..a01ed8b698 100644 --- a/src/app/state-management/reducers/samples.reducer.spec.ts +++ b/src/app/state-management/reducers/samples.reducer.spec.ts @@ -7,9 +7,9 @@ import { mockDataset as dataset, mockAttachment as attachment, } from "shared/MockStubs"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; -const sample = createMock({ +const sample = createMock({ sampleId: "testId", ownerGroup: "testGroup", createdBy: "", diff --git a/src/app/state-management/selectors/samples.selectors.spec.ts b/src/app/state-management/selectors/samples.selectors.spec.ts index a8d00f426d..2018632cb4 100644 --- a/src/app/state-management/selectors/samples.selectors.spec.ts +++ b/src/app/state-management/selectors/samples.selectors.spec.ts @@ -2,9 +2,9 @@ import * as fromSelectors from "./samples.selectors"; import { SampleState } from "state-management/state/samples.store"; import { initialUserState } from "state-management/state/user.store"; import { createMock } from "shared/MockStubs"; -import { SampleClass } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputSampleDto } from "@scicatproject/scicat-sdk-ts-angular"; -const sample = createMock({ +const sample = createMock({ sampleId: "testId", ownerGroup: "testGroup", createdBy: "", diff --git a/src/app/state-management/state/samples.store.ts b/src/app/state-management/state/samples.store.ts index 1adc49ad11..ee2c286310 100644 --- a/src/app/state-management/state/samples.store.ts +++ b/src/app/state-management/state/samples.store.ts @@ -1,14 +1,14 @@ import { OutputAttachmentV3Dto, OutputDatasetObsoleteDto, - SampleClass, + OutputSampleDto, } from "@scicatproject/scicat-sdk-ts-angular"; import { SampleFilters, GenericFilters } from "state-management/models"; export interface SampleState { - samples: SampleClass[]; + samples: OutputSampleDto[]; attachments: OutputAttachmentV3Dto[]; - currentSample: SampleClass | undefined; + currentSample: OutputSampleDto | undefined; datasets: OutputDatasetObsoleteDto[]; metadataKeys: string[];