Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Injectable } from "@angular/core";
import { mergeWith } from "lodash-es";
import { firstValueFrom, of } from "rxjs";
import { catchError, timeout } from "rxjs/operators";
import { DialogOptionData } from "shared/modules/dialog/dialog.component";
import {
DatasetDetailComponentConfig,
IngestorComponentConfig,
Expand Down Expand Up @@ -129,7 +130,7 @@ export interface AppConfigInterface {
multipleDownloadUseAuthToken: boolean;
oAuth2Endpoints: OAuth2Endpoint[];
policiesEnabled: boolean;
retrieveDestinations?: RetrieveDestinations[];
retrieveDestinations?: DialogOptionData[];
riotBaseUrl: string | null;
scienceSearchEnabled: boolean;
scienceSearchUnitsEnabled: boolean;
Expand Down Expand Up @@ -170,6 +171,7 @@ export interface AppConfigInterface {
defaultTab?: DefaultTab;
statusBannerMessage?: string;
statusBannerCode?: "INFO" | "WARN";
markForDeletionCodes?: DialogOptionData[];
}

function isMainPageConfiguration(obj: any): obj is MainPageConfiguration {
Expand Down
88 changes: 75 additions & 13 deletions src/app/datasets/archiving.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,20 @@ describe("ArchivingService", () => {
pid: dataset.pid,
files: [],
}));
const archive = true;
const destinationPath = { destinationPath: "/test/path/" };
const jobType = "archive";
const additionalJobParams = { destinationPath: "/test/path/" };

const job = service["createJob"](
user,
datasets,
archive,
destinationPath,
jobType,
additionalJobParams,
);

expect(job).toBeDefined();
expect(job["emailJobInitiator"]).toEqual("test@email.com");
expect(job["jobParams"]["username"]).toEqual("testName");
expect(job["jobParams"]["destinationPath"]).toEqual("/test/path/");
expect(job["datasetList"]).toEqual(datasetList);
expect(job["type"]).toEqual("archive");
});
Expand All @@ -84,9 +85,9 @@ describe("ArchivingService", () => {
describe("#archiveOrRetrieve()", () => {
xit("should throw an error if no datasets are selected", () => {
const datasets = [];
const archive = true;
const jobType = "archive";

service["archiveOrRetrieve"](datasets, archive).subscribe((res) => {
service["archiveOrRetrieve"](datasets, jobType).subscribe((res) => {
expect(res).toThrowError("No datasets selected");
});
});
Expand Down Expand Up @@ -121,20 +122,20 @@ describe("ArchivingService", () => {
"createJob",
).and.returnValue(job);

service["archiveOrRetrieve"](datasets, archive).subscribe(() => {
service["archiveOrRetrieve"](datasets, "archive").subscribe(() => {
expect(createJobSpy).toHaveBeenCalledWith(
user,
datasets,
archive,
undefined,
"archive",
{},
);
expect(dispatchSpy).toHaveBeenCalledOnceWith(submitJobAction({ job }));
});
});
});

describe("#archive()", () => {
it("should call #archiveOrRetrieve() with archive set to `true`", () => {
it("should call #archiveOrRetrieve() with the archive job type", () => {
const archiveOrRetrieveSpy = spyOn<any, string>(
service,
"archiveOrRetrieve",
Expand All @@ -143,12 +144,15 @@ describe("ArchivingService", () => {

service.archive(datasets);

expect(archiveOrRetrieveSpy).toHaveBeenCalledOnceWith(datasets, true);
expect(archiveOrRetrieveSpy).toHaveBeenCalledOnceWith(
datasets,
"archive",
);
});
});

describe("#retrieve()", () => {
it("should call #archiveOrRetrieve() with archive set to `false`", () => {
it("should call #archiveOrRetrieve() with the retrieve job type", () => {
const archiveOrRetrieveSpy = spyOn<any, string>(
service,
"archiveOrRetrieve",
Expand All @@ -160,12 +164,34 @@ describe("ArchivingService", () => {

expect(archiveOrRetrieveSpy).toHaveBeenCalledOnceWith(
datasets,
false,
"retrieve",
destinationPath,
);
});
});

describe("#markForDeletion()", () => {
it("should call #archiveOrRetrieve() with the markForDeletion job type", () => {
const archiveOrRetrieveSpy = spyOn<any, string>(
service,
"archiveOrRetrieve",
);
const datasets = [mockDataset];
const additionalJobParams = {
deletionCode: "MARKED_FOR_DELETION",
explanation: "Requested by data manager",
};

service.markForDeletion(datasets, additionalJobParams);

expect(archiveOrRetrieveSpy).toHaveBeenCalledOnceWith(
datasets,
"markForDeletion",
additionalJobParams,
);
});
});

describe("#generateOptionLocation()", () => {
it("should return the generated path", () => {
const result = { option: "option", location: "relative" };
Expand Down Expand Up @@ -199,4 +225,40 @@ describe("ArchivingService", () => {
});
});
});

describe("#markForDeletionDialogOptions()", () => {
it("should return required fields for the mark-for-deletion dialog", () => {
const deletionCodes = [
{ option: "RETRIEVAL_FAILURE" },
{ option: "MARKED_FOR_DELETION" },
];

expect(service.markForDeletionDialogOptions(deletionCodes)).toEqual({
width: "auto",
data: {
title: "Mark for deletion reason",
additionalFields: {
deletionCode: {
label: "Deletion code",
type: "select",
required: true,
options: [
{
option: "RETRIEVAL_FAILURE",
},
{
option: "MARKED_FOR_DELETION",
},
],
},
explanation: {
label: "Explanation for deletion",
type: "textarea",
required: true,
},
},
},
});
});
});
});
68 changes: 56 additions & 12 deletions src/app/datasets/archiving.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import {
OutputDatasetObsoleteDto,
ReturnedUserDto,
} from "@scicatproject/scicat-sdk-ts-angular";
import {
DynamicDialogData,
DialogOptionData,
} from "shared/modules/dialog/dialog.component";

@Injectable()
export class ArchivingService {
Expand All @@ -24,14 +28,13 @@ export class ArchivingService {
private createJob(
user: ReturnedUserDto,
datasets: OutputDatasetObsoleteDto[],
archive: boolean,
destinationPath?: Record<string, string>,
jobType: string,
additionalJobParams: Record<string, string> = {},
// Do not specify tape copies here
) {
const extra = archive ? {} : destinationPath;
const jobParams = {
username: user.username,
...extra,
...additionalJobParams,
};

this.store.select(selectProfile).subscribe((profile) => {
Expand All @@ -46,16 +49,16 @@ export class ArchivingService {
pid: dataset.pid,
files: [],
})),
type: archive ? "archive" : "retrieve",
type: jobType,
};

return data;
}

private archiveOrRetrieve(
datasets: OutputDatasetObsoleteDto[],
archive: boolean,
destPath?: Record<string, string>,
jobType: string,
additionalJobParams: Record<string, string> = {},
): Observable<void> {
return combineLatest([this.currentUser$, this.tapeCopies$]).pipe(
first(),
Expand All @@ -72,7 +75,12 @@ export class ArchivingService {
throw new Error("No datasets selected");
}

const job = this.createJob(user, datasets, archive, destPath);
const job = this.createJob(
user,
datasets,
jobType,
additionalJobParams,
);

this.store.dispatch(submitJobAction({ job: job as any }));
}
Expand All @@ -81,14 +89,25 @@ export class ArchivingService {
}

public archive(datasets: OutputDatasetObsoleteDto[]): Observable<void> {
return this.archiveOrRetrieve(datasets, true);
return this.archiveOrRetrieve(datasets, "archive");
}

public retrieve(
datasets: OutputDatasetObsoleteDto[],
destinationPath: Record<string, string>,
additionalJobParams: Record<string, string>,
): Observable<void> {
return this.archiveOrRetrieve(datasets, "retrieve", additionalJobParams);
}

public markForDeletion(
datasets: OutputDatasetObsoleteDto[],
additionalJobParams: Record<string, string>,
): Observable<void> {
return this.archiveOrRetrieve(datasets, false, destinationPath);
return this.archiveOrRetrieve(
datasets,
"markForDeletion",
additionalJobParams,
);
}

public generateOptionLocation(
Expand Down Expand Up @@ -117,7 +136,7 @@ export class ArchivingService {
}

public retriveDialogOptions(
retrieveDestinations: RetrieveDestinations[] = [],
retrieveDestinations: DialogOptionData[] = [],
): object {
return {
width: "auto",
Expand All @@ -131,4 +150,29 @@ export class ArchivingService {
},
};
}

public markForDeletionDialogOptions(deletionCodes: DialogOptionData[] = []): {
data: DynamicDialogData;
width: string;
} {
return {
width: "auto",
data: {
title: "Mark for deletion reason",
additionalFields: {
deletionCode: {
label: "Deletion code",
type: "select",
required: true,
options: deletionCodes,
},
explanation: {
label: "Explanation for deletion",
type: "textarea",
required: true,
},
},
},
};
}
}
10 changes: 10 additions & 0 deletions src/app/datasets/batch-view/batch-view.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@
<mat-icon> cloud_download </mat-icon>
Retrieve
</button>
<button
mat-button
*ngIf="markForDeletion"
(click)="onMarkForDeletion()"
class="button"
color="primary"
>
<mat-icon> delete </mat-icon>
Mark for Deletion
</button>
</ng-container>
</div>

Expand Down
Loading
Loading