Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ describe("DatasetTableActionsComponent", () => {
setArchiveViewModeAction({ modeToggle }),
);
});

it("should dispatch selected non-default archive mode", () => {
dispatchSpy = spyOn(store, "dispatch");
const modeToggle = ArchViewMode.deleted;

component.onModeChange(modeToggle);

expect(dispatchSpy).toHaveBeenCalledTimes(1);
expect(dispatchSpy).toHaveBeenCalledWith(
setArchiveViewModeAction({ modeToggle }),
);
});
});

describe("#isEmptySelection()", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class DatasetTableActionsComponent implements OnInit, OnDestroy {
ArchViewMode.work_in_progress,
ArchViewMode.system_error,
ArchViewMode.user_error,
ArchViewMode.deleted,
];

searchPublicDataEnabled = this.appConfig.searchPublicDataEnabled;
Expand Down
66 changes: 65 additions & 1 deletion src/app/shared/modules/breadcrumb/breadcrumb.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@ import {
provideHttpClient,
withInterceptorsFromDi,
} from "@angular/common/http";
import { Location } from "@angular/common";
import { of } from "rxjs";
import { MockStore } from "shared/MockStubs";
import { BreadcrumbComponent } from "./breadcrumb.component";
import { Store } from "@ngrx/store";
import { provideRouter } from "@angular/router";
import { provideRouter, Router } from "@angular/router";
import { ArchViewMode } from "state-management/models";
import {
setArchiveViewModeAction,
setFiltersAction,
} from "state-management/actions/datasets.actions";

describe("BreadcrumbComponent", () => {
let component: BreadcrumbComponent;
let fixture: ComponentFixture<BreadcrumbComponent>;
let store: MockStore;
let router: Router;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand All @@ -27,6 +36,8 @@ describe("BreadcrumbComponent", () => {
beforeEach(() => {
fixture = TestBed.createComponent(BreadcrumbComponent);
component = fixture.componentInstance;
store = TestBed.inject(Store) as unknown as MockStore;
router = TestBed.inject(Router);
fixture.detectChanges();
});

Expand All @@ -37,4 +48,57 @@ describe("BreadcrumbComponent", () => {
it("should create", () => {
expect(component).toBeTruthy();
});

it("should dispatch setFiltersAction and setArchiveViewModeAction for datasets breadcrumb", () => {
const dispatchSpy = spyOn(store, "dispatch");
const selectSpy = spyOn(store, "select").and.returnValues(
of({ text: "abc", skip: 7 }) as unknown as ReturnType<
MockStore["select"]
>,
of(ArchViewMode.deleted) as unknown as ReturnType<MockStore["select"]>,
);
const backSpy = spyOn(TestBed.inject(Location), "back");
const crumb = {
label: "datasets",
path: "datasets",
params: {},
url: "/datasets",
fallback: "/datasets",
};

component.crumbClick(0, crumb);

expect(selectSpy).toHaveBeenCalledTimes(2);
expect(dispatchSpy).toHaveBeenCalledTimes(2);
expect((dispatchSpy.calls.argsFor(0) as object)[0]).toEqual(
setFiltersAction({
datasetFilters: {
text: "abc",
skip: 7,
},
}),
);
expect((dispatchSpy.calls.argsFor(1) as object)[0]).toEqual(
setArchiveViewModeAction({ modeToggle: ArchViewMode.deleted }),
);
expect(backSpy).toHaveBeenCalled();
});

it("should navigate by url for non-datasets breadcrumb", async () => {
const navigateSpy = spyOn(router, "navigateByUrl").and.returnValue(
Promise.resolve(true),
);
const crumb = {
label: "about",
path: "about",
params: {},
url: "/about",
fallback: "/about",
};

component.crumbClick(0, crumb);
await fixture.whenStable();

expect(navigateSpy).toHaveBeenCalledWith("/about");
});
});
91 changes: 17 additions & 74 deletions src/app/shared/modules/breadcrumb/breadcrumb.component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { Component, OnInit } from "@angular/core";
import { Router, ActivatedRoute, NavigationEnd, Params } from "@angular/router";
import { Store } from "@ngrx/store";
import { combineLatest } from "rxjs";

import {
selectArchiveViewMode,
selectFilters,
} from "state-management/selectors/datasets.selectors";
import { take, filter } from "rxjs/operators";
import { TitleCasePipe } from "shared/pipes/title-case.pipe";
import { ArchViewMode } from "state-management/models";
import { Location } from "@angular/common";
import {
setFiltersAction,
setArchiveViewModeAction,
} from "state-management/actions/datasets.actions";

interface Breadcrumb {
label: string;
Expand Down Expand Up @@ -49,7 +53,7 @@ export class BreadcrumbComponent implements OnInit {
// Update breadcrumb when navigating to child routes
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((event) => {
.subscribe(() => {
this.setBreadcrumbs();
});
}
Expand Down Expand Up @@ -115,81 +119,20 @@ export class BreadcrumbComponent implements OnInit {
}
// this catches errors and redirects to the fallback, this could/should be set in the routing module?
if (crumb.fallback === "/datasets") {
this.store
.select(selectFilters)
.pipe(take(1))
.subscribe((filters) => {
this.store
.select(selectArchiveViewMode)
.pipe(take(1))
.subscribe((currentMode) => {
filters["mode"] = setMode(currentMode);
this.location.back();
});
});
combineLatest([
this.store.select(selectFilters).pipe(take(1)),
this.store.select(selectArchiveViewMode).pipe(take(1)),
]).subscribe(([filters, modeToggle]) => {
this.store.dispatch(
setFiltersAction({ datasetFilters: { ...filters } }),
);
this.store.dispatch(setArchiveViewModeAction({ modeToggle }));
this.location.back();
});
} else {
this.router
.navigateByUrl(url + crumb.url)
.catch((error) => this.router.navigateByUrl(url + crumb.fallback));
.catch(() => this.router.navigateByUrl(url + crumb.fallback));
}
}
}

const setMode = (modeToggle: ArchViewMode) => {
switch (modeToggle) {
case ArchViewMode.all:
return {};
case ArchViewMode.archivable:
return {
"datasetlifecycle.archivable": true,
"datasetlifecycle.retrievable": false,
};
case ArchViewMode.retrievable:
return {
"datasetlifecycle.retrievable": true,
"datasetlifecycle.archivable": false,
};
case ArchViewMode.work_in_progress:
return {
$or: [
{
"datasetlifecycle.retrievable": false,
"datasetlifecycle.archivable": false,
"datasetlifecycle.archiveStatusMessage": {
$ne: "scheduleArchiveJobFailed",
},
"datasetlifecycle.retrieveStatusMessage": {
$ne: "scheduleRetrieveJobFailed",
},
},
],
};
case ArchViewMode.system_error:
return {
$or: [
{
"datasetlifecycle.retrievable": true,
"datasetlifecycle.archivable": true,
},
{
"datasetlifecycle.archiveStatusMessage": "scheduleArchiveJobFailed",
},
{
"datasetlifecycle.retrieveStatusMessage":
"scheduleRetrieveJobFailed",
},
],
};
case ArchViewMode.user_error:
return {
$or: [
{
"datasetlifecycle.archiveStatusMessage": "missingFilesError",
},
],
};
default: {
return {};
}
}
};
8 changes: 8 additions & 0 deletions src/app/shared/services/datasets-list.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ export class DatasetsListService implements OnDestroy {
return false;
}

deletedCondition(dataset: DatasetClass): boolean {
return dataset.datasetlifecycle.archiveStatusMessage === "deleted";
}

convertSavedDatasetColumns(columns: TableColumn[]): TableField<any>[] {
return columns
.filter((column) => column.name !== "select")
Expand Down Expand Up @@ -188,6 +192,8 @@ export class DatasetsListService implements OnDestroy {
return "Archivable";
} else if (this.retrievableCondition(row)) {
return "Retrievable";
} else if (this.deletedCondition(row)) {
return "Deleted";
} else if (this.systemErrorCondition(row)) {
return "System error";
} else if (this.userErrorCondition(row)) {
Expand All @@ -204,6 +210,8 @@ export class DatasetsListService implements OnDestroy {
return "Archivable";
} else if (this.retrievableCondition(row)) {
return "Retrievable";
} else if (this.deletedCondition(row)) {
return "Deleted";
} else if (this.systemErrorCondition(row)) {
return "System error";
} else if (this.userErrorCondition(row)) {
Expand Down
5 changes: 1 addition & 4 deletions src/app/state-management/actions/datasets.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,7 @@ export const setTextFilterAction = createAction(
export const setFiltersAction = createAction(
"[Dataset] Set Filters",
props<{
datasetFilters: Record<
string,
string | DateRange | string[] | INumericRange
>;
datasetFilters: Partial<DatasetFilters>;
}>(),
);
export const addDatasetFilterAction = createAction(
Expand Down
1 change: 1 addition & 0 deletions src/app/state-management/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export enum ArchViewMode {
work_in_progress = "work in progress",
system_error = "system error",
user_error = "user error",
deleted = "deleted",
}
export enum JobViewMode {
myJobs = "my jobs",
Expand Down
64 changes: 64 additions & 0 deletions src/app/state-management/reducers/datasets.reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,40 @@ describe("DatasetsReducer", () => {
expect(state.filters.modeToggle).toEqual(modeToggle);
expect(state.filters.skip).toEqual(0);
});

it("should set deleted mode filter", () => {
const modeToggle = ArchViewMode.deleted;

const action = fromActions.setArchiveViewModeAction({ modeToggle });
const state = fromDatasets.datasetsReducer(initialDatasetState, action);

expect(state.filters.mode).toEqual({
"datasetlifecycle.archiveStatusMessage": "deleted",
});
expect(state.filters.modeToggle).toEqual(modeToggle);
expect(state.filters.skip).toEqual(0);
});

it("should preserve existing skip when mode changes", () => {
const modeToggle = ArchViewMode.archivable;
const stateIn = {
...initialDatasetState,
filters: {
...initialDatasetState.filters,
skip: 42,
},
};

const action = fromActions.setArchiveViewModeAction({ modeToggle });
const state = fromDatasets.datasetsReducer(stateIn, action);

expect(state.filters.skip).toEqual(42);
expect(state.filters.modeToggle).toEqual(modeToggle);
expect(state.filters.mode).toEqual({
"datasetlifecycle.archivable": true,
"datasetlifecycle.retrievable": false,
});
});
});

describe("on setPublicViewMode", () => {
Expand Down Expand Up @@ -377,6 +411,36 @@ describe("DatasetsReducer", () => {
});
});

describe("on setFiltersAction", () => {
it("should restore filters without updating searchTerms or hasPrefilledFilters", () => {
const stateIn = {
...initialDatasetState,
searchTerms: "keep-me",
hasPrefilledFilters: false,
};
const datasetFilters = {
text: "restored",
skip: 12,
modeToggle: ArchViewMode.deleted,
mode: {
"datasetlifecycle.archiveStatusMessage": "deleted",
},
};

const action = fromActions.setFiltersAction({ datasetFilters });
const state = fromDatasets.datasetsReducer(stateIn, action);

expect(state.filters.text).toEqual("restored");
expect(state.filters.skip).toEqual(12);
expect(state.filters.modeToggle).toEqual(ArchViewMode.deleted);
expect(state.filters.mode).toEqual({
"datasetlifecycle.archiveStatusMessage": "deleted",
});
expect(state.searchTerms).toEqual("keep-me");
expect(state.hasPrefilledFilters).toEqual(false);
});
});

describe("on clearFacetsAction", () => {
it("should clear filters while saving the filters limit and set searchTerms to an empty string", () => {
const limit = 10;
Expand Down
7 changes: 6 additions & 1 deletion src/app/state-management/reducers/datasets.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,16 @@ const reducer = createReducer(
],
};
break;
case ArchViewMode.deleted:
mode = {
"datasetlifecycle.archiveStatusMessage": "deleted",
};
break;
default: {
break;
}
}
const filters = { ...state.filters, skip: 0, mode, modeToggle };
const filters = { skip: 0, ...state.filters, mode, modeToggle };
return { ...state, filters };
},
),
Expand Down
Loading