diff --git a/CHANGELOG.md b/CHANGELOG.md index 211128bed2..10f2f204c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/) ### Fixed 🐞 - Fix suspicious metrics and risk profile docs not loading [#3272](https://github.com/MaibornWolff/codecharta/pull/3272) +- Show again delta of a building which have nothing in common in red or green [#3271](https://github.com/MaibornWolff/codecharta/pull/3271) + +### Chore 👨‍💻 👩‍💻 + +- Replace custom Redux adapter through real NgRx [#3271](https://github.com/MaibornWolff/codecharta/pull/3271) ## [1.115.1] - 2023-04-06 diff --git a/visualization/app/app.module.ts b/visualization/app/app.module.ts index 93f3e025ed..ec3960c79b 100644 --- a/visualization/app/app.module.ts +++ b/visualization/app/app.module.ts @@ -4,14 +4,12 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic" import { HttpClientModule } from "@angular/common/http" import { FormsModule, ReactiveFormsModule } from "@angular/forms" import { MaterialModule } from "./material/material.module" -import { EffectsModule } from "./codeCharta/state/angular-redux/effects/effects.module" +import { EffectsModule } from "@ngrx/effects" import { UnfocusNodesEffect } from "./codeCharta/state/effects/unfocusNodes/unfocusNodes.effect" import { AddBlacklistItemsIfNotResultsInEmptyMapEffect } from "./codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect" import { dialogs } from "./codeCharta/ui/dialogs/dialogs" import { OpenNodeContextMenuEffect } from "./codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect" import { BlacklistSearchPatternEffect } from "./codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect" -import { ResetColorRangeEffect } from "./codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect" -import { ResetChosenMetricsEffect } from "./codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect" import { UpdateEdgePreviewsEffect } from "./codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect" import { ChangelogDialogModule } from "./codeCharta/ui/dialogs/changelogDialog/changelogDialog.module" import { VersionService } from "./codeCharta/services/version/version.service" @@ -19,16 +17,22 @@ import { RenderCodeMapEffect } from "./codeCharta/state/effects/renderCodeMapEff import { AutoFitCodeMapEffect } from "./codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect" import { CodeChartaModule } from "./codeCharta/codeCharta.module" import { UpdateVisibleTopLabelsEffect } from "./codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect" -import { ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect } from "./codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect" import { LinkColorMetricToHeightMetricEffect } from "./codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect" import { UpdateFileSettingsEffect } from "./codeCharta/state/effects/updateFileSettings/updateFileSettings.effect" import { CodeChartaComponent } from "./codeCharta/codeCharta.component" import { NodeContextMenuCardModule } from "./codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.module" +import { StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "./codeCharta/state/store/state.manager" +import { ResetColorRangeEffect } from "./codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect" +import { ResetChosenMetricsEffect } from "./codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect" +import { ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect } from "./codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect" +import { SetLoadingIndicatorEffect } from "./codeCharta/state/effects/setLoadingIndicator/setLoadingIndicator.effect" @NgModule({ imports: [ BrowserModule, HttpClientModule, + StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] }), EffectsModule.forRoot([ UnfocusNodesEffect, AddBlacklistItemsIfNotResultsInEmptyMapEffect, @@ -42,7 +46,8 @@ import { NodeContextMenuCardModule } from "./codeCharta/state/effects/nodeContex UpdateVisibleTopLabelsEffect, LinkColorMetricToHeightMetricEffect, ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect, - UpdateFileSettingsEffect + UpdateFileSettingsEffect, + SetLoadingIndicatorEffect ]), MaterialModule, FormsModule, diff --git a/visualization/app/codeCharta/codeCharta.component.spec.ts b/visualization/app/codeCharta/codeCharta.component.spec.ts index 266164dcf3..e2f4f005e5 100644 --- a/visualization/app/codeCharta/codeCharta.component.spec.ts +++ b/visualization/app/codeCharta/codeCharta.component.spec.ts @@ -2,8 +2,8 @@ import { TestBed } from "@angular/core/testing" import { LoadInitialFileService } from "./services/loadInitialFile/loadInitialFile.service" import { CodeChartaModule } from "./codeCharta.module" import { CodeChartaComponent } from "./codeCharta.component" -import { Store } from "./state/angular-redux/store" import { setIsLoadingFile } from "./state/store/appSettings/isLoadingFile/isLoadingFile.actions" +import { Store } from "@ngrx/store" describe("codeChartaComponent", () => { beforeEach(() => { @@ -20,7 +20,7 @@ describe("codeChartaComponent", () => { const codeChartaComponent = new CodeChartaComponent(mockedStore, mockedLoadInitialFileService) await codeChartaComponent.ngOnInit() - expect(mockedStore.dispatch).toHaveBeenCalledWith(setIsLoadingFile(true)) + expect(mockedStore.dispatch).toHaveBeenCalledWith(setIsLoadingFile({ value: true })) expect(mockedLoadInitialFileService.loadFileOrSample).toHaveBeenCalled() }) diff --git a/visualization/app/codeCharta/codeCharta.component.ts b/visualization/app/codeCharta/codeCharta.component.ts index a7358f6f53..b86280e244 100755 --- a/visualization/app/codeCharta/codeCharta.component.ts +++ b/visualization/app/codeCharta/codeCharta.component.ts @@ -2,7 +2,7 @@ import { setIsLoadingFile } from "./state/store/appSettings/isLoadingFile/isLoad import packageJson from "../../package.json" import { LoadInitialFileService } from "./services/loadInitialFile/loadInitialFile.service" import { Component, OnInit, ViewEncapsulation } from "@angular/core" -import { Store } from "./state/angular-redux/store" +import { Store } from "@ngrx/store" @Component({ selector: "cc-code-charta", @@ -21,7 +21,7 @@ export class CodeChartaComponent implements OnInit { } async ngOnInit(): Promise { - this.store.dispatch(setIsLoadingFile(true)) + this.store.dispatch(setIsLoadingFile({ value: true })) await this.loadInitialFileService.loadFileOrSample() } } diff --git a/visualization/app/codeCharta/codeCharta.model.ts b/visualization/app/codeCharta/codeCharta.model.ts index 308d6f9ea4..fd696ff270 100644 --- a/visualization/app/codeCharta/codeCharta.model.ts +++ b/visualization/app/codeCharta/codeCharta.model.ts @@ -1,11 +1,14 @@ import { Vector3 } from "three" -import { Action } from "redux" import { ExportCCFile } from "./codeCharta.api.model" import { FileState } from "./model/files/files" import { CustomConfig } from "./model/customConfig/customConfig.api.model" import Rectangle from "./util/algorithm/streetLayout/rectangle" -import { RightClickedNodeData } from "./state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" -import { Scaling } from "./state/store/appSettings/scaling/scaling.actions" + +export type Scaling = { + x: number + y: number + z: number +} export interface NameDataPair { fileName: string @@ -85,7 +88,7 @@ export enum SortingOption { NUMBER_OF_FILES = "Number of Files" } -export interface colorLabelOptions { +export interface ColorLabelOptions { positive: boolean negative: boolean neutral: boolean @@ -155,7 +158,7 @@ export interface AppSettings { sharpnessMode: SharpnessMode experimentalFeaturesEnabled: boolean screenshotToClipboardEnabled: boolean - colorLabels: colorLabelOptions + colorLabels: ColorLabelOptions isColorMetricLinkedToHeightMetric: boolean enableFloorLabels: boolean } @@ -347,7 +350,7 @@ export interface Node { outgoingEdgePoint: Vector3 } -export interface State { +export interface CcState { fileSettings: FileSettings dynamicSettings: DynamicSettings appSettings: AppSettings @@ -382,23 +385,12 @@ export function stateObjectReviver(_, valueToRevive) { return valueToRevive } -export interface CCAction extends Action { - // TODO: Do not use any here! Make sure all our actions are properly declared. - // - // As a starting point: - // - // RecursivePartial & { - // metricData: MetricData - // dynamicSettings: DynamicSettings - // fileSettings: FileSettings - // appSettings: AppSettings - // files: FileState[] - // } - payload?: any -} - export interface AppStatus { hoveredNodeId: number | null selectedBuildingId: number | null - rightClickedNodeData: RightClickedNodeData + rightClickedNodeData: { + nodeId: number + xPositionOfRightClickEvent: number + yPositionOfRightClickEvent: number + } | null } diff --git a/visualization/app/codeCharta/services/loadFile/loadFile.service.spec.ts b/visualization/app/codeCharta/services/loadFile/loadFile.service.spec.ts index fd927e4724..fba0553873 100644 --- a/visualization/app/codeCharta/services/loadFile/loadFile.service.spec.ts +++ b/visualization/app/codeCharta/services/loadFile/loadFile.service.spec.ts @@ -1,8 +1,8 @@ import { TestBed } from "@angular/core/testing" import { LoadFileService } from "./loadFile.service" import { TEST_FILE_CONTENT } from "../../util/dataMocks" -import { CCFile, NodeMetricData, NodeType } from "../../codeCharta.model" -import { removeFile, setDeltaReference, setFiles, setStandard } from "../../state/store/files/files.actions" +import { CCFile, CcState, NodeMetricData, NodeType } from "../../codeCharta.model" +import { removeFile, setDeltaReference, setStandard } from "../../state/store/files/files.actions" import { ExportBlacklistType, ExportCCFile } from "../../codeCharta.api.model" import { getCCFiles, isPartialState } from "../../model/files/files.helper" import { CCFileValidationResult, ERROR_MESSAGES } from "../../util/fileValidator" @@ -11,11 +11,11 @@ import { clone } from "../../util/clone" import { klona } from "klona" import { ErrorDialogComponent } from "../../ui/dialogs/errorDialog/errorDialog.component" import { loadFilesValidationToErrorDialog } from "../../util/loadFilesValidationToErrorDialog" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" import { fileRoot } from "./fileRoot" import { MatDialog } from "@angular/material/dialog" import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" const mockedMetricDataSelector = metricDataSelector as unknown as jest.Mock jest.mock("../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ @@ -24,8 +24,8 @@ jest.mock("../../state/selectors/accumulatedData/metricData/metricData.selector" describe("loadFileService", () => { let codeChartaService: LoadFileService - let store: Store - let state: State + let store: Store + let state: State let dialog: MatDialog let validFileContent: ExportCCFile let metricData: NodeMetricData[] @@ -41,7 +41,6 @@ describe("loadFileService", () => { { name: "mcc", maxValue: 1, minValue: 1 }, { name: "rloc", maxValue: 2, minValue: 1 } ] - store.dispatch(setFiles([])) }) afterEach(() => { @@ -49,6 +48,9 @@ describe("loadFileService", () => { }) function restartSystem() { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) store = TestBed.inject(Store) state = TestBed.inject(State) dialog = { open: jest.fn() } as unknown as MatDialog @@ -365,7 +367,7 @@ describe("loadFileService", () => { { fileName: "SecondFile", content: validFileContent, fileSize: 42 } ]) - store.dispatch(removeFile("FirstFile")) + store.dispatch(removeFile({ fileName: "FirstFile" })) expect(state.getValue().files).toHaveLength(1) expect(state.getValue().files[0].file.fileMeta.fileName).toEqual("SecondFile") }) @@ -376,12 +378,12 @@ describe("loadFileService", () => { const updateRootDataSpy = jest.spyOn(fileRoot, "updateRoot") const newReferenceFile = state.getValue().files[0].file - store.dispatch(setDeltaReference(newReferenceFile)) + store.dispatch(setDeltaReference({ file: newReferenceFile })) expect(updateRootDataSpy).toHaveBeenCalledTimes(1) expect(updateRootDataSpy).toHaveBeenCalledWith(state.getValue().files[0].file.map.name) // set reference file to a partial selected file. Therefore reference file becomes undefined - store.dispatch(setStandard([state.getValue().files[0].file])) + store.dispatch(setStandard({ files: [state.getValue().files[0].file] })) expect(updateRootDataSpy).toHaveBeenCalledTimes(1) }) }) diff --git a/visualization/app/codeCharta/services/loadFile/loadFile.service.ts b/visualization/app/codeCharta/services/loadFile/loadFile.service.ts index 00d0cd5f40..cabfe65c4d 100644 --- a/visualization/app/codeCharta/services/loadFile/loadFile.service.ts +++ b/visualization/app/codeCharta/services/loadFile/loadFile.service.ts @@ -5,14 +5,13 @@ import { clone } from "../../util/clone" import { CCFileValidationResult } from "../../util/fileValidator" import { setFiles, setStandardByNames } from "../../state/store/files/files.actions" import { FileState } from "../../model/files/files" -import { NameDataPair } from "../../codeCharta.model" +import { NameDataPair, CcState } from "../../codeCharta.model" import { referenceFileSelector } from "../../state/selectors/referenceFile/referenceFile.selector" import { ErrorDialogComponent } from "../../ui/dialogs/errorDialog/errorDialog.component" import { loadFilesValidationToErrorDialog } from "../../util/loadFilesValidationToErrorDialog" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" import { enrichFileStatesAndRecentFilesWithValidationResults } from "./fileParser" import { fileRoot } from "./fileRoot" +import { Store, State } from "@ngrx/store" @Injectable({ providedIn: "root" }) export class LoadFileService implements OnDestroy { @@ -29,7 +28,7 @@ export class LoadFileService implements OnDestroy { ) .subscribe() - constructor(private store: Store, private state: State, private dialog: MatDialog) {} + constructor(private store: Store, private state: State, private dialog: MatDialog) {} ngOnDestroy(): void { this.referenceFileSubscription.unsubscribe() @@ -52,11 +51,11 @@ export class LoadFileService implements OnDestroy { throw new Error("No files could be uploaded") } - this.store.dispatch(setFiles(fileStates)) + this.store.dispatch(setFiles({ value: fileStates })) const recentFile = recentFiles[0] const rootName = this.state.getValue().files.find(f => f.file.fileMeta.fileName === recentFile).file.map.name - this.store.dispatch(setStandardByNames(recentFiles)) + this.store.dispatch(setStandardByNames({ fileNames: recentFiles })) fileRoot.updateRoot(rootName) } diff --git a/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.spec.ts b/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.spec.ts index 2a728e74b4..e0c2ff5990 100644 --- a/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.spec.ts +++ b/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.spec.ts @@ -1,11 +1,9 @@ import { TestBed } from "@angular/core/testing" import { HttpClient } from "@angular/common/http" import { CCFile, LayoutAlgorithm } from "../../codeCharta.model" -import { State } from "../../state/angular-redux/state" import { GLOBAL_SETTINGS } from "../../util/dataMocks" import { GlobalSettingsHelper } from "../../util/globalSettingsHelper" import { LoadInitialFileService } from "./loadInitialFile.service" -import { Store } from "../../state/angular-redux/store" import { LoadFileService } from "../loadFile/loadFile.service" import { ErrorDialogComponent } from "../../ui/dialogs/errorDialog/errorDialog.component" import sample1 from "../../assets/sample1.cc.json" @@ -13,6 +11,8 @@ import sample2 from "../../assets/sample2.cc.json" import { FileSelectionState, FileState } from "../../model/files/files" import { setFiles } from "../../state/store/files/files.actions" import { MatDialog } from "@angular/material/dialog" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" describe("LoadInitialFileService", () => { let loadInitialFileService: LoadInitialFileService @@ -23,9 +23,8 @@ describe("LoadInitialFileService", () => { mockedDialog = { open: jest.fn() } as unknown as MatDialog TestBed.configureTestingModule({ + imports: [[StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })]], providers: [ - Store, - State, { provide: MatDialog, useValue: mockedDialog }, { provide: HttpClient, useValue: {} }, { provide: LoadFileService, useValue: { loadFiles: jest.fn() } } @@ -74,36 +73,36 @@ describe("LoadInitialFileService", () => { it("should set files to standard mode when no 'mode' parameter is given", () => { const store = TestBed.inject(Store) const fileState: FileState[] = [{ file: {} as CCFile, selectedAs: FileSelectionState.None }] - store.dispatch(setFiles(fileState)) + store.dispatch(setFiles({ value: fileState })) store.dispatch = jest.fn() loadInitialFileService["urlUtils"].getParameterByName = () => "" loadInitialFileService["setRenderStateFromUrl"]() - expect(store.dispatch).toHaveBeenCalledWith({ payload: [{}], type: "SET_STANDARD" }) + expect(store.dispatch).toHaveBeenCalledWith({ files: [{}], type: "SET_STANDARD" }) }) it("should set files to multiple mode when any string (except 'Delta') is given", () => { const store = TestBed.inject(Store) const fileState: FileState[] = [{ file: {} as CCFile, selectedAs: FileSelectionState.None }] - store.dispatch(setFiles(fileState)) + store.dispatch(setFiles({ value: fileState })) store.dispatch = jest.fn() loadInitialFileService["urlUtils"].getParameterByName = () => "invalidMode" loadInitialFileService["setRenderStateFromUrl"]() - expect(store.dispatch).toHaveBeenCalledWith({ payload: [{}], type: "SET_STANDARD" }) + expect(store.dispatch).toHaveBeenCalledWith({ files: [{}], type: "SET_STANDARD" }) }) it("should set files to delta mode when 'mode=delta' parameter is given", () => { const store = TestBed.inject(Store) const fileState: FileState[] = [{ file: {} as CCFile, selectedAs: FileSelectionState.None }] - store.dispatch(setFiles(fileState)) + store.dispatch(setFiles({ value: fileState })) store.dispatch = jest.fn() loadInitialFileService["urlUtils"].getParameterByName = () => "Delta" loadInitialFileService["setRenderStateFromUrl"]() - expect(store.dispatch).toHaveBeenCalledWith({ payload: [{}], type: "SET_STANDARD" }) + expect(store.dispatch).toHaveBeenCalledWith({ files: [{}], type: "SET_STANDARD" }) }) }) diff --git a/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.ts b/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.ts index f3d270bdb2..e7fef5b38c 100644 --- a/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.ts +++ b/visualization/app/codeCharta/services/loadInitialFile/loadInitialFile.service.ts @@ -1,10 +1,8 @@ import { Injectable } from "@angular/core" import { MatDialog } from "@angular/material/dialog" import { HttpClient } from "@angular/common/http" -import { NameDataPair } from "../../codeCharta.model" +import { NameDataPair, CcState } from "../../codeCharta.model" import { getCCFiles } from "../../model/files/files.helper" -import { State } from "../../state/angular-redux/state" -import { Store } from "../../state/angular-redux/store" import { setDelta, setStandard } from "../../state/store/files/files.actions" import { ErrorDialogComponent } from "../../ui/dialogs/errorDialog/errorDialog.component" import { GlobalSettingsHelper } from "../../util/globalSettingsHelper" @@ -13,6 +11,7 @@ import { UrlExtractor } from "./urlExtractor" import sample1 from "../../assets/sample1.cc.json" import sample2 from "../../assets/sample2.cc.json" import { ExportCCFile } from "../../codeCharta.api.model" +import { Store, State } from "@ngrx/store" @Injectable({ providedIn: "root" }) export class LoadInitialFileService { @@ -20,7 +19,7 @@ export class LoadInitialFileService { constructor( private store: Store, - private state: State, + private state: State, private dialog: MatDialog, private loadFileService: LoadFileService, private httpClient: HttpClient @@ -67,9 +66,9 @@ export class LoadInitialFileService { const files = getCCFiles(this.state.getValue().files) if (renderState === "Delta" && files.length >= 2) { - this.store.dispatch(setDelta(files[0], files[1])) + this.store.dispatch(setDelta({ referenceFile: files[0], comparisonFile: files[1] })) } else { - this.store.dispatch(setStandard(files)) + this.store.dispatch(setStandard({ files })) } } } diff --git a/visualization/app/codeCharta/state/angular-redux/createSelector.spec.ts b/visualization/app/codeCharta/state/angular-redux/createSelector.spec.ts deleted file mode 100644 index 9b8a050c1a..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/createSelector.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createSelector } from "./createSelector" - -describe("createSelector", () => { - it("should project correct value", () => { - const state = { x: 2 } - const selector = (s: typeof state) => s.x - const doubledProjector = createSelector([selector], (n: number) => 2 * n) - expect(doubledProjector(state)).toBe(4) - }) - - it("should not recalculate projector if its input hasn't changed", () => { - const state = { x: 2 } - const selector = (s: typeof state) => s.x - const double = jest.fn((n: number) => 2 * n) - const doubledProjector = createSelector([selector], double) - expect(doubledProjector(state)).toBe(4) - - expect(doubledProjector(state)).toBe(4) - expect(double).toHaveBeenCalledTimes(1) - }) -}) diff --git a/visualization/app/codeCharta/state/angular-redux/createSelector.ts b/visualization/app/codeCharta/state/angular-redux/createSelector.ts deleted file mode 100644 index f89ebf3783..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/createSelector.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { CcState } from "../store/store" - -type Selector = (state: State) => T - -export function createSelector(selectors: [Selector], projector: (s1: S1) => P): (state: State) => P -export function createSelector( - selectors: [Selector, Selector?], - projector: (s1: S1, s2: S2) => P -): (state: State) => P -export function createSelector( - selectors: [Selector, Selector?, Selector?], - projector: (s1: S1, s2?: S2, s3?: S3) => P -): (state: State) => P -export function createSelector( - selectors: [Selector, Selector?, Selector?, Selector?], - projector: (s1: S1, s2?: S2, s3?: S3, s4?: S4) => P -): (state: State) => P -export function createSelector( - selectors: [Selector, Selector?, Selector?, Selector?, Selector?], - projector: (s1: S1, s2?: S2, s3?: S3, s4?: S4, s5?: S5) => P -): (state: State) => P - -export function createSelector( - selectors: [Selector, Selector?, Selector?, Selector?, Selector?], - projector: (s1: S1, s2?: S2, s3?: S3, s4?: S4, s5?: S5) => P -): (state: State) => P { - let lastValues = [] - let memorizedResult: P - - return (state: State) => { - const values: [S1, S2?, S3?, S4?, S5?] = [selectors[0](state)] - for (let index = 1; index < selectors.length; index++) { - values.push(selectors[index](state)) - } - - if (values.some((value, index) => value !== lastValues[index])) { - lastValues = values - memorizedResult = projector(...values) - } - return memorizedResult - } -} diff --git a/visualization/app/codeCharta/state/angular-redux/effects/createEffect.spec.ts b/visualization/app/codeCharta/state/angular-redux/effects/createEffect.spec.ts deleted file mode 100644 index dd2ba545a7..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/effects/createEffect.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Subject } from "rxjs" -import { Store } from "../../store/store" -import { createEffect } from "./createEffect" - -jest.mock("../../store/store", () => ({ - Store: {} -})) -const MockedStore = jest.mocked(Store) - -describe("createEffect", () => { - let source - - beforeEach(() => { - source = new Subject() - MockedStore.dispatch = jest.fn() - }) - - afterEach(() => { - source.complete() - }) - - it("should observe and dispatch each received value", () => { - createEffect(() => source) - source.next({ type: "some-action-type" }) - source.next({ type: "some-other-action-type" }) - expect(MockedStore.dispatch).toHaveBeenCalledTimes(2) - expect(MockedStore.dispatch.mock.calls[0][0]).toEqual({ type: "some-action-type" }) - expect(MockedStore.dispatch.mock.calls[1][0]).toEqual({ type: "some-other-action-type" }) - }) - - it("should not dispatch if dispatch is set to false", () => { - createEffect(() => source, { dispatch: false }) - source.next({ type: "some-action-type" }) - expect(MockedStore.dispatch).not.toHaveBeenCalled() - }) - - it("should return an observable which outputs whenever given source outputs", () => { - const effect$ = createEffect(() => source) - const onEffect = jest.fn() - effect$.subscribe(onEffect) - - source.next({ type: "some-action-type" }) - expect(onEffect).toBeCalledWith({ type: "some-action-type" }) - }) -}) diff --git a/visualization/app/codeCharta/state/angular-redux/effects/createEffect.ts b/visualization/app/codeCharta/state/angular-redux/effects/createEffect.ts deleted file mode 100644 index 5198fb9305..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/effects/createEffect.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Action } from "redux" -import { Observable, Subject } from "rxjs" -import { Store } from "../../store/store" - -type DontDispatchConfig = { dispatch: false } -type DispatchConfig = { dispatch?: true } -type Config = DispatchConfig | DontDispatchConfig - -/** Simple placeholder for NgRx's createEffect. The goal is to provide the - * same api as NgRx, so that we can switch to NgRx in the long run. - * Please note that its functionality is very minimal so far. - */ -export function createEffect(source: () => Observable, config?: Config) { - const subjectOfEffect = new Subject() - - source().subscribe(output => { - if (!config || config.dispatch !== false) { - if (!isAction(output)) { - throw new Error("output must be an action") - } - Store.dispatch(output) - } - - subjectOfEffect.next(output) - }) - - return subjectOfEffect as Observable -} - -function isAction(something: unknown): something is Action { - return something && Object.prototype.hasOwnProperty.call(something, "type") -} diff --git a/visualization/app/codeCharta/state/angular-redux/effects/effects.module.ts b/visualization/app/codeCharta/state/angular-redux/effects/effects.module.ts deleted file mode 100644 index 96165273b0..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/effects/effects.module.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { APP_INITIALIZER, InjectionToken, ModuleWithProviders, NgModule } from "@angular/core" -import { Action } from "redux" -import { Observable, Subject } from "rxjs" - -export type Actions = Observable -export const ActionsToken = new InjectionToken("Actions") - -/** Simple placeholder for NgRx's EffectsModule. The goal is to provide the - * same api as NgRx, so that we can switch to NgRx in the long run. - */ -@NgModule({}) -export class EffectsModule { - static actions$ = new Subject() - - static forRoot(effects = []): ModuleWithProviders { - return { - ngModule: EffectsModule, - providers: [ - { provide: ActionsToken, useValue: EffectsModule.actions$ }, - effects, - { - provide: APP_INITIALIZER, - deps: effects, - useFactory: () => () => { - // initialized effects" - }, - multi: true - } - ] - } - } -} diff --git a/visualization/app/codeCharta/state/angular-redux/ofType.ts b/visualization/app/codeCharta/state/angular-redux/ofType.ts deleted file mode 100644 index 8adcc91c6d..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/ofType.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Action } from "redux" -import { filter, map, Observable } from "rxjs" - -export function ofType(type: string) { - return function (source: Observable) { - return source.pipe( - filter(action => action.type === type), - map(action => action as T) - ) - } -} diff --git a/visualization/app/codeCharta/state/angular-redux/state.ts b/visualization/app/codeCharta/state/angular-redux/state.ts deleted file mode 100644 index 6f08ab2894..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/state.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Injectable } from "@angular/core" - -import { Store as PlainStore } from "../store/store" - -@Injectable({ - providedIn: "root" -}) -export class State { - getValue() { - return PlainStore.store.getState() - } -} diff --git a/visualization/app/codeCharta/state/angular-redux/store.spec.ts b/visualization/app/codeCharta/state/angular-redux/store.spec.ts deleted file mode 100644 index 98622a8ced..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/store.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Store } from "./store" -import { Store as PlainStore } from "../store/store" - -import { sortingOrderAscendingSelector } from "../store/appSettings/sortingOrderAscending/sortingOrderAscending.selector" -import { toggleSortingOrderAscending } from "../store/appSettings/sortingOrderAscending/sortingOrderAscending.actions" - -describe("NgRx like store", () => { - const storeService = new Store() - - beforeEach(() => { - PlainStore["initialize"]() - }) - - it("should have initial value on selection and it should update its value", () => { - const initialValue = sortingOrderAscendingSelector(PlainStore.store.getState()) - const sortingOrderAscending$ = storeService.select(sortingOrderAscendingSelector) - let value - sortingOrderAscending$.subscribe(v => { - value = v - }) - expect(value).toBe(initialValue) - - PlainStore.store.dispatch(toggleSortingOrderAscending()) - - expect(value).toBe(!initialValue) - }) - - it("should not call selector, when no one is subscribed", () => { - const selector = jest.fn() - storeService.select(selector) - PlainStore.store.dispatch(toggleSortingOrderAscending()) - expect(selector).not.toHaveBeenCalled() - }) - - it("can unsubscribe from a subscription", () => { - const selector = jest.fn() - const selected$ = storeService.select(selector) - const subscription = selected$.subscribe(jest.fn()) - expect(selector).toHaveBeenCalledTimes(1) - - subscription.unsubscribe() - PlainStore.store.dispatch(toggleSortingOrderAscending()) - expect(selector).toHaveBeenCalledTimes(1) - }) -}) diff --git a/visualization/app/codeCharta/state/angular-redux/store.ts b/visualization/app/codeCharta/state/angular-redux/store.ts deleted file mode 100644 index 12ca564294..0000000000 --- a/visualization/app/codeCharta/state/angular-redux/store.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from "@angular/core" -import { Observable } from "rxjs" - -import { CCAction } from "../../codeCharta.model" -import { CcState, Store as PlainStore } from "../store/store" - -/** - * NgRx like connection to our redux store. The goal is to provide the - * same api as NgRx, so that we can switch to NgRx in the long run. - */ -@Injectable({ - providedIn: "root" -}) -export class Store { - select(selector: (state: CcState) => T): Observable { - return new Observable(subscriber => { - let lastValue = selector(PlainStore.store.getState()) - subscriber.next(lastValue) - - return PlainStore.store.subscribe(() => { - const value = selector(PlainStore.store.getState()) - if (lastValue !== value) { - lastValue = value - subscriber.next(value) - } - }) - }) - } - - dispatch(action: CCAction) { - PlainStore.dispatch(action) - } -} diff --git a/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts b/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts index 60b7a2debe..1f2afb552d 100644 --- a/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts @@ -1,55 +1,71 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" import { MatDialog } from "@angular/material/dialog" -import { Action } from "redux" -import { Subject } from "rxjs" -import { FILE_STATES_JAVA } from "../../../util/dataMocks" +import { BehaviorSubject } from "rxjs" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { setFiles } from "../../store/files/files.actions" -import { addBlacklistItems, addBlacklistItemsIfNotResultsInEmptyMap } from "../../store/fileSettings/blacklist/blacklist.actions" -import { Store } from "../../store/store" import { AddBlacklistItemsIfNotResultsInEmptyMapEffect } from "./addBlacklistItemsIfNotResultsInEmptyMap.effect" +import { EffectsModule } from "@ngrx/effects" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { provideMockActions } from "@ngrx/effects/testing" +import { Action } from "@ngrx/store" +import { getLastAction } from "../../../util/testUtils/store.utils" +import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" +import { blacklistSelector } from "../../store/fileSettings/blacklist/blacklist.selector" +import { addBlacklistItems, addBlacklistItemsIfNotResultsInEmptyMap } from "../../store/fileSettings/blacklist/blacklist.actions" +import { FILE_STATES_JAVA } from "../../../util/dataMocks" describe("AddBlacklistItemsIfNotResultsInEmptyMapEffect", () => { const mockedDialog = { open: jest.fn() } - let storeDispatchSpy + let actions$: BehaviorSubject + let store: MockStore - beforeEach(async () => { - Store["initialize"]() - storeDispatchSpy = jest.spyOn(Store, "dispatch") + beforeEach(() => { + actions$ = new BehaviorSubject({ type: "" }) mockedDialog.open = jest.fn() - EffectsModule.actions$ = new Subject() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([AddBlacklistItemsIfNotResultsInEmptyMapEffect])], - providers: [{ provide: MatDialog, useValue: mockedDialog }] + providers: [ + { provide: MatDialog, useValue: mockedDialog }, + provideMockStore({ + selectors: [ + { + selector: visibleFileStatesSelector, + value: [] + }, + { + selector: blacklistSelector, + value: [] + } + ] + }), + provideMockActions(() => actions$) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise + store = TestBed.inject(MockStore) }) afterEach(() => { - EffectsModule.actions$.complete() + actions$.complete() }) - it("should ignore a not relevant action", () => { - EffectsModule.actions$.next({ type: "whatever" }) - expect(storeDispatchSpy).not.toHaveBeenCalled() + it("should ignore a not relevant action", async () => { + actions$.next({ type: "whatever" }) + expect(await getLastAction(store)).toEqual({ type: "@ngrx/effects/init" }) expect(mockedDialog.open).not.toHaveBeenCalled() }) it("should not blacklist items if it would lead to an empty map but show error dialog", () => { - EffectsModule.actions$.next(addBlacklistItemsIfNotResultsInEmptyMap([{ type: "exclude", path: "foo/bar" }])) - expect(storeDispatchSpy).not.toHaveBeenCalledWith(addBlacklistItems([{ type: "exclude", path: "foo/bar" }])) + actions$.next(addBlacklistItemsIfNotResultsInEmptyMap({ items: [{ type: "exclude", path: "foo/bar" }] })) + store.refreshState() expect(mockedDialog.open).toHaveBeenCalledTimes(1) }) - it("should blacklist items if it doesn't lead to an empty map", () => { - Store.dispatch(setFiles(FILE_STATES_JAVA)) - - EffectsModule.actions$.next(addBlacklistItemsIfNotResultsInEmptyMap([{ type: "exclude", path: "/root/src/main/file1.java" }])) + it("should blacklist items if it doesn't lead to an empty map", async () => { + store.overrideSelector(visibleFileStatesSelector, FILE_STATES_JAVA) + store.refreshState() + actions$.next(addBlacklistItemsIfNotResultsInEmptyMap({ items: [{ type: "exclude", path: "/root/src/main/file1.java" }] })) - expect(storeDispatchSpy).toHaveBeenCalledWith(addBlacklistItems([{ type: "exclude", path: "/root/src/main/file1.java" }])) + expect(await getLastAction(store)).toEqual(addBlacklistItems({ items: [{ type: "exclude", path: "/root/src/main/file1.java" }] })) expect(mockedDialog.open).not.toHaveBeenCalled() }) }) diff --git a/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts b/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts index 8b0fb2e5af..19ec9ba7f5 100644 --- a/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts +++ b/visualization/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts @@ -1,38 +1,27 @@ -import { Inject, Injectable } from "@angular/core" -import { Actions, ActionsToken } from "../../angular-redux/effects/effects.module" +import { Injectable } from "@angular/core" import { MatDialog } from "@angular/material/dialog" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { filter, map, tap, withLatestFrom } from "rxjs" -import { - addBlacklistItems, - AddBlacklistItemsIfNotResultsInEmptyMapAction, - BlacklistActions -} from "../../store/fileSettings/blacklist/blacklist.actions" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { filter, map, share, tap, withLatestFrom } from "rxjs" +import { addBlacklistItems, addBlacklistItemsIfNotResultsInEmptyMap } from "../../store/fileSettings/blacklist/blacklist.actions" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { blacklistSelector } from "../../store/fileSettings/blacklist/blacklist.selector" -import { Store } from "../../angular-redux/store" import { resultsInEmptyMap } from "./resultsInEmptyMap" import { ErrorDialogComponent } from "../../../ui/dialogs/errorDialog/errorDialog.component" -import { ofType } from "../../angular-redux/ofType" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Injectable() export class AddBlacklistItemsIfNotResultsInEmptyMapEffect { - constructor( - @Inject(ActionsToken) private actions$: Actions, - @Inject(Store) private store: Store, - @Inject(MatDialog) private dialog: MatDialog - ) {} - - private visibleFiles$ = this.store.select(visibleFileStatesSelector) - private blacklist$ = this.store.select(blacklistSelector) + constructor(private actions$: Actions, private store: Store, private dialog: MatDialog) {} doBlacklistItemsResultInEmptyMap$ = this.actions$.pipe( - ofType(BlacklistActions.ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP), - withLatestFrom(this.visibleFiles$, this.blacklist$), - map(([addBlacklistItemsIfNotResultsInEmptyMapAction, visibleFiles, blacklist]) => ({ - items: addBlacklistItemsIfNotResultsInEmptyMapAction.payload, - resultsInEmptyMap: resultsInEmptyMap(visibleFiles, blacklist, addBlacklistItemsIfNotResultsInEmptyMapAction.payload) - })) + ofType(addBlacklistItemsIfNotResultsInEmptyMap), + withLatestFrom(this.store.select(visibleFileStatesSelector), this.store.select(blacklistSelector)), + map(([action, visibleFiles, blacklist]) => ({ + items: action.items, + resultsInEmptyMap: resultsInEmptyMap(visibleFiles, blacklist, action.items) + })), + share() ) showErrorDialogIfBlacklistItemsResultInEmptyMap$ = createEffect( @@ -51,7 +40,7 @@ export class AddBlacklistItemsIfNotResultsInEmptyMapEffect { addBlacklistItems$ = createEffect(() => this.doBlacklistItemsResultInEmptyMap$.pipe( filter(event => !event.resultsInEmptyMap), - map(event => addBlacklistItems(event.items)) + map(event => addBlacklistItems({ items: event.items })) ) ) } diff --git a/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.spec.ts b/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.spec.ts index 4eb2978289..dc5ec1af89 100644 --- a/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.spec.ts @@ -1,92 +1,60 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { Subject } from "rxjs" +import { BehaviorSubject, Subject } from "rxjs" import { ThreeOrbitControlsService } from "../../../ui/codeMap/threeViewer/threeOrbitControls.service" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { Store } from "../../angular-redux/store" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { layoutAlgorithmSelector } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.selector" import { resetCameraIfNewFileIsLoadedSelector } from "../../store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector" import { focusedNodePathSelector } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector" import { RenderCodeMapEffect } from "../renderCodeMapEffect/renderCodeMap.effect" import { AutoFitCodeMapEffect } from "./autoFitCodeMap.effect" - -jest.mock("../../store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector", () => ({ - resetCameraIfNewFileIsLoadedSelector: jest.fn() -})) -const mockedResetCameraIfNewFileIsLoadedSelector = jest.mocked(resetCameraIfNewFileIsLoadedSelector) +import { EffectsModule } from "@ngrx/effects" +import { Action } from "@ngrx/store" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { provideMockActions } from "@ngrx/effects/testing" +import { LayoutAlgorithm } from "../../../codeCharta.model" describe("autoFitCodeMapOnFileSelectionChangeEffect", () => { let mockedRenderCodeMap$: Subject - let mockedVisibleFileStates$: Subject - let mockedFocusedNodePath$: Subject - let mockedLayoutAlgorithm$: Subject - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case visibleFileStatesSelector: - return mockedVisibleFileStates$ - case focusedNodePathSelector: - return mockedFocusedNodePath$ - case layoutAlgorithmSelector: - return mockedLayoutAlgorithm$ - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } let mockedAutoFitTo: jest.Mock + let actions$: BehaviorSubject + let store: MockStore - beforeEach(async () => { + beforeEach(() => { + actions$ = new BehaviorSubject({ type: "" }) mockedRenderCodeMap$ = new Subject() - mockedVisibleFileStates$ = new Subject() - mockedFocusedNodePath$ = new Subject() - mockedLayoutAlgorithm$ = new Subject() mockedAutoFitTo = jest.fn() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([AutoFitCodeMapEffect])], providers: [ { provide: RenderCodeMapEffect, useValue: { renderCodeMap$: mockedRenderCodeMap$ } }, - { provide: Store, useValue: mockedStore }, + provideMockStore({ + selectors: [ + { selector: visibleFileStatesSelector, value: [] }, + { selector: focusedNodePathSelector, value: [] }, + { selector: layoutAlgorithmSelector, value: LayoutAlgorithm.StreetMap }, + { selector: resetCameraIfNewFileIsLoadedSelector, value: true } + ] + }), + provideMockActions(() => actions$), { provide: ThreeOrbitControlsService, useValue: { autoFitTo: mockedAutoFitTo } } ] }) - await TestBed.inject(ApplicationInitStatus).donePromise - - mockedVisibleFileStates$.next("") - mockedFocusedNodePath$.next("") - mockedLayoutAlgorithm$.next("") - mockedRenderCodeMap$.next("") + store = TestBed.inject(MockStore) }) afterEach(() => { mockedRenderCodeMap$.complete() - mockedVisibleFileStates$.complete() - mockedFocusedNodePath$.complete() - mockedLayoutAlgorithm$.complete() + actions$.complete() }) it("should skip first change", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => true) mockedRenderCodeMap$.next("") expect(mockedAutoFitTo).toHaveBeenCalledTimes(0) }) - it("should auto fit map once after render after selected files have changed", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => true) - mockedVisibleFileStates$.next("") - mockedRenderCodeMap$.next("") - expect(mockedAutoFitTo).toHaveBeenCalledTimes(1) - - mockedRenderCodeMap$.next("") - expect(mockedAutoFitTo).toHaveBeenCalledTimes(1) - }) - - it("should switch and not concat inner observable, so auto fit map gets called only once", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => true) - mockedVisibleFileStates$.next("") - mockedFocusedNodePath$.next("") + it("should auto fit map once after render after selected files have changed once", () => { + store.overrideSelector(visibleFileStatesSelector, []) + store.refreshState() mockedRenderCodeMap$.next("") expect(mockedAutoFitTo).toHaveBeenCalledTimes(1) @@ -95,23 +63,25 @@ describe("autoFitCodeMapOnFileSelectionChangeEffect", () => { }) it("should do nothing when 'reset camera if new file is loaded' is deactivated", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => false) - mockedVisibleFileStates$.next("") - mockedRenderCodeMap$.next("") + store.overrideSelector(resetCameraIfNewFileIsLoadedSelector, false) + store.refreshState() + store.overrideSelector(visibleFileStatesSelector, []) + store.refreshState() + mockedRenderCodeMap$.next(undefined) expect(mockedAutoFitTo).not.toHaveBeenCalled() }) it("should auto fit map when focused node paths has changed", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => true) - mockedFocusedNodePath$.next("") - mockedRenderCodeMap$.next("") + store.overrideSelector(focusedNodePathSelector, []) + store.refreshState() + mockedRenderCodeMap$.next(undefined) expect(mockedAutoFitTo).toHaveBeenCalledTimes(1) }) it("should auto fit map when layout algorithm has changed", () => { - mockedResetCameraIfNewFileIsLoadedSelector.mockImplementation(() => true) - mockedLayoutAlgorithm$.next("") - mockedRenderCodeMap$.next("") + store.overrideSelector(layoutAlgorithmSelector, LayoutAlgorithm.TreeMapStreet) + store.refreshState() + mockedRenderCodeMap$.next(undefined) expect(mockedAutoFitTo).toHaveBeenCalledTimes(1) }) }) diff --git a/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.ts b/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.ts index 9b16ca9de2..1bbe964beb 100644 --- a/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.ts +++ b/visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.ts @@ -1,9 +1,9 @@ import { Injectable } from "@angular/core" -import { switchMap, filter, skip, take, tap, combineLatest } from "rxjs" +import { Store } from "@ngrx/store" +import { createEffect } from "@ngrx/effects" +import { switchMap, filter, skip, take, tap, combineLatest, withLatestFrom } from "rxjs" +import { CcState } from "../../../codeCharta.model" import { ThreeOrbitControlsService } from "../../../ui/codeMap/threeViewer/threeOrbitControls.service" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { State } from "../../angular-redux/state" -import { Store } from "../../angular-redux/store" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { layoutAlgorithmSelector } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.selector" import { resetCameraIfNewFileIsLoadedSelector } from "../../store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector" @@ -13,8 +13,7 @@ import { RenderCodeMapEffect } from "../renderCodeMapEffect/renderCodeMap.effect @Injectable() export class AutoFitCodeMapEffect { constructor( - private store: Store, - private state: State, + private store: Store, private renderCodeMapEffect: RenderCodeMapEffect, private threeOrbitControlsService: ThreeOrbitControlsService ) {} @@ -27,7 +26,8 @@ export class AutoFitCodeMapEffect { this.store.select(layoutAlgorithmSelector) ]).pipe( skip(1), // initial map load is already fitted - filter(() => resetCameraIfNewFileIsLoadedSelector(this.state.getValue())), + withLatestFrom(this.store.select(resetCameraIfNewFileIsLoadedSelector)), + filter(([, resetCameraIfNewFileIsLoaded]) => resetCameraIfNewFileIsLoaded), switchMap(() => this.renderCodeMapEffect.renderCodeMap$.pipe(take(1))), tap(() => { this.threeOrbitControlsService.autoFitTo() diff --git a/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.spec.ts b/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.spec.ts index c827b0af61..065eaa50b6 100644 --- a/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.spec.ts @@ -1,58 +1,51 @@ import { TestBed } from "@angular/core/testing" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { ApplicationInitStatus } from "@angular/core" -import { Subject } from "rxjs" -import { Store } from "../../angular-redux/store" -import { Store as PlainStoreUsedByEffects } from "../../store/store" +import { BehaviorSubject } from "rxjs" import { heightMetricSelector } from "../../store/dynamicSettings/heightMetric/heightMetric.selector" import { isColorMetricLinkedToHeightMetricSelector } from "../../store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" import { LinkColorMetricToHeightMetricEffect } from "./linkColorMetricToHeightMetric.effect" import { setColorMetric } from "../../store/dynamicSettings/colorMetric/colorMetric.actions" +import { EffectsModule } from "@ngrx/effects" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { Action } from "@ngrx/store" +import { provideMockActions } from "@ngrx/effects/testing" +import { getLastAction } from "../../../util/testUtils/store.utils" describe("linkHeightAndColorMetricEffect", () => { - let mockedHeightMetricSelector$ = new Subject() - let mockedIsHeightAndColorMetricLinkedSelector$ = new Subject() + let actions$: BehaviorSubject + let store: MockStore - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case heightMetricSelector: - return mockedHeightMetricSelector$ - case isColorMetricLinkedToHeightMetricSelector: - return mockedIsHeightAndColorMetricLinkedSelector$ - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } - - beforeEach(async () => { - mockedStore.dispatch = jest.fn() - PlainStoreUsedByEffects.store.dispatch = mockedStore.dispatch - mockedHeightMetricSelector$ = new Subject() - mockedIsHeightAndColorMetricLinkedSelector$ = new Subject() + beforeEach(() => { + actions$ = new BehaviorSubject({ type: "" }) TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([LinkColorMetricToHeightMetricEffect])], - providers: [{ provide: Store, useValue: mockedStore }] + providers: [ + provideMockStore({ + selectors: [ + { selector: heightMetricSelector, value: "loc" }, + { selector: isColorMetricLinkedToHeightMetricSelector, value: true } + ] + }), + provideMockActions(() => actions$) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise + store = TestBed.inject(MockStore) }) afterEach(() => { - mockedHeightMetricSelector$.complete() - mockedIsHeightAndColorMetricLinkedSelector$.complete() + actions$.complete() }) - it("should not set color metric when height metric changes but height and color metric are not linked", () => { - mockedHeightMetricSelector$.next("rloc") - mockedIsHeightAndColorMetricLinkedSelector$.next(false) - expect(mockedStore.dispatch).not.toHaveBeenCalledWith(setColorMetric("rloc")) + it("should not set color metric when height metric changes but height and color metric are not linked", async () => { + store.overrideSelector(isColorMetricLinkedToHeightMetricSelector, false) + store.refreshState() + store.overrideSelector(heightMetricSelector, "rloc") + store.refreshState() + expect(await getLastAction(store)).toEqual({ type: "@ngrx/effects/init" }) }) - it("should set color metric to the same height metric when height metric changes and height and color metric are linked", () => { - mockedHeightMetricSelector$.next("rloc") - mockedIsHeightAndColorMetricLinkedSelector$.next(true) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setColorMetric("rloc")) + it("should set color metric to the same height metric when height metric changes and height and color metric are linked", async () => { + store.overrideSelector(heightMetricSelector, "rloc") + store.refreshState() + expect(await getLastAction(store)).toEqual(setColorMetric({ value: "rloc" })) }) }) diff --git a/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.ts b/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.ts index 545ccbd793..fe3095de7c 100644 --- a/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.ts +++ b/visualization/app/codeCharta/state/effects/linkColorMetricToHeightMetric/linkColorMetricToHeightMetric.effect.ts @@ -1,7 +1,8 @@ import { Injectable } from "@angular/core" -import { Store } from "../../angular-redux/store" -import { createEffect } from "../../angular-redux/effects/createEffect" +import { createEffect } from "@ngrx/effects" +import { Store } from "@ngrx/store" import { combineLatest, filter, map } from "rxjs" +import { CcState } from "../../../codeCharta.model" import { isColorMetricLinkedToHeightMetricSelector } from "../../store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" import { setColorMetric } from "../../store/dynamicSettings/colorMetric/colorMetric.actions" @@ -9,12 +10,12 @@ import { heightMetricSelector } from "../../store/dynamicSettings/heightMetric/h @Injectable() export class LinkColorMetricToHeightMetricEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} linkHeightAndColorMetric$ = createEffect(() => combineLatest([this.store.select(heightMetricSelector), this.store.select(isColorMetricLinkedToHeightMetricSelector)]).pipe( filter(([, isColorMetricLinkedToHeightMetric]) => isColorMetricLinkedToHeightMetric), - map(([heightMetric]) => setColorMetric(heightMetric)) + map(([heightMetric]) => setColorMetric({ value: heightMetric })) ) ) } diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts index 0deed59873..9fc651861f 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts @@ -1,6 +1,6 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../angular-redux/store" import { addBlacklistItemsIfNotResultsInEmptyMap } from "../../../store/fileSettings/blacklist/blacklist.actions" @Component({ @@ -15,13 +15,15 @@ export class ExcludeButtonComponent { excludeNode() { this.store.dispatch( - addBlacklistItemsIfNotResultsInEmptyMap([ - { - path: this.codeMapNode.path, - type: "exclude", - nodeType: this.codeMapNode.type - } - ]) + addBlacklistItemsIfNotResultsInEmptyMap({ + items: [ + { + path: this.codeMapNode.path, + type: "exclude", + nodeType: this.codeMapNode.type + } + ] + }) ) } } diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts index 5ae2a58762..71eaffa15a 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts @@ -4,13 +4,17 @@ import { FlattenButtonsComponent } from "./flattenButtons.component" import { FlattenButtonsModule } from "./flattenButtons.module" import { NodeType } from "../../../../codeCharta.model" import userEvent from "@testing-library/user-event" -import { Store } from "../../../store/store" +import { Store } from "@ngrx/store" +import { addBlacklistItem, removeBlacklistItem } from "../../../store/fileSettings/blacklist/blacklist.actions" describe("flattenButtonsComponent", () => { + let mockedStore: { dispatch: jest.Mock } + beforeEach(() => { - Store["initialize"]() + mockedStore = { dispatch: jest.fn() } TestBed.configureTestingModule({ - imports: [FlattenButtonsModule] + imports: [FlattenButtonsModule], + providers: [{ provide: Store, useValue: mockedStore }] }) }) @@ -24,19 +28,18 @@ describe("flattenButtonsComponent", () => { expect(screen.queryByText("FLATTEN")).not.toBe(null) await userEvent.click(screen.queryByText("FLATTEN")) - expect(Store.store.getState().fileSettings.blacklist).toContainEqual({ - nodeType: NodeType.FILE, - path: "/root/foo.ts", - type: "flatten" - }) + expect(mockedStore.dispatch).toHaveBeenCalledWith( + addBlacklistItem({ + item: { + nodeType: NodeType.FILE, + path: "/root/foo.ts", + type: "flatten" + } + }) + ) }) it("should show un-flatten button for a flattened node", async () => { - Store.store.getState().fileSettings.blacklist.push({ - nodeType: NodeType.FILE, - path: "/root/foo.ts", - type: "flatten" - }) await render(FlattenButtonsComponent, { excludeComponentDeclaration: true, componentProperties: { codeMapNode: { path: "/root/foo.ts", type: NodeType.FILE, isFlattened: true } } @@ -46,10 +49,14 @@ describe("flattenButtonsComponent", () => { expect(screen.queryByText("SHOW")).not.toBe(null) await userEvent.click(screen.queryByText("SHOW")) - expect(Store.store.getState().fileSettings.blacklist).not.toContainEqual({ - nodeType: NodeType.FILE, - path: "/root/foo.ts", - type: "flatten" - }) + expect(mockedStore.dispatch).toHaveBeenLastCalledWith( + removeBlacklistItem({ + item: { + nodeType: NodeType.FILE, + path: "/root/foo.ts", + type: "flatten" + } + }) + ) }) }) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts index b9dea6bc6e..564fe63413 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts @@ -1,6 +1,6 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../angular-redux/store" import { addBlacklistItem, removeBlacklistItem } from "../../../store/fileSettings/blacklist/blacklist.actions" @Component({ @@ -16,9 +16,11 @@ export class FlattenButtonsComponent { flattenNode() { this.store.dispatch( addBlacklistItem({ - path: this.codeMapNode.path, - type: "flatten", - nodeType: this.codeMapNode.type + item: { + path: this.codeMapNode.path, + type: "flatten", + nodeType: this.codeMapNode.type + } }) ) } @@ -26,9 +28,11 @@ export class FlattenButtonsComponent { unFlattenNode() { this.store.dispatch( removeBlacklistItem({ - path: this.codeMapNode.path, - type: "flatten", - nodeType: this.codeMapNode.type + item: { + path: this.codeMapNode.path, + type: "flatten", + nodeType: this.codeMapNode.type + } }) ) } diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.spec.ts index dae8007c79..da92ea494e 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.spec.ts @@ -4,18 +4,24 @@ import { expect } from "@jest/globals" import { FocusButtonsComponent } from "./focusButtons.component" import { FocusButtonsModule } from "./focusButtons.module" import { focusedNodePathSelector } from "../../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector" - -jest.mock("../../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector", () => ({ - focusedNodePathSelector: jest.fn() -})) -const mockedFocusedNodePathSelector = focusedNodePathSelector as jest.Mock +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { currentFocusedNodePathSelector } from "../../../store/dynamicSettings/focusedNodePath/currentFocused.selector" describe("focusButton", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [FocusButtonsModule] + imports: [FocusButtonsModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: currentFocusedNodePathSelector, value: undefined }, + { selector: focusedNodePathSelector, value: [] } + ] + }) + ] }) }) + it("should render only 'focus' button if neither node nor one of its parents is focused", async () => { const { container } = await render(FocusButtonsComponent, { excludeComponentDeclaration: true, @@ -28,11 +34,15 @@ describe("focusButton", () => { }) it("should render 'focus' and 'unfocus parent' buttons if a parent is focused", async () => { - mockedFocusedNodePathSelector.mockImplementation(() => ["/root/foo"]) - const { container } = await render(FocusButtonsComponent, { + const { container, detectChanges } = await render(FocusButtonsComponent, { excludeComponentDeclaration: true, componentProperties: { codeMapNode: { path: "/root/foo/bar" } } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(focusedNodePathSelector, ["/root/foo"]) + store.overrideSelector(currentFocusedNodePathSelector, "/root/foo") + store.refreshState() + detectChanges() const buttons = container.querySelectorAll("button") expect(buttons.length).toBe(2) @@ -41,11 +51,15 @@ describe("focusButton", () => { }) it("should render 'unfocus' and 'unfocus all' buttons if node is focused and there was node focused before", async () => { - mockedFocusedNodePathSelector.mockImplementation(() => ["/root/foo", "/root/bar"]) - const { container } = await render(FocusButtonsComponent, { + const { container, detectChanges } = await render(FocusButtonsComponent, { excludeComponentDeclaration: true, componentProperties: { codeMapNode: { path: "/root/foo" } } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(focusedNodePathSelector, ["/root/foo", "/root/bar"]) + store.overrideSelector(currentFocusedNodePathSelector, "/root/foo") + store.refreshState() + detectChanges() const buttons = container.querySelectorAll("button") expect(buttons.length).toBe(2) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.ts index 9b915f53ba..8eddec6de3 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/focusButtons/focusButtons.component.ts @@ -1,8 +1,8 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" -import { Observable, map } from "rxjs" +import { Store } from "@ngrx/store" +import { map } from "rxjs" -import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../angular-redux/store" +import { CodeMapNode, CcState } from "../../../../codeCharta.model" import { currentFocusedNodePathSelector } from "../../../store/dynamicSettings/focusedNodePath/currentFocused.selector" import { focusNode, unfocusAllNodes, unfocusNode } from "../../../store/dynamicSettings/focusedNodePath/focusedNodePath.actions" import { focusedNodePathSelector } from "../../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector" @@ -15,18 +15,13 @@ import { focusedNodePathSelector } from "../../../store/dynamicSettings/focusedN export class FocusButtonsComponent { @Input() codeMapNode: Pick - currentFocusedNodePath$: Observable - hasPreviousFocusedNodePath$: Observable + currentFocusedNodePath$ = this.store.select(currentFocusedNodePathSelector) + hasPreviousFocusedNodePath$ = this.store.select(focusedNodePathSelector).pipe(map(focusedNodePaths => focusedNodePaths.length > 1)) - constructor(private store: Store) { - this.currentFocusedNodePath$ = this.store.select(currentFocusedNodePathSelector) - this.hasPreviousFocusedNodePath$ = this.store - .select(focusedNodePathSelector) - .pipe(map(focusedNodePaths => focusedNodePaths.length > 1)) - } + constructor(private store: Store) {} handleFocusNodeClicked() { - this.store.dispatch(focusNode(this.codeMapNode.path)) + this.store.dispatch(focusNode({ value: this.codeMapNode.path })) } handleUnfocusNodeClicked() { diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts index dbf907058c..6d3d20b792 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts @@ -2,30 +2,50 @@ import { TestBed } from "@angular/core/testing" import { fireEvent, render } from "@testing-library/angular" import { MarkFolderRowComponent } from "./markFolderRow.component" import { MarkFolderRowModule } from "./markFolderRow.module" - -jest.mock("../rightClickedCodeMapNode.selector", () => ({ - rightClickedCodeMapNodeSelector: () => ({ path: "/root" }) -})) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { markFolderItemsSelector } from "./selectors/markFolderItems.selector" +import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector" +import { getLastAction } from "../../../../util/testUtils/store.utils" +import { markPackages, unmarkPackage } from "../../../store/fileSettings/markedPackages/markedPackages.actions" describe("markFolderRow component", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MarkFolderRowModule] + imports: [MarkFolderRowModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: markFolderItemsSelector, value: [{ color: "red", isMarked: false }] }, + { selector: rightClickedCodeMapNodeSelector, value: { path: "/root" } } + ] + }) + ] }) }) it("should let a user mark and unmark a node", async () => { - const { container } = await render(MarkFolderRowComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(MarkFolderRowComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) - expect(container.querySelectorAll("button").length).toBe(5) + expect(container.querySelectorAll("button").length).toBe(1) expect(container.querySelectorAll("cc-color-picker").length).toBe(1) expect(container.querySelectorAll(".fa-times").length).toBe(0) fireEvent.click(getFirstColorButton(container)) + expect(await getLastAction(store)).toEqual(markPackages({ packages: [{ path: "/root", color: "red" }] })) + + store.overrideSelector(markFolderItemsSelector, [{ color: "red", isMarked: true }]) + store.refreshState() + detectChanges() expect(container.querySelectorAll(".fa-times").length).toBe(1) expect(getFirstColorButton(container).querySelector(".fa-times")).not.toBe(null) fireEvent.click(getFirstColorButton(container)) + expect(await getLastAction(store)).toEqual(unmarkPackage({ path: "/root" })) + + store.overrideSelector(markFolderItemsSelector, [{ color: "red", isMarked: false }]) + store.refreshState() + detectChanges() expect(container.querySelectorAll(".fa-times").length).toBe(0) function getFirstColorButton(container: Element) { diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.ts index f06505dc28..8bc0e9cb30 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/markFolderRow.component.ts @@ -1,10 +1,9 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../angular-redux/store" import { markPackages, unmarkPackage } from "../../../store/fileSettings/markedPackages/markedPackages.actions" -import { Observable } from "rxjs" -import { MarkFolderItem, markFolderItemsSelector } from "./selectors/markFolderItems.selector" -import { CodeMapNode } from "../../../../codeCharta.model" +import { markFolderItemsSelector } from "./selectors/markFolderItems.selector" +import { CcState } from "../../../../codeCharta.model" import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector" +import { Store } from "@ngrx/store" @Component({ selector: "cc-mark-folder-row", @@ -13,16 +12,13 @@ import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.sele encapsulation: ViewEncapsulation.None }) export class MarkFolderRowComponent { - markFolderItems$: Observable - codeMapNode$: Observable + markFolderItems$ = this.store.select(markFolderItemsSelector) + codeMapNode$ = this.store.select(rightClickedCodeMapNodeSelector) - constructor(private store: Store) { - this.markFolderItems$ = store.select(markFolderItemsSelector) - this.codeMapNode$ = store.select(rightClickedCodeMapNodeSelector) - } + constructor(private store: Store) {} markFolder(path: string, color: string) { - this.store.dispatch(markPackages([{ path, color }])) + this.store.dispatch(markPackages({ packages: [{ path, color }] })) } unmarkFolder(path: string) { diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts index 43fa37b774..d81e3ce8ff 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts @@ -1,9 +1,8 @@ +import { createSelector } from "@ngrx/store" import { MarkedPackage } from "../../../../../codeCharta.model" -import { createSelector } from "../../../../angular-redux/createSelector" import { mapColorsSelector } from "../../../../store/appSettings/mapColors/mapColors.selector" import { markedPackagesSelector } from "../../../../store/fileSettings/markedPackages/markedPackages.selector" import { findIndexOfMarkedPackageOrParent } from "../../../../store/fileSettings/markedPackages/util/findIndexOfMarkedPackageOrParent" -import { CcState } from "../../../../store/store" import { rightClickedCodeMapNodeSelector } from "../../rightClickedCodeMapNode.selector" export type MarkFolderItem = { @@ -11,7 +10,7 @@ export type MarkFolderItem = { isMarked: boolean } -const markingColorsSelector = createSelector([mapColorsSelector], mapColors => mapColors.markingColors) +const markingColorsSelector = createSelector(mapColorsSelector, mapColors => mapColors.markingColors) export const _getMarkFolderItems = (node: { path?: string } | null, markingColors: string[], markedPackages: MarkedPackage[]) => { if (node === null) { @@ -25,7 +24,9 @@ export const _getMarkFolderItems = (node: { path?: string } | null, markingColor })) } -export const markFolderItemsSelector: (state: CcState) => MarkFolderItem[] = createSelector( - [rightClickedCodeMapNodeSelector, markingColorsSelector, markedPackagesSelector], +export const markFolderItemsSelector = createSelector( + rightClickedCodeMapNodeSelector, + markingColorsSelector, + markedPackagesSelector, _getMarkFolderItems ) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts index 60932fcd39..c780e27898 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts @@ -2,22 +2,20 @@ import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" import { fireEvent } from "@testing-library/angular" import { MaterialModule } from "../../../../material/material.module" -import { EffectsModule } from "../../angular-redux/effects/effects.module" import { NodeContextMenuService } from "./nodeContextMenu.service" import { NodeContextMenuCardModule } from "./nodeContextMenuCard/nodeContextMenuCard.module" -import { OpenNodeContextMenuEffect } from "./openNodeContextMenu.effect" +import { Store } from "@ngrx/store" describe("nodeContextMenuService", () => { let mockedWheelTargetElement beforeEach(async () => { mockedWheelTargetElement = { addEventListener: jest.fn(), removeEventListener: jest.fn() } - // @ts-ignore jest.spyOn(document, "getElementById").mockImplementation(() => mockedWheelTargetElement) TestBed.configureTestingModule({ - imports: [MaterialModule, EffectsModule.forRoot([OpenNodeContextMenuEffect]), NodeContextMenuCardModule], - providers: [NodeContextMenuService] + imports: [MaterialModule, NodeContextMenuCardModule], + providers: [NodeContextMenuService, { provide: Store, useValue: { dispatch: jest.fn() } }] }) await TestBed.inject(ApplicationInitStatus).donePromise }) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts index 88cae4d2eb..bc5683dbeb 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts @@ -1,7 +1,7 @@ import { Overlay, OverlayRef } from "@angular/cdk/overlay" import { ComponentPortal } from "@angular/cdk/portal" import { Injectable } from "@angular/core" -import { Store } from "../../angular-redux/store" +import { Store } from "@ngrx/store" import { setRightClickedNodeData } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" import { NodeContextMenuCardComponent } from "./nodeContextMenuCard/nodeContextMenuCard.component" diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts index f29d5adb5a..e1fd02b6eb 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts @@ -3,14 +3,10 @@ import { render, screen } from "@testing-library/angular" import { IdToBuildingService } from "../../../../services/idToBuilding/idToBuilding.service" import { ThreeSceneService } from "../../../../ui/codeMap/threeViewer/threeSceneService" import { VALID_FILE_NODE_WITH_ID, VALID_NODE_WITH_PATH } from "../../../../util/dataMocks" -import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector" import { NodeContextMenuCardComponent } from "./nodeContextMenuCard.component" import { NodeContextMenuCardModule } from "./nodeContextMenuCard.module" - -jest.mock("../rightClickedCodeMapNode.selector", () => ({ - rightClickedCodeMapNodeSelector: jest.fn() -})) -const mockedRightClickedCodeMapNodeSelector = jest.mocked(rightClickedCodeMapNodeSelector) +import { provideMockStore } from "@ngrx/store/testing" +import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector" describe("NodeContextMenuCardComponent", () => { beforeEach(() => { @@ -30,21 +26,25 @@ describe("NodeContextMenuCardComponent", () => { }) }) - it("should not display mark folder option if node is a leaf", async () => { - mockedRightClickedCodeMapNodeSelector.mockImplementation(() => VALID_FILE_NODE_WITH_ID) - await render(NodeContextMenuCardComponent, { excludeComponentDeclaration: true }) - expect(screen.queryByTitle("Colorize folder")).toBe(null) - }) - it("should display all information", async () => { - mockedRightClickedCodeMapNodeSelector.mockImplementation(() => VALID_NODE_WITH_PATH) - await render(NodeContextMenuCardComponent, { excludeComponentDeclaration: true }) + const { container } = await render(NodeContextMenuCardComponent, { + excludeComponentDeclaration: true, + providers: provideMockStore({ selectors: [{ selector: rightClickedCodeMapNodeSelector, value: VALID_NODE_WITH_PATH }] }) + }) + + expect(screen.getByText("/root")).not.toBe(null) + expect(screen.getByText("FOCUS")).not.toBe(null) + expect(screen.getByText("FLATTEN")).not.toBe(null) + expect(screen.getByText("KEEP HIGHLIGHT")).not.toBe(null) + expect(screen.getByText("EXCLUDE")).not.toBe(null) + expect(container.querySelector("cc-mark-folder-row")).not.toBe(null) + }) - expect(screen.queryByText("/root")).not.toBe(null) - expect(screen.queryByText("FOCUS")).not.toBe(null) - expect(screen.queryByText("FLATTEN")).not.toBe(null) - expect(screen.queryByText("KEEP HIGHLIGHT")).not.toBe(null) - expect(screen.queryByText("EXCLUDE")).not.toBe(null) - expect(screen.queryAllByTitle("Colorize folder").length).toBe(5) + it("should not display mark folder option if node is a leaf", async () => { + const { container } = await render(NodeContextMenuCardComponent, { + excludeComponentDeclaration: true, + providers: provideMockStore({ selectors: [{ selector: rightClickedCodeMapNodeSelector, value: VALID_FILE_NODE_WITH_ID }] }) + }) + expect(container.querySelector("cc-mark-folder-row")).toBe(null) }) }) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts index 878dfe0bb6..350841bf45 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../angular-redux/store" import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector" import { Observable } from "rxjs" -import { CodeMapNode } from "../../../../codeCharta.model" +import { CodeMapNode, CcState } from "../../../../codeCharta.model" +import { Store } from "@ngrx/store" @Component({ templateUrl: "./nodeContextMenuCard.component.html", @@ -12,7 +12,7 @@ import { CodeMapNode } from "../../../../codeCharta.model" export class NodeContextMenuCardComponent implements OnInit { codeMapNode$: Observable - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.codeMapNode$ = this.store.select(rightClickedCodeMapNodeSelector) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts index def5fbaf7a..44b88414e3 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts @@ -1,31 +1,43 @@ import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { Action } from "redux" import { Subject } from "rxjs" -import { EffectsModule } from "../../angular-redux/effects/effects.module" import { setRightClickedNodeData } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" import { NodeContextMenuService } from "./nodeContextMenu.service" import { OpenNodeContextMenuEffect } from "./openNodeContextMenu.effect" +import { Action } from "@ngrx/store" +import { EffectsModule } from "@ngrx/effects" +import { provideMockActions } from "@ngrx/effects/testing" +import { provideMockStore } from "@ngrx/store/testing" describe("OpenNodeContextMenuEffect", () => { let openSpy + let actions$: Subject + beforeEach(async () => { openSpy = jest.fn() - EffectsModule.actions$ = new Subject() + actions$ = new Subject() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([OpenNodeContextMenuEffect])], - providers: [{ provide: NodeContextMenuService, useValue: { open: openSpy } }] + providers: [ + { provide: NodeContextMenuService, useValue: { open: openSpy } }, + provideMockStore(), + provideMockActions(() => actions$) + ] }) await TestBed.inject(ApplicationInitStatus).donePromise }) + afterEach(() => { + actions$.complete() + }) + it("should ignore empty rightClickedNodeData", () => { - EffectsModule.actions$.next(setRightClickedNodeData(null)) + actions$.next(setRightClickedNodeData(null)) expect(openSpy).not.toHaveBeenCalled() }) it("should open node context menu", () => { - EffectsModule.actions$.next(setRightClickedNodeData({ nodeId: 1, xPositionOfRightClickEvent: 2, yPositionOfRightClickEvent: 3 })) + actions$.next(setRightClickedNodeData({ value: { nodeId: 1, xPositionOfRightClickEvent: 2, yPositionOfRightClickEvent: 3 } })) expect(openSpy).toHaveBeenCalledTimes(1) expect(openSpy).toHaveBeenCalledWith(2, 3) }) diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts index 6b3b8e97d8..83cda22021 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts @@ -1,28 +1,20 @@ -import { Inject, Injectable } from "@angular/core" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Actions, ActionsToken } from "../../angular-redux/effects/effects.module" -import { ofType } from "../../angular-redux/ofType" +import { Injectable } from "@angular/core" +import { createEffect, ofType, Actions } from "@ngrx/effects" import { NodeContextMenuService } from "./nodeContextMenu.service" -import { - RightClickedNodeDataActions, - SetRightClickedNodeDataAction -} from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" +import { setRightClickedNodeData } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" import { tap } from "rxjs" @Injectable() export class OpenNodeContextMenuEffect { - constructor(@Inject(ActionsToken) private actions$: Actions, private nodeContextMenu: NodeContextMenuService) {} + constructor(private actions$: Actions, private nodeContextMenu: NodeContextMenuService) {} openNodeContextMenu$ = createEffect( () => this.actions$.pipe( - ofType(RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA), - tap(rightClickedNodeData => { - if (rightClickedNodeData.payload) { - this.nodeContextMenu.open( - rightClickedNodeData.payload.xPositionOfRightClickEvent, - rightClickedNodeData.payload.yPositionOfRightClickEvent - ) + ofType(setRightClickedNodeData), + tap(action => { + if (action.value) { + this.nodeContextMenu.open(action.value.xPositionOfRightClickEvent, action.value.yPositionOfRightClickEvent) } }) ), diff --git a/visualization/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts b/visualization/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts index 57b2d05d79..a14c29a693 100644 --- a/visualization/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts +++ b/visualization/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts @@ -1,8 +1,9 @@ -import { createSelector } from "../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { idToNodeSelector } from "../../selectors/accumulatedData/idToNode.selector" import { rightClickedNodeDataSelector } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.selector" export const rightClickedCodeMapNodeSelector = createSelector( - [rightClickedNodeDataSelector, idToNodeSelector], + rightClickedNodeDataSelector, + idToNodeSelector, (rightClickedNodeData, idToNode) => (rightClickedNodeData ? idToNode.get(rightClickedNodeData.nodeId) : null) ) diff --git a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.spec.ts b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.spec.ts deleted file mode 100644 index 69ca3ad525..0000000000 --- a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { MarkedPackagesActions } from "../../store/fileSettings/markedPackages/markedPackages.actions" -import { actionsRequiringRerender } from "./actionsRequiringRerender" - -describe("actionsRequiringRerender", () => { - it("should include marked packages actions", () => { - expect(actionsRequiringRerender).toContain(MarkedPackagesActions) - }) -}) diff --git a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.ts b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.ts index 8c9c736763..ca6fda80d3 100644 --- a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.ts +++ b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/actionsRequiringRerender.ts @@ -1,59 +1,71 @@ -import { AmountOfEdgePreviewsActions } from "../../store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions" -import { AmountOfTopLabelsActions } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" -import { ColorLabelsActions } from "../../store/appSettings/colorLabels/colorLabels.actions" -import { EdgeHeightActions } from "../../store/appSettings/edgeHeight/edgeHeight.actions" -import { HideFlatBuildingsActions } from "../../store/appSettings/hideFlatBuildings/hideFlatBuildings.actions" -import { InvertAreaActions } from "../../store/appSettings/invertArea/invertArea.actions" -import { InvertHeightActions } from "../../store/appSettings/invertHeight/invertHeight.actions" -import { IsWhiteBackgroundActions } from "../../store/appSettings/isWhiteBackground/isWhiteBackground.actions" -import { LayoutAlgorithmActions } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.actions" -import { MapColorsActions } from "../../store/appSettings/mapColors/mapColors.actions" -import { MaxTreeMapFilesActions } from "../../store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions" -import { ScalingActions } from "../../store/appSettings/scaling/scaling.actions" -import { SharpnessModeActions } from "../../store/appSettings/sharpnessMode/sharpnessMode.actions" -import { ShowMetricLabelNameValueActions } from "../../store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions" -import { ShowMetricLabelNodeNameActions } from "../../store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions" -import { ShowOnlyBuildingsWithEdgesActions } from "../../store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions" -import { AreaMetricActions } from "../../store/dynamicSettings/areaMetric/areaMetric.actions" -import { ColorMetricActions } from "../../store/dynamicSettings/colorMetric/colorMetric.actions" -import { ColorModeActions } from "../../store/dynamicSettings/colorMode/colorMode.actions" -import { ColorRangeActions } from "../../store/dynamicSettings/colorRange/colorRange.actions" -import { EdgeMetricActions } from "../../store/dynamicSettings/edgeMetric/edgeMetric.actions" -import { FocusedNodePathActions } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.actions" -import { HeightMetricActions } from "../../store/dynamicSettings/heightMetric/heightMetric.actions" -import { MarginActions } from "../../store/dynamicSettings/margin/margin.actions" -import { SearchPatternActions } from "../../store/dynamicSettings/searchPattern/searchPattern.actions" -import { MarkedPackagesActions } from "../../store/fileSettings/markedPackages/markedPackages.actions" -import { StateActions } from "../../store/state.actions" -import { EnableFloorLabelsActions } from "../../store/appSettings/enableFloorLabels/enableFloorLabels.actions" +import { setAmountOfEdgePreviews } from "../../store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions" +import { setAmountOfTopLabels } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" +import { setColorLabels } from "../../store/appSettings/colorLabels/colorLabels.actions" +import { setEdgeHeight } from "../../store/appSettings/edgeHeight/edgeHeight.actions" +import { setHideFlatBuildings } from "../../store/appSettings/hideFlatBuildings/hideFlatBuildings.actions" +import { setInvertArea } from "../../store/appSettings/invertArea/invertArea.actions" +import { setInvertHeight } from "../../store/appSettings/invertHeight/invertHeight.actions" +import { setIsWhiteBackground } from "../../store/appSettings/isWhiteBackground/isWhiteBackground.actions" +import { setLayoutAlgorithm } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.actions" +import { setMapColors, invertColorRange, invertDeltaColors } from "../../store/appSettings/mapColors/mapColors.actions" +import { setMaxTreeMapFiles } from "../../store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions" +import { setScaling } from "../../store/appSettings/scaling/scaling.actions" +import { setSharpnessMode } from "../../store/appSettings/sharpnessMode/sharpnessMode.actions" +import { setShowMetricLabelNameValue } from "../../store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions" +import { setShowMetricLabelNodeName } from "../../store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions" +import { setShowOnlyBuildingsWithEdges } from "../../store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions" +import { setAreaMetric } from "../../store/dynamicSettings/areaMetric/areaMetric.actions" +import { setColorMetric } from "../../store/dynamicSettings/colorMetric/colorMetric.actions" +import { setColorMode } from "../../store/dynamicSettings/colorMode/colorMode.actions" +import { setColorRange } from "../../store/dynamicSettings/colorRange/colorRange.actions" +import { setEdgeMetric } from "../../store/dynamicSettings/edgeMetric/edgeMetric.actions" +import { + setAllFocusedNodes, + focusNode, + unfocusAllNodes, + unfocusNode +} from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.actions" +import { setHeightMetric } from "../../store/dynamicSettings/heightMetric/heightMetric.actions" +import { setMargin } from "../../store/dynamicSettings/margin/margin.actions" +import { setSearchPattern } from "../../store/dynamicSettings/searchPattern/searchPattern.actions" +import { setMarkedPackages, markPackages, unmarkPackage } from "../../store/fileSettings/markedPackages/markedPackages.actions" +import { setEnableFloorLabels } from "../../store/appSettings/enableFloorLabels/enableFloorLabels.actions" +import { setState } from "../../store/state.actions" export const actionsRequiringRerender = [ - ColorLabelsActions, - MapColorsActions, - ShowMetricLabelNodeNameActions, - ShowMetricLabelNameValueActions, - IsWhiteBackgroundActions, - InvertAreaActions, - InvertHeightActions, - HideFlatBuildingsActions, - ScalingActions, - EdgeHeightActions, - AmountOfEdgePreviewsActions, - AmountOfTopLabelsActions, - LayoutAlgorithmActions, - MaxTreeMapFilesActions, - SharpnessModeActions, - ColorModeActions, - EdgeMetricActions, - ColorRangeActions, - MarginActions, - SearchPatternActions, - FocusedNodePathActions, - HeightMetricActions, - AreaMetricActions, - ColorMetricActions, - ShowOnlyBuildingsWithEdgesActions, - MarkedPackagesActions, - StateActions, - EnableFloorLabelsActions + setColorLabels, + setMapColors, + invertColorRange, + invertDeltaColors, + setShowMetricLabelNodeName, + setShowMetricLabelNameValue, + setIsWhiteBackground, + setInvertArea, + setInvertHeight, + setHideFlatBuildings, + setScaling, + setEdgeHeight, + setAmountOfEdgePreviews, + setAmountOfTopLabels, + setLayoutAlgorithm, + setMaxTreeMapFiles, + setSharpnessMode, + setColorMode, + setEdgeMetric, + setColorRange, + setMargin, + setSearchPattern, + setAllFocusedNodes, + focusNode, + unfocusAllNodes, + unfocusNode, + setHeightMetric, + setAreaMetric, + setColorMetric, + setShowOnlyBuildingsWithEdges, + setMarkedPackages, + markPackages, + unmarkPackage, + setEnableFloorLabels, + setState ] diff --git a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.spec.ts b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.spec.ts index 32fd92520f..cc8206a10f 100644 --- a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.spec.ts @@ -1,62 +1,54 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { Action } from "redux" -import { BehaviorSubject, Subject } from "rxjs" +import { Subject } from "rxjs" import { Vector3 } from "three" import { CodeMapRenderService } from "../../../ui/codeMap/codeMap.render.service" import { ThreeRendererService } from "../../../ui/codeMap/threeViewer/threeRenderer.service" import { UploadFilesService } from "../../../ui/toolBar/uploadFilesButton/uploadFiles.service" import { wait } from "../../../util/testUtils/wait" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { Store } from "../../angular-redux/store" import { accumulatedDataSelector } from "../../selectors/accumulatedData/accumulatedData.selector" import { setInvertArea } from "../../store/appSettings/invertArea/invertArea.actions" -import { setIsLoadingFile } from "../../store/appSettings/isLoadingFile/isLoadingFile.actions" -import { setIsLoadingMap } from "../../store/appSettings/isLoadingMap/isLoadingMap.actions" import { setScaling } from "../../store/appSettings/scaling/scaling.actions" import { maxFPS, RenderCodeMapEffect } from "./renderCodeMap.effect" +import { provideMockActions } from "@ngrx/effects/testing" +import { Action } from "@ngrx/store" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { EffectsModule } from "@ngrx/effects" +import { setIsLoadingFile } from "../../store/appSettings/isLoadingFile/isLoadingFile.actions" +import { setIsLoadingMap } from "../../store/appSettings/isLoadingMap/isLoadingMap.actions" describe("renderCodeMapEffect", () => { - let mockedStore + let actions$: Subject let threeRendererService: ThreeRendererService let codeMapRenderService: CodeMapRenderService + let dispatchSpy: jest.SpyInstance - beforeEach(async () => { - mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case accumulatedDataSelector: - return new BehaviorSubject({ unifiedMapNode: {} }) - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } + beforeEach(() => { threeRendererService = { render: jest.fn() } as unknown as ThreeRendererService codeMapRenderService = { render: jest.fn(), scaleMap: jest.fn() } as unknown as CodeMapRenderService - - EffectsModule.actions$ = new Subject() + actions$ = new Subject() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([RenderCodeMapEffect])], providers: [ - { provide: Store, useValue: mockedStore }, { provide: UploadFilesService, useValue: { isUploading: false } }, { provide: ThreeRendererService, useValue: threeRendererService }, - { provide: CodeMapRenderService, useValue: codeMapRenderService } + { provide: CodeMapRenderService, useValue: codeMapRenderService }, + provideMockStore({ selectors: [{ selector: accumulatedDataSelector, value: { unifiedMapNode: {} } }] }), + provideMockActions(() => actions$) ] }) - await TestBed.inject(ApplicationInitStatus).donePromise + + const store = TestBed.inject(MockStore) + dispatchSpy = jest.spyOn(store, "dispatch") }) afterEach(() => { - EffectsModule.actions$.complete() + actions$.complete() }) - it("should render once throttled after actions requiring rerender, but not scale map", async () => { - EffectsModule.actions$.next(setInvertArea(true)) - EffectsModule.actions$.next(setInvertArea(true)) + it("should render throttled after actions requiring rerender, but not scale map", async () => { + actions$.next(setInvertArea({ value: true })) + actions$.next(setInvertArea({ value: true })) expect(codeMapRenderService.render).toHaveBeenCalledTimes(0) expect(threeRendererService.render).toHaveBeenCalledTimes(0) @@ -67,24 +59,24 @@ describe("renderCodeMapEffect", () => { }) it("should scale map when scaling changes", async () => { - EffectsModule.actions$.next(setScaling(new Vector3(1, 1, 1))) + actions$.next(setScaling({ value: new Vector3(1, 1, 1) })) await wait(maxFPS) expect(codeMapRenderService.scaleMap).toHaveBeenCalledTimes(1) }) it("should remove loading indicators after render", async () => { - EffectsModule.actions$.next(setInvertArea(true)) + actions$.next(setInvertArea({ value: true })) await wait(maxFPS) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setIsLoadingFile(false)) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setIsLoadingMap(false)) + expect(dispatchSpy).toHaveBeenCalledWith(setIsLoadingFile({ value: false })) + expect(dispatchSpy).toHaveBeenCalledWith(setIsLoadingMap({ value: false })) }) it("should not remove loading indicators after render when a file is still being uploaded", async () => { const uploadFileService = TestBed.inject(UploadFilesService) uploadFileService.isUploading = true - EffectsModule.actions$.next(setInvertArea(true)) + actions$.next(setInvertArea({ value: true })) await wait(maxFPS) - expect(mockedStore.dispatch).not.toHaveBeenCalledWith(setIsLoadingFile(false)) - expect(mockedStore.dispatch).not.toHaveBeenCalledWith(setIsLoadingMap(false)) + expect(dispatchSpy).not.toHaveBeenCalledWith(setIsLoadingFile({ value: false })) + expect(dispatchSpy).not.toHaveBeenCalledWith(setIsLoadingMap({ value: false })) }) }) diff --git a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.ts b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.ts index c855309d5a..9fc5e3e40d 100644 --- a/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.ts +++ b/visualization/app/codeCharta/state/effects/renderCodeMapEffect/renderCodeMap.effect.ts @@ -1,33 +1,30 @@ -import { Inject, Injectable } from "@angular/core" -import { asyncScheduler, combineLatest, filter, tap, throttleTime } from "rxjs" +import { Injectable } from "@angular/core" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { Store } from "@ngrx/store" +import { asyncScheduler, combineLatest, filter, share, tap, throttleTime } from "rxjs" +import { CcState } from "../../../codeCharta.model" import { CodeMapRenderService } from "../../../ui/codeMap/codeMap.render.service" import { ThreeRendererService } from "../../../ui/codeMap/threeViewer/threeRenderer.service" import { UploadFilesService } from "../../../ui/toolBar/uploadFilesButton/uploadFiles.service" -import { isActionOfType } from "../../../util/reduxHelper" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Actions, ActionsToken } from "../../angular-redux/effects/effects.module" -import { Store } from "../../angular-redux/store" import { accumulatedDataSelector } from "../../selectors/accumulatedData/accumulatedData.selector" +import { setScaling } from "../../store/appSettings/scaling/scaling.actions" +import { actionsRequiringRerender } from "./actionsRequiringRerender" import { setIsLoadingFile } from "../../store/appSettings/isLoadingFile/isLoadingFile.actions" import { setIsLoadingMap } from "../../store/appSettings/isLoadingMap/isLoadingMap.actions" -import { ScalingActions } from "../../store/appSettings/scaling/scaling.actions" -import { actionsRequiringRerender } from "./actionsRequiringRerender" export const maxFPS = 1000 / 60 @Injectable() export class RenderCodeMapEffect { constructor( - private store: Store, - @Inject(ActionsToken) private actions$: Actions, + private store: Store, + private actions$: Actions, private uploadFilesService: UploadFilesService, private threeRendererService: ThreeRendererService, private codeMapRenderService: CodeMapRenderService ) {} - private actionsRequiringRender$ = this.actions$.pipe( - filter(action => actionsRequiringRerender.some(actions => isActionOfType(action.type, actions))) - ) + private actionsRequiringRender$ = this.actions$.pipe(ofType(...actionsRequiringRerender)) renderCodeMap$ = createEffect( () => @@ -37,10 +34,11 @@ export class RenderCodeMapEffect { tap(([accumulatedData, action]) => { this.codeMapRenderService.render(accumulatedData.unifiedMapNode) this.threeRendererService.render() - if (isActionOfType(action.type, ScalingActions)) { + if (action.type === setScaling.type) { this.codeMapRenderService.scaleMap() } - }) + }), + share() ), { dispatch: false } ) @@ -50,8 +48,8 @@ export class RenderCodeMapEffect { this.renderCodeMap$.pipe( filter(() => !this.uploadFilesService.isUploading), tap(() => { - this.store.dispatch(setIsLoadingFile(false)) - this.store.dispatch(setIsLoadingMap(false)) + this.store.dispatch(setIsLoadingFile({ value: false })) + this.store.dispatch(setIsLoadingMap({ value: false })) }) ), { dispatch: false } diff --git a/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.spec.ts b/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.spec.ts index a5fff88e05..5b027adddb 100644 --- a/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.spec.ts @@ -1,8 +1,4 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { BehaviorSubject, Subject } from "rxjs" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { Store } from "../../angular-redux/store" import { metricDataSelector } from "../../selectors/accumulatedData/metricData/metricData.selector" import { areChosenMetricsAvailableSelector } from "../../selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector" import { setAreaMetric } from "../../store/dynamicSettings/areaMetric/areaMetric.actions" @@ -10,82 +6,74 @@ import { setColorMetric } from "../../store/dynamicSettings/colorMetric/colorMet import { setDistributionMetric } from "../../store/dynamicSettings/distributionMetric/distributionMetric.actions" import { setHeightMetric } from "../../store/dynamicSettings/heightMetric/heightMetric.actions" import { ResetChosenMetricsEffect } from "./resetChosenMetrics.effect" +import { EffectsModule } from "@ngrx/effects" +import { MockStore, provideMockStore } from "@ngrx/store/testing" describe("resetChosenMetricsEffect", () => { - let mockedMetricDataSelector = new Subject() - const mockedAreChosenMetricsAvailableSelector = new BehaviorSubject(false) - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case metricDataSelector: - return mockedMetricDataSelector - case areChosenMetricsAvailableSelector: - return mockedAreChosenMetricsAvailableSelector - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } + let store: MockStore - beforeEach(async () => { - mockedStore.dispatch = jest.fn() - mockedMetricDataSelector = new Subject() + beforeEach(() => { TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([ResetChosenMetricsEffect])], - providers: [{ provide: Store, useValue: mockedStore }] + providers: [ + provideMockStore({ + selectors: [ + { selector: metricDataSelector, value: { nodeMetricData: [] } }, + { selector: areChosenMetricsAvailableSelector, value: false } + ] + }) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise - }) - - afterEach(() => { - mockedMetricDataSelector.complete() + store = TestBed.inject(MockStore) + store.dispatch = jest.fn() }) it("should do nothing, when there are no metrics available", () => { - mockedMetricDataSelector.next({ nodeMetricData: [] }) - expect(mockedStore.dispatch).not.toHaveBeenCalled() + expect(store.dispatch).not.toHaveBeenCalled() }) it("should apply matching metrics, when area, height and color metrics of matching category are available", () => { - mockedMetricDataSelector.next({ + store.overrideSelector(metricDataSelector, { nodeMetricData: [ { name: "rloc", maxValue: 9001 }, { name: "mcc", maxValue: 9001 } ] - }) + } as any) + store.refreshState() - expect(mockedStore.dispatch).toHaveBeenCalledTimes(4) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setDistributionMetric("rloc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setAreaMetric("rloc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setHeightMetric("mcc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setColorMetric("mcc")) + expect(store.dispatch).toHaveBeenCalledTimes(4) + expect(store.dispatch).toHaveBeenCalledWith(setDistributionMetric({ value: "rloc" })) + expect(store.dispatch).toHaveBeenCalledWith(setAreaMetric({ value: "rloc" })) + expect(store.dispatch).toHaveBeenCalledWith(setHeightMetric({ value: "mcc" })) + expect(store.dispatch).toHaveBeenCalledWith(setColorMetric({ value: "mcc" })) }) it("should apply available metrics when no matching scenario was found", () => { - mockedMetricDataSelector.next({ + store.overrideSelector(metricDataSelector, { nodeMetricData: [ { name: "rloc", maxValue: 9001 }, { name: "loc", maxValue: 9001 } ] - }) + } as any) + store.refreshState() - expect(mockedStore.dispatch).toHaveBeenCalledTimes(4) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setDistributionMetric("rloc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setAreaMetric("rloc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setHeightMetric("loc")) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setColorMetric("loc")) + expect(store.dispatch).toHaveBeenCalledTimes(4) + expect(store.dispatch).toHaveBeenCalledWith(setDistributionMetric({ value: "rloc" })) + expect(store.dispatch).toHaveBeenCalledWith(setAreaMetric({ value: "rloc" })) + expect(store.dispatch).toHaveBeenCalledWith(setHeightMetric({ value: "loc" })) + expect(store.dispatch).toHaveBeenCalledWith(setColorMetric({ value: "loc" })) }) it("should do nothing, when chosen metrics are still available", () => { - mockedAreChosenMetricsAvailableSelector.next(true) - mockedMetricDataSelector.next({ + store.overrideSelector(areChosenMetricsAvailableSelector, true) + store.overrideSelector(metricDataSelector, { nodeMetricData: [ { name: "rloc", maxValue: 9001 }, { name: "loc", maxValue: 9001 } ] - }) + } as any) + store.refreshState() - expect(mockedStore.dispatch).not.toHaveBeenCalled() + expect(store.dispatch).not.toHaveBeenCalled() }) }) diff --git a/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.ts b/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.ts index 582802d4aa..6df9738071 100644 --- a/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.ts +++ b/visualization/app/codeCharta/state/effects/resetChosenMetrics/resetChosenMetrics.effect.ts @@ -1,8 +1,7 @@ import { Injectable } from "@angular/core" +import { createEffect } from "@ngrx/effects" import { filter, tap, withLatestFrom, map } from "rxjs" import { defaultNMetrics, isAnyMetricAvailable, preselectCombination } from "./utils/metricHelper" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Store } from "../../angular-redux/store" import { setDistributionMetric } from "../../store/dynamicSettings/distributionMetric/distributionMetric.actions" import { getDefaultDistribution } from "./utils/getDefaultDistributionMetric" import { setAreaMetric } from "../../store/dynamicSettings/areaMetric/areaMetric.actions" @@ -10,10 +9,12 @@ import { setHeightMetric } from "../../store/dynamicSettings/heightMetric/height import { setColorMetric } from "../../store/dynamicSettings/colorMetric/colorMetric.actions" import { areChosenMetricsAvailableSelector } from "../../selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector" import { metricDataSelector } from "../../selectors/accumulatedData/metricData/metricData.selector" +import { CcState } from "../../../codeCharta.model" +import { Store } from "@ngrx/store" @Injectable() export class ResetChosenMetricsEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} resetChosenDistributionMetric$ = createEffect( () => @@ -23,16 +24,16 @@ export class ResetChosenMetricsEffect { withLatestFrom(this.store.select(areChosenMetricsAvailableSelector)), filter(([, areChosenMetricsAvailable]) => !areChosenMetricsAvailable), tap(([nodeMetricData]) => { - this.store.dispatch(setDistributionMetric(getDefaultDistribution(nodeMetricData))) + this.store.dispatch(setDistributionMetric({ value: getDefaultDistribution(nodeMetricData) })) let [defaultedAreaMetric, defaultedHeightMetric, defaultedColorMetric] = preselectCombination(nodeMetricData) if (!defaultedAreaMetric || !defaultedHeightMetric || !defaultedColorMetric) { ;[defaultedAreaMetric, defaultedHeightMetric, defaultedColorMetric] = defaultNMetrics(nodeMetricData, 3) } - this.store.dispatch(setAreaMetric(defaultedAreaMetric)) - this.store.dispatch(setHeightMetric(defaultedHeightMetric)) - this.store.dispatch(setColorMetric(defaultedColorMetric)) + this.store.dispatch(setAreaMetric({ value: defaultedAreaMetric })) + this.store.dispatch(setHeightMetric({ value: defaultedHeightMetric })) + this.store.dispatch(setColorMetric({ value: defaultedColorMetric })) }) ), { dispatch: false } diff --git a/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.spec.ts b/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.spec.ts index d8a012c7e2..db8333ab07 100644 --- a/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.spec.ts @@ -1,78 +1,46 @@ import { TestBed } from "@angular/core/testing" -import { ApplicationInitStatus } from "@angular/core" -import { Subject } from "rxjs" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { Store } from "../../angular-redux/store" import { metricDataSelector } from "../../selectors/accumulatedData/metricData/metricData.selector" import { edgeMetricSelector } from "../../store/dynamicSettings/edgeMetric/edgeMetric.selector" -import { Store as PlainStoreUsedByEffects } from "../../store/store" import { ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect } from "./resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect" import { setEdgeMetric } from "../../store/dynamicSettings/edgeMetric/edgeMetric.actions" +import { EffectsModule } from "@ngrx/effects" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { getLastAction } from "../../../util/testUtils/store.utils" describe("ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect", () => { - let mockedMetricDataSelector$ = new Subject() - let mockedEdgeMetricSelector$ = new Subject() - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case metricDataSelector: - return mockedMetricDataSelector$ - case edgeMetricSelector: - return mockedEdgeMetricSelector$ - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } + let store: MockStore beforeEach(async () => { - mockedStore.dispatch = jest.fn() - PlainStoreUsedByEffects.store.dispatch = mockedStore.dispatch - mockedMetricDataSelector$ = new Subject() - mockedEdgeMetricSelector$ = new Subject() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect])], - providers: [{ provide: Store, useValue: mockedStore }] + providers: [ + provideMockStore({ + selectors: [ + { selector: edgeMetricSelector, value: "avgCommits" }, + { selector: metricDataSelector, value: { edgeMetricData: [{ name: "avgCommits" }, { name: "pairingRate" }] } } + ] + }) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise + store = TestBed.inject(MockStore) }) - afterEach(() => { - mockedMetricDataSelector$.complete() - mockedEdgeMetricSelector$.complete() + it("should reset selected edge metric to first available, when current isn't available anymore", async () => { + store.overrideSelector(metricDataSelector, { edgeMetricData: [{ name: "pairingRate" }] } as ReturnType) + store.refreshState() + expect(await getLastAction(store)).toEqual(setEdgeMetric({ value: "pairingRate" })) }) - it("should reset selected edge metric to first available, when current isn't available anymore", () => { - mockedEdgeMetricSelector$.next("avgCommits") - mockedMetricDataSelector$.next({ edgeMetricData: [{ name: "pairingRate" }] }) - expect(mockedStore.dispatch).toHaveBeenLastCalledWith(setEdgeMetric("pairingRate")) + it("should do nothing, when current selected edge metric is still available", async () => { + store.overrideSelector(metricDataSelector, { edgeMetricData: [{ name: "avgCommits" }] } as ReturnType) + store.refreshState() + expect(await getLastAction(store)).toEqual({ type: "@ngrx/effects/init" }) }) - it("should do nothing, when current selected edge metric is still available", () => { - mockedEdgeMetricSelector$.next("avgCommits") - mockedMetricDataSelector$.next({ edgeMetricData: [{ name: "avgCommits" }] }) - expect(mockedStore.dispatch).not.toHaveBeenCalled() - }) - - it("should not set reselect edge metric to null", () => { - mockedEdgeMetricSelector$.next("avgCommits") - mockedMetricDataSelector$.next({ edgeMetricData: [] }) - expect(mockedStore.dispatch).toHaveBeenLastCalledWith(setEdgeMetric(undefined)) - - mockedMetricDataSelector$.next({ edgeMetricData: [] }) - expect(mockedStore.dispatch).toHaveBeenCalledTimes(1) - }) - - it("should reset when an edge metric becomes available again", () => { - mockedEdgeMetricSelector$.next("pairingRate") - mockedMetricDataSelector$.next({ edgeMetricData: [{ name: "avgCommits" }] }) - expect(mockedStore.dispatch).toHaveBeenLastCalledWith(setEdgeMetric("avgCommits")) - - mockedMetricDataSelector$.next({ edgeMetricData: [] }) - mockedEdgeMetricSelector$.next(null) - mockedMetricDataSelector$.next({ edgeMetricData: [{ name: "avgCommits" }] }) - expect(mockedStore.dispatch).toHaveBeenCalledTimes(3) - expect(mockedStore.dispatch.mock.calls[0][0]).toEqual(setEdgeMetric("avgCommits")) + it("should set set edge metric to undefined, when there is no edge metric available", async () => { + store.overrideSelector(edgeMetricSelector, "pairingRate") + store.overrideSelector(metricDataSelector, { edgeMetricData: [] } as ReturnType) + store.refreshState() + expect(await getLastAction(store)).toEqual(setEdgeMetric(undefined)) }) }) diff --git a/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.ts b/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.ts index 386eda9a40..1b142388d4 100644 --- a/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.ts +++ b/visualization/app/codeCharta/state/effects/resetSelectedEdgeMetricWhenItDoesntExistAnymore/resetSelectedEdgeMetricWhenItDoesntExistAnymore.effect.ts @@ -1,14 +1,15 @@ import { Injectable } from "@angular/core" +import { createEffect } from "@ngrx/effects" +import { Store } from "@ngrx/store" import { filter, withLatestFrom, map, distinctUntilChanged } from "rxjs" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Store } from "../../angular-redux/store" +import { CcState } from "../../../codeCharta.model" import { metricDataSelector } from "../../selectors/accumulatedData/metricData/metricData.selector" import { setEdgeMetric } from "../../store/dynamicSettings/edgeMetric/edgeMetric.actions" import { edgeMetricSelector } from "../../store/dynamicSettings/edgeMetric/edgeMetric.selector" @Injectable() export class ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} resetSelectedEdgeMetricWhenItDoesntExistAnymore$ = createEffect(() => this.store.select(metricDataSelector).pipe( @@ -16,7 +17,7 @@ export class ResetSelectedEdgeMetricWhenItDoesntExistAnymoreEffect { filter(([metricData, selectedEdgeMetric]) => !metricData.edgeMetricData.some(metric => metric.name === selectedEdgeMetric)), map(([metricData]) => metricData.edgeMetricData[0]?.name), distinctUntilChanged(), - map(newEdgeMetric => setEdgeMetric(newEdgeMetric)) + map(newEdgeMetric => setEdgeMetric({ value: newEdgeMetric })) ) ) } diff --git a/visualization/app/codeCharta/state/effects/setLoadingIndicator/setLoadingIndicator.effect.ts b/visualization/app/codeCharta/state/effects/setLoadingIndicator/setLoadingIndicator.effect.ts new file mode 100644 index 0000000000..e65380e6c3 --- /dev/null +++ b/visualization/app/codeCharta/state/effects/setLoadingIndicator/setLoadingIndicator.effect.ts @@ -0,0 +1,26 @@ +import { Injectable } from "@angular/core" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { fileActions } from "../../store/files/files.actions" +import { map } from "rxjs" +import { setIsLoadingFile } from "../../store/appSettings/isLoadingFile/isLoadingFile.actions" +import { actionsRequiringRerender } from "../renderCodeMapEffect/actionsRequiringRerender" +import { setIsLoadingMap } from "../../store/appSettings/isLoadingMap/isLoadingMap.actions" + +@Injectable() +export class SetLoadingIndicatorEffect { + constructor(private actions$: Actions) {} + + setIsLoadingFile$ = createEffect(() => + this.actions$.pipe( + ofType(...fileActions), + map(() => setIsLoadingFile({ value: true })) + ) + ) + + setIsLoadingMap$ = createEffect(() => + this.actions$.pipe( + ofType(...actionsRequiringRerender), + map(() => setIsLoadingMap({ value: true })) + ) + ) +} diff --git a/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.spec.ts b/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.spec.ts index 8f5aa6d546..b351bee125 100644 --- a/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.spec.ts @@ -1,43 +1,24 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { Subject } from "rxjs" -import { Store as PlainStoreUsedByEffects } from "../../store/store" -import { EffectsModule } from "../../angular-redux/effects/effects.module" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { unfocusAllNodes } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.actions" import { UnfocusNodesEffect } from "./unfocusNodes.effect" -import { Store } from "../../angular-redux/store" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { FILE_STATES } from "../../../util/dataMocks" +import { getLastAction } from "../../../util/testUtils/store.utils" +import { EffectsModule } from "@ngrx/effects" describe("UnfocusNodesEffect", () => { - let mockedVisibleFileStates$: Subject - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case visibleFileStatesSelector: - return mockedVisibleFileStates$ - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } - - beforeEach(async () => { - mockedVisibleFileStates$ = new Subject() - PlainStoreUsedByEffects.store.dispatch = mockedStore.dispatch + beforeEach(() => { TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([UnfocusNodesEffect])], - providers: [{ provide: Store, useValue: mockedStore }] + providers: [provideMockStore({ selectors: [{ selector: visibleFileStatesSelector, value: [] }] })] }) - await TestBed.inject(ApplicationInitStatus).donePromise - }) - - afterEach(() => { - mockedVisibleFileStates$.complete() }) - it("should unfocus all nodes on visible file state changes", () => { - mockedVisibleFileStates$.next("") - expect(mockedStore.dispatch).toHaveBeenCalledWith(unfocusAllNodes()) + it("should unfocus all nodes on visible file state changes", async () => { + const store = TestBed.inject(MockStore) + store.overrideSelector(visibleFileStatesSelector, FILE_STATES) + store.refreshState() + expect(await getLastAction(store)).toEqual(unfocusAllNodes()) }) }) diff --git a/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.ts b/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.ts index 633a2a7d41..1bf4125696 100644 --- a/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.ts +++ b/visualization/app/codeCharta/state/effects/unfocusNodes/unfocusNodes.effect.ts @@ -1,13 +1,14 @@ import { Injectable } from "@angular/core" import { map } from "rxjs" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Store } from "../../angular-redux/store" +import { createEffect } from "@ngrx/effects" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { unfocusAllNodes } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.actions" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Injectable() export class UnfocusNodesEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} unfocusNodes$ = createEffect(() => this.store.select(visibleFileStatesSelector).pipe(map(() => unfocusAllNodes()))) } diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.spec.ts b/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.spec.ts index 1bd4fd151f..b0e49ac38c 100644 --- a/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.spec.ts @@ -1,44 +1,51 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { setAmountOfEdgePreviews } from "../../store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions" +import { EffectsModule } from "@ngrx/effects" +import { provideMockActions } from "@ngrx/effects/testing" +import { Subject } from "rxjs" +import { Action } from "@ngrx/store" +import { provideMockStore, MockStore } from "@ngrx/store/testing" import { toggleEdgeMetricVisible } from "../../store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" -import { setEdgeMetric } from "../../store/dynamicSettings/edgeMetric/edgeMetric.actions" -import { setEdges } from "../../store/fileSettings/edges/edges.actions" -import { Store } from "../../store/store" import { UpdateEdgePreviewsEffect } from "./updateEdgePreviews.effect" +import { edgeMetricSelector } from "../../store/dynamicSettings/edgeMetric/edgeMetric.selector" +import { isEdgeMetricVisibleSelector } from "../../store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector" +import { getLastAction } from "../../../util/testUtils/store.utils" describe("updateEdgePreviewsEffect", () => { - let dispatchSpy + let actions$: Subject + let store: MockStore - beforeEach(async () => { - Store["initialize"]() + beforeEach(() => { + actions$ = new Subject() TestBed.configureTestingModule({ - imports: [EffectsModule.forRoot([UpdateEdgePreviewsEffect])] + imports: [EffectsModule.forRoot([UpdateEdgePreviewsEffect])], + providers: [ + provideMockStore({ + selectors: [ + { selector: edgeMetricSelector, value: "loc" }, + { selector: isEdgeMetricVisibleSelector, value: false } + ] + }), + provideMockActions(() => actions$) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise - - dispatchSpy = jest.spyOn(Store.store, "dispatch") + store = TestBed.inject(MockStore) }) - it("should ignore a not relevant action", () => { - Store.dispatch({ type: "whatever" }) - expect(dispatchSpy).toHaveBeenCalledTimes(1) + afterEach(() => { + actions$.complete() }) - it("should set isEdgeMetricVisible to true on edgeMetric change, if it was false", () => { - Store.dispatch(toggleEdgeMetricVisible()) // toggle first as it is true initially - Store.dispatch(setEdgeMetric("rloc")) - expect(dispatchSpy.mock.calls[2][0]).toEqual(toggleEdgeMetricVisible()) - }) + it("should set isEdgeMetricVisible to true on edgeMetric change, if it was false", async () => { + store.overrideSelector(edgeMetricSelector, "rloc") + store.refreshState() - it("should not set isEdgeMetricVisible to false on edgeMetric change, if it was true", () => { - Store.dispatch(setEdgeMetric("rloc")) - expect(dispatchSpy).not.toHaveBeenCalledWith(toggleEdgeMetricVisible()) + expect(await getLastAction(store)).toEqual(toggleEdgeMetricVisible()) }) - it("should update edges on amountOfEdgePreviewsSelector changed", () => { - Store.dispatch(setAmountOfEdgePreviews(0)) - expect(dispatchSpy).toHaveBeenCalledWith(setEdges([])) + it("should not set isEdgeMetricVisible to false on edgeMetric change, if it was true", async () => { + store.overrideSelector(isEdgeMetricVisibleSelector, true) + store.overrideSelector(edgeMetricSelector, "rloc") + store.refreshState() + expect(await getLastAction(store)).toEqual({ type: "@ngrx/effects/init" }) }) }) diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.ts b/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.ts index eb80558cbe..fd1472bd87 100644 --- a/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.ts +++ b/visualization/app/codeCharta/state/effects/updateEdgePreviews/updateEdgePreviews.effect.ts @@ -1,21 +1,15 @@ import { Injectable } from "@angular/core" -import { combineLatest, filter, map, withLatestFrom } from "rxjs" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Store } from "../../angular-redux/store" -import { amountOfEdgePreviewsSelector } from "../../store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector" -import { edgeHeightSelector } from "../../store/appSettings/edgeHeight/edgeHeight.selector" +import { filter, map, withLatestFrom } from "rxjs" +import { createEffect } from "@ngrx/effects" import { toggleEdgeMetricVisible } from "../../store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" import { isEdgeMetricVisibleSelector } from "../../store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector" -import { showOnlyBuildingsWithEdgesSelector } from "../../store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector" import { edgeMetricSelector } from "../../store/dynamicSettings/edgeMetric/edgeMetric.selector" -import { setEdges } from "../../store/fileSettings/edges/edges.actions" -import { edgesSelector } from "../../store/fileSettings/edges/edges.selector" -import { edgePreviewNodesSelector } from "./utils/edgePreviewNodes.selector" -import { setEdgeVisibility } from "./utils/setEdgeVisibility" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Injectable() export class UpdateEdgePreviewsEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} resetIsEdgeMetricVisible$ = createEffect(() => this.store.select(edgeMetricSelector).pipe( @@ -24,19 +18,4 @@ export class UpdateEdgePreviewsEffect { map(() => toggleEdgeMetricVisible()) ) ) - - updateEdgePreviews$ = createEffect(() => - combineLatest([ - this.store.select(edgeMetricSelector), - this.store.select(amountOfEdgePreviewsSelector), - this.store.select(edgeHeightSelector), - this.store.select(showOnlyBuildingsWithEdgesSelector) - ]).pipe( - withLatestFrom(this.store.select(edgePreviewNodesSelector), this.store.select(edgesSelector)), - map(([[edgeMetric], edgePreviewNodes, edges]) => { - setEdgeVisibility(edgePreviewNodes, edges, edgeMetric) - return setEdges(edges) - }) - ) - ) } diff --git a/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.spec.ts b/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.spec.ts index fd23d2483d..266531b14e 100644 --- a/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.spec.ts +++ b/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.spec.ts @@ -1,50 +1,47 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" -import { Action } from "redux" import { Subject } from "rxjs" +import { Action, State } from "@ngrx/store" +import { EffectsModule } from "@ngrx/effects" +import { provideMockActions } from "@ngrx/effects/testing" +import { provideMockStore, MockStore } from "@ngrx/store/testing" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { State } from "../../angular-redux/state" import { setFiles } from "../../store/files/files.actions" import { setState } from "../../store/state.actions" -import { Store } from "../../store/store" import { UpdateFileSettingsEffect } from "./updateFileSettings.effect" +import { getLastAction } from "../../../util/testUtils/store.utils" describe("UpdateFileSettingsEffect", () => { - const mockedDialog = { open: jest.fn() } - let storeDispatchSpy + let actions$: Subject beforeEach(async () => { - storeDispatchSpy = jest.spyOn(Store, "dispatch") - mockedDialog.open = jest.fn() - - EffectsModule.actions$ = new Subject() + actions$ = new Subject() TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([UpdateFileSettingsEffect])], - providers: [{ provide: State, useValue: { getValue: () => ({ files: [] }) } }] + providers: [ + { provide: State, useValue: { getValue: () => ({ files: [] }) } }, + provideMockStore(), + provideMockActions(() => actions$) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise }) afterEach(() => { - EffectsModule.actions$.complete() - }) - - it("should ignore a not relevant action", () => { - EffectsModule.actions$.next({ type: "whatever" }) - expect(storeDispatchSpy).not.toHaveBeenCalled() + actions$.complete() }) - it("should not blacklist items if it would lead to an empty map but show error dialog", () => { - EffectsModule.actions$.next(setFiles([])) - expect(storeDispatchSpy).not.toHaveBeenCalledWith( + it("should update fileSettings when files have changed", async () => { + const store = TestBed.inject(MockStore) + actions$.next(setFiles({ value: [] })) + expect(await getLastAction(store)).toEqual( setState({ - fileSettings: { - edges: [], - markedPackages: [], - blacklist: [], - attributeTypes: {}, - attributeDescriptors: {} + value: { + fileSettings: { + edges: [], + markedPackages: [], + blacklist: [], + attributeTypes: { edges: {}, nodes: {} }, + attributeDescriptors: {} + } } }) ) diff --git a/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.ts b/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.ts index f1892ce767..6f63434725 100644 --- a/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.ts +++ b/visualization/app/codeCharta/state/effects/updateFileSettings/updateFileSettings.effect.ts @@ -1,26 +1,25 @@ -import { Injectable, Inject } from "@angular/core" -import { filter, map } from "rxjs" +import { Injectable } from "@angular/core" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { fileActions } from "../../store/files/files.actions" +import { setState } from "../../store/state.actions" +import { CcState } from "../../../codeCharta.model" +import { map } from "rxjs" import { getVisibleFiles, isPartialState } from "../../../model/files/files.helper" -import { isActionOfType } from "../../../util/reduxHelper" -import { createEffect } from "../../angular-redux/effects/createEffect" -import { Actions, ActionsToken } from "../../angular-redux/effects/effects.module" -import { State } from "../../angular-redux/state" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" -import { FilesSelectionActions } from "../../store/files/files.actions" -import { setState } from "../../store/state.actions" -import { getMergedAttributeTypes } from "./utils/attributeTypes.merger" -import { getMergedBlacklist } from "./utils/blacklist.merger" import { getMergedEdges } from "./utils/edges.merger" import { getMergedMarkedPackages } from "./utils/markedPackages.merger" +import { getMergedBlacklist } from "./utils/blacklist.merger" +import { getMergedAttributeTypes } from "./utils/attributeTypes.merger" import { getMergedAttributeDescriptors } from "./utils/attributeDescriptors.merger" +import { State } from "@ngrx/store" @Injectable() export class UpdateFileSettingsEffect { - constructor(@Inject(ActionsToken) private actions$: Actions, private state: State) {} + constructor(private actions$: Actions, private state: State) {} updateFileSettings$ = createEffect(() => this.actions$.pipe( - filter(action => isActionOfType(action.type, FilesSelectionActions)), + ofType(...fileActions), map(() => { const state = this.state.getValue() const visibleFiles = getVisibleFiles(state.files) @@ -29,13 +28,16 @@ export class UpdateFileSettingsEffect { const allAttributeDescriptors = visibleFileStatesSelector(state).map( ({ file }) => file.settings.fileSettings.attributeDescriptors ) + return setState({ - fileSettings: { - edges: getMergedEdges(visibleFiles, withUpdatedPath), - markedPackages: getMergedMarkedPackages(visibleFiles, withUpdatedPath), - blacklist: getMergedBlacklist(visibleFiles, withUpdatedPath), - attributeTypes: getMergedAttributeTypes(allAttributeTypes), - attributeDescriptors: getMergedAttributeDescriptors(allAttributeDescriptors) + value: { + fileSettings: { + edges: getMergedEdges(visibleFiles, withUpdatedPath), + markedPackages: getMergedMarkedPackages(visibleFiles, withUpdatedPath), + blacklist: getMergedBlacklist(visibleFiles, withUpdatedPath), + attributeTypes: getMergedAttributeTypes(allAttributeTypes), + attributeDescriptors: getMergedAttributeDescriptors(allAttributeDescriptors) + } } }) }) diff --git a/visualization/app/codeCharta/state/effects/updateFileSettings/utils/edges.merger.ts b/visualization/app/codeCharta/state/effects/updateFileSettings/utils/edges.merger.ts index 1b79161e6d..bbf7be5f9b 100644 --- a/visualization/app/codeCharta/state/effects/updateFileSettings/utils/edges.merger.ts +++ b/visualization/app/codeCharta/state/effects/updateFileSettings/utils/edges.merger.ts @@ -1,5 +1,6 @@ import { getUpdatedPath } from "../../../../util/nodePathHelper" import { CCFile, Edge } from "../../../../codeCharta.model" +import { clone } from "../../../../util/clone" export function getMergedEdges(inputFiles: CCFile[], withUpdatedPath: boolean) { const edges: Map = new Map() @@ -16,7 +17,7 @@ export function getMergedEdges(inputFiles: CCFile[], withUpdatedPath: boolean) { ? getUpdatedPath(inputFile.fileMeta.fileName, oldEdge.fromNodeName) : oldEdge.fromNodeName, toNodeName: withUpdatedPath ? getUpdatedPath(inputFile.fileMeta.fileName, oldEdge.toNodeName) : oldEdge.toNodeName, - attributes: oldEdge.attributes, + attributes: clone(oldEdge.attributes), visible: oldEdge.visible } const equalEdgeItem = edges.get(`${edge.fromNodeName}|${edge.toNodeName}`) diff --git a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.spec.ts b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.spec.ts new file mode 100644 index 0000000000..ae355f4c9e --- /dev/null +++ b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.spec.ts @@ -0,0 +1,18 @@ +import { getNumberOfTopLabels } from "./getNumberOfTopLabels" + +describe("getNumberOfTopLabels", () => { + it("should return 1 when number of nodes are equal or less than 100", () => { + const nodes = Array.from({ length: 10 }).fill({}) + expect(getNumberOfTopLabels(nodes)).toBe(1) + }) + + it("should return 2 when number of nodes are greater than or equal to 200 and less than 300", () => { + const nodes = Array.from({ length: 200 }).fill({}) + expect(getNumberOfTopLabels(nodes)).toBe(2) + }) + + it("should return 10 (max limit for displayed top labels) when number of nodes are greater than 1000", () => { + const nodes = Array.from({ length: 1001 }).fill({}) + expect(getNumberOfTopLabels(nodes)).toBe(10) + }) +}) diff --git a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.ts b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.ts index 3565c37f6c..6be4b7a64d 100644 --- a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.ts +++ b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/getNumberOfTopLabels.ts @@ -1,4 +1,4 @@ -import { defaultAmountOfTopLabels } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" +import { defaultAmountOfTopLabels } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer" const BUILDINGS_PER_LABEL = 100 const MAX_NUMBER_OF_LABELS = 10 diff --git a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.spec.ts b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.spec.ts deleted file mode 100644 index a051421ce0..0000000000 --- a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { TestBed } from "@angular/core/testing" -import { EffectsModule } from "../../angular-redux/effects/effects.module" -import { ApplicationInitStatus } from "@angular/core" -import { UpdateVisibleTopLabelsEffect } from "./updateVisibleTopLabels.effect" -import { setAmountOfTopLabels } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" -import { codeMapNodesSelector } from "../../selectors/accumulatedData/codeMapNodes.selector" -import { Subject } from "rxjs" -import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" -import { Store } from "../../angular-redux/store" -import { Store as PlainStoreUsedByEffects } from "../../store/store" - -describe("updateVisibleTopLabelsEffect", () => { - let mockedVisibleFileStatesSelector = new Subject() - let mockedCodeMapNodesSelector = new Subject() - - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case visibleFileStatesSelector: - return mockedVisibleFileStatesSelector - case codeMapNodesSelector: - return mockedCodeMapNodesSelector - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } - - beforeEach(async () => { - mockedStore.dispatch = jest.fn() - PlainStoreUsedByEffects.store.dispatch = mockedStore.dispatch - mockedVisibleFileStatesSelector = new Subject() - mockedCodeMapNodesSelector = new Subject() - TestBed.configureTestingModule({ - imports: [EffectsModule.forRoot([UpdateVisibleTopLabelsEffect])], - providers: [{ provide: Store, useValue: mockedStore }] - }) - await TestBed.inject(ApplicationInitStatus).donePromise - }) - - afterEach(() => { - mockedVisibleFileStatesSelector.complete() - mockedCodeMapNodesSelector.complete() - }) - - it("should set setAmountOfTopLabels to 1 on FileState change when number of nodes are equal or less than 100", () => { - mockedCodeMapNodesSelector.next(Array.from({ length: 10 }).fill({})) - mockedVisibleFileStatesSelector.next([]) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setAmountOfTopLabels(1)) - }) - - it("should set setAmountOfTopLabels to 2 on FileState change when number of nodes are greater than or equal to 200 and less than 300", () => { - mockedCodeMapNodesSelector.next(Array.from({ length: 200 }).fill({})) - mockedVisibleFileStatesSelector.next([]) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setAmountOfTopLabels(2)) - }) - - it("should set setAmountOfTopLabels to 10 (max limit for displayed top labels) on FileState change when number of nodes are greater than 1000", () => { - mockedCodeMapNodesSelector.next(Array.from({ length: 1001 }).fill({})) - mockedVisibleFileStatesSelector.next([]) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setAmountOfTopLabels(10)) - }) -}) diff --git a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.ts b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.ts index 50efd867b3..7cc0b0a750 100644 --- a/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.ts +++ b/visualization/app/codeCharta/state/effects/updateVisibleTopLabels/updateVisibleTopLabels.effect.ts @@ -1,21 +1,23 @@ import { Injectable } from "@angular/core" -import { Store } from "../../angular-redux/store" -import { createEffect } from "../../angular-redux/effects/createEffect" +import { createEffect } from "@ngrx/effects" + import { map, withLatestFrom } from "rxjs" import { visibleFileStatesSelector } from "../../selectors/visibleFileStates.selector" import { codeMapNodesSelector } from "../../selectors/accumulatedData/codeMapNodes.selector" import { setAmountOfTopLabels } from "../../store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" import { getNumberOfTopLabels } from "./getNumberOfTopLabels" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Injectable() export class UpdateVisibleTopLabelsEffect { - constructor(private store: Store) {} + constructor(private store: Store) {} updateVisibleTopLabels$ = createEffect(() => this.store.select(visibleFileStatesSelector).pipe( withLatestFrom(this.store.select(codeMapNodesSelector)), map(([, codeMapNodes]) => { - return setAmountOfTopLabels(getNumberOfTopLabels(codeMapNodes)) + return setAmountOfTopLabels({ value: getNumberOfTopLabels(codeMapNodes) }) }) ) ) diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/accumulatedData.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/accumulatedData.selector.ts index 84ad6ee0a2..b507d6b275 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/accumulatedData.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/accumulatedData.selector.ts @@ -3,7 +3,6 @@ import { FileState } from "../../../model/files/files" import { fileStatesAvailable, isDeltaState, isPartialState } from "../../../model/files/files.helper" import { AggregationGenerator } from "../../../util/aggregationGenerator" import { NodeDecorator } from "../../../util/nodeDecorator" -import { CcState } from "../../store/store" import { metricNamesSelector } from "./metricData/metricNames.selector" import { getDeltaFile } from "./utils/getDeltaFile" import { addEdgeMetricsForLeaves } from "./utils/addEdgeMetricsForLeaves" @@ -11,23 +10,28 @@ import { blacklistSelector } from "../../store/fileSettings/blacklist/blacklist. import { attributeTypesSelector } from "../../store/fileSettings/attributeTypes/attributeTypes.selector" import { visibleFileStatesSelector } from "../visibleFileStates.selector" import { metricDataSelector } from "./metricData/metricData.selector" -import { createSelector } from "../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" +import { clone } from "../../../util/clone" -const accumulatedDataFallback = Object.freeze({ +const accumulatedDataFallback: AccumulatedData = Object.freeze({ unifiedMapNode: undefined, unifiedFileMeta: undefined }) -export type AccumulatedData = { unifiedMapNode: CodeMapNode; unifiedFileMeta: FileMeta } +export type AccumulatedData = { unifiedMapNode: CodeMapNode | undefined; unifiedFileMeta: FileMeta | undefined } -export const accumulatedDataSelector: (state: CcState) => AccumulatedData = createSelector( - [metricDataSelector, visibleFileStatesSelector, attributeTypesSelector, blacklistSelector, metricNamesSelector], +export const accumulatedDataSelector = createSelector( + metricDataSelector, + visibleFileStatesSelector, + attributeTypesSelector, + blacklistSelector, + metricNamesSelector, (metricData, fileStates, attributeTypes, blacklist, metricNames) => { if (!fileStatesAvailable(fileStates) || !metricData.nodeMetricData) { return accumulatedDataFallback } - const data = _getUndecoratedAccumulatedData(fileStates) + const data = _getUndecoratedAccumulatedData(clone(fileStates)) if (!data?.map) { return accumulatedDataFallback } diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/codeMapNodes.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/codeMapNodes.selector.ts index d88e57f43f..9f8e06f00d 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/codeMapNodes.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/codeMapNodes.selector.ts @@ -1,10 +1,10 @@ import { AccumulatedData, accumulatedDataSelector } from "./accumulatedData.selector" -import { createSelector } from "../../angular-redux/createSelector" import { getAllNodes } from "../../../util/codeMapHelper" import { CodeMapNode } from "../../../codeCharta.model" +import { createSelector } from "@ngrx/store" export const codeMapNodesSelector = createSelector( - [accumulatedDataSelector], + accumulatedDataSelector, (accumulatedData: Pick): CodeMapNode[] => { return getAllNodes(accumulatedData.unifiedMapNode) } diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/idToNode.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/idToNode.selector.ts index 9d0a5b5c59..755b8b8c56 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/idToNode.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/idToNode.selector.ts @@ -1,6 +1,6 @@ +import { createSelector } from "@ngrx/store" import { hierarchy } from "d3-hierarchy" import { CodeMapNode } from "../../../codeCharta.model" -import { createSelector } from "../../angular-redux/createSelector" import { AccumulatedData, accumulatedDataSelector } from "./accumulatedData.selector" export const _calculateIdToNode = (accumulatedData: Pick): Map => { @@ -15,4 +15,4 @@ export const _calculateIdToNode = (accumulatedData: Pick { +export const metricDataSelector = createSelector(visibleFileStatesSelector, blacklistSelector, (visibleFileStates, blacklist) => { return { nodeMetricData: calculateNodeMetricData(visibleFileStates, blacklist), ...calculateEdgeMetricData(visibleFileStates, blacklist) diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.spec.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.spec.ts index 1c14371fcb..1bb620a5fe 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.spec.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.spec.ts @@ -1,4 +1,4 @@ -import { CcState } from "../../../store/store" +import { CcState } from "../../../../codeCharta.model" import { metricDataSelector } from "./metricData.selector" import { metricNamesSelector } from "./metricNames.selector" diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.ts index 10f578a13d..ff741f7bf4 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/metricNames.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { metricDataSelector } from "./metricData.selector" -export const metricNamesSelector = createSelector([metricDataSelector], metricData => metricData.edgeMetricData.map(x => x.name)) +export const metricNamesSelector = createSelector(metricDataSelector, metricData => metricData.edgeMetricData.map(x => x.name)) diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/selectedColorMetricData.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/selectedColorMetricData.selector.ts index 5582a8a71b..a433d2346a 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/selectedColorMetricData.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/metricData/selectedColorMetricData.selector.ts @@ -1,6 +1,5 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { colorMetricSelector } from "../../../store/dynamicSettings/colorMetric/colorMetric.selector" -import { CcState } from "../../../store/store" import { metricDataSelector } from "./metricData.selector" export type MetricMinMax = { @@ -8,13 +7,10 @@ export type MetricMinMax = { maxValue: number } -export const selectedColorMetricDataSelector: (state: CcState) => MetricMinMax = createSelector( - [metricDataSelector, colorMetricSelector], - (metricData, colorMetric) => { - const data = metricData.nodeMetricData.find(x => x.name === colorMetric) - return { - minValue: data?.minValue ?? 0, - maxValue: data?.maxValue ?? 0 - } +export const selectedColorMetricDataSelector = createSelector(metricDataSelector, colorMetricSelector, (metricData, colorMetric) => { + const data = metricData.nodeMetricData.find(x => x.name === colorMetric) + return { + minValue: data?.minValue ?? 0, + maxValue: data?.maxValue ?? 0 } -) +}) diff --git a/visualization/app/codeCharta/state/selectors/accumulatedData/rootUnary.selector.ts b/visualization/app/codeCharta/state/selectors/accumulatedData/rootUnary.selector.ts index 8c97cec567..c47cf630e4 100644 --- a/visualization/app/codeCharta/state/selectors/accumulatedData/rootUnary.selector.ts +++ b/visualization/app/codeCharta/state/selectors/accumulatedData/rootUnary.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { accumulatedDataSelector } from "./accumulatedData.selector" export const rootUnarySelector = createSelector( - [accumulatedDataSelector], + accumulatedDataSelector, accumulatedData => accumulatedData.unifiedMapNode?.attributes.unary ) diff --git a/visualization/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts b/visualization/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts index 0895d2bbe0..84eefaa75c 100644 --- a/visualization/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts +++ b/visualization/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { fileStatesAvailable } from "../../../model/files/files.helper" -import { createSelector } from "../../angular-redux/createSelector" import { areaMetricSelector } from "../../store/dynamicSettings/areaMetric/areaMetric.selector" import { colorMetricSelector } from "../../store/dynamicSettings/colorMetric/colorMetric.selector" import { dynamicSettingsSelector } from "../../store/dynamicSettings/dynamicSettings.selector" @@ -9,20 +9,26 @@ import { metricDataSelector } from "../accumulatedData/metricData/metricData.sel import { areDynamicSettingsAvailable } from "./utils/areDynamicSettingsAvailable" import { areMetricsAvailable } from "./utils/areMetricsAvailable" -const areFileStatesAvailableSelector = createSelector([filesSelector], files => fileStatesAvailable(files)) +const areFileStatesAvailableSelector = createSelector(filesSelector, files => fileStatesAvailable(files)) export const areChosenMetricsAvailableSelector = createSelector( - [metricDataSelector, areaMetricSelector, colorMetricSelector, heightMetricSelector], + metricDataSelector, + areaMetricSelector, + colorMetricSelector, + heightMetricSelector, (metricData, areaMetric, colorMetric, heightMetric) => areMetricsAvailable(metricData.nodeMetricData, [areaMetric, colorMetric, heightMetric]) ) -const areDynamicSettingsAvailableSelector = createSelector([dynamicSettingsSelector], dynamicSettings => +const areDynamicSettingsAvailableSelector = createSelector(dynamicSettingsSelector, dynamicSettings => areDynamicSettingsAvailable(dynamicSettings) ) export const areAllNecessaryRenderDataAvailableSelector = createSelector( - [metricDataSelector, areFileStatesAvailableSelector, areChosenMetricsAvailableSelector, areDynamicSettingsAvailableSelector], + metricDataSelector, + areFileStatesAvailableSelector, + areChosenMetricsAvailableSelector, + areDynamicSettingsAvailableSelector, (metricData, areFileStatesAvailable, areChosenMetricsAvailable, areDynamicSettingsAvailable) => { if (metricData.nodeMetricData === null || !areFileStatesAvailable || !areChosenMetricsAvailable || !areDynamicSettingsAvailable) { return false diff --git a/visualization/app/codeCharta/state/selectors/hoveredNode.selector.ts b/visualization/app/codeCharta/state/selectors/hoveredNode.selector.ts index 6a779631f6..c309ad3a34 100644 --- a/visualization/app/codeCharta/state/selectors/hoveredNode.selector.ts +++ b/visualization/app/codeCharta/state/selectors/hoveredNode.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { hoveredNodeIdSelector } from "../store/appStatus/hoveredNodeId/hoveredNodeId.selector" import { idToNodeSelector } from "./accumulatedData/idToNode.selector" -export const hoveredNodeSelector = createSelector([idToNodeSelector, hoveredNodeIdSelector], (idToNode, hoveredNodeId) => +export const hoveredNodeSelector = createSelector(idToNodeSelector, hoveredNodeIdSelector, (idToNode, hoveredNodeId) => idToNode.get(hoveredNodeId) ) diff --git a/visualization/app/codeCharta/state/selectors/isDeltaState.selector.ts b/visualization/app/codeCharta/state/selectors/isDeltaState.selector.ts index eb76484b4c..9dea03c1a9 100644 --- a/visualization/app/codeCharta/state/selectors/isDeltaState.selector.ts +++ b/visualization/app/codeCharta/state/selectors/isDeltaState.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { isDeltaState } from "../../model/files/files.helper" -import { createSelector } from "../angular-redux/createSelector" import { filesSelector } from "../store/files/files.selector" -export const isDeltaStateSelector = createSelector([filesSelector], files => isDeltaState(files)) +export const isDeltaStateSelector = createSelector(filesSelector, files => isDeltaState(files)) diff --git a/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetricNames.selector.ts b/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetricNames.selector.ts index 1d1abd1d10..bd2e0eb714 100644 --- a/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetricNames.selector.ts +++ b/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetricNames.selector.ts @@ -1,13 +1,15 @@ -import { PrimaryMetrics } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" + import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" import { colorMetricSelector } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.selector" import { edgeMetricSelector } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" import { heightMetricSelector } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.selector" -import { CcState } from "../../../state/store/store" -export const primaryMetricNamesSelector: (state: CcState) => PrimaryMetrics = createSelector( - [areaMetricSelector, heightMetricSelector, colorMetricSelector, edgeMetricSelector], +export const primaryMetricNamesSelector = createSelector( + areaMetricSelector, + heightMetricSelector, + colorMetricSelector, + edgeMetricSelector, (areaMetric, heightMetric, colorMetric, edgeMetric) => ({ areaMetric, heightMetric, diff --git a/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetrics.selector.ts b/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetrics.selector.ts index 503fb18f51..b88ab51a28 100644 --- a/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetrics.selector.ts +++ b/visualization/app/codeCharta/state/selectors/primaryMetrics/primaryMetrics.selector.ts @@ -1,13 +1,12 @@ import { selectedNodeSelector } from "../selectedNode.selector" -import { CcState } from "../../store/store" import { Metric } from "../../../ui/attributeSideBar/util/metric" import { primaryMetricNamesSelector } from "./primaryMetricNames.selector" -import { createSelector } from "../../angular-redux/createSelector" import { getMetricDescriptors } from "../../../ui/attributeSideBar/util/metricDescriptors" import { attributeDescriptorsSelector } from "../../store/fileSettings/attributeDescriptors/attributeDescriptors.selector" import { Edge } from "app/codeCharta/ui/attributeSideBar/util/edge" import { CodeMapNode } from "app/codeCharta/codeCharta.model" import { AttributeDescriptors } from "../../../codeCharta.model" +import { createSelector } from "@ngrx/store" export type PrimaryMetrics = { area: Metric @@ -16,8 +15,10 @@ export type PrimaryMetrics = { edge: Edge } -export const primaryMetricsSelector: (state: CcState) => PrimaryMetrics | undefined = createSelector( - [selectedNodeSelector, primaryMetricNamesSelector, attributeDescriptorsSelector], +export const primaryMetricsSelector = createSelector( + selectedNodeSelector, + primaryMetricNamesSelector, + attributeDescriptorsSelector, (selectedNode, primaryMetricNames, attributeDescriptors) => { if (!selectedNode) { return diff --git a/visualization/app/codeCharta/state/selectors/referenceFile/referenceFile.selector.ts b/visualization/app/codeCharta/state/selectors/referenceFile/referenceFile.selector.ts index 88fdcdd356..fb0121b6c9 100644 --- a/visualization/app/codeCharta/state/selectors/referenceFile/referenceFile.selector.ts +++ b/visualization/app/codeCharta/state/selectors/referenceFile/referenceFile.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { FileSelectionState, FileState } from "../../../model/files/files" -import { createSelector } from "../../angular-redux/createSelector" import { filesSelector } from "../../store/files/files.selector" type Selectable = Pick @@ -8,4 +8,4 @@ type SelectableFile = Selectable & { file: File } export const _getReferenceFile = (fileStates: SelectableFile[]) => fileStates.find(file => file.selectedAs === FileSelectionState.Reference)?.file -export const referenceFileSelector = createSelector([filesSelector], _getReferenceFile) +export const referenceFileSelector = createSelector(filesSelector, _getReferenceFile) diff --git a/visualization/app/codeCharta/state/selectors/searchedNodes/getNodesByGitignorePath.ts b/visualization/app/codeCharta/state/selectors/searchedNodes/getNodesByGitignorePath.ts index 6e1dc60739..1ff85934bf 100644 --- a/visualization/app/codeCharta/state/selectors/searchedNodes/getNodesByGitignorePath.ts +++ b/visualization/app/codeCharta/state/selectors/searchedNodes/getNodesByGitignorePath.ts @@ -3,7 +3,7 @@ import { hierarchy } from "d3-hierarchy" import { CodeMapNode } from "../../../codeCharta.model" import { returnIgnore, transformPath } from "../../../util/codeMapHelper" -export function getNodesByGitignorePath(root: CodeMapNode, gitignorePath: string) { +export function getNodesByGitignorePath(root: CodeMapNode, gitignorePath: string): CodeMapNode[] { gitignorePath = gitignorePath.trimStart() if (gitignorePath.length === 0 || !root) { return [] diff --git a/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodePaths.selector.ts b/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodePaths.selector.ts index 50c1ea8508..cf926233d6 100644 --- a/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodePaths.selector.ts +++ b/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodePaths.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { searchedNodesSelector } from "./searchedNodes.selector" -export const searchedNodePathsSelector = createSelector([searchedNodesSelector], searchedNodes => new Set(searchedNodes.map(x => x.path))) +export const searchedNodePathsSelector = createSelector(searchedNodesSelector, searchedNodes => new Set(searchedNodes.map(x => x.path))) diff --git a/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodes.selector.ts b/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodes.selector.ts index a9cd1729eb..bbef833423 100644 --- a/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodes.selector.ts +++ b/visualization/app/codeCharta/state/selectors/searchedNodes/searchedNodes.selector.ts @@ -1,8 +1,8 @@ import { getNodesByGitignorePath } from "./getNodesByGitignorePath" import { searchPatternSelector } from "../../store/dynamicSettings/searchPattern/searchPattern.selector" import { accumulatedDataSelector } from "../accumulatedData/accumulatedData.selector" -import { createSelector } from "../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" -export const searchedNodesSelector = createSelector([accumulatedDataSelector, searchPatternSelector], (accumulatedData, searchPattern) => +export const searchedNodesSelector = createSelector(accumulatedDataSelector, searchPatternSelector, (accumulatedData, searchPattern) => getNodesByGitignorePath(accumulatedData.unifiedMapNode, searchPattern) ) diff --git a/visualization/app/codeCharta/state/selectors/selectedNode.selector.ts b/visualization/app/codeCharta/state/selectors/selectedNode.selector.ts index 3f1f34a50e..83e7458a60 100644 --- a/visualization/app/codeCharta/state/selectors/selectedNode.selector.ts +++ b/visualization/app/codeCharta/state/selectors/selectedNode.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { selectedBuildingIdSelector } from "../store/appStatus/selectedBuildingId/selectedBuildingId.selector" import { idToNodeSelector } from "./accumulatedData/idToNode.selector" -export const selectedNodeSelector = createSelector([selectedBuildingIdSelector, idToNodeSelector], (selectedBuildingId, idToNode) => +export const selectedNodeSelector = createSelector(selectedBuildingIdSelector, idToNodeSelector, (selectedBuildingId, idToNode) => idToNode?.get(selectedBuildingId) ) diff --git a/visualization/app/codeCharta/state/selectors/visibleFileStates.selector.ts b/visualization/app/codeCharta/state/selectors/visibleFileStates.selector.ts index 3ad9cb5b3f..6d4f055703 100644 --- a/visualization/app/codeCharta/state/selectors/visibleFileStates.selector.ts +++ b/visualization/app/codeCharta/state/selectors/visibleFileStates.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { getVisibleFileStates } from "../../model/files/files.helper" -import { createSelector } from "../angular-redux/createSelector" import { filesSelector } from "../store/files/files.selector" -export const visibleFileStatesSelector = createSelector([filesSelector], getVisibleFileStates) +export const visibleFileStatesSelector = createSelector(filesSelector, getVisibleFileStates) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions.ts index ef8a1139f6..2fde6f504d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum AmountOfEdgePreviewsActions { - SET_AMOUNT_OF_EDGE_PREVIEWS = "SET_AMOUNT_OF_EDGE_PREVIEWS" -} - -export interface SetAmountOfEdgePreviewsAction extends CCAction { - type: AmountOfEdgePreviewsActions.SET_AMOUNT_OF_EDGE_PREVIEWS - payload: number -} - -export type AmountOfEdgePreviewsAction = SetAmountOfEdgePreviewsAction - -export function setAmountOfEdgePreviews(amountOfEdgePreviews: number = defaultAmountOfEdgePreviews): SetAmountOfEdgePreviewsAction { - return { - type: AmountOfEdgePreviewsActions.SET_AMOUNT_OF_EDGE_PREVIEWS, - payload: amountOfEdgePreviews - } -} - -export const defaultAmountOfEdgePreviews = 1 +export const setAmountOfEdgePreviews = createAction("SET_AMOUNT_OF_EDGE_PREVIEWS", props<{ value: number }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.spec.ts index 1f0cfd5f3c..a62d805ae6 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.spec.ts @@ -1,26 +1,10 @@ import { amountOfEdgePreviews } from "./amountOfEdgePreviews.reducer" -import { AmountOfEdgePreviewsAction, setAmountOfEdgePreviews } from "./amountOfEdgePreviews.actions" +import { setAmountOfEdgePreviews } from "./amountOfEdgePreviews.actions" describe("amountOfEdgePreviews", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = amountOfEdgePreviews(undefined, {} as AmountOfEdgePreviewsAction) + it("should set new amountOfEdgePreviews", () => { + const result = amountOfEdgePreviews(1, setAmountOfEdgePreviews({ value: 2 })) - expect(result).toEqual(1) - }) - }) - - describe("Action: SET_AMOUNT_OF_EDGE_PREVIEWS", () => { - it("should set new amountOfEdgePreviews", () => { - const result = amountOfEdgePreviews(1, setAmountOfEdgePreviews(2)) - - expect(result).toEqual(2) - }) - - it("should set default amountOfEdgePreviews", () => { - const result = amountOfEdgePreviews(2, setAmountOfEdgePreviews()) - - expect(result).toEqual(1) - }) + expect(result).toEqual(2) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.ts index c3dc641233..d86c0acd1a 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.reducer.ts @@ -1,10 +1,9 @@ -import { AmountOfEdgePreviewsAction, AmountOfEdgePreviewsActions, setAmountOfEdgePreviews } from "./amountOfEdgePreviews.actions" +import { createReducer, on } from "@ngrx/store" +import { setAmountOfEdgePreviews } from "./amountOfEdgePreviews.actions" +import { setState } from "../../util/setState.reducer.factory" -export function amountOfEdgePreviews(state = setAmountOfEdgePreviews().payload, action: AmountOfEdgePreviewsAction) { - switch (action.type) { - case AmountOfEdgePreviewsActions.SET_AMOUNT_OF_EDGE_PREVIEWS: - return action.payload - default: - return state - } -} +export const defaultAmountOfEdgesPreviews = 1 +export const amountOfEdgePreviews = createReducer( + defaultAmountOfEdgesPreviews, + on(setAmountOfEdgePreviews, setState(defaultAmountOfEdgesPreviews)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector.ts index a2b3f720b4..da66a93f84 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const amountOfEdgePreviewsSelector = createSelector([appSettingsSelector], appSettings => appSettings.amountOfEdgePreviews) +export const amountOfEdgePreviewsSelector = createSelector(appSettingsSelector, appSettings => appSettings.amountOfEdgePreviews) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.actions.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.actions.ts index a5d4bfd929..dae56cc92b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum AmountOfTopLabelsActions { - SET_AMOUNT_OF_TOP_LABELS = "SET_AMOUNT_OF_TOP_LABELS" -} - -export interface SetAmountOfTopLabelsAction extends CCAction { - type: AmountOfTopLabelsActions.SET_AMOUNT_OF_TOP_LABELS - payload: number -} - -export type AmountOfTopLabelsAction = SetAmountOfTopLabelsAction - -export function setAmountOfTopLabels(amountOfTopLabels: number = defaultAmountOfTopLabels): SetAmountOfTopLabelsAction { - return { - type: AmountOfTopLabelsActions.SET_AMOUNT_OF_TOP_LABELS, - payload: amountOfTopLabels - } -} - -export const defaultAmountOfTopLabels = 1 +export const setAmountOfTopLabels = createAction("SET_AMOUNT_OF_TOP_LABELS", props<{ value: number }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.spec.ts index 9c81b095fe..8175eba540 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.spec.ts @@ -1,26 +1,10 @@ import { amountOfTopLabels } from "./amountOfTopLabels.reducer" -import { AmountOfTopLabelsAction, setAmountOfTopLabels } from "./amountOfTopLabels.actions" +import { setAmountOfTopLabels } from "./amountOfTopLabels.actions" describe("amountOfTopLabels", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = amountOfTopLabels(undefined, {} as AmountOfTopLabelsAction) + it("should set new amountOfTopLabels", () => { + const result = amountOfTopLabels(1, setAmountOfTopLabels({ value: 2 })) - expect(result).toEqual(1) - }) - }) - - describe("Action: SET_AMOUNT_OF_TOP_LABELS", () => { - it("should set new amountOfTopLabels", () => { - const result = amountOfTopLabels(1, setAmountOfTopLabels(2)) - - expect(result).toEqual(2) - }) - - it("should set default amountOfTopLabels", () => { - const result = amountOfTopLabels(2, setAmountOfTopLabels()) - - expect(result).toEqual(1) - }) + expect(result).toEqual(2) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.ts index 3ade34e0a2..bc806d4020 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.reducer.ts @@ -1,10 +1,6 @@ -import { AmountOfTopLabelsAction, AmountOfTopLabelsActions, setAmountOfTopLabels } from "./amountOfTopLabels.actions" +import { createReducer, on } from "@ngrx/store" +import { setAmountOfTopLabels } from "./amountOfTopLabels.actions" +import { setState } from "../../util/setState.reducer.factory" -export function amountOfTopLabels(state = setAmountOfTopLabels().payload, action: AmountOfTopLabelsAction) { - switch (action.type) { - case AmountOfTopLabelsActions.SET_AMOUNT_OF_TOP_LABELS: - return action.payload - default: - return state - } -} +export const defaultAmountOfTopLabels = 1 +export const amountOfTopLabels = createReducer(defaultAmountOfTopLabels, on(setAmountOfTopLabels, setState(defaultAmountOfTopLabels))) diff --git a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.selector.ts b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.selector.ts index 9cb26c580d..523a6f8ff5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/amountOfTopLabels/amountOfTopLabels.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const amountOfTopLabelsSelector = createSelector([appSettingsSelector], appSettings => appSettings.amountOfTopLabels) +export const amountOfTopLabelsSelector = createSelector(appSettingsSelector, appSettings => appSettings.amountOfTopLabels) diff --git a/visualization/app/codeCharta/state/store/appSettings/appSettings.actions.ts b/visualization/app/codeCharta/state/store/appSettings/appSettings.actions.ts deleted file mode 100644 index 77a6a5e56a..0000000000 --- a/visualization/app/codeCharta/state/store/appSettings/appSettings.actions.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AppSettings, CCAction, RecursivePartial } from "../../../codeCharta.model" - -import { defaultColorLabels } from "./colorLabels/colorLabels.actions" -import { defaultShowMetricLabelNodeName } from "./showMetricLabelNodeName/showMetricLabelNodeName.actions" -import { defaultShowMetricLabelNameValue } from "./showMetricLabelNameValue/showMetricLabelNameValue.actions" -import { defaultAmountOfEdgePreviews } from "./amountOfEdgePreviews/amountOfEdgePreviews.actions" -import { defaultAmountOfTopLabels } from "./amountOfTopLabels/amountOfTopLabels.actions" -import { defaultEdgeHeight } from "./edgeHeight/edgeHeight.actions" -import { defaultScaling } from "./scaling/scaling.actions" -import { defaultHideFlatBuildings } from "./hideFlatBuildings/hideFlatBuildings.actions" -import { defaultInvertHeight } from "./invertHeight/invertHeight.actions" -import { defaultIsWhiteBackground } from "./isWhiteBackground/isWhiteBackground.actions" -import { defaultMapColors } from "./mapColors/mapColors.actions" -import { defaultIsPresentationMode } from "./isPresentationMode/isPresentationMode.actions" -import { defaultShowOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions" -import { defaultResetIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions" -import { defaultIsLoadingMap } from "./isLoadingMap/isLoadingMap.actions" -import { defaultIsLoadingFile } from "./isLoadingFile/isLoadingFile.actions" -import { defaultSortingOrderAscending } from "./sortingOrderAscending/sortingOrderAscending.actions" -import { defaultExperimentalFeaturesEnabled } from "./enableExperimentalFeatures/experimentalFeaturesEnabled.actions" -import { defaultLayoutAlgorithm } from "./layoutAlgorithm/layoutAlgorithm.actions" -import { defaultMaxTreeMapFiles } from "./maxTreeMapFiles/maxTreeMapFiles.actions" -import { defaultSharpnessMode } from "./sharpnessMode/sharpnessMode.actions" -import { defaultScreenshotToClipboardEnabled } from "./enableClipboard/screenshotToClipboardEnabled.actions" -import { defaultInvertArea } from "./invertArea/invertArea.actions" -import { defaultIsEdgeMetricVisible } from "./isEdgeMetricVisible/isEdgeMetricVisible.actions" -import { defaultIsColorMetricLinkedToHeightMetric } from "./isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions" -import { defaultEnableFloorLabel } from "./enableFloorLabels/enableFloorLabels.actions" - -export enum AppSettingsActions { - SET_APP_SETTINGS = "SET_APP_SETTINGS" -} - -export interface SetAppSettingsAction extends CCAction { - type: AppSettingsActions.SET_APP_SETTINGS - payload: RecursivePartial -} - -export type AppSettingsAction = SetAppSettingsAction - -export function setAppSettings(appSettings: RecursivePartial = defaultAppSettings): AppSettingsAction { - return { - type: AppSettingsActions.SET_APP_SETTINGS, - payload: appSettings - } -} - -export const defaultAppSettings: AppSettings = { - colorLabels: defaultColorLabels, - showMetricLabelNodeName: defaultShowMetricLabelNodeName, - showMetricLabelNameValue: defaultShowMetricLabelNameValue, - amountOfTopLabels: defaultAmountOfTopLabels, - amountOfEdgePreviews: defaultAmountOfEdgePreviews, - edgeHeight: defaultEdgeHeight, - scaling: defaultScaling, - hideFlatBuildings: defaultHideFlatBuildings, - invertHeight: defaultInvertHeight, - invertArea: defaultInvertArea, - isWhiteBackground: defaultIsWhiteBackground, - mapColors: defaultMapColors, - isPresentationMode: defaultIsPresentationMode, - showOnlyBuildingsWithEdges: defaultShowOnlyBuildingsWithEdges, - isEdgeMetricVisible: defaultIsEdgeMetricVisible, - resetCameraIfNewFileIsLoaded: defaultResetIfNewFileIsLoaded, - isLoadingMap: defaultIsLoadingMap, - isLoadingFile: defaultIsLoadingFile, - sortingOrderAscending: defaultSortingOrderAscending, - experimentalFeaturesEnabled: defaultExperimentalFeaturesEnabled, - screenshotToClipboardEnabled: defaultScreenshotToClipboardEnabled, - layoutAlgorithm: defaultLayoutAlgorithm, - maxTreeMapFiles: defaultMaxTreeMapFiles, - sharpnessMode: defaultSharpnessMode, - isColorMetricLinkedToHeightMetric: defaultIsColorMetricLinkedToHeightMetric, - enableFloorLabels: defaultEnableFloorLabel -} diff --git a/visualization/app/codeCharta/state/store/appSettings/appSettings.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/appSettings.reducer.ts index 0bf16e8411..0934349c1b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/appSettings.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/appSettings.reducer.ts @@ -1,32 +1,44 @@ -import { colorLabels } from "./colorLabels/colorLabels.reducer" -import { showMetricLabelNodeName } from "./showMetricLabelNodeName/showMetricLabelNodeName.reducer" -import { showMetricLabelNameValue } from "./showMetricLabelNameValue/showMetricLabelNameValue.reducer" -import { sortingOrderAscending } from "./sortingOrderAscending/sortingOrderAscending.reducer" -import { isLoadingFile } from "./isLoadingFile/isLoadingFile.reducer" -import { isLoadingMap } from "./isLoadingMap/isLoadingMap.reducer" -import { mapColors } from "./mapColors/mapColors.reducer" -import { resetCameraIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer" -import { showOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer" -import { isWhiteBackground } from "./isWhiteBackground/isWhiteBackground.reducer" -import { invertHeight } from "./invertHeight/invertHeight.reducer" -import { hideFlatBuildings } from "./hideFlatBuildings/hideFlatBuildings.reducer" -import { scaling } from "./scaling/scaling.reducer" -import { edgeHeight } from "./edgeHeight/edgeHeight.reducer" -import { amountOfEdgePreviews } from "./amountOfEdgePreviews/amountOfEdgePreviews.reducer" -import { amountOfTopLabels } from "./amountOfTopLabels/amountOfTopLabels.reducer" -import { isPresentationMode } from "./isPresentationMode/isPresentationMode.reducer" -import { combineReducers } from "redux" -import { experimentalFeaturesEnabled } from "./enableExperimentalFeatures/experimentalFeaturesEnabled.reducer" -import { layoutAlgorithm } from "./layoutAlgorithm/layoutAlgorithm.reducer" -import { maxTreeMapFiles } from "./maxTreeMapFiles/maxTreeMapFiles.reducer" -import { sharpnessMode } from "./sharpnessMode/sharpnessMode.reducer" -import { screenshotToClipboardEnabled } from "./enableClipboard/screenshotToClipboardEnabled.reducer" -import { invertArea } from "./invertArea/invertArea.reducer" -import { isEdgeMetricVisible } from "./isEdgeMetricVisible/isEdgeMetricVisible.reducer" -import { isColorMetricLinkedToHeightMetric } from "./isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer" -import { enableFloorLabels } from "./enableFloorLabels/enableFloorLabels.reducer" +import { colorLabels, defaultColorLabelOptions } from "./colorLabels/colorLabels.reducer" +import { defaultShowMetricLabelNodeName, showMetricLabelNodeName } from "./showMetricLabelNodeName/showMetricLabelNodeName.reducer" +import { defaultShowMetricLabelNameValue, showMetricLabelNameValue } from "./showMetricLabelNameValue/showMetricLabelNameValue.reducer" +import { defaultSortingOrderAscending, sortingOrderAscending } from "./sortingOrderAscending/sortingOrderAscending.reducer" +import { defaultIsLoadingFile, isLoadingFile } from "./isLoadingFile/isLoadingFile.reducer" +import { defaultIsLoadingMap, isLoadingMap } from "./isLoadingMap/isLoadingMap.reducer" +import { defaultMapColors, mapColors } from "./mapColors/mapColors.reducer" +import { + defaultResetCameraIfNewFileIsLoaded, + resetCameraIfNewFileIsLoaded +} from "./resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer" +import { + defaultShowOnlyBuildingsWithEdges, + showOnlyBuildingsWithEdges +} from "./showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer" +import { defaultIsWhiteBackground, isWhiteBackground } from "./isWhiteBackground/isWhiteBackground.reducer" +import { defaultInvertHeight, invertHeight } from "./invertHeight/invertHeight.reducer" +import { defaultHideFlatBuildings, hideFlatBuildings } from "./hideFlatBuildings/hideFlatBuildings.reducer" +import { defaultScaling, scaling } from "./scaling/scaling.reducer" +import { defaultEdgeHeight, edgeHeight } from "./edgeHeight/edgeHeight.reducer" +import { amountOfEdgePreviews, defaultAmountOfEdgesPreviews } from "./amountOfEdgePreviews/amountOfEdgePreviews.reducer" +import { amountOfTopLabels, defaultAmountOfTopLabels } from "./amountOfTopLabels/amountOfTopLabels.reducer" +import { defaultIsPresentationMode, isPresentationMode } from "./isPresentationMode/isPresentationMode.reducer" +import { + defaultExperimentalFeaturesEnabled, + experimentalFeaturesEnabled +} from "./enableExperimentalFeatures/experimentalFeaturesEnabled.reducer" +import { defaultLayoutAlgorithm, layoutAlgorithm } from "./layoutAlgorithm/layoutAlgorithm.reducer" +import { defaultMaxTreeMapFiles, maxTreeMapFiles } from "./maxTreeMapFiles/maxTreeMapFiles.reducer" +import { defaultSharpnessMode, sharpnessMode } from "./sharpnessMode/sharpnessMode.reducer" +import { defaultScreenshotToClipboardEnabled, screenshotToClipboardEnabled } from "./enableClipboard/screenshotToClipboardEnabled.reducer" +import { defaultInvertArea, invertArea } from "./invertArea/invertArea.reducer" +import { defaultIsEdgeMetricVisible, isEdgeMetricVisible } from "./isEdgeMetricVisible/isEdgeMetricVisible.reducer" +import { + defaultIsColorMetricLinkedToHeightMetric, + isColorMetricLinkedToHeightMetric +} from "./isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer" +import { defaultEnableFloorLabels, enableFloorLabels } from "./enableFloorLabels/enableFloorLabels.reducer" +import { combineReducers } from "@ngrx/store" -const appSettings = combineReducers({ +export const appSettings = combineReducers({ colorLabels, showMetricLabelNodeName, showMetricLabelNameValue, @@ -55,4 +67,31 @@ const appSettings = combineReducers({ enableFloorLabels }) -export default appSettings +export const defaultAppSettings = { + colorLabels: defaultColorLabelOptions, + showMetricLabelNodeName: defaultShowMetricLabelNodeName, + showMetricLabelNameValue: defaultShowMetricLabelNameValue, + sortingOrderAscending: defaultSortingOrderAscending, + isLoadingFile: defaultIsLoadingFile, + isLoadingMap: defaultIsLoadingMap, + mapColors: defaultMapColors, + resetCameraIfNewFileIsLoaded: defaultResetCameraIfNewFileIsLoaded, + showOnlyBuildingsWithEdges: defaultShowOnlyBuildingsWithEdges, + isEdgeMetricVisible: defaultIsEdgeMetricVisible, + isWhiteBackground: defaultIsWhiteBackground, + invertHeight: defaultInvertHeight, + invertArea: defaultInvertArea, + hideFlatBuildings: defaultHideFlatBuildings, + scaling: defaultScaling, + edgeHeight: defaultEdgeHeight, + amountOfEdgePreviews: defaultAmountOfEdgesPreviews, + amountOfTopLabels: defaultAmountOfTopLabels, + isPresentationMode: defaultIsPresentationMode, + experimentalFeaturesEnabled: defaultExperimentalFeaturesEnabled, + screenshotToClipboardEnabled: defaultScreenshotToClipboardEnabled, + layoutAlgorithm: defaultLayoutAlgorithm, + maxTreeMapFiles: defaultMaxTreeMapFiles, + sharpnessMode: defaultSharpnessMode, + isColorMetricLinkedToHeightMetric: defaultIsColorMetricLinkedToHeightMetric, + enableFloorLabels: defaultEnableFloorLabels +} diff --git a/visualization/app/codeCharta/state/store/appSettings/appSettings.selector.ts b/visualization/app/codeCharta/state/store/appSettings/appSettings.selector.ts index 26263896fe..1d0a3816f0 100644 --- a/visualization/app/codeCharta/state/store/appSettings/appSettings.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/appSettings.selector.ts @@ -1,3 +1,3 @@ -import { CcState } from "../store" +import { CcState } from "../../../codeCharta.model" export const appSettingsSelector = (state: CcState) => state.appSettings diff --git a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.actions.ts b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.actions.ts index 44dc98f70d..fa2aecc734 100644 --- a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.actions.ts @@ -1,26 +1,4 @@ -import { Action } from "redux" -import { colorLabelOptions } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { ColorLabelOptions } from "../../../../codeCharta.model" -export enum ColorLabelsActions { - SET_COLOR_LABELS = "SET_COLOR_LABELS" -} - -export interface SetColorLabelsAction extends Action { - type: ColorLabelsActions.SET_COLOR_LABELS - payload: Partial -} - -export type ColorLabelsAction = SetColorLabelsAction - -export function setColorLabels(colorLabels: Partial = defaultColorLabels): SetColorLabelsAction { - return { - type: ColorLabelsActions.SET_COLOR_LABELS, - payload: colorLabels - } -} - -export const defaultColorLabels: colorLabelOptions = { - positive: false, - negative: false, - neutral: false -} +export const setColorLabels = createAction("SET_COLOR_LABELS", props<{ value: Partial }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.spec.ts index 3f6522fd87..b739738cf9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.spec.ts @@ -1,38 +1,16 @@ -import { colorLabels } from "./colorLabels.reducer" -import { ColorLabelsAction, defaultColorLabels, setColorLabels } from "./colorLabels.actions" +import { colorLabels, defaultColorLabelOptions } from "./colorLabels.reducer" +import { setColorLabels } from "./colorLabels.actions" describe("colorLabels", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = colorLabels(undefined, {} as ColorLabelsAction) + const otherColorLabelOption = { + positive: true, + negative: true, + neutral: false + } - expect(result).toEqual(defaultColorLabels) - }) - }) - - describe("Action: SET_COLOR_LABELS", () => { - const otherColorLabelOption = { - positive: true, - negative: true, - neutral: false - } - - it("should set new colorLabels", () => { - const result = colorLabels(defaultColorLabels, setColorLabels(otherColorLabelOption)) - - expect(result).toEqual(otherColorLabelOption) - }) - - it("should set default colorLabels", () => { - const oldColorLabelOption = { - positive: true, - negative: true, - neutral: false - } - - const result = colorLabels(oldColorLabelOption, setColorLabels()) + it("should set new colorLabels", () => { + const result = colorLabels(defaultColorLabelOptions, setColorLabels({ value: otherColorLabelOption })) - expect(result).toEqual(defaultColorLabels) - }) + expect(result).toEqual(otherColorLabelOption) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.ts index 5995766c03..552ccf742d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.reducer.ts @@ -1,10 +1,7 @@ -import { ColorLabelsAction, ColorLabelsActions, defaultColorLabels } from "./colorLabels.actions" +import { createReducer, on } from "@ngrx/store" +import { setColorLabels } from "./colorLabels.actions" +import { ColorLabelOptions } from "../../../../codeCharta.model" +import { mergeState } from "../../util/setState.reducer.factory" -export function colorLabels(state = defaultColorLabels, action: ColorLabelsAction) { - switch (action.type) { - case ColorLabelsActions.SET_COLOR_LABELS: - return { ...state, ...action.payload } - default: - return state - } -} +export const defaultColorLabelOptions: ColorLabelOptions = { positive: false, negative: false, neutral: false } +export const colorLabels = createReducer(defaultColorLabelOptions, on(setColorLabels, mergeState(defaultColorLabelOptions))) diff --git a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.selector.ts b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.selector.ts index 37bbf5f368..89de267aa5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/colorLabels/colorLabels.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const colorLabelsSelector = createSelector([appSettingsSelector], appSettings => appSettings.colorLabels) +export const colorLabelsSelector = createSelector(appSettingsSelector, appSettings => appSettings.colorLabels) diff --git a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.actions.ts b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.actions.ts index ca297311ce..f9d77dec43 100644 --- a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum EdgeHeightActions { - SET_EDGE_HEIGHT = "SET_EDGE_HEIGHT" -} - -export interface SetEdgeHeightAction extends CCAction { - type: EdgeHeightActions.SET_EDGE_HEIGHT - payload: number -} - -export type EdgeHeightAction = SetEdgeHeightAction - -export function setEdgeHeight(edgeHeight: number = defaultEdgeHeight): SetEdgeHeightAction { - return { - type: EdgeHeightActions.SET_EDGE_HEIGHT, - payload: edgeHeight - } -} - -export const defaultEdgeHeight = 4 +export const setEdgeHeight = createAction("SET_EDGE_HEIGHT", props<{ value: number }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.spec.ts index ee28d55865..2f3225ba6c 100644 --- a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.spec.ts @@ -1,26 +1,10 @@ import { edgeHeight } from "./edgeHeight.reducer" -import { EdgeHeightAction, setEdgeHeight } from "./edgeHeight.actions" +import { setEdgeHeight } from "./edgeHeight.actions" describe("edgeHeight", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = edgeHeight(undefined, {} as EdgeHeightAction) + it("should set new edgeHeight", () => { + const result = edgeHeight(4, setEdgeHeight({ value: 1 })) - expect(result).toEqual(4) - }) - }) - - describe("Action: SET_EDGE_HEIGHT", () => { - it("should set new edgeHeight", () => { - const result = edgeHeight(4, setEdgeHeight(1)) - - expect(result).toEqual(1) - }) - - it("should set default edgeHeight", () => { - const result = edgeHeight(5, setEdgeHeight()) - - expect(result).toEqual(4) - }) + expect(result).toEqual(1) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.ts index 3ef605f962..4affdf75e0 100644 --- a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.reducer.ts @@ -1,10 +1,6 @@ -import { EdgeHeightAction, EdgeHeightActions, setEdgeHeight } from "./edgeHeight.actions" +import { createReducer, on } from "@ngrx/store" +import { setEdgeHeight } from "./edgeHeight.actions" +import { setState } from "../../util/setState.reducer.factory" -export function edgeHeight(state = setEdgeHeight().payload, action: EdgeHeightAction) { - switch (action.type) { - case EdgeHeightActions.SET_EDGE_HEIGHT: - return action.payload - default: - return state - } -} +export const defaultEdgeHeight = 4 +export const edgeHeight = createReducer(defaultEdgeHeight, on(setEdgeHeight, setState(defaultEdgeHeight))) diff --git a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.selector.ts b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.selector.ts index e0a360faad..6210c87dce 100644 --- a/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/edgeHeight/edgeHeight.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const edgeHeightSelector = createSelector([appSettingsSelector], appSettings => appSettings.edgeHeight) +export const edgeHeightSelector = createSelector(appSettingsSelector, appSettings => appSettings.edgeHeight) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions.ts b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions.ts index 18cc11f1e4..7f210f170b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions.ts @@ -1,23 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum ScreenshotToClipboardEnabledActions { - SET_SCREENSHOT_TO_CLIPBOARD_ENABLED = "SET_SCREENSHOT_TO_CLIPBOARD_ENABLED" -} - -export interface SetScreenshotToClipboardEnabledAction extends CCAction { - type: ScreenshotToClipboardEnabledActions.SET_SCREENSHOT_TO_CLIPBOARD_ENABLED - payload: boolean -} - -export type ScreenshotToClipboardEnabledAction = SetScreenshotToClipboardEnabledAction - -export function setScreenshotToClipboardEnabled( - screenshotToClipboardEnabled: boolean = defaultScreenshotToClipboardEnabled -): SetScreenshotToClipboardEnabledAction { - return { - type: ScreenshotToClipboardEnabledActions.SET_SCREENSHOT_TO_CLIPBOARD_ENABLED, - payload: screenshotToClipboardEnabled - } -} - -export const defaultScreenshotToClipboardEnabled = false +export const setScreenshotToClipboardEnabled = createAction("SET_SCREENSHOT_TO_CLIPBOARD_ENABLED", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.spec.ts index 831a2b7a3d..427b8c4dbb 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.spec.ts @@ -1,26 +1,10 @@ -import { ScreenshotToClipboardEnabledAction, setScreenshotToClipboardEnabled } from "./screenshotToClipboardEnabled.actions" +import { setScreenshotToClipboardEnabled } from "./screenshotToClipboardEnabled.actions" import { screenshotToClipboardEnabled } from "./screenshotToClipboardEnabled.reducer" describe("screenshotToClipboardEnabled", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = screenshotToClipboardEnabled(undefined, {} as ScreenshotToClipboardEnabledAction) + it("should set new screenshotToClipboardEnabled", () => { + const result = screenshotToClipboardEnabled(false, setScreenshotToClipboardEnabled({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_SCREENSHOT_TO_CLIPBOARD_ENABLED", () => { - it("should set new screenshotToClipboardEnabled", () => { - const result = screenshotToClipboardEnabled(false, setScreenshotToClipboardEnabled(true)) - - expect(result).toBeTruthy() - }) - - it("should set default screenshotToClipboardEnabled", () => { - const result = screenshotToClipboardEnabled(true, setScreenshotToClipboardEnabled()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.ts index 9bee1676aa..92f32f09e1 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.reducer.ts @@ -1,17 +1,9 @@ -import { - ScreenshotToClipboardEnabledAction, - ScreenshotToClipboardEnabledActions, - setScreenshotToClipboardEnabled -} from "./screenshotToClipboardEnabled.actions" +import { createReducer, on } from "@ngrx/store" +import { setScreenshotToClipboardEnabled } from "./screenshotToClipboardEnabled.actions" +import { setState } from "../../util/setState.reducer.factory" -export function screenshotToClipboardEnabled( - state = setScreenshotToClipboardEnabled().payload, - action: ScreenshotToClipboardEnabledAction -) { - switch (action.type) { - case ScreenshotToClipboardEnabledActions.SET_SCREENSHOT_TO_CLIPBOARD_ENABLED: - return action.payload - default: - return state - } -} +export const defaultScreenshotToClipboardEnabled = false +export const screenshotToClipboardEnabled = createReducer( + defaultScreenshotToClipboardEnabled, + on(setScreenshotToClipboardEnabled, setState(defaultScreenshotToClipboardEnabled)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector.ts b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector.ts index 37a706b0f5..848046fbf4 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" export const screenshotToClipboardEnabledSelector = createSelector( - [appSettingsSelector], + appSettingsSelector, appSettings => appSettings.screenshotToClipboardEnabled ) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.actions.ts b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.actions.ts index 133f7f7c58..d455c3c5e9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.actions.ts @@ -1,23 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum ExperimentalFeaturesEnabledActions { - SET_EXPERIMENTAL_FEATURES_ENABLED = "SET_EXPERIMENTAL_FEATURES_ENABLED" -} - -export interface SetExperimentalFeaturesEnabledAction extends CCAction { - type: ExperimentalFeaturesEnabledActions.SET_EXPERIMENTAL_FEATURES_ENABLED - payload: boolean -} - -export type ExperimentalFeaturesEnabledAction = SetExperimentalFeaturesEnabledAction - -export function setExperimentalFeaturesEnabled( - experimentalFeaturesEnabled: boolean = defaultExperimentalFeaturesEnabled -): SetExperimentalFeaturesEnabledAction { - return { - type: ExperimentalFeaturesEnabledActions.SET_EXPERIMENTAL_FEATURES_ENABLED, - payload: experimentalFeaturesEnabled - } -} - -export const defaultExperimentalFeaturesEnabled = false +export const setExperimentalFeaturesEnabled = createAction("SET_EXPERIMENTAL_FEATURES_ENABLED", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.spec.ts index dd1547eb40..a6a291e16a 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.spec.ts @@ -1,26 +1,10 @@ import { experimentalFeaturesEnabled } from "./experimentalFeaturesEnabled.reducer" -import { ExperimentalFeaturesEnabledAction, setExperimentalFeaturesEnabled } from "./experimentalFeaturesEnabled.actions" +import { setExperimentalFeaturesEnabled } from "./experimentalFeaturesEnabled.actions" describe("experimentalFeaturesEnabled", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = experimentalFeaturesEnabled(undefined, {} as ExperimentalFeaturesEnabledAction) + it("should set new experimentalFeaturesEnabled", () => { + const result = experimentalFeaturesEnabled(false, setExperimentalFeaturesEnabled({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_EXPERIMENTAL_FEATURES_ENABLED", () => { - it("should set new experimentalFeaturesEnabled", () => { - const result = experimentalFeaturesEnabled(false, setExperimentalFeaturesEnabled(true)) - - expect(result).toBeTruthy() - }) - - it("should set default experimentalFeaturesEnabled", () => { - const result = experimentalFeaturesEnabled(true, setExperimentalFeaturesEnabled()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.ts index 89c222efec..c2f63162d5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.reducer.ts @@ -1,14 +1,9 @@ -import { - ExperimentalFeaturesEnabledAction, - ExperimentalFeaturesEnabledActions, - setExperimentalFeaturesEnabled -} from "./experimentalFeaturesEnabled.actions" +import { createReducer, on } from "@ngrx/store" +import { setExperimentalFeaturesEnabled } from "./experimentalFeaturesEnabled.actions" +import { setState } from "../../util/setState.reducer.factory" -export function experimentalFeaturesEnabled(state = setExperimentalFeaturesEnabled().payload, action: ExperimentalFeaturesEnabledAction) { - switch (action.type) { - case ExperimentalFeaturesEnabledActions.SET_EXPERIMENTAL_FEATURES_ENABLED: - return action.payload - default: - return state - } -} +export const defaultExperimentalFeaturesEnabled = false +export const experimentalFeaturesEnabled = createReducer( + defaultExperimentalFeaturesEnabled, + on(setExperimentalFeaturesEnabled, setState(defaultExperimentalFeaturesEnabled)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector.ts b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector.ts index d81acb8a09..c1a221fbe6 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" export const experimentalFeaturesEnabledSelector = createSelector( - [appSettingsSelector], + appSettingsSelector, appSettings => appSettings.experimentalFeaturesEnabled ) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.actions.ts b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.actions.ts index 7e1b555fef..3092ed75a9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum EnableFloorLabelsActions { - SET_ENABLE_FLOOR_LABELS = "SET_ENABLE_FLOOR_LABELS" -} - -export interface SetEnableFloorLabelsAction extends CCAction { - type: EnableFloorLabelsActions.SET_ENABLE_FLOOR_LABELS - payload: boolean -} - -export type EnableFloorLabelAction = SetEnableFloorLabelsAction - -export function setEnableFloorLabels(enableFloorLabel: boolean = defaultEnableFloorLabel): SetEnableFloorLabelsAction { - return { - type: EnableFloorLabelsActions.SET_ENABLE_FLOOR_LABELS, - payload: enableFloorLabel - } -} - -export const defaultEnableFloorLabel = true +export const setEnableFloorLabels = createAction("SET_ENABLE_FLOOR_LABELS", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.spec.ts index 4accdbcf08..e49d961af9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.spec.ts @@ -1,26 +1,10 @@ import { enableFloorLabels } from "./enableFloorLabels.reducer" -import { EnableFloorLabelAction, setEnableFloorLabels } from "./enableFloorLabels.actions" +import { setEnableFloorLabels } from "./enableFloorLabels.actions" describe("enableFloorLabel", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = enableFloorLabels(undefined, {} as EnableFloorLabelAction) + it("should set new enableFloorLabel", () => { + const result = enableFloorLabels(true, setEnableFloorLabels({ value: false })) - expect(result).toBeTruthy() - }) - }) - - describe("Action: SET_ENABLE_FLOOR_LABEL", () => { - it("should set new enableFloorLabel", () => { - const result = enableFloorLabels(true, setEnableFloorLabels(false)) - - expect(result).toBeFalsy() - }) - - it("should set default colorMetric", () => { - const result = enableFloorLabels(false, setEnableFloorLabels()) - - expect(result).toBeTruthy() - }) + expect(result).toBeFalsy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.ts index 60dfd3d7a3..413b6a54b5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.reducer.ts @@ -1,10 +1,6 @@ -import { EnableFloorLabelAction, EnableFloorLabelsActions, setEnableFloorLabels } from "./enableFloorLabels.actions" +import { createReducer, on } from "@ngrx/store" +import { setEnableFloorLabels } from "./enableFloorLabels.actions" +import { setState } from "../../util/setState.reducer.factory" -export function enableFloorLabels(state = setEnableFloorLabels().payload, action: EnableFloorLabelAction) { - switch (action.type) { - case EnableFloorLabelsActions.SET_ENABLE_FLOOR_LABELS: - return action.payload - default: - return state - } -} +export const defaultEnableFloorLabels = true +export const enableFloorLabels = createReducer(defaultEnableFloorLabels, on(setEnableFloorLabels, setState(defaultEnableFloorLabels))) diff --git a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.selector.ts b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.selector.ts index c4935ec5d1..4fab34f29e 100644 --- a/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/enableFloorLabels/enableFloorLabels.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const enableFloorLabelsSelector = createSelector([appSettingsSelector], appSettings => appSettings.enableFloorLabels) +export const enableFloorLabelsSelector = createSelector(appSettingsSelector, appSettings => appSettings.enableFloorLabels) diff --git a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.actions.ts b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.actions.ts index 64b57841c4..2323f25dd5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum HideFlatBuildingsActions { - SET_HIDE_FLAT_BUILDINGS = "SET_HIDE_FLAT_BUILDINGS" -} - -export interface SetHideFlatBuildingsAction extends CCAction { - type: HideFlatBuildingsActions.SET_HIDE_FLAT_BUILDINGS - payload: boolean -} - -export type HideFlatBuildingsAction = SetHideFlatBuildingsAction - -export function setHideFlatBuildings(hideFlatBuildings: boolean = defaultHideFlatBuildings): SetHideFlatBuildingsAction { - return { - type: HideFlatBuildingsActions.SET_HIDE_FLAT_BUILDINGS, - payload: hideFlatBuildings - } -} - -export const defaultHideFlatBuildings = false +export const setHideFlatBuildings = createAction("SET_HIDE_FLAT_BUILDINGS", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.spec.ts index 3bababb5b2..7891bbf168 100644 --- a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.spec.ts @@ -1,26 +1,10 @@ import { hideFlatBuildings } from "./hideFlatBuildings.reducer" -import { HideFlatBuildingsAction, setHideFlatBuildings } from "./hideFlatBuildings.actions" +import { setHideFlatBuildings } from "./hideFlatBuildings.actions" describe("hideFlatBuildings", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = hideFlatBuildings(undefined, {} as HideFlatBuildingsAction) + it("should set new hideFlatBuildings", () => { + const result = hideFlatBuildings(false, setHideFlatBuildings({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_HIDE_FLAT_BUILDINGS", () => { - it("should set new hideFlatBuildings", () => { - const result = hideFlatBuildings(false, setHideFlatBuildings(true)) - - expect(result).toBeTruthy() - }) - - it("should set default hideFlatBuildings", () => { - const result = hideFlatBuildings(true, setHideFlatBuildings()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.ts index 75e89de16d..34c1fc97fa 100644 --- a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.reducer.ts @@ -1,10 +1,6 @@ -import { HideFlatBuildingsAction, HideFlatBuildingsActions, setHideFlatBuildings } from "./hideFlatBuildings.actions" +import { createReducer, on } from "@ngrx/store" +import { setHideFlatBuildings } from "./hideFlatBuildings.actions" +import { setState } from "../../util/setState.reducer.factory" -export function hideFlatBuildings(state = setHideFlatBuildings().payload, action: HideFlatBuildingsAction) { - switch (action.type) { - case HideFlatBuildingsActions.SET_HIDE_FLAT_BUILDINGS: - return action.payload - default: - return state - } -} +export const defaultHideFlatBuildings = false +export const hideFlatBuildings = createReducer(defaultHideFlatBuildings, on(setHideFlatBuildings, setState(defaultHideFlatBuildings))) diff --git a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.selector.ts b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.selector.ts index 95552026a3..887bcb1a0f 100644 --- a/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/hideFlatBuildings/hideFlatBuildings.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const hideFlatBuildingsSelector = createSelector([appSettingsSelector], appSettings => appSettings.hideFlatBuildings) +export const hideFlatBuildingsSelector = createSelector(appSettingsSelector, appSettings => appSettings.hideFlatBuildings) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts index 536d59c311..ac08a6c53a 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts @@ -1,21 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum InvertAreaActions { - SET_INVERT_AREA = "SET_INVERT_AREA" -} - -export interface SetInvertAreaAction extends Action { - type: InvertAreaActions.SET_INVERT_AREA - payload: boolean -} - -export type InvertAreaAction = SetInvertAreaAction - -export const defaultInvertArea = false - -export function setInvertArea(invertArea: boolean = defaultInvertArea): SetInvertAreaAction { - return { - type: InvertAreaActions.SET_INVERT_AREA, - payload: invertArea - } -} +export const setInvertArea = createAction("SET_INVERT_AREA", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts index 6ab80005e1..896a236901 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts @@ -1,26 +1,10 @@ import { invertArea } from "./invertArea.reducer" -import { InvertAreaAction, setInvertArea } from "./invertArea.actions" +import { setInvertArea } from "./invertArea.actions" describe("invertArea", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = invertArea(undefined, {} as InvertAreaAction) + it("should set new invertArea", () => { + const result = invertArea(false, setInvertArea({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_INVERT_AREA", () => { - it("should set new invertArea", () => { - const result = invertArea(false, setInvertArea(true)) - - expect(result).toBeTruthy() - }) - - it("should set default invertArea", () => { - const result = invertArea(true, setInvertArea()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts index b2ba4a5928..b928e2d61c 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts @@ -1,10 +1,6 @@ -import { InvertAreaAction, InvertAreaActions, setInvertArea } from "./invertArea.actions" +import { createReducer, on } from "@ngrx/store" +import { setInvertArea } from "./invertArea.actions" +import { setState } from "../../util/setState.reducer.factory" -export function invertArea(state = setInvertArea().payload, action: InvertAreaAction) { - switch (action.type) { - case InvertAreaActions.SET_INVERT_AREA: - return action.payload - default: - return state - } -} +export const defaultInvertArea = false +export const invertArea = createReducer(defaultInvertArea, on(setInvertArea, setState(defaultInvertArea))) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts index ea83cb055d..0e0edca806 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { appSettingsSelector } from "../appSettings.selector" -export const invertAreaSelector = (state: CcState): boolean => state.appSettings.invertArea +export const invertAreaSelector = createSelector(appSettingsSelector, appSettings => appSettings.invertArea) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.actions.ts b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.actions.ts index 15a3e43e6c..0e247c40dd 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum InvertHeightActions { - SET_INVERT_HEIGHT = "SET_INVERT_HEIGHT" -} - -export interface SetInvertHeightAction extends CCAction { - type: InvertHeightActions.SET_INVERT_HEIGHT - payload: boolean -} - -export type InvertHeightAction = SetInvertHeightAction - -export function setInvertHeight(invertHeight: boolean = defaultInvertHeight): SetInvertHeightAction { - return { - type: InvertHeightActions.SET_INVERT_HEIGHT, - payload: invertHeight - } -} - -export const defaultInvertHeight = false +export const setInvertHeight = createAction("SET_INVERT_HEIGHT", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.spec.ts index 4f5d660ba3..a2186b73f5 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.spec.ts @@ -1,26 +1,10 @@ import { invertHeight } from "./invertHeight.reducer" -import { InvertHeightAction, setInvertHeight } from "./invertHeight.actions" +import { setInvertHeight } from "./invertHeight.actions" describe("invertHeight", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = invertHeight(undefined, {} as InvertHeightAction) + it("should set new invertHeight", () => { + const result = invertHeight(false, setInvertHeight({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_INVERT_HEIGHT", () => { - it("should set new invertHeight", () => { - const result = invertHeight(false, setInvertHeight(true)) - - expect(result).toBeTruthy() - }) - - it("should set default invertHeight", () => { - const result = invertHeight(true, setInvertHeight()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.ts index c7cdb3cd4d..3754327a87 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.reducer.ts @@ -1,10 +1,6 @@ -import { InvertHeightAction, InvertHeightActions, setInvertHeight } from "./invertHeight.actions" +import { createReducer, on } from "@ngrx/store" +import { setInvertHeight } from "./invertHeight.actions" +import { setState } from "../../util/setState.reducer.factory" -export function invertHeight(state = setInvertHeight().payload, action: InvertHeightAction) { - switch (action.type) { - case InvertHeightActions.SET_INVERT_HEIGHT: - return action.payload - default: - return state - } -} +export const defaultInvertHeight = false +export const invertHeight = createReducer(defaultInvertHeight, on(setInvertHeight, setState(defaultInvertHeight))) diff --git a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.selector.ts b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.selector.ts index f4c606d711..335a14e522 100644 --- a/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/invertHeight/invertHeight.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const invertHeightSelector = createSelector([appSettingsSelector], appSettings => appSettings.invertHeight) +export const invertHeightSelector = createSelector(appSettingsSelector, appSettings => appSettings.invertHeight) diff --git a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions.ts index c6cd7fb67b..fbb5c4289f 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions.ts @@ -1,19 +1,3 @@ -import { Action } from "redux" +import { createAction } from "@ngrx/store" -export enum IsEdgeMetricVisibleActions { - TOGGLE_IS_EDGE_METRIC_VISIBLE = "TOGGLE_IS_EDGE_METRIC_VISIBLE" -} - -export interface ToggleIsEdgeMetricVisibleAction extends Action { - type: IsEdgeMetricVisibleActions.TOGGLE_IS_EDGE_METRIC_VISIBLE -} - -export type IsEdgeMetricVisibleAction = ToggleIsEdgeMetricVisibleAction - -export function toggleEdgeMetricVisible(): ToggleIsEdgeMetricVisibleAction { - return { - type: IsEdgeMetricVisibleActions.TOGGLE_IS_EDGE_METRIC_VISIBLE - } -} - -export const defaultIsEdgeMetricVisible = true +export const toggleEdgeMetricVisible = createAction("TOGGLE_IS_EDGE_METRIC_VISIBLE") diff --git a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.spec.ts index 6b81b50a34..0c132d1362 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.spec.ts @@ -1,21 +1,11 @@ -import { IsEdgeMetricVisibleAction, toggleEdgeMetricVisible } from "./isEdgeMetricVisible.actions" +import { toggleEdgeMetricVisible } from "./isEdgeMetricVisible.actions" import { isEdgeMetricVisible } from "./isEdgeMetricVisible.reducer" describe("isEdgeMetricVisible", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isEdgeMetricVisible(undefined, {} as IsEdgeMetricVisibleAction) + it("should toggle state", () => { + const result = isEdgeMetricVisible(false, toggleEdgeMetricVisible()) + const toggledResult = isEdgeMetricVisible(result, toggleEdgeMetricVisible()) - expect(result).toEqual(true) - }) - }) - - describe("Action: TOGGLE_IS_EDGE_METRIC_VISIBLE", () => { - it("should toggle state", () => { - const result = isEdgeMetricVisible(false, toggleEdgeMetricVisible()) - const toggledResult = isEdgeMetricVisible(result, toggleEdgeMetricVisible()) - - expect(toggledResult).toBe(!result) - }) + expect(toggledResult).toBe(!result) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.ts index 4b0c978355..c4180a2bc3 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.reducer.ts @@ -1,10 +1,8 @@ -import { IsEdgeMetricVisibleActions, IsEdgeMetricVisibleAction, defaultIsEdgeMetricVisible } from "./isEdgeMetricVisible.actions" +import { createReducer, on } from "@ngrx/store" +import { toggleEdgeMetricVisible } from "./isEdgeMetricVisible.actions" -export function isEdgeMetricVisible(state = defaultIsEdgeMetricVisible, action: IsEdgeMetricVisibleAction) { - switch (action.type) { - case IsEdgeMetricVisibleActions.TOGGLE_IS_EDGE_METRIC_VISIBLE: - return !state - default: - return state - } -} +export const defaultIsEdgeMetricVisible = true +export const isEdgeMetricVisible = createReducer( + defaultIsEdgeMetricVisible, + on(toggleEdgeMetricVisible, state => !state) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector.ts index 863a5f1080..5eff9b090e 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const isEdgeMetricVisibleSelector = createSelector([appSettingsSelector], appSettings => appSettings.isEdgeMetricVisible) +export const isEdgeMetricVisibleSelector = createSelector(appSettingsSelector, appSettings => appSettings.isEdgeMetricVisible) diff --git a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions.ts index d1e6a2ce63..f56103238b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions.ts @@ -1,32 +1,7 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum IsColorMetricLinkedToHeightMetricActions { - TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC = "TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC", - SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC = "SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC" -} - -export interface ToggleHeightAndColorMetricLinkedAction extends Action { - type: IsColorMetricLinkedToHeightMetricActions.TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC -} - -export interface SetIsColorMetricLinkedToHeightMetricAction extends Action { - type: IsColorMetricLinkedToHeightMetricActions.SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC - payload: boolean -} - -export type IsColorMetricLinkedToHeightMetricAction = ToggleHeightAndColorMetricLinkedAction | SetIsColorMetricLinkedToHeightMetricAction - -export function toggleIsColorMetricLinkedToHeightMetric(): ToggleHeightAndColorMetricLinkedAction { - return { - type: IsColorMetricLinkedToHeightMetricActions.TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC - } -} - -export function setIsColorMetricLinkedToHeightMetricAction(payload: boolean): SetIsColorMetricLinkedToHeightMetricAction { - return { - type: IsColorMetricLinkedToHeightMetricActions.SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC, - payload - } -} - -export const defaultIsColorMetricLinkedToHeightMetric = false +export const setIsColorMetricLinkedToHeightMetricAction = createAction( + "SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC", + props<{ value: boolean }>() +) +export const toggleIsColorMetricLinkedToHeightMetric = createAction("TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC") diff --git a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.spec.ts index f22375ff60..cd6335356b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.spec.ts @@ -1,19 +1,10 @@ import { - IsColorMetricLinkedToHeightMetricAction, setIsColorMetricLinkedToHeightMetricAction, toggleIsColorMetricLinkedToHeightMetric } from "./isColorMetricLinkedToHeightMetric.actions" import { isColorMetricLinkedToHeightMetric } from "./isColorMetricLinkedToHeightMetric.reducer" describe("isColorMetricLinkedToHeightMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isColorMetricLinkedToHeightMetric(undefined, {} as IsColorMetricLinkedToHeightMetricAction) - - expect(result).toBe(false) - }) - }) - describe("Action: TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC", () => { it("should toggle state", () => { const result = isColorMetricLinkedToHeightMetric(false, toggleIsColorMetricLinkedToHeightMetric()) @@ -25,8 +16,8 @@ describe("isColorMetricLinkedToHeightMetric", () => { describe("Action: SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC", () => { it("should set new isColorMetricLinkedToHeightMetric state", () => { - const isLinked = isColorMetricLinkedToHeightMetric(false, setIsColorMetricLinkedToHeightMetricAction(true)) - const isNotLinked = isColorMetricLinkedToHeightMetric(isLinked, setIsColorMetricLinkedToHeightMetricAction(false)) + const isLinked = isColorMetricLinkedToHeightMetric(false, setIsColorMetricLinkedToHeightMetricAction({ value: true })) + const isNotLinked = isColorMetricLinkedToHeightMetric(isLinked, setIsColorMetricLinkedToHeightMetricAction({ value: false })) expect(isLinked).not.toBe(isNotLinked) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.ts index f55d27e6b2..64b5ea839c 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.reducer.ts @@ -1,19 +1,12 @@ +import { createReducer, on } from "@ngrx/store" import { - defaultIsColorMetricLinkedToHeightMetric, - IsColorMetricLinkedToHeightMetricAction, - IsColorMetricLinkedToHeightMetricActions + setIsColorMetricLinkedToHeightMetricAction, + toggleIsColorMetricLinkedToHeightMetric } from "./isColorMetricLinkedToHeightMetric.actions" -export function isColorMetricLinkedToHeightMetric( - state = defaultIsColorMetricLinkedToHeightMetric, - action: IsColorMetricLinkedToHeightMetricAction -) { - switch (action.type) { - case IsColorMetricLinkedToHeightMetricActions.TOGGLE_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC: - return !state - case IsColorMetricLinkedToHeightMetricActions.SET_IS_COLOR_METRIC_LINKED_TO_HEIGHT_METRIC: - return action.payload - default: - return state - } -} +export const defaultIsColorMetricLinkedToHeightMetric = false +export const isColorMetricLinkedToHeightMetric = createReducer( + defaultIsColorMetricLinkedToHeightMetric, + on(setIsColorMetricLinkedToHeightMetricAction, (_state, action) => action.value), + on(toggleIsColorMetricLinkedToHeightMetric, state => !state) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector.ts index 8479ab135e..11fe9ceee9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" export const isColorMetricLinkedToHeightMetricSelector = createSelector( - [appSettingsSelector], + appSettingsSelector, appSettings => appSettings.isColorMetricLinkedToHeightMetric ) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.actions.ts index 61290a2ebb..40b04dfdd0 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.actions.ts @@ -1,21 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum IsLoadingFileActions { - SET_IS_LOADING_FILE = "SET_IS_LOADING_FILE" -} - -export interface SetIsLoadingFileAction extends Action { - type: IsLoadingFileActions.SET_IS_LOADING_FILE - payload: boolean -} - -export type IsLoadingFileAction = SetIsLoadingFileAction - -export function setIsLoadingFile(isLoadingFile: boolean = defaultIsLoadingFile): SetIsLoadingFileAction { - return { - type: IsLoadingFileActions.SET_IS_LOADING_FILE, - payload: isLoadingFile - } -} - -export const defaultIsLoadingFile = true +export const setIsLoadingFile = createAction("SET_IS_LOADING_FILE", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.spec.ts index e0c6ef6d4c..a2b6ae650c 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.spec.ts @@ -1,26 +1,10 @@ import { isLoadingFile } from "./isLoadingFile.reducer" -import { IsLoadingFileAction, setIsLoadingFile } from "./isLoadingFile.actions" +import { setIsLoadingFile } from "./isLoadingFile.actions" describe("isLoadingFile", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isLoadingFile(undefined, {} as IsLoadingFileAction) + it("should set new isLoadingFile", () => { + const result = isLoadingFile(true, setIsLoadingFile({ value: false })) - expect(result).toEqual(true) - }) - }) - - describe("Action: SET_IS_LOADING_FILE", () => { - it("should set new isLoadingFile", () => { - const result = isLoadingFile(true, setIsLoadingFile(false)) - - expect(result).toEqual(false) - }) - - it("should set default isLoadingFile", () => { - const result = isLoadingFile(false, setIsLoadingFile()) - - expect(result).toEqual(true) - }) + expect(result).toEqual(false) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.ts index 1e7c14915c..23cc7edb0a 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.reducer.ts @@ -1,15 +1,6 @@ -import { isActionOfType } from "../../../../util/reduxHelper" -import { FilesSelectionActions } from "../../files/files.actions" -import { defaultIsLoadingFile, IsLoadingFileAction, IsLoadingFileActions } from "./isLoadingFile.actions" +import { createReducer, on } from "@ngrx/store" +import { setIsLoadingFile } from "./isLoadingFile.actions" +import { setState } from "../../util/setState.reducer.factory" -export function isLoadingFile(state = defaultIsLoadingFile, action: IsLoadingFileAction) { - if (action.type === IsLoadingFileActions.SET_IS_LOADING_FILE) { - return action.payload - } - - if (isActionOfType(action.type, FilesSelectionActions)) { - return true - } - - return state -} +export const defaultIsLoadingFile = true +export const isLoadingFile = createReducer(defaultIsLoadingFile, on(setIsLoadingFile, setState(defaultIsLoadingFile))) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.selector.ts index 1c66347b2e..7800a8e2e0 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingFile/isLoadingFile.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const isLoadingFileSelector = createSelector([appSettingsSelector], appSettings => appSettings.isLoadingFile) +export const isLoadingFileSelector = createSelector(appSettingsSelector, appSettings => appSettings.isLoadingFile) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.actions.ts index b3569c5d9f..2ecacbc772 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.actions.ts @@ -1,21 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum IsLoadingMapActions { - SET_IS_LOADING_MAP = "SET_IS_LOADING_MAP" -} - -export interface SetIsLoadingMapAction extends Action { - type: IsLoadingMapActions.SET_IS_LOADING_MAP - payload: boolean -} - -export type IsLoadingMapAction = SetIsLoadingMapAction - -export function setIsLoadingMap(isLoadingMap: boolean = defaultIsLoadingMap): SetIsLoadingMapAction { - return { - type: IsLoadingMapActions.SET_IS_LOADING_MAP, - payload: isLoadingMap - } -} - -export const defaultIsLoadingMap = true +export const setIsLoadingMap = createAction("SET_IS_LOADING_MAP", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts index ce75c23fa9..e6c336baef 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts @@ -1,37 +1,10 @@ import { isLoadingMap } from "./isLoadingMap.reducer" -import { IsLoadingMapAction, setIsLoadingMap } from "./isLoadingMap.actions" -import { setInvertArea } from "../invertArea/invertArea.actions" +import { setIsLoadingMap } from "./isLoadingMap.actions" describe("isLoadingMap", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isLoadingMap(undefined, {} as IsLoadingMapAction) + it("should set new isLoadingMap", () => { + const result = isLoadingMap(true, setIsLoadingMap({ value: false })) - expect(result).toBe(true) - }) - }) - - describe("Action: SET_IS_LOADING_MAP", () => { - it("should set new isLoadingMap", () => { - const result = isLoadingMap(true, setIsLoadingMap(false)) - - expect(result).toBe(false) - }) - - it("should set default isLoadingMap", () => { - const result = isLoadingMap(false, setIsLoadingMap()) - - expect(result).toBe(true) - }) - }) - - describe("Other Actions to (not) set isLoadingMap to true", () => { - it("should not set isLoadingMap to true on a random action", () => { - expect(isLoadingMap(false, { type: "any" } as unknown as IsLoadingMapAction)).toBe(false) - }) - - it("should set isLoadingMap to true on actions requiring rerender", () => { - expect(isLoadingMap(false, setInvertArea(true) as unknown as IsLoadingMapAction)).toBe(true) - }) + expect(result).toBe(false) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts index c3bddf9a8f..c6627a19ec 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts @@ -1,15 +1,6 @@ -import { isActionOfType } from "../../../../util/reduxHelper" -import { IsLoadingMapAction, IsLoadingMapActions, setIsLoadingMap } from "./isLoadingMap.actions" -import { actionsRequiringRerender } from "../../../effects/renderCodeMapEffect/actionsRequiringRerender" +import { setState } from "../../util/setState.reducer.factory" +import { setIsLoadingMap } from "./isLoadingMap.actions" +import { createReducer, on } from "@ngrx/store" -export function isLoadingMap(state = setIsLoadingMap().payload, action: IsLoadingMapAction) { - if (action.type === IsLoadingMapActions.SET_IS_LOADING_MAP) { - return action.payload - } - - if (actionsRequiringRerender.some(actions => isActionOfType(action.type, actions))) { - return true - } - - return state -} +export const defaultIsLoadingMap = true +export const isLoadingMap = createReducer(defaultIsLoadingMap, on(setIsLoadingMap, setState(defaultIsLoadingMap))) diff --git a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.selector.ts index c7f5a3f91c..9b121de763 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const isLoadingMapSelector = createSelector([appSettingsSelector], appSettings => appSettings.isLoadingMap) +export const isLoadingMapSelector = createSelector(appSettingsSelector, appSettings => appSettings.isLoadingMap) diff --git a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.actions.ts index b66545fe10..8e5b0c8325 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum PresentationModeActions { - SET_PRESENTATION_MODE = "SET_PRESENTATION_MODE" -} - -export interface SetPresentationModeAction extends CCAction { - type: PresentationModeActions.SET_PRESENTATION_MODE - payload: boolean -} - -export type PresentationModeAction = SetPresentationModeAction - -export function setPresentationMode(active: boolean = defaultIsPresentationMode): SetPresentationModeAction { - return { - type: PresentationModeActions.SET_PRESENTATION_MODE, - payload: active - } -} - -export const defaultIsPresentationMode = false +export const setPresentationMode = createAction("SET_PRESENTATION_MODE", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.spec.ts index 5425987899..6036b985d3 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.spec.ts @@ -1,26 +1,10 @@ import { isPresentationMode } from "./isPresentationMode.reducer" -import { PresentationModeAction, setPresentationMode } from "./isPresentationMode.actions" +import { setPresentationMode } from "./isPresentationMode.actions" describe("isPresentationMode", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isPresentationMode(undefined, {} as PresentationModeAction) + it("should activate presentation mode", () => { + const result = isPresentationMode(false, setPresentationMode({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_PRESENTATION_MODE", () => { - it("should activate presentation mode", () => { - const result = isPresentationMode(false, setPresentationMode(true)) - - expect(result).toBeTruthy() - }) - - it("should set default presentation mode", () => { - const result = isPresentationMode(true, setPresentationMode()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.ts index 04cac1f396..c806c37219 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.reducer.ts @@ -1,10 +1,6 @@ -import { PresentationModeAction, PresentationModeActions, setPresentationMode } from "./isPresentationMode.actions" +import { createReducer, on } from "@ngrx/store" +import { setPresentationMode } from "./isPresentationMode.actions" +import { setState } from "../../util/setState.reducer.factory" -export function isPresentationMode(state = setPresentationMode().payload, action: PresentationModeAction) { - switch (action.type) { - case PresentationModeActions.SET_PRESENTATION_MODE: - return action.payload - default: - return state - } -} +export const defaultIsPresentationMode = false +export const isPresentationMode = createReducer(defaultIsPresentationMode, on(setPresentationMode, setState(defaultIsPresentationMode))) diff --git a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.selector.ts index 3b5fab378f..4f702fe372 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isPresentationMode/isPresentationMode.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const isPresentationModeSelector = createSelector([appSettingsSelector], appSettings => appSettings.isPresentationMode) +export const isPresentationModeSelector = createSelector(appSettingsSelector, appSettings => appSettings.isPresentationMode) diff --git a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.actions.ts b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.actions.ts index f933d1b662..9259198730 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum IsWhiteBackgroundActions { - SET_IS_WHITE_BACKGROUND = "SET_IS_WHITE_BACKGROUND" -} - -export interface SetIsWhiteBackgroundAction extends CCAction { - type: IsWhiteBackgroundActions.SET_IS_WHITE_BACKGROUND - payload: boolean -} - -export type IsWhiteBackgroundAction = SetIsWhiteBackgroundAction - -export function setIsWhiteBackground(isWhiteBackground: boolean = defaultIsWhiteBackground): SetIsWhiteBackgroundAction { - return { - type: IsWhiteBackgroundActions.SET_IS_WHITE_BACKGROUND, - payload: isWhiteBackground - } -} - -export const defaultIsWhiteBackground = false +export const setIsWhiteBackground = createAction("SET_IS_WHITE_BACKGROUND", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.spec.ts index 1bdd3c27c1..a3b0312f73 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.spec.ts @@ -1,26 +1,10 @@ import { isWhiteBackground } from "./isWhiteBackground.reducer" -import { IsWhiteBackgroundAction, setIsWhiteBackground } from "./isWhiteBackground.actions" +import { setIsWhiteBackground } from "./isWhiteBackground.actions" describe("isWhiteBackground", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = isWhiteBackground(undefined, {} as IsWhiteBackgroundAction) + it("should set new isWhiteBackground", () => { + const result = isWhiteBackground(false, setIsWhiteBackground({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_IS_WHITE_BACKGROUND", () => { - it("should set new isWhiteBackground", () => { - const result = isWhiteBackground(false, setIsWhiteBackground(true)) - - expect(result).toBeTruthy() - }) - - it("should set default isWhiteBackground", () => { - const result = isWhiteBackground(true, setIsWhiteBackground()) - - expect(result).toBeFalsy() - }) + expect(result).toBe(true) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.ts index 1777ab1cd1..45948dbdfa 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.reducer.ts @@ -1,10 +1,6 @@ -import { IsWhiteBackgroundAction, IsWhiteBackgroundActions, setIsWhiteBackground } from "./isWhiteBackground.actions" +import { createReducer, on } from "@ngrx/store" +import { setIsWhiteBackground } from "./isWhiteBackground.actions" +import { setState } from "../../util/setState.reducer.factory" -export function isWhiteBackground(state = setIsWhiteBackground().payload, action: IsWhiteBackgroundAction) { - switch (action.type) { - case IsWhiteBackgroundActions.SET_IS_WHITE_BACKGROUND: - return action.payload - default: - return state - } -} +export const defaultIsWhiteBackground = false +export const isWhiteBackground = createReducer(defaultIsWhiteBackground, on(setIsWhiteBackground, setState(defaultIsWhiteBackground))) diff --git a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.selector.ts b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.selector.ts index 32e2acbbf7..d1c8c47463 100644 --- a/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/isWhiteBackground/isWhiteBackground.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const isWhiteBackgroundSelector = createSelector([appSettingsSelector], appSettings => appSettings.isWhiteBackground) +export const isWhiteBackgroundSelector = createSelector(appSettingsSelector, appSettings => appSettings.isWhiteBackground) diff --git a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions.ts b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions.ts index e51eedb983..85e6021e86 100644 --- a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions.ts @@ -1,21 +1,4 @@ -import { CCAction, LayoutAlgorithm } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { LayoutAlgorithm } from "../../../../codeCharta.model" -export enum LayoutAlgorithmActions { - SET_LAYOUT_ALGORITHM = "SET_LAYOUT_ALGORITHM" -} - -export interface SetLayoutAlgorithmAction extends CCAction { - type: LayoutAlgorithmActions.SET_LAYOUT_ALGORITHM - payload: LayoutAlgorithm -} - -export type LayoutAlgorithmAction = SetLayoutAlgorithmAction - -export function setLayoutAlgorithm(layoutAlgorithm: LayoutAlgorithm = defaultLayoutAlgorithm): SetLayoutAlgorithmAction { - return { - type: LayoutAlgorithmActions.SET_LAYOUT_ALGORITHM, - payload: layoutAlgorithm - } -} - -export const defaultLayoutAlgorithm: LayoutAlgorithm = LayoutAlgorithm.SquarifiedTreeMap +export const setLayoutAlgorithm = createAction("SET_LAYOUT_ALGORITHM", props<{ value: LayoutAlgorithm }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.spec.ts index d4b6797f34..239bf783fe 100644 --- a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.spec.ts @@ -1,24 +1,12 @@ import { layoutAlgorithm } from "./layoutAlgorithm.reducer" -import { LayoutAlgorithmAction, setLayoutAlgorithm } from "./layoutAlgorithm.actions" +import { setLayoutAlgorithm } from "./layoutAlgorithm.actions" import { LayoutAlgorithm } from "../../../../codeCharta.model" describe("layoutAlgorithm", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = layoutAlgorithm(undefined, {} as LayoutAlgorithmAction) - expect(result).toEqual(LayoutAlgorithm.SquarifiedTreeMap) - }) - }) - describe("setLayoutAlgorithm", () => { it("should set new layoutAlgorithm", () => { - const result = layoutAlgorithm(LayoutAlgorithm.SquarifiedTreeMap, setLayoutAlgorithm(LayoutAlgorithm.StreetMap)) + const result = layoutAlgorithm(LayoutAlgorithm.SquarifiedTreeMap, setLayoutAlgorithm({ value: LayoutAlgorithm.StreetMap })) expect(result).toEqual(LayoutAlgorithm.StreetMap) }) - - it("should set default layoutAlgorithm", () => { - const result = layoutAlgorithm(LayoutAlgorithm.StreetMap, setLayoutAlgorithm()) - expect(result).toEqual(LayoutAlgorithm.SquarifiedTreeMap) - }) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.ts index 61ddaf9b7c..c84d617148 100644 --- a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.reducer.ts @@ -1,11 +1,7 @@ -import { LayoutAlgorithmAction, LayoutAlgorithmActions, setLayoutAlgorithm } from "./layoutAlgorithm.actions" +import { createReducer, on } from "@ngrx/store" import { LayoutAlgorithm } from "../../../../codeCharta.model" +import { setLayoutAlgorithm } from "./layoutAlgorithm.actions" +import { setState } from "../../util/setState.reducer.factory" -export function layoutAlgorithm(state: LayoutAlgorithm = setLayoutAlgorithm().payload, action: LayoutAlgorithmAction): LayoutAlgorithm { - switch (action.type) { - case LayoutAlgorithmActions.SET_LAYOUT_ALGORITHM: - return action.payload - default: - return state - } -} +export const defaultLayoutAlgorithm = LayoutAlgorithm.SquarifiedTreeMap +export const layoutAlgorithm = createReducer(defaultLayoutAlgorithm, on(setLayoutAlgorithm, setState(defaultLayoutAlgorithm))) diff --git a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector.ts b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector.ts index b127b5ef0e..977da55feb 100644 --- a/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const layoutAlgorithmSelector = createSelector([appSettingsSelector], appSettings => appSettings.layoutAlgorithm) +export const layoutAlgorithmSelector = createSelector(appSettingsSelector, appSettings => appSettings.layoutAlgorithm) diff --git a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.actions.ts b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.actions.ts index 328c9b1827..b16c5d818b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.actions.ts @@ -1,43 +1,6 @@ +import { createAction, props } from "@ngrx/store" import { MapColors } from "../../../../codeCharta.model" -export enum MapColorsActions { - SET_MAP_COLORS = "SET_MAP_COLORS", - INVERT_COLOR_RANGE = "INVERT_COLOR_RANGE", - INVERT_DELTA_COLORS = "INVERT_DELTA_COLORS" -} - -export type MapColorsAction = ReturnType | ReturnType | ReturnType - -export function setMapColors(mapColors: Partial = defaultMapColors) { - return { - type: MapColorsActions.SET_MAP_COLORS, - payload: mapColors - } -} - -export function invertColorRange() { - return { - type: MapColorsActions.INVERT_COLOR_RANGE - } -} - -export function invertDeltaColors() { - return { - type: MapColorsActions.INVERT_DELTA_COLORS - } -} - -export const defaultMapColors: MapColors = { - positive: "#69AE40", - neutral: "#ddcc00", - negative: "#820E0E", - selected: "#EB8319", - positiveDelta: "#64d051", - negativeDelta: "#ff0E0E", - base: "#666666", - flat: "#AAAAAA", - markingColors: ["#FF1D8E", "#1d8eff", "#1DFFFF", "#8eff1d", "#8e1dff"], - incomingEdge: "#00ffff", - outgoingEdge: "#ff00ff", - labelColorAndAlpha: { rgb: "#e0e0e0", alpha: 0.7 } -} +export const setMapColors = createAction("SET_MAP_COLORS", props<{ value: Partial }>()) +export const invertColorRange = createAction("INVERT_COLOR_RANGE") +export const invertDeltaColors = createAction("INVERT_DELTA_COLORS") diff --git a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.spec.ts index 548f369692..080829ac48 100644 --- a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.spec.ts @@ -1,18 +1,11 @@ -import { mapColors } from "./mapColors.reducer" -import { defaultMapColors, invertColorRange, invertDeltaColors, MapColorsAction, setMapColors } from "./mapColors.actions" -import { MapColors } from "../../../../codeCharta.model" +import { defaultMapColors, mapColors } from "./mapColors.reducer" +import { invertColorRange, invertDeltaColors, setMapColors } from "./mapColors.actions" describe("mapColors", () => { - it("should initialize the default state", () => { - const result = mapColors(undefined, {} as MapColorsAction) - - expect(result).toEqual(defaultMapColors) - }) - it("should set new mapColors", () => { const newMapColors = { ...defaultMapColors, positive: "ABCDEF" } - const result = mapColors(defaultMapColors, setMapColors(newMapColors)) + const result = mapColors(defaultMapColors, setMapColors({ value: newMapColors })) expect(result).toEqual(newMapColors) }) @@ -20,7 +13,7 @@ describe("mapColors", () => { it("should update mapColors with partial mapColors object", () => { const oldMapColors = { ...defaultMapColors } - const result = mapColors(oldMapColors, setMapColors({ positive: "ABCDEF" } as MapColors)) + const result = mapColors(oldMapColors, setMapColors({ value: { positive: "ABCDEF" } })) expect(Object.values(result)).toHaveLength(12) expect(result.positive).toEqual("ABCDEF") diff --git a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.ts index e8571bc1e0..50f871c94f 100644 --- a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.reducer.ts @@ -1,27 +1,26 @@ +import { createReducer, on } from "@ngrx/store" import { MapColors } from "../../../../codeCharta.model" -import { defaultMapColors, MapColorsAction, MapColorsActions, setMapColors } from "./mapColors.actions" +import { invertColorRange, invertDeltaColors, setMapColors } from "./mapColors.actions" +import { mergeState } from "../../util/setState.reducer.factory" -export function mapColors(state: MapColors = defaultMapColors, action: MapColorsAction) { - if (isSetMapColorsAction(action)) { - return { ...state, ...action.payload } - } - if (action.type === MapColorsActions.INVERT_COLOR_RANGE) { - return { - ...state, - positive: state.negative, - negative: state.positive - } - } - if (action.type === MapColorsActions.INVERT_DELTA_COLORS) { - return { - ...state, - positiveDelta: state.negativeDelta, - negativeDelta: state.positiveDelta - } - } - return state +export const defaultMapColors: MapColors = { + positive: "#69AE40", + neutral: "#ddcc00", + negative: "#820E0E", + selected: "#EB8319", + positiveDelta: "#64d051", + negativeDelta: "#ff0E0E", + base: "#666666", + flat: "#AAAAAA", + markingColors: ["#FF1D8E", "#1d8eff", "#1DFFFF", "#8eff1d", "#8e1dff"], + incomingEdge: "#00ffff", + outgoingEdge: "#ff00ff", + labelColorAndAlpha: { rgb: "#e0e0e0", alpha: 0.7 } } -function isSetMapColorsAction(action: MapColorsAction): action is ReturnType { - return action.type === MapColorsActions.SET_MAP_COLORS -} +export const mapColors = createReducer( + defaultMapColors, + on(setMapColors, mergeState(defaultMapColors)), + on(invertColorRange, state => ({ ...state, positive: state.negative, negative: state.positive })), + on(invertDeltaColors, state => ({ ...state, positiveDelta: state.negativeDelta, negativeDelta: state.positiveDelta })) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.selector.ts b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.selector.ts index a4df5bce10..7d40980305 100644 --- a/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/mapColors/mapColors.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { appSettingsSelector } from "../appSettings.selector" -export const mapColorsSelector = (state: CcState) => state.appSettings.mapColors +export const mapColorsSelector = createSelector(appSettingsSelector, appSettings => appSettings.mapColors) diff --git a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions.ts b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions.ts index 34c942efa1..71fcba0425 100644 --- a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum MaxTreeMapFilesActions { - SET_MAX_TREE_MAP_FILES = "SET_MAX_TREE_MAP_FILES" -} - -export interface SetMaxTreeMapFilesAction extends CCAction { - type: MaxTreeMapFilesActions.SET_MAX_TREE_MAP_FILES - payload: number -} - -export type MaxTreeMapFilesAction = SetMaxTreeMapFilesAction - -export function setMaxTreeMapFiles(maxTreeMapFiles: number = defaultMaxTreeMapFiles): SetMaxTreeMapFilesAction { - return { - type: MaxTreeMapFilesActions.SET_MAX_TREE_MAP_FILES, - payload: maxTreeMapFiles - } -} - -export const defaultMaxTreeMapFiles = 100 +export const setMaxTreeMapFiles = createAction("SET_MAX_TREE_MAP_FILES", props<{ value: number }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.spec.ts index 171bcce96c..93ddefe0a3 100644 --- a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.spec.ts @@ -1,26 +1,10 @@ import { maxTreeMapFiles } from "./maxTreeMapFiles.reducer" -import { MaxTreeMapFilesAction, setMaxTreeMapFiles } from "./maxTreeMapFiles.actions" +import { setMaxTreeMapFiles } from "./maxTreeMapFiles.actions" describe("maxTreeMapFiles", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = maxTreeMapFiles(undefined, {} as MaxTreeMapFilesAction) + it("should set new maxTreeMapFiles", () => { + const result = maxTreeMapFiles(100, setMaxTreeMapFiles({ value: 200 })) - expect(result).toEqual(100) - }) - }) - - describe("Action: SET_MAX_TREE_MAP_FILES", () => { - it("should set new maxTreeMapFiles", () => { - const result = maxTreeMapFiles(100, setMaxTreeMapFiles(200)) - - expect(result).toEqual(200) - }) - - it("should set default maxTreeMapFiles", () => { - const result = maxTreeMapFiles(200, setMaxTreeMapFiles()) - - expect(result).toEqual(100) - }) + expect(result).toEqual(200) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.ts index 8e53206cde..ffe342ac9d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.reducer.ts @@ -1,10 +1,6 @@ -import { MaxTreeMapFilesAction, MaxTreeMapFilesActions, setMaxTreeMapFiles } from "./maxTreeMapFiles.actions" +import { createReducer, on } from "@ngrx/store" +import { setMaxTreeMapFiles } from "./maxTreeMapFiles.actions" +import { setState } from "../../util/setState.reducer.factory" -export function maxTreeMapFiles(state: number = setMaxTreeMapFiles().payload, action: MaxTreeMapFilesAction): number { - switch (action.type) { - case MaxTreeMapFilesActions.SET_MAX_TREE_MAP_FILES: - return action.payload - default: - return state - } -} +export const defaultMaxTreeMapFiles = 100 +export const maxTreeMapFiles = createReducer(defaultMaxTreeMapFiles, on(setMaxTreeMapFiles, setState(defaultMaxTreeMapFiles))) diff --git a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.selector.ts b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.selector.ts index 1a24bc4621..afcc4abbaf 100644 --- a/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const maxTreeMapFilesSelector = createSelector([appSettingsSelector], appSettings => appSettings.maxTreeMapFiles) +export const maxTreeMapFilesSelector = createSelector(appSettingsSelector, appSettings => appSettings.maxTreeMapFiles) diff --git a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions.ts b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions.ts index fe0eb26eb5..d20394e239 100644 --- a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions.ts @@ -1,23 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum ResetCameraIfNewFileIsLoadedActions { - SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED = "SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED" -} - -export interface SetResetCameraIfNewFileIsLoadedAction extends CCAction { - type: ResetCameraIfNewFileIsLoadedActions.SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED - payload: boolean -} - -export type ResetCameraIfNewFileIsLoadedAction = SetResetCameraIfNewFileIsLoadedAction - -export function setResetCameraIfNewFileIsLoaded( - resetCameraIfNewFileIsLoaded: boolean = defaultResetIfNewFileIsLoaded -): SetResetCameraIfNewFileIsLoadedAction { - return { - type: ResetCameraIfNewFileIsLoadedActions.SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED, - payload: resetCameraIfNewFileIsLoaded - } -} - -export const defaultResetIfNewFileIsLoaded = true +export const setResetCameraIfNewFileIsLoaded = createAction("SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.spec.ts index 679509248c..934acb9aa6 100644 --- a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.spec.ts @@ -1,26 +1,10 @@ import { resetCameraIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded.reducer" -import { ResetCameraIfNewFileIsLoadedAction, setResetCameraIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded.actions" +import { setResetCameraIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded.actions" describe("resetCameraIfNewFileIsLoaded", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = resetCameraIfNewFileIsLoaded(undefined, {} as ResetCameraIfNewFileIsLoadedAction) + it("should set new resetCameraIfNewFileIsLoaded", () => { + const result = resetCameraIfNewFileIsLoaded(true, setResetCameraIfNewFileIsLoaded({ value: false })) - expect(result).toBeTruthy() - }) - }) - - describe("Action: SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED", () => { - it("should set new resetCameraIfNewFileIsLoaded", () => { - const result = resetCameraIfNewFileIsLoaded(true, setResetCameraIfNewFileIsLoaded(false)) - - expect(result).toBeFalsy() - }) - - it("should set default resetCameraIfNewFileIsLoaded", () => { - const result = resetCameraIfNewFileIsLoaded(false, setResetCameraIfNewFileIsLoaded()) - - expect(result).toBeTruthy() - }) + expect(result).toBeFalsy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.ts index 71019b46ec..f3499bb9ae 100644 --- a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.reducer.ts @@ -1,17 +1,9 @@ -import { - ResetCameraIfNewFileIsLoadedAction, - ResetCameraIfNewFileIsLoadedActions, - setResetCameraIfNewFileIsLoaded -} from "./resetCameraIfNewFileIsLoaded.actions" +import { createReducer, on } from "@ngrx/store" +import { setResetCameraIfNewFileIsLoaded } from "./resetCameraIfNewFileIsLoaded.actions" +import { setState } from "../../util/setState.reducer.factory" -export function resetCameraIfNewFileIsLoaded( - state = setResetCameraIfNewFileIsLoaded().payload, - action: ResetCameraIfNewFileIsLoadedAction -) { - switch (action.type) { - case ResetCameraIfNewFileIsLoadedActions.SET_RESET_CAMERA_IF_NEW_FILE_IS_LOADED: - return action.payload - default: - return state - } -} +export const defaultResetCameraIfNewFileIsLoaded = true +export const resetCameraIfNewFileIsLoaded = createReducer( + defaultResetCameraIfNewFileIsLoaded, + on(setResetCameraIfNewFileIsLoaded, setState(defaultResetCameraIfNewFileIsLoaded)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector.ts b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector.ts index fc73b586bf..26b082c69e 100644 --- a/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" export const resetCameraIfNewFileIsLoadedSelector = createSelector( - [appSettingsSelector], + appSettingsSelector, appSettings => appSettings.resetCameraIfNewFileIsLoaded ) diff --git a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.actions.ts b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.actions.ts index c872248adb..ba61aad865 100644 --- a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.actions.ts @@ -1,28 +1,4 @@ -import { Vector3 } from "three" -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { Scaling } from "../../../../codeCharta.model" -export type Scaling = { - x: number - y: number - z: number -} - -export enum ScalingActions { - SET_SCALING = "SET_SCALING" -} - -export interface SetScalingAction extends CCAction { - type: ScalingActions.SET_SCALING - payload: Partial -} - -export type ScalingAction = SetScalingAction - -export function setScaling(scaling: Partial = defaultScaling): SetScalingAction { - return { - type: ScalingActions.SET_SCALING, - payload: scaling - } -} - -export const defaultScaling = { x: 1, y: 1, z: 1 } +export const setScaling = createAction("SET_SCALING", props<{ value: Partial }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.spec.ts index 1e93ff33ce..99d5a9a342 100644 --- a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.spec.ts @@ -1,26 +1,16 @@ import { scaling } from "./scaling.reducer" -import { ScalingAction, setScaling } from "./scaling.actions" +import { setScaling } from "./scaling.actions" describe("scaling", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = scaling(undefined, {} as ScalingAction) + it("should set new scaling", () => { + const result = scaling({ x: 1, y: 1, z: 1 }, setScaling({ value: { x: 2, y: 2, z: 2 } })) - expect(result).toEqual({ x: 1, y: 1, z: 1 }) - }) + expect(result).toEqual({ x: 2, y: 2, z: 2 }) }) - describe("Action: SET_SCALING", () => { - it("should set new scaling", () => { - const result = scaling({ x: 1, y: 1, z: 1 }, setScaling({ x: 2, y: 2, z: 2 })) + it("should update partial scaling", () => { + const result = scaling({ x: 2, y: 2, z: 2 }, setScaling({ value: { y: 1 } })) - expect(result).toEqual({ x: 2, y: 2, z: 2 }) - }) - - it("should update partial scaling", () => { - const result = scaling({ x: 2, y: 2, z: 2 }, setScaling({ y: 1 })) - - expect(result).toEqual({ x: 2, y: 1, z: 2 }) - }) + expect(result).toEqual({ x: 2, y: 1, z: 2 }) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.ts index 1021ff2d60..3bb89400eb 100644 --- a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.reducer.ts @@ -1,11 +1,7 @@ -import { defaultScaling, Scaling, ScalingAction, ScalingActions } from "./scaling.actions" +import { createReducer, on } from "@ngrx/store" +import { setScaling } from "./scaling.actions" +import { Scaling } from "../../../../codeCharta.model" +import { mergeState } from "../../util/setState.reducer.factory" -export function scaling(state: Scaling = defaultScaling, action: ScalingAction): Scaling { - switch (action.type) { - case ScalingActions.SET_SCALING: - return { ...state, ...action.payload } - - default: - return state - } -} +export const defaultScaling: Scaling = { x: 1, y: 1, z: 1 } +export const scaling = createReducer(defaultScaling, on(setScaling, mergeState(defaultScaling))) diff --git a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.selector.ts b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.selector.ts index 2e90e6b50f..85998b0ac9 100644 --- a/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/scaling/scaling.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const scalingSelector = createSelector([appSettingsSelector], appSettings => appSettings.scaling) +export const scalingSelector = createSelector(appSettingsSelector, appSettings => appSettings.scaling) diff --git a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.actions.ts b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.actions.ts index a554ae437a..44cff50c1d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.actions.ts @@ -1,21 +1,4 @@ -import { CCAction, SharpnessMode } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { SharpnessMode } from "../../../../codeCharta.model" -export enum SharpnessModeActions { - SET_SHARPNESS_MODE = "SET_SHARPNESS_MODE" -} - -export interface SetSharpnessModeAction extends CCAction { - type: SharpnessModeActions.SET_SHARPNESS_MODE - payload: SharpnessMode -} - -export type SharpnessModeAction = SetSharpnessModeAction - -export function setSharpnessMode(sharpnessMode: SharpnessMode = defaultSharpnessMode): SetSharpnessModeAction { - return { - type: SharpnessModeActions.SET_SHARPNESS_MODE, - payload: sharpnessMode - } -} - -export const defaultSharpnessMode: SharpnessMode = SharpnessMode.Standard +export const setSharpnessMode = createAction("SET_SHARPNESS_MODE", props<{ value: SharpnessMode }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.spec.ts index 78ff813cab..73f0df6c8c 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.spec.ts @@ -1,27 +1,11 @@ import { sharpnessMode } from "./sharpnessMode.reducer" -import { SharpnessModeAction, setSharpnessMode } from "./sharpnessMode.actions" +import { setSharpnessMode } from "./sharpnessMode.actions" import { SharpnessMode } from "../../../../codeCharta.model" describe("sharpnessMode", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = sharpnessMode(undefined, {} as SharpnessModeAction) + it("should set new sharpness", () => { + const result = sharpnessMode(SharpnessMode.Standard, setSharpnessMode({ value: SharpnessMode.PixelRatioAA })) - expect(result).toEqual(SharpnessMode.Standard) - }) - }) - - describe("Action: setSharpnessMode", () => { - it("should set new sharpness", () => { - const result = sharpnessMode(SharpnessMode.Standard, setSharpnessMode(SharpnessMode.PixelRatioAA)) - - expect(result).toEqual(SharpnessMode.PixelRatioAA) - }) - - it("should set default panelSelection", () => { - const result = sharpnessMode(SharpnessMode.PixelRatioAA, setSharpnessMode()) - - expect(result).toEqual(SharpnessMode.Standard) - }) + expect(result).toEqual(SharpnessMode.PixelRatioAA) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.ts index 39151b8c2f..f88cc41a13 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.reducer.ts @@ -1,11 +1,7 @@ -import { SharpnessModeAction, SharpnessModeActions, setSharpnessMode } from "./sharpnessMode.actions" +import { createReducer, on } from "@ngrx/store" import { SharpnessMode } from "../../../../codeCharta.model" +import { setSharpnessMode } from "./sharpnessMode.actions" +import { setState } from "../../util/setState.reducer.factory" -export function sharpnessMode(state: SharpnessMode = setSharpnessMode().payload, action: SharpnessModeAction): SharpnessMode { - switch (action.type) { - case SharpnessModeActions.SET_SHARPNESS_MODE: - return action.payload - default: - return state - } -} +export const defaultSharpnessMode = SharpnessMode.Standard +export const sharpnessMode = createReducer(defaultSharpnessMode, on(setSharpnessMode, setState(defaultSharpnessMode))) diff --git a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.selector.ts b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.selector.ts index d81afc689d..1cfcf4c6cb 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sharpnessMode/sharpnessMode.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const sharpnessModeSelector = createSelector([appSettingsSelector], appSettings => appSettings.sharpnessMode) +export const sharpnessModeSelector = createSelector(appSettingsSelector, appSettings => appSettings.sharpnessMode) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions.ts index b6524f9e4c..5572c64090 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions.ts @@ -1,23 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum ShowMetricLabelNameValueActions { - SET_SHOW_METRIC_LABEL_NAME_VALUE = "SET_SHOW_METRIC_LABEL_NAME_VALUE" -} - -export interface SetShowMetricLabelNameValueAction extends Action { - type: ShowMetricLabelNameValueActions.SET_SHOW_METRIC_LABEL_NAME_VALUE - payload: boolean -} - -export type ShowMetricLabelNameValueAction = SetShowMetricLabelNameValueAction - -export function setShowMetricLabelNameValue( - showMetricLabelNameValue: boolean = defaultShowMetricLabelNameValue -): SetShowMetricLabelNameValueAction { - return { - type: ShowMetricLabelNameValueActions.SET_SHOW_METRIC_LABEL_NAME_VALUE, - payload: showMetricLabelNameValue - } -} - -export const defaultShowMetricLabelNameValue = false +export const setShowMetricLabelNameValue = createAction("SET_SHOW_METRIC_LABEL_NAME_VALUE", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.spec.ts index cab0d98067..5698b64db1 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.spec.ts @@ -1,26 +1,10 @@ import { showMetricLabelNameValue } from "./showMetricLabelNameValue.reducer" -import { ShowMetricLabelNameValueAction, setShowMetricLabelNameValue } from "./showMetricLabelNameValue.actions" +import { setShowMetricLabelNameValue } from "./showMetricLabelNameValue.actions" describe("showMetricLabelNameValue", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = showMetricLabelNameValue(undefined, {} as ShowMetricLabelNameValueAction) + it("should set new showMetricLabelNameValue", () => { + const result = showMetricLabelNameValue(true, setShowMetricLabelNameValue({ value: false })) - expect(result).toEqual(false) - }) - }) - - describe("Action: SET_SHOW_METRIC_LABEL_NAME_VALUE", () => { - it("should set new showMetricLabelNameValue", () => { - const result = showMetricLabelNameValue(true, setShowMetricLabelNameValue(false)) - - expect(result).toEqual(false) - }) - - it("should set default showMetricLabelNameValue", () => { - const result = showMetricLabelNameValue(false, setShowMetricLabelNameValue()) - - expect(result).toEqual(false) - }) + expect(result).toEqual(false) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.ts index e98d37780b..a8d193364d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.reducer.ts @@ -1,14 +1,9 @@ -import { - ShowMetricLabelNameValueAction, - ShowMetricLabelNameValueActions, - setShowMetricLabelNameValue -} from "./showMetricLabelNameValue.actions" +import { createReducer, on } from "@ngrx/store" +import { setShowMetricLabelNameValue } from "./showMetricLabelNameValue.actions" +import { setState } from "../../util/setState.reducer.factory" -export function showMetricLabelNameValue(state = setShowMetricLabelNameValue().payload, action: ShowMetricLabelNameValueAction) { - switch (action.type) { - case ShowMetricLabelNameValueActions.SET_SHOW_METRIC_LABEL_NAME_VALUE: - return action.payload - default: - return state - } -} +export const defaultShowMetricLabelNameValue = false +export const showMetricLabelNameValue = createReducer( + defaultShowMetricLabelNameValue, + on(setShowMetricLabelNameValue, setState(defaultShowMetricLabelNameValue)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.selector.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.selector.ts index 687dfb87ca..3076b1c33d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const showMetricLabelNodeValueSelector = createSelector([appSettingsSelector], appSettings => appSettings.showMetricLabelNameValue) +export const showMetricLabelNodeValueSelector = createSelector(appSettingsSelector, appSettings => appSettings.showMetricLabelNameValue) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions.ts index a89e871c2b..03dda2d344 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions.ts @@ -1,23 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum ShowMetricLabelNodeNameActions { - SET_SHOW_METRIC_LABEL_NODE_NAME = "SET_SHOW_METRIC_LABEL_NODE_NAME" -} - -export interface SetShowMetricLabelNodeNameAction extends Action { - type: ShowMetricLabelNodeNameActions.SET_SHOW_METRIC_LABEL_NODE_NAME - payload: boolean -} - -export type ShowMetricLabelNodeNameAction = SetShowMetricLabelNodeNameAction - -export function setShowMetricLabelNodeName( - showMetricLabelNodeName: boolean = defaultShowMetricLabelNodeName -): SetShowMetricLabelNodeNameAction { - return { - type: ShowMetricLabelNodeNameActions.SET_SHOW_METRIC_LABEL_NODE_NAME, - payload: showMetricLabelNodeName - } -} - -export const defaultShowMetricLabelNodeName = true +export const setShowMetricLabelNodeName = createAction("SET_SHOW_METRIC_LABEL_NODE_NAME", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.spec.ts index d3770f6805..8c5805b4a8 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.spec.ts @@ -1,26 +1,10 @@ import { showMetricLabelNodeName } from "./showMetricLabelNodeName.reducer" -import { ShowMetricLabelNodeNameAction, setShowMetricLabelNodeName } from "./showMetricLabelNodeName.actions" +import { setShowMetricLabelNodeName } from "./showMetricLabelNodeName.actions" describe("showMetricLabelNodeName", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = showMetricLabelNodeName(undefined, {} as ShowMetricLabelNodeNameAction) + it("should set new showMetricLabelNodeName", () => { + const result = showMetricLabelNodeName(true, setShowMetricLabelNodeName({ value: false })) - expect(result).toEqual(true) - }) - }) - - describe("Action: SET_SHOW_METRIC_LABEL_NODE_NAME", () => { - it("should set new showMetricLabelNodeName", () => { - const result = showMetricLabelNodeName(true, setShowMetricLabelNodeName(false)) - - expect(result).toEqual(false) - }) - - it("should set default showMetricLabelNodeName", () => { - const result = showMetricLabelNodeName(false, setShowMetricLabelNodeName()) - - expect(result).toEqual(true) - }) + expect(result).toEqual(false) }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.ts index 26ca7f0247..f343c56944 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.reducer.ts @@ -1,14 +1,9 @@ -import { - ShowMetricLabelNodeNameAction, - ShowMetricLabelNodeNameActions, - setShowMetricLabelNodeName -} from "./showMetricLabelNodeName.actions" +import { createReducer, on } from "@ngrx/store" +import { setShowMetricLabelNodeName } from "./showMetricLabelNodeName.actions" +import { setState } from "../../util/setState.reducer.factory" -export function showMetricLabelNodeName(state = setShowMetricLabelNodeName().payload, action: ShowMetricLabelNodeNameAction) { - switch (action.type) { - case ShowMetricLabelNodeNameActions.SET_SHOW_METRIC_LABEL_NODE_NAME: - return action.payload - default: - return state - } -} +export const defaultShowMetricLabelNodeName = true +export const showMetricLabelNodeName = createReducer( + defaultShowMetricLabelNodeName, + on(setShowMetricLabelNodeName, setState(defaultShowMetricLabelNodeName)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.selector.ts b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.selector.ts index f3f2e72558..72a66a2500 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const showMetricLabelNodeNameSelector = createSelector([appSettingsSelector], appSettings => appSettings.showMetricLabelNodeName) +export const showMetricLabelNodeNameSelector = createSelector(appSettingsSelector, appSettings => appSettings.showMetricLabelNodeName) diff --git a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions.ts b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions.ts index da3b512407..ff7026b87d 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.actions.ts @@ -1,23 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum ShowOnlyBuildingsWithEdgesActions { - SET_SHOW_ONLY_BUILDINGS_WITH_EDGES = "SET_SHOW_ONLY_BUILDINGS_WITH_EDGES" -} - -export interface SetShowOnlyBuildingsWithEdgesAction extends CCAction { - type: ShowOnlyBuildingsWithEdgesActions.SET_SHOW_ONLY_BUILDINGS_WITH_EDGES - payload: boolean -} - -export type ShowOnlyBuildingsWithEdgesAction = SetShowOnlyBuildingsWithEdgesAction - -export function setShowOnlyBuildingsWithEdges( - showOnlyBuildingsWithEdges: boolean = defaultShowOnlyBuildingsWithEdges -): SetShowOnlyBuildingsWithEdgesAction { - return { - type: ShowOnlyBuildingsWithEdgesActions.SET_SHOW_ONLY_BUILDINGS_WITH_EDGES, - payload: showOnlyBuildingsWithEdges - } -} - -export const defaultShowOnlyBuildingsWithEdges = false +export const setShowOnlyBuildingsWithEdges = createAction("SET_SHOW_ONLY_BUILDINGS_WITH_EDGES", props<{ value: boolean }>()) diff --git a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.spec.ts index 28b4f94568..4ef3ae5e8b 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.spec.ts @@ -1,26 +1,10 @@ import { showOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges.reducer" -import { ShowOnlyBuildingsWithEdgesAction, setShowOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges.actions" +import { setShowOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges.actions" describe("showOnlyBuildingsWithEdges", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = showOnlyBuildingsWithEdges(undefined, {} as ShowOnlyBuildingsWithEdgesAction) + it("should set new showOnlyBuildingsWithEdges", () => { + const result = showOnlyBuildingsWithEdges(false, setShowOnlyBuildingsWithEdges({ value: true })) - expect(result).toBeFalsy() - }) - }) - - describe("Action: SET_SHOW_ONLY_BUILDINGS_WITH_EDGES", () => { - it("should set new showOnlyBuildingsWithEdges", () => { - const result = showOnlyBuildingsWithEdges(false, setShowOnlyBuildingsWithEdges(true)) - - expect(result).toBeTruthy() - }) - - it("should set default showOnlyBuildingsWithEdges", () => { - const result = showOnlyBuildingsWithEdges(true, setShowOnlyBuildingsWithEdges()) - - expect(result).toBeFalsy() - }) + expect(result).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.ts index 58dfedead7..6e05c26647 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.reducer.ts @@ -1,14 +1,9 @@ -import { - setShowOnlyBuildingsWithEdges, - ShowOnlyBuildingsWithEdgesAction, - ShowOnlyBuildingsWithEdgesActions -} from "./showOnlyBuildingsWithEdges.actions" +import { createReducer, on } from "@ngrx/store" +import { setShowOnlyBuildingsWithEdges } from "./showOnlyBuildingsWithEdges.actions" +import { setState } from "../../util/setState.reducer.factory" -export function showOnlyBuildingsWithEdges(state = setShowOnlyBuildingsWithEdges().payload, action: ShowOnlyBuildingsWithEdgesAction) { - switch (action.type) { - case ShowOnlyBuildingsWithEdgesActions.SET_SHOW_ONLY_BUILDINGS_WITH_EDGES: - return action.payload - default: - return state - } -} +export const defaultShowOnlyBuildingsWithEdges = false +export const showOnlyBuildingsWithEdges = createReducer( + defaultShowOnlyBuildingsWithEdges, + on(setShowOnlyBuildingsWithEdges, setState(defaultShowOnlyBuildingsWithEdges)) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector.ts b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector.ts index cd3e729c89..75d092845a 100644 --- a/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector.ts @@ -1,7 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appSettingsSelector } from "../appSettings.selector" -export const showOnlyBuildingsWithEdgesSelector = createSelector( - [appSettingsSelector], - appSettings => appSettings.showOnlyBuildingsWithEdges -) +export const showOnlyBuildingsWithEdgesSelector = createSelector(appSettingsSelector, appSettings => appSettings.showOnlyBuildingsWithEdges) diff --git a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions.ts b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions.ts index 40721e5835..a4795848e2 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions.ts @@ -1,32 +1,4 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum SortingOrderAscendingActions { - SET_SORTING_ORDER_ASCENDING = "SET_SORTING_ORDER_ASCENDING", - TOGGLE_SORTING_ORDER_ASCENDING = "TOGGLE_SORTING_ORDER_ASCENDING" -} - -export interface SetSortingOrderAscendingAction extends Action { - type: SortingOrderAscendingActions.SET_SORTING_ORDER_ASCENDING - payload: boolean -} - -export type SortingOrderAscendingAction = SetSortingOrderAscendingAction - -export const defaultSortingOrderAscending = true - -export function setSortingOrderAscending(sortingOrderAscending: boolean = defaultSortingOrderAscending): SetSortingOrderAscendingAction { - return { - type: SortingOrderAscendingActions.SET_SORTING_ORDER_ASCENDING, - payload: sortingOrderAscending - } -} - -export interface ToggleSortingOrderAscendingAction extends Action { - type: SortingOrderAscendingActions.TOGGLE_SORTING_ORDER_ASCENDING -} - -export function toggleSortingOrderAscending(): ToggleSortingOrderAscendingAction { - return { - type: SortingOrderAscendingActions.TOGGLE_SORTING_ORDER_ASCENDING - } -} +export const setSortingOrderAscending = createAction("SET_SORTING_ORDER_ASCENDING", props<{ value: boolean }>()) +export const toggleSortingOrderAscending = createAction("TOGGLE_SORTING_ORDER_ASCENDING") diff --git a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.spec.ts b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.spec.ts index ba68b89d30..c3f942206e 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.spec.ts @@ -1,18 +1,10 @@ import { sortingOrderAscending } from "./sortingOrderAscending.reducer" -import { SortingOrderAscendingAction, setSortingOrderAscending, toggleSortingOrderAscending } from "./sortingOrderAscending.actions" +import { setSortingOrderAscending, toggleSortingOrderAscending } from "./sortingOrderAscending.actions" describe("sortingOrderAscending", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = sortingOrderAscending(undefined, {} as SortingOrderAscendingAction) - - expect(result).toEqual(true) - }) - }) - describe("Action: SET_SORTING_ORDER_ASCENDING", () => { it("should set new sortingOrderAscending", () => { - const result = sortingOrderAscending(false, setSortingOrderAscending(true)) + const result = sortingOrderAscending(false, setSortingOrderAscending({ value: true })) expect(result).toEqual(true) }) @@ -20,7 +12,7 @@ describe("sortingOrderAscending", () => { describe("Action: TOGGLE_SORTING_ORDER_ASCENDING", () => { it("should toggle state", () => { - const result = sortingOrderAscending(false, setSortingOrderAscending(true)) + const result = sortingOrderAscending(false, setSortingOrderAscending({ value: true })) const toggledResult = sortingOrderAscending(result, toggleSortingOrderAscending()) expect(toggledResult).toBe(!result) diff --git a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.ts b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.ts index 071b87d36b..122442facf 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.reducer.ts @@ -1,20 +1,10 @@ -import { - SortingOrderAscendingAction, - SortingOrderAscendingActions, - setSortingOrderAscending, - ToggleSortingOrderAscendingAction -} from "./sortingOrderAscending.actions" +import { createReducer, on } from "@ngrx/store" +import { setSortingOrderAscending, toggleSortingOrderAscending } from "./sortingOrderAscending.actions" +import { setState } from "../../util/setState.reducer.factory" -export function sortingOrderAscending( - state = setSortingOrderAscending().payload, - action: SortingOrderAscendingAction | ToggleSortingOrderAscendingAction -) { - switch (action.type) { - case SortingOrderAscendingActions.SET_SORTING_ORDER_ASCENDING: - return action.payload - case SortingOrderAscendingActions.TOGGLE_SORTING_ORDER_ASCENDING: - return !state - default: - return state - } -} +export const defaultSortingOrderAscending = true +export const sortingOrderAscending = createReducer( + defaultSortingOrderAscending, + on(setSortingOrderAscending, setState(defaultSortingOrderAscending)), + on(toggleSortingOrderAscending, state => !state) +) diff --git a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector.ts b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector.ts index 17a0d5e863..0cac51f485 100644 --- a/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector.ts +++ b/visualization/app/codeCharta/state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { appSettingsSelector } from "../appSettings.selector" -export const sortingOrderAscendingSelector = (state: CcState): boolean => state.appSettings.sortingOrderAscending +export const sortingOrderAscendingSelector = createSelector(appSettingsSelector, appSettings => appSettings.sortingOrderAscending) diff --git a/visualization/app/codeCharta/state/store/appStatus/appStatus.reducer.ts b/visualization/app/codeCharta/state/store/appStatus/appStatus.reducer.ts index aac8c1efd0..ba732e6bb0 100644 --- a/visualization/app/codeCharta/state/store/appStatus/appStatus.reducer.ts +++ b/visualization/app/codeCharta/state/store/appStatus/appStatus.reducer.ts @@ -1,13 +1,16 @@ -import { combineReducers } from "redux" +import { combineReducers } from "@ngrx/store" +import { defaultHoveredNodeId, hoveredNodeId } from "./hoveredNodeId/hoveredNodeId.reducer" +import { defaultRightClickedNodeData, rightClickedNodeData } from "./rightClickedNodeData/rightClickedNodeData.reducer" +import { defaultSelectedBuildingId, selectedBuildingId } from "./selectedBuildingId/selectedBuildingId.reducer" -import { hoveredNodeId } from "./hoveredNodeId/hoveredNodeId.reducer" -import { rightClickedNodeData } from "./rightClickedNodeData/rightClickedNodeData.reducer" -import { selectedBuildingId } from "./selectedBuildingId/selectedBuildingId.reducer" - -const appStatus = combineReducers({ +export const appStatus = combineReducers({ hoveredNodeId, selectedBuildingId, rightClickedNodeData }) -export default appStatus +export const defaultAppStatus = { + hoveredNodeId: defaultHoveredNodeId, + selectedBuildingId: defaultSelectedBuildingId, + rightClickedNodeData: defaultRightClickedNodeData +} diff --git a/visualization/app/codeCharta/state/store/appStatus/appStatus.selector.ts b/visualization/app/codeCharta/state/store/appStatus/appStatus.selector.ts index bfaa75983c..dfc10dfd11 100644 --- a/visualization/app/codeCharta/state/store/appStatus/appStatus.selector.ts +++ b/visualization/app/codeCharta/state/store/appStatus/appStatus.selector.ts @@ -1,3 +1,3 @@ -import { CcState } from "../store" +import { CcState } from "../../../codeCharta.model" export const appStatusSelector = (state: CcState) => state.appStatus diff --git a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.actions.ts b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.actions.ts index 5caa3e15fd..98842b493c 100644 --- a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.actions.ts +++ b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.actions.ts @@ -1,19 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum HoveredNodeIdActions { - SET_HOVERED_NODE_ID = "SET_HOVERED_NODE_ID" -} - -export interface SetHoveredNodeIdAction extends Action { - type: HoveredNodeIdActions.SET_HOVERED_NODE_ID - payload: number | null -} - -export type SetHoveredNodeIdPayload = SetHoveredNodeIdAction["payload"] - -export const defaultHoveredNodeId: SetHoveredNodeIdPayload = null - -export const setHoveredNodeId = (hoveredNodeId: SetHoveredNodeIdPayload = defaultHoveredNodeId): SetHoveredNodeIdAction => ({ - type: HoveredNodeIdActions.SET_HOVERED_NODE_ID, - payload: hoveredNodeId -}) +export const setHoveredNodeId = createAction("SET_HOVERED_NODE_ID", props<{ value: null | number }>()) diff --git a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.spec.ts b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.spec.ts index d1dda3c9de..4e15c200a7 100644 --- a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.spec.ts @@ -1,12 +1,8 @@ -import { setHoveredNodeId, SetHoveredNodeIdAction, SetHoveredNodeIdPayload } from "./hoveredNodeId.actions" +import { setHoveredNodeId } from "./hoveredNodeId.actions" import { hoveredNodeId } from "./hoveredNodeId.reducer" describe("hoveredNodeId", () => { - it("should be initialized to null", () => { - expect(hoveredNodeId(undefined as SetHoveredNodeIdPayload, {} as SetHoveredNodeIdAction)).toBe(null) - }) - it("should set hovered node id", () => { - expect(hoveredNodeId(null, setHoveredNodeId(42))).toBe(42) + expect(hoveredNodeId(null, setHoveredNodeId({ value: 42 }))).toBe(42) }) }) diff --git a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.ts b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.ts index 67beb1999e..aaf793ad44 100644 --- a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.ts +++ b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.reducer.ts @@ -1,10 +1,7 @@ -import { SetHoveredNodeIdPayload, defaultHoveredNodeId, HoveredNodeIdActions, SetHoveredNodeIdAction } from "./hoveredNodeId.actions" +import { createReducer, on } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" +import { setHoveredNodeId } from "./hoveredNodeId.actions" +import { setState } from "../../util/setState.reducer.factory" -export const hoveredNodeId = (state: SetHoveredNodeIdPayload = defaultHoveredNodeId, action: SetHoveredNodeIdAction) => { - switch (action.type) { - case HoveredNodeIdActions.SET_HOVERED_NODE_ID: - return action.payload - default: - return state - } -} +export const defaultHoveredNodeId: CcState["appStatus"]["hoveredNodeId"] = null +export const hoveredNodeId = createReducer(defaultHoveredNodeId, on(setHoveredNodeId, setState(defaultHoveredNodeId))) diff --git a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.selector.ts b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.selector.ts index c4c51f61bb..992d7248c3 100644 --- a/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.selector.ts +++ b/visualization/app/codeCharta/state/store/appStatus/hoveredNodeId/hoveredNodeId.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appStatusSelector } from "../appStatus.selector" -export const hoveredNodeIdSelector = createSelector([appStatusSelector], appStatus => appStatus.hoveredNodeId) +export const hoveredNodeIdSelector = createSelector(appStatusSelector, appStatus => appStatus.hoveredNodeId) diff --git a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts index af6c732baa..91393dc781 100644 --- a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts +++ b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts @@ -1,23 +1,7 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" -export enum RightClickedNodeDataActions { - SET_RIGHT_CLICKED_NODE_DATA = "SET_RIGHT_CLICKED_NODE_DATA" -} - -export type RightClickedNodeData = { - nodeId: number - xPositionOfRightClickEvent: number - yPositionOfRightClickEvent: number -} | null - -export interface SetRightClickedNodeDataAction extends Action { - type: RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA - payload: RightClickedNodeData -} - -export const defaultRightClickedNodeData: RightClickedNodeData = null - -export const setRightClickedNodeData = (payload: RightClickedNodeData): SetRightClickedNodeDataAction => ({ - type: RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA, - payload -}) +export const setRightClickedNodeData = createAction( + "SET_RIGHT_CLICKED_NODE_DATA", + props<{ value: CcState["appStatus"]["rightClickedNodeData"] }>() +) diff --git a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts index 7d7a90a530..0ac72075ea 100644 --- a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts +++ b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts @@ -1,15 +1,9 @@ -import { - defaultRightClickedNodeData, - RightClickedNodeData, - RightClickedNodeDataActions, - SetRightClickedNodeDataAction -} from "./rightClickedNodeData.actions" +import { createReducer, on } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" +import { setRightClickedNodeData } from "./rightClickedNodeData.actions" -export const rightClickedNodeData = (state: RightClickedNodeData = defaultRightClickedNodeData, action: SetRightClickedNodeDataAction) => { - switch (action.type) { - case RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA: - return action.payload - default: - return state - } -} +export const defaultRightClickedNodeData: CcState["appStatus"]["rightClickedNodeData"] = null +export const rightClickedNodeData = createReducer( + defaultRightClickedNodeData, + on(setRightClickedNodeData, (_state, action) => action.value) +) diff --git a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts index 809be48697..d4a2d0a71b 100644 --- a/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts +++ b/visualization/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { appStatusSelector } from "../appStatus.selector" -export const rightClickedNodeDataSelector = createSelector([appStatusSelector], appStatus => appStatus.rightClickedNodeData) +export const rightClickedNodeDataSelector = createSelector(appStatusSelector, appStatus => appStatus.rightClickedNodeData) diff --git a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.actions.ts b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.actions.ts index 1a7eb91ff4..6e60beefec 100644 --- a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.actions.ts +++ b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.actions.ts @@ -1,21 +1,3 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" -export enum SelectedBuildingIdActions { - SET_SELECTED_BUILDING_ID = "SET_SELECTED_BUILDING_ID" -} - -export type SetSelectedBuildingIdPayload = number | null - -export interface SetSelectedBuildingIdAction extends Action { - type: SelectedBuildingIdActions.SET_SELECTED_BUILDING_ID - payload: SetSelectedBuildingIdPayload -} - -export const defaultSelectedBuildingId: SetSelectedBuildingIdPayload = null - -export const setSelectedBuildingId = ( - selectedBuilding: SetSelectedBuildingIdPayload = defaultSelectedBuildingId -): SetSelectedBuildingIdAction => ({ - type: SelectedBuildingIdActions.SET_SELECTED_BUILDING_ID, - payload: selectedBuilding -}) +export const setSelectedBuildingId = createAction("SET_SELECTED_BUILDING_ID", props<{ value: number | null }>()) diff --git a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.spec.ts b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.spec.ts index 9bed678ba8..48c50ebac3 100644 --- a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.spec.ts @@ -1,19 +1,9 @@ -import { setSelectedBuildingId, SetSelectedBuildingIdAction } from "./selectedBuildingId.actions" +import { setSelectedBuildingId } from "./selectedBuildingId.actions" import { selectedBuildingId } from "./selectedBuildingId.reducer" describe("selectedBuildingId", () => { - it("should set default state", () => { - const newState = selectedBuildingId(undefined, {} as SetSelectedBuildingIdAction) - expect(newState).toBe(null) - }) - it("should update state", () => { - const newState = selectedBuildingId(undefined, setSelectedBuildingId(1)) - expect(newState).toBe(1) - }) - - it("should ignore actions other than its own", () => { - const newState = selectedBuildingId(1, { type: "someType", payload: 2 } as unknown as SetSelectedBuildingIdAction) + const newState = selectedBuildingId(undefined, setSelectedBuildingId({ value: 1 })) expect(newState).toBe(1) }) }) diff --git a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.ts b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.ts index deb57141d8..541ec40453 100644 --- a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.ts +++ b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.reducer.ts @@ -1,18 +1,7 @@ -import { - SetSelectedBuildingIdPayload, - SelectedBuildingIdActions, - SetSelectedBuildingIdAction, - setSelectedBuildingId -} from "./selectedBuildingId.actions" +import { createReducer, on } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" +import { setSelectedBuildingId } from "./selectedBuildingId.actions" +import { setState } from "../../util/setState.reducer.factory" -export const selectedBuildingId = ( - state: SetSelectedBuildingIdPayload = setSelectedBuildingId().payload, - action: SetSelectedBuildingIdAction -) => { - switch (action.type) { - case SelectedBuildingIdActions.SET_SELECTED_BUILDING_ID: - return action.payload - default: - return state - } -} +export const defaultSelectedBuildingId: CcState["appStatus"]["selectedBuildingId"] = null +export const selectedBuildingId = createReducer(defaultSelectedBuildingId, on(setSelectedBuildingId, setState(defaultSelectedBuildingId))) diff --git a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.selector.ts b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.selector.ts index 932978700f..c4bba284cc 100644 --- a/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.selector.ts +++ b/visualization/app/codeCharta/state/store/appStatus/selectedBuildingId/selectedBuildingId.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { appStatusSelector } from "../appStatus.selector" -export const selectedBuildingIdSelector = (state: CcState) => state.appStatus.selectedBuildingId +export const selectedBuildingIdSelector = createSelector(appStatusSelector, appStatus => appStatus.selectedBuildingId) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.actions.ts index d18a1561cb..e0ef99273f 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum AreaMetricActions { - SET_AREA_METRIC = "SET_AREA_METRIC" -} - -export interface SetAreaMetricAction extends CCAction { - type: AreaMetricActions.SET_AREA_METRIC - payload: string -} - -export type AreaMetricAction = SetAreaMetricAction - -export function setAreaMetric(areaMetric: string = defaultAreaMetric): SetAreaMetricAction { - return { - type: AreaMetricActions.SET_AREA_METRIC, - payload: areaMetric - } -} - -export const defaultAreaMetric = null +export const setAreaMetric = createAction("SET_AREA_METRIC", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.spec.ts index 40a6589960..e9346126cd 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.spec.ts @@ -1,26 +1,10 @@ import { areaMetric } from "./areaMetric.reducer" -import { AreaMetricAction, setAreaMetric } from "./areaMetric.actions" +import { setAreaMetric } from "./areaMetric.actions" describe("areaMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = areaMetric(undefined, {} as AreaMetricAction) + it("should set new areaMetric", () => { + const result = areaMetric("mcc", setAreaMetric({ value: "another_area_metric" })) - expect(result).toBeNull() - }) - }) - - describe("Action: SET_AREA_METRIC", () => { - it("should set new areaMetric", () => { - const result = areaMetric("mcc", setAreaMetric("another_area_metric")) - - expect(result).toEqual("another_area_metric") - }) - - it("should set new areaMetric", () => { - const result = areaMetric("another_area_metric", setAreaMetric()) - - expect(result).toBeNull() - }) + expect(result).toEqual("another_area_metric") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.ts index 024caca497..6647229fa2 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.reducer.ts @@ -1,10 +1,6 @@ -import { AreaMetricAction, AreaMetricActions, setAreaMetric } from "./areaMetric.actions" +import { createReducer, on } from "@ngrx/store" +import { setAreaMetric } from "./areaMetric.actions" +import { setState } from "../../util/setState.reducer.factory" -export function areaMetric(state = setAreaMetric().payload, action: AreaMetricAction) { - switch (action.type) { - case AreaMetricActions.SET_AREA_METRIC: - return action.payload - default: - return state - } -} +export const defaultAreaMetric: null | string = null +export const areaMetric = createReducer(defaultAreaMetric, on(setAreaMetric, setState(defaultAreaMetric))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.selector.ts index d2713b430b..3ffbdc9dc6 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/areaMetric/areaMetric.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const areaMetricSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.areaMetric) +export const areaMetricSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.areaMetric) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.actions.ts index 04b5f0d31d..12866bd50c 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum ColorMetricActions { - SET_COLOR_METRIC = "SET_COLOR_METRIC" -} - -export interface SetColorMetricAction extends CCAction { - type: ColorMetricActions.SET_COLOR_METRIC - payload: string -} - -export type ColorMetricAction = SetColorMetricAction - -export function setColorMetric(colorMetric: string = defaultColorMetric): SetColorMetricAction { - return { - type: ColorMetricActions.SET_COLOR_METRIC, - payload: colorMetric - } -} - -export const defaultColorMetric = null +export const setColorMetric = createAction("SET_COLOR_METRIC", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.spec.ts index 4d7b03bcaf..bc3f9451af 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.spec.ts @@ -1,26 +1,10 @@ import { colorMetric } from "./colorMetric.reducer" -import { ColorMetricAction, setColorMetric } from "./colorMetric.actions" +import { setColorMetric } from "./colorMetric.actions" describe("colorMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = colorMetric(undefined, {} as ColorMetricAction) + it("should set new colorMetric", () => { + const result = colorMetric("mcc", setColorMetric({ value: "another_color_metric" })) - expect(result).toBeNull() - }) - }) - - describe("Action: SET_COLOR_METRIC", () => { - it("should set new colorMetric", () => { - const result = colorMetric("mcc", setColorMetric("another_color_metric")) - - expect(result).toEqual("another_color_metric") - }) - - it("should set default colorMetric", () => { - const result = colorMetric("another_color_metric", setColorMetric()) - - expect(result).toBeNull() - }) + expect(result).toEqual("another_color_metric") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.ts index 5424d205cd..423accac22 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.reducer.ts @@ -1,10 +1,6 @@ -import { ColorMetricAction, ColorMetricActions, setColorMetric } from "./colorMetric.actions" +import { createReducer, on } from "@ngrx/store" +import { setColorMetric } from "./colorMetric.actions" +import { setState } from "../../util/setState.reducer.factory" -export function colorMetric(state = setColorMetric().payload, action: ColorMetricAction) { - switch (action.type) { - case ColorMetricActions.SET_COLOR_METRIC: - return action.payload - default: - return state - } -} +export const defaultColorMetric: null | string = null +export const colorMetric = createReducer(defaultColorMetric, on(setColorMetric, setState(defaultColorMetric))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.selector.ts index c14aae93e2..6a39d16f03 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMetric/colorMetric.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const colorMetricSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.colorMetric) +export const colorMetricSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.colorMetric) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.actions.ts index 496954aa5b..ef2abe9ed5 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.actions.ts @@ -1,22 +1,4 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" import { ColorMode } from "../../../../codeCharta.model" -export enum ColorModeActions { - SET_COLOR_MODE = "SET_COLOR_MODE" -} - -export interface SetColorModeAction extends Action { - type: ColorModeActions.SET_COLOR_MODE - payload: ColorMode -} - -export type ColorModeAction = SetColorModeAction - -export function setColorMode(colorMode: ColorMode = defaultColorMode): SetColorModeAction { - return { - type: ColorModeActions.SET_COLOR_MODE, - payload: colorMode - } -} - -export const defaultColorMode: ColorMode = ColorMode.weightedGradient +export const setColorMode = createAction("SET_COLOR_MODE", props<{ value: ColorMode }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.spec.ts index 03a5df3e41..22c74ab85a 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.spec.ts @@ -1,27 +1,11 @@ import { colorMode } from "./colorMode.reducer" -import { ColorModeAction, setColorMode } from "./colorMode.actions" +import { setColorMode } from "./colorMode.actions" import { ColorMode } from "../../../../codeCharta.model" describe("colorMode", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = colorMode(undefined, {} as ColorModeAction) + it("should set new colorMode", () => { + const result = colorMode(ColorMode.weightedGradient, setColorMode({ value: ColorMode.absolute })) - expect(result).toEqual(ColorMode.weightedGradient) - }) - }) - - describe("Action: SET_COLOR_MODE", () => { - it("should set new colorMode", () => { - const result = colorMode(ColorMode.weightedGradient, setColorMode(ColorMode.absolute)) - - expect(result).toEqual(ColorMode.absolute) - }) - - it("should set default colorMode", () => { - const result = colorMode(ColorMode.absolute, setColorMode()) - - expect(result).toEqual(ColorMode.weightedGradient) - }) + expect(result).toEqual(ColorMode.absolute) }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.ts index 06099f4cb8..3d9c0e4ed4 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.reducer.ts @@ -1,10 +1,7 @@ -import { ColorModeAction, ColorModeActions, setColorMode } from "./colorMode.actions" +import { createReducer, on } from "@ngrx/store" +import { ColorMode } from "../../../../codeCharta.model" +import { setColorMode } from "./colorMode.actions" +import { setState } from "../../util/setState.reducer.factory" -export function colorMode(state = setColorMode().payload, action: ColorModeAction) { - switch (action.type) { - case ColorModeActions.SET_COLOR_MODE: - return action.payload - default: - return state - } -} +export const defaultColorMode = ColorMode.weightedGradient +export const colorMode = createReducer(defaultColorMode, on(setColorMode, setState(defaultColorMode))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.selector.ts index 29c00c3b69..0951b0b9ce 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorMode/colorMode.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const colorModeSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.colorMode) +export const colorModeSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.colorMode) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.actions.ts index 2a9483a99d..8b3c0a137f 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.actions.ts @@ -1,21 +1,4 @@ -import { CCAction, ColorRange } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { ColorRange } from "../../../../codeCharta.model" -export enum ColorRangeActions { - SET_COLOR_RANGE = "SET_COLOR_RANGE" -} - -export interface SetColorRangeAction extends CCAction { - type: ColorRangeActions.SET_COLOR_RANGE - payload: Partial -} - -export type ColorRangeAction = SetColorRangeAction - -export function setColorRange(colorRange: Partial = defaultColorRange): SetColorRangeAction { - return { - type: ColorRangeActions.SET_COLOR_RANGE, - payload: colorRange - } -} - -export const defaultColorRange: ColorRange = { from: null, to: null } +export const setColorRange = createAction("SET_COLOR_RANGE", props<{ value: Partial }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.spec.ts index 383d1d9018..da9436407e 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.spec.ts @@ -1,16 +1,10 @@ import { colorRange } from "./colorRange.reducer" -import { defaultColorRange, setColorRange } from "./colorRange.actions" +import { setColorRange } from "./colorRange.actions" describe("colorRange", () => { it("should set new colorRange", () => { - const result = colorRange({ from: 0, to: 0 }, setColorRange({ from: 21, to: 42 })) + const result = colorRange({ from: 0, to: 0 }, setColorRange({ value: { from: 21, to: 42 } })) expect(result).toEqual({ from: 21, to: 42 }) }) - - it("should set default colorRange", () => { - const result = colorRange({ from: 33, to: 66 }, setColorRange()) - - expect(result).toEqual(defaultColorRange) - }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.ts index 8c8a9727cd..f07ae9a5cc 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.reducer.ts @@ -1,10 +1,7 @@ -import { ColorRangeAction, ColorRangeActions, defaultColorRange } from "./colorRange.actions" +import { createReducer, on } from "@ngrx/store" +import { setColorRange } from "./colorRange.actions" +import { ColorRange } from "../../../../codeCharta.model" +import { mergeState } from "../../util/setState.reducer.factory" -export function colorRange(state = defaultColorRange, action: ColorRangeAction) { - switch (action.type) { - case ColorRangeActions.SET_COLOR_RANGE: - return { ...state, ...action.payload } - default: - return state - } -} +export const defaultColorRange: ColorRange = { from: 0, to: 0 } +export const colorRange = createReducer(defaultColorRange, on(setColorRange, mergeState(defaultColorRange))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.selector.ts index d88498cc36..81a38cebe9 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/colorRange.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const colorRangeSelector = createSelector([dynamicSettingsSelector], dynamicAppSettings => dynamicAppSettings.colorRange) +export const colorRangeSelector = createSelector(dynamicSettingsSelector, dynamicAppSettings => dynamicAppSettings.colorRange) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.spec.ts index 6bfcd86790..acaab4ecf2 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.spec.ts @@ -1,62 +1,51 @@ import { TestBed } from "@angular/core/testing" -import { ApplicationInitStatus } from "@angular/core" -import { Subject } from "rxjs" -import { - MetricMinMax, - selectedColorMetricDataSelector -} from "../../../selectors/accumulatedData/metricData/selectedColorMetricData.selector" -import { ActionsToken, EffectsModule } from "../../../angular-redux/effects/effects.module" -import { Store } from "../../../angular-redux/store" -import { Store as PlainStoreUsedByEffects } from "../../../store/store" +import { provideMockStore, MockStore } from "@ngrx/store/testing" +import { selectedColorMetricDataSelector } from "../../../selectors/accumulatedData/metricData/selectedColorMetricData.selector" import { ResetColorRangeEffect } from "./resetColorRange.effect" -import { Action } from "redux" -import { FilesSelectionActions } from "../../files/files.actions" -import { setColorRange } from "./colorRange.actions" +import { EffectsModule } from "@ngrx/effects" +import { provideMockActions } from "@ngrx/effects/testing" +import { BehaviorSubject } from "rxjs" +import { Action } from "@ngrx/store" +import { setStandard } from "../../files/files.actions" +import { getLastAction } from "../../../../util/testUtils/store.utils" describe("ResetColorRangeEffect", () => { - let selectedColorMetricDataSelector$ = new Subject() - let actions$ = new Subject() - const mockedStore = { - select: (selector: unknown) => { - switch (selector) { - case selectedColorMetricDataSelector: - return selectedColorMetricDataSelector$ - default: - throw new Error("selector is not mocked") - } - }, - dispatch: jest.fn() - } + let actions$: BehaviorSubject - beforeEach(async () => { - mockedStore.dispatch = jest.fn() - PlainStoreUsedByEffects.store.dispatch = mockedStore.dispatch - selectedColorMetricDataSelector$ = new Subject() - actions$ = new Subject() + beforeEach(() => { + actions$ = new BehaviorSubject({ type: "" }) TestBed.configureTestingModule({ imports: [EffectsModule.forRoot([ResetColorRangeEffect])], providers: [ - { provide: Store, useValue: mockedStore }, - { provide: ActionsToken, useValue: actions$ } + provideMockStore({ + selectors: [ + { + selector: selectedColorMetricDataSelector, + value: { minValue: 0, maxValue: 0 } + } + ] + }), + provideMockActions(() => actions$) ] }) - await TestBed.inject(ApplicationInitStatus).donePromise }) afterEach(() => { - selectedColorMetricDataSelector$.complete() actions$.complete() }) - it("should not fire when only selectedColorMetricData changed", () => { - selectedColorMetricDataSelector$.next({ minValue: 20, maxValue: 120 }) - expect(mockedStore.dispatch).not.toHaveBeenCalled() + it("should fire on file selection actions after color metric data are recalculated", async () => { + const store = TestBed.inject(MockStore) + actions$.next(setStandard({ files: [] })) + store.overrideSelector(selectedColorMetricDataSelector, { minValue: 20, maxValue: 120 }) + store.refreshState() + expect(await getLastAction(store)).toEqual({ value: { from: 53, to: 86 }, type: "SET_COLOR_RANGE" }) }) - it("should fire on file selection actions", () => { - selectedColorMetricDataSelector$.next({ minValue: 20, maxValue: 120 }) - actions$.next({ type: FilesSelectionActions.SET_STANDARD }) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setColorRange({ from: 53, to: 86 })) - expect(mockedStore.dispatch).toHaveBeenCalledTimes(1) + it("should not fire when only selectedColorMetricData changed", async () => { + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedColorMetricDataSelector, { minValue: 20, maxValue: 120 }) + store.refreshState() + expect(await getLastAction(store)).not.toEqual({ value: { from: 53, to: 86 }, type: "SET_COLOR_RANGE" }) }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.ts b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.ts index 47640362f9..a5b2987407 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.ts @@ -1,32 +1,22 @@ -import { Inject, Injectable } from "@angular/core" -import { filter, map, withLatestFrom } from "rxjs" -import { isAction, isActionOfType } from "../../../../util/reduxHelper" -import { createEffect } from "../../../angular-redux/effects/createEffect" -import { Actions, ActionsToken } from "../../../angular-redux/effects/effects.module" -import { Store } from "../../../angular-redux/store" +import { Injectable } from "@angular/core" +import { Store } from "@ngrx/store" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { map, skip, switchMap, take } from "rxjs" import { selectedColorMetricDataSelector } from "../../../selectors/accumulatedData/metricData/selectedColorMetricData.selector" -import { FilesSelectionActions } from "../../files/files.actions" import { calculateInitialColorRange } from "./calculateInitialColorRange" -import { ColorRangeActions, setColorRange, SetColorRangeAction } from "./colorRange.actions" +import { setColorRange } from "./colorRange.actions" +import { fileActions } from "../../files/files.actions" +import { CcState } from "../../../../codeCharta.model" @Injectable() export class ResetColorRangeEffect { - private resetActions$ = this.actions$.pipe( - filter( - action => - isActionOfType(action.type, FilesSelectionActions) || - (isAction(action, ColorRangeActions.SET_COLOR_RANGE) && - action.payload.from === null && - action.payload.to === null) - ) - ) - - constructor(@Inject(ActionsToken) private actions$: Actions, private store: Store) {} + constructor(private actions$: Actions, private store: Store) {} resetColorRange$ = createEffect(() => - this.resetActions$.pipe( - withLatestFrom(this.store.select(selectedColorMetricDataSelector)), - map(([, selectedColorMetricData]) => setColorRange(calculateInitialColorRange(selectedColorMetricData))) + this.actions$.pipe( + ofType(...fileActions), + switchMap(() => this.store.select(selectedColorMetricDataSelector).pipe(skip(1), take(1))), + map(selectedColorMetricData => setColorRange({ value: calculateInitialColorRange(selectedColorMetricData) })) ) ) } diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.actions.ts index 290fe953a7..79e53414e7 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum DistributionMetricActions { - SET_DISTRIBUTION_METRIC = "SET_DISTRIBUTION_METRIC" -} - -export interface SetDistributionMetricAction extends CCAction { - type: DistributionMetricActions.SET_DISTRIBUTION_METRIC - payload: string -} - -export type DistributionMetricAction = SetDistributionMetricAction - -export function setDistributionMetric(distributionMetric: string = defaultDistributionMetric): SetDistributionMetricAction { - return { - type: DistributionMetricActions.SET_DISTRIBUTION_METRIC, - payload: distributionMetric - } -} - -export const defaultDistributionMetric = null +export const setDistributionMetric = createAction("SET_DISTRIBUTION_METRIC", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.spec.ts index cbe3f44292..d579460a6c 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.spec.ts @@ -1,26 +1,10 @@ import { distributionMetric } from "./distributionMetric.reducer" -import { DistributionMetricAction, setDistributionMetric } from "./distributionMetric.actions" +import { setDistributionMetric } from "./distributionMetric.actions" describe("distributionMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = distributionMetric(undefined, {} as DistributionMetricAction) + it("should set new distributionMetric", () => { + const result = distributionMetric("mcc", setDistributionMetric({ value: "another_distribution_metric" })) - expect(result).toBeNull() - }) - }) - - describe("Action: SET_DISTRIBUTION_METRIC", () => { - it("should set new distributionMetric", () => { - const result = distributionMetric("mcc", setDistributionMetric("another_distribution_metric")) - - expect(result).toEqual("another_distribution_metric") - }) - - it("should set new distributionMetric", () => { - const result = distributionMetric("another_distribution_metric", setDistributionMetric()) - - expect(result).toBeNull() - }) + expect(result).toEqual("another_distribution_metric") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.ts index 68f175cddc..b2048423d9 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.reducer.ts @@ -1,10 +1,6 @@ -import { DistributionMetricAction, DistributionMetricActions, setDistributionMetric } from "./distributionMetric.actions" +import { createReducer, on } from "@ngrx/store" +import { setDistributionMetric } from "./distributionMetric.actions" +import { setState } from "../../util/setState.reducer.factory" -export function distributionMetric(state = setDistributionMetric().payload, action: DistributionMetricAction) { - switch (action.type) { - case DistributionMetricActions.SET_DISTRIBUTION_METRIC: - return action.payload - default: - return state - } -} +export const defaultDistributionMetric: null | string = null +export const distributionMetric = createReducer(defaultDistributionMetric, on(setDistributionMetric, setState(defaultDistributionMetric))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.selector.ts index 5d9e5eb968..f6336cc33a 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/distributionMetric/distributionMetric.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const distributionMetricSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.distributionMetric) +export const distributionMetricSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.distributionMetric) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.actions.ts deleted file mode 100644 index 41c2da687c..0000000000 --- a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.actions.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { CCAction, DynamicSettings, RecursivePartial } from "../../../codeCharta.model" - -import { defaultColorMode } from "./colorMode/colorMode.actions" -import { defaultSortingOption } from "./sortingOption/sortingOption.actions" -import { defaultAreaMetric } from "./areaMetric/areaMetric.actions" -import { defaultColorMetric } from "./colorMetric/colorMetric.actions" -import { defaultColorRange } from "./colorRange/colorRange.actions" -import { defaultDistributionMetric } from "./distributionMetric/distributionMetric.actions" -import { defaultEdgeMetric } from "./edgeMetric/edgeMetric.actions" -import { defaultFocusedNodePath } from "./focusedNodePath/focusedNodePath.actions" -import { defaultHeightMetric } from "./heightMetric/heightMetric.actions" -import { defaultMargin } from "./margin/margin.actions" -import { defaultSearchPattern } from "./searchPattern/searchPattern.actions" - -export enum DynamicSettingsActions { - SET_DYNAMIC_SETTINGS = "SET_DYNAMIC_SETTINGS" -} - -export interface SetDynamicSettingsAction extends CCAction { - type: DynamicSettingsActions.SET_DYNAMIC_SETTINGS - payload: RecursivePartial -} - -export type DynamicSettingsAction = SetDynamicSettingsAction - -export function setDynamicSettings(dynamicSettings: RecursivePartial = defaultDynamicSettings): DynamicSettingsAction { - return { - type: DynamicSettingsActions.SET_DYNAMIC_SETTINGS, - payload: dynamicSettings - } -} - -export const defaultDynamicSettings: DynamicSettings = { - colorMode: defaultColorMode, - sortingOption: defaultSortingOption, - areaMetric: defaultAreaMetric, - heightMetric: defaultHeightMetric, - colorMetric: defaultColorMetric, - distributionMetric: defaultDistributionMetric, - edgeMetric: defaultEdgeMetric, - focusedNodePath: defaultFocusedNodePath, - searchPattern: defaultSearchPattern, - margin: defaultMargin, - colorRange: defaultColorRange -} diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.reducer.ts index c39326d77d..345febbd09 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.reducer.ts @@ -1,17 +1,17 @@ -import { colorMode } from "./colorMode/colorMode.reducer" -import { sortingOption } from "./sortingOption/sortingOption.reducer" -import { edgeMetric } from "./edgeMetric/edgeMetric.reducer" -import { colorRange } from "./colorRange/colorRange.reducer" -import { margin } from "./margin/margin.reducer" -import { searchPattern } from "./searchPattern/searchPattern.reducer" -import { focusedNodePath } from "./focusedNodePath/focusedNodePath.reducer" -import { heightMetric } from "./heightMetric/heightMetric.reducer" -import { distributionMetric } from "./distributionMetric/distributionMetric.reducer" -import { colorMetric } from "./colorMetric/colorMetric.reducer" -import { areaMetric } from "./areaMetric/areaMetric.reducer" -import { combineReducers } from "redux" +import { colorMode, defaultColorMode } from "./colorMode/colorMode.reducer" +import { defaultSortingOption, sortingOption } from "./sortingOption/sortingOption.reducer" +import { defaultEdgeMetric, edgeMetric } from "./edgeMetric/edgeMetric.reducer" +import { colorRange, defaultColorRange } from "./colorRange/colorRange.reducer" +import { defaultMargin, margin } from "./margin/margin.reducer" +import { defaultSearchPattern, searchPattern } from "./searchPattern/searchPattern.reducer" +import { defaultFocusedNodePath, focusedNodePath } from "./focusedNodePath/focusedNodePath.reducer" +import { defaultHeightMetric, heightMetric } from "./heightMetric/heightMetric.reducer" +import { defaultDistributionMetric, distributionMetric } from "./distributionMetric/distributionMetric.reducer" +import { colorMetric, defaultColorMetric } from "./colorMetric/colorMetric.reducer" +import { areaMetric, defaultAreaMetric } from "./areaMetric/areaMetric.reducer" +import { combineReducers } from "@ngrx/store" -const dynamicSettings = combineReducers({ +export const dynamicSettings = combineReducers({ colorMode, sortingOption, edgeMetric, @@ -25,4 +25,16 @@ const dynamicSettings = combineReducers({ areaMetric }) -export default dynamicSettings +export const defaultDynamicSettings = { + colorMode: defaultColorMode, + sortingOption: defaultSortingOption, + edgeMetric: defaultEdgeMetric, + colorRange: defaultColorRange, + margin: defaultMargin, + searchPattern: defaultSearchPattern, + focusedNodePath: defaultFocusedNodePath, + heightMetric: defaultHeightMetric, + distributionMetric: defaultDistributionMetric, + colorMetric: defaultColorMetric, + areaMetric: defaultAreaMetric +} diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.selector.ts index 1733ccbd2b..371d166ad4 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/dynamicSettings.selector.ts @@ -1,3 +1,3 @@ -import { CcState } from "../store" +import { CcState } from "../../../codeCharta.model" export const dynamicSettingsSelector = (state: CcState) => state.dynamicSettings diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.actions.ts index b0ba4ceaf2..843f697eaf 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum EdgeMetricActions { - SET_EDGE_METRIC = "SET_EDGE_METRIC" -} - -export interface SetEdgeMetricAction extends CCAction { - type: EdgeMetricActions.SET_EDGE_METRIC - payload: string -} - -export type EdgeMetricAction = SetEdgeMetricAction - -export function setEdgeMetric(edgeMetric: string = defaultEdgeMetric): SetEdgeMetricAction { - return { - type: EdgeMetricActions.SET_EDGE_METRIC, - payload: edgeMetric - } -} - -export const defaultEdgeMetric = null +export const setEdgeMetric = createAction("SET_EDGE_METRIC", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.spec.ts index b657730808..a083d37d28 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.spec.ts @@ -1,26 +1,10 @@ import { edgeMetric } from "./edgeMetric.reducer" -import { EdgeMetricAction, setEdgeMetric } from "./edgeMetric.actions" +import { setEdgeMetric } from "./edgeMetric.actions" describe("edgeMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = edgeMetric(undefined, {} as EdgeMetricAction) + it("should set new edgeMetric", () => { + const result = edgeMetric("mcc", setEdgeMetric({ value: "another_edge_metric" })) - expect(result).toBeNull() - }) - }) - - describe("Action: SET_EDGE_METRIC", () => { - it("should set new edgeMetric", () => { - const result = edgeMetric("mcc", setEdgeMetric("another_edge_metric")) - - expect(result).toEqual("another_edge_metric") - }) - - it("should set default edgeMetric", () => { - const result = edgeMetric("another_edge_metric", setEdgeMetric()) - - expect(result).toBeNull() - }) + expect(result).toEqual("another_edge_metric") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.ts index 53ee409c74..3f97714439 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.reducer.ts @@ -1,10 +1,6 @@ -import { EdgeMetricAction, EdgeMetricActions, setEdgeMetric } from "./edgeMetric.actions" +import { createReducer, on } from "@ngrx/store" +import { setEdgeMetric } from "./edgeMetric.actions" +import { setState } from "../../util/setState.reducer.factory" -export function edgeMetric(state = setEdgeMetric().payload, action: EdgeMetricAction) { - switch (action.type) { - case EdgeMetricActions.SET_EDGE_METRIC: - return action.payload - default: - return state - } -} +export const defaultEdgeMetric: null | string = null +export const edgeMetric = createReducer(defaultEdgeMetric, on(setEdgeMetric, setState(defaultEdgeMetric))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.selector.ts index 3362953665..505985d40c 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/edgeMetric/edgeMetric.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const edgeMetricSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.edgeMetric) +export const edgeMetricSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.edgeMetric) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/currentFocused.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/currentFocused.selector.ts index 12f787ec90..85a219292d 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/currentFocused.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/currentFocused.selector.ts @@ -1,8 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" import { focusedNodePathSelector } from "./focusedNodePath.selector" -export const currentFocusedNodePathSelector: (state: CcState) => string | undefined = createSelector( - [focusedNodePathSelector], - focusedNodePath => focusedNodePath[0] -) +export const currentFocusedNodePathSelector = createSelector(focusedNodePathSelector, focusedNodePath => focusedNodePath[0]) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.actions.ts index 54b8d5726b..8b569da9cb 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.actions.ts @@ -1,54 +1,6 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum FocusedNodePathActions { - FOCUS_NODE = "FOCUS_NODE", - UNFOCUS_NODE = "UNFOCUS_NODE", - UNFOCUS_ALL_NODES = "UNFOCUS_ALL_NODES", - SET_ALL_FOCUSED_NODES = "SET_ALL_FOCUSED_NODES" -} - -export interface FocusNodeAction extends CCAction { - type: FocusedNodePathActions.FOCUS_NODE - payload: string -} - -export interface UnfocusNodeAction extends CCAction { - type: FocusedNodePathActions.UNFOCUS_NODE -} - -export interface UnfocusAllNodesAction extends CCAction { - type: FocusedNodePathActions.UNFOCUS_ALL_NODES -} -export interface SetAllFocusedNodesAction extends CCAction { - type: FocusedNodePathActions.SET_ALL_FOCUSED_NODES - payload: string[] -} - -export type FocusedNodePathAction = FocusNodeAction | UnfocusNodeAction | UnfocusAllNodesAction | SetAllFocusedNodesAction - -export function focusNode(focusedNodePath: string): FocusNodeAction { - return { - type: FocusedNodePathActions.FOCUS_NODE, - payload: focusedNodePath - } -} - -export function unfocusNode(): UnfocusNodeAction { - return { - type: FocusedNodePathActions.UNFOCUS_NODE - } -} - -export function unfocusAllNodes(): UnfocusAllNodesAction { - return { - type: FocusedNodePathActions.UNFOCUS_ALL_NODES - } -} -export function setAllFocusedNodes(focusedNodePaths: string[]): SetAllFocusedNodesAction { - return { - type: FocusedNodePathActions.SET_ALL_FOCUSED_NODES, - payload: focusedNodePaths - } -} - -export const defaultFocusedNodePath: string[] = [] +export const setAllFocusedNodes = createAction("SET_ALL_FOCUSED_NODES", props<{ value: string[] }>()) +export const focusNode = createAction("FOCUS_NODE", props<{ value: string }>()) +export const unfocusAllNodes = createAction("UNFOCUS_ALL_NODES") +export const unfocusNode = createAction("UNFOCUS_NODE") diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.spec.ts index 00bb701541..f372374660 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.spec.ts @@ -1,30 +1,22 @@ import { focusedNodePath } from "./focusedNodePath.reducer" -import { FocusedNodePathAction, focusNode, setAllFocusedNodes, unfocusAllNodes, unfocusNode } from "./focusedNodePath.actions" +import { focusNode, setAllFocusedNodes, unfocusAllNodes, unfocusNode } from "./focusedNodePath.actions" describe("focusedNodePath", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = focusedNodePath(undefined, {} as FocusedNodePathAction) - - expect(result).toEqual([]) - }) - }) - describe("Action: FOCUS_NODE", () => { it("should set new focusedNodePath", () => { - const result = focusedNodePath([], focusNode("some/path/*.ts")) + const result = focusedNodePath([], focusNode({ value: "some/path/*.ts" })) expect(result).toEqual(["some/path/*.ts"]) }) it("should add focusedNodePath", () => { - const result = focusedNodePath(["some/path/*.ts"], focusNode("foo.ts")) + const result = focusedNodePath(["some/path/*.ts"], focusNode({ value: "foo.ts" })) expect(result).toEqual(["foo.ts", "some/path/*.ts"]) }) it("should not allow to focus root folder", () => { - const result = focusedNodePath([], focusNode("/root")) + const result = focusedNodePath([], focusNode({ value: "/root" })) expect(result).toEqual([]) }) @@ -48,7 +40,7 @@ describe("focusedNodePath", () => { describe("Action: SET_ALL_FOCUSED_NODES", () => { it("should set all focusedNodePaths", () => { - const result = focusedNodePath([], setAllFocusedNodes(["some/path/*.ts", "foo.ts"])) + const result = focusedNodePath([], setAllFocusedNodes({ value: ["some/path/*.ts", "foo.ts"] })) expect(result).toEqual(["some/path/*.ts", "foo.ts"]) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.ts index f74ea747b8..1fb64a1846 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.reducer.ts @@ -1,21 +1,12 @@ -import { defaultFocusedNodePath, FocusedNodePathAction, FocusedNodePathActions } from "./focusedNodePath.actions" +import { focusNode, setAllFocusedNodes, unfocusAllNodes, unfocusNode } from "./focusedNodePath.actions" import { fileRoot } from "../../../../services/loadFile/fileRoot" +import { createReducer, on } from "@ngrx/store" -export function focusedNodePath(state = defaultFocusedNodePath, action: FocusedNodePathAction) { - switch (action.type) { - case FocusedNodePathActions.FOCUS_NODE: - if (action.payload === fileRoot.rootPath) { - return state - } - return [action.payload, ...state] - - case FocusedNodePathActions.UNFOCUS_NODE: - return state.slice(1) - case FocusedNodePathActions.UNFOCUS_ALL_NODES: - return [] - case FocusedNodePathActions.SET_ALL_FOCUSED_NODES: - return [...action.payload] - default: - return state - } -} +export const defaultFocusedNodePath: string[] = [] +export const focusedNodePath = createReducer( + defaultFocusedNodePath, + on(setAllFocusedNodes, (_state, action) => [...action.value]), + on(unfocusAllNodes, () => []), + on(focusNode, (state, action) => (action.value === fileRoot.rootPath ? state : [action.value, ...state])), + on(unfocusNode, state => state.slice(1)) +) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.selector.ts index 431b583cda..4e1dac6646 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/focusedNodePath/focusedNodePath.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const focusedNodePathSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.focusedNodePath) +export const focusedNodePathSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.focusedNodePath) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.actions.ts index 7a0b1054ad..d4bac10b10 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum HeightMetricActions { - SET_HEIGHT_METRIC = "SET_HEIGHT_METRIC" -} - -export interface SetHeightMetricAction extends CCAction { - type: HeightMetricActions.SET_HEIGHT_METRIC - payload: string -} - -export type HeightMetricAction = SetHeightMetricAction - -export function setHeightMetric(heightMetric: string = defaultHeightMetric): SetHeightMetricAction { - return { - type: HeightMetricActions.SET_HEIGHT_METRIC, - payload: heightMetric - } -} - -export const defaultHeightMetric = null +export const setHeightMetric = createAction("SET_HEIGHT_METRIC", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.spec.ts index c5743935d0..92c947c74f 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.spec.ts @@ -1,26 +1,10 @@ import { heightMetric } from "./heightMetric.reducer" -import { HeightMetricAction, setHeightMetric } from "./heightMetric.actions" +import { setHeightMetric } from "./heightMetric.actions" describe("heightMetric", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = heightMetric(undefined, {} as HeightMetricAction) + it("should set new heightMetric", () => { + const result = heightMetric("mcc", setHeightMetric({ value: "another_height_metric" })) - expect(result).toBeNull() - }) - }) - - describe("Action: SET_HEIGHT_METRIC", () => { - it("should set new heightMetric", () => { - const result = heightMetric("mcc", setHeightMetric("another_height_metric")) - - expect(result).toEqual("another_height_metric") - }) - - it("should set default heightMetric", () => { - const result = heightMetric("another_height_metric", setHeightMetric()) - - expect(result).toBeNull() - }) + expect(result).toEqual("another_height_metric") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.ts index 1e4e1d9d55..df8bec783b 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.reducer.ts @@ -1,10 +1,6 @@ -import { HeightMetricAction, HeightMetricActions, setHeightMetric } from "./heightMetric.actions" +import { createReducer, on } from "@ngrx/store" +import { setHeightMetric } from "./heightMetric.actions" +import { setState } from "../../util/setState.reducer.factory" -export function heightMetric(state = setHeightMetric().payload, action: HeightMetricAction) { - switch (action.type) { - case HeightMetricActions.SET_HEIGHT_METRIC: - return action.payload - default: - return state - } -} +export const defaultHeightMetric: null | string = null +export const heightMetric = createReducer(defaultHeightMetric, on(setHeightMetric, setState(defaultHeightMetric))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.selector.ts index 4b182f6e9e..6753cb68a1 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/heightMetric/heightMetric.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const heightMetricSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.heightMetric) +export const heightMetricSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.heightMetric) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.actions.ts index 9be6fff027..bd63cfd2fc 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum MarginActions { - SET_MARGIN = "SET_MARGIN" -} - -export interface SetMarginAction extends CCAction { - type: MarginActions.SET_MARGIN - payload: number -} - -export type MarginAction = SetMarginAction - -export function setMargin(margin: number = defaultMargin): SetMarginAction { - return { - type: MarginActions.SET_MARGIN, - payload: margin - } -} - -export const defaultMargin = 50 +export const setMargin = createAction("SET_MARGIN", props<{ value: number }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.spec.ts index 77d29840b3..4859d446dc 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.spec.ts @@ -1,12 +1,8 @@ import { margin } from "./margin.reducer" -import { defaultMargin, MarginAction, setMargin } from "./margin.actions" +import { setMargin } from "./margin.actions" describe("margin", () => { - it("should initialize the default state", () => { - expect(margin(undefined, {} as MarginAction)).toBe(defaultMargin) - }) - it("should set new margin", () => { - expect(margin(21, setMargin(42))).toEqual(42) + expect(margin(21, setMargin({ value: 42 }))).toEqual(42) }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.ts index aadf026d41..e35641efe9 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.reducer.ts @@ -1,10 +1,6 @@ -import { defaultMargin, MarginAction, MarginActions } from "./margin.actions" +import { createReducer, on } from "@ngrx/store" +import { setMargin } from "./margin.actions" +import { setState } from "../../util/setState.reducer.factory" -export function margin(state = defaultMargin, action: MarginAction) { - switch (action.type) { - case MarginActions.SET_MARGIN: - return action.payload - default: - return state - } -} +export const defaultMargin = 50 +export const margin = createReducer(defaultMargin, on(setMargin, setState(defaultMargin))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.selector.ts index 7e34839ef3..5f5242bd6f 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/margin/margin.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const marginSelector = createSelector([dynamicSettingsSelector], dynamicSettings => dynamicSettings.margin) +export const marginSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.margin) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.actions.ts index fdc64d5766..5661d9ba4e 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.actions.ts @@ -1,21 +1,3 @@ -import { CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" -export enum SearchPatternActions { - SET_SEARCH_PATTERN = "SET_SEARCH_PATTERN" -} - -export interface SetSearchPatternAction extends CCAction { - type: SearchPatternActions.SET_SEARCH_PATTERN - payload: string -} - -export type SearchPatternAction = SetSearchPatternAction - -export function setSearchPattern(searchPattern: string = defaultSearchPattern): SetSearchPatternAction { - return { - type: SearchPatternActions.SET_SEARCH_PATTERN, - payload: searchPattern - } -} - -export const defaultSearchPattern = "" +export const setSearchPattern = createAction("SET_SEARCH_PATTERN", props<{ value: string }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.spec.ts index 0e7350330e..0431d0d8a3 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.spec.ts @@ -1,25 +1,15 @@ import { searchPattern } from "./searchPattern.reducer" -import { SearchPatternAction, setSearchPattern } from "./searchPattern.actions" +import { setSearchPattern } from "./searchPattern.actions" import { setStandard } from "../../files/files.actions" describe("searchPattern", () => { - it("should initialize the default state", () => { - const result = searchPattern(undefined, {} as SearchPatternAction) - expect(result).toEqual("") - }) - it("should set new searchPattern", () => { - const result = searchPattern("", setSearchPattern("mySearch/*.ts")) + const result = searchPattern("", setSearchPattern({ value: "mySearch/*.ts" })) expect(result).toEqual("mySearch/*.ts") }) - it("should set default searchPattern", () => { - const result = searchPattern("mySearch/*.ts", setSearchPattern()) - expect(result).toEqual("") - }) - it("should reset searchPattern on FilesSelectionActions", () => { - const result = searchPattern("mySearch/*.ts", setStandard([])) + const result = searchPattern("mySearch/*.ts", setStandard({ files: [] })) expect(result).toBe("") }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.ts index c573093e13..27cf1b087d 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.reducer.ts @@ -1,16 +1,11 @@ -import { isActionOfType } from "../../../../util/reduxHelper" -import { FilesAction, FilesSelectionActions } from "../../files/files.actions" -import { SearchPatternAction, SearchPatternActions, setSearchPattern } from "./searchPattern.actions" +import { createReducer, on } from "@ngrx/store" +import { setSearchPattern } from "./searchPattern.actions" +import { setStandard } from "../../files/files.actions" +import { setState } from "../../util/setState.reducer.factory" -export function searchPattern(state = setSearchPattern().payload, action: SearchPatternAction | FilesAction) { - if (isActionOfType(action.type, FilesSelectionActions)) { - return "" - } - - switch (action.type) { - case SearchPatternActions.SET_SEARCH_PATTERN: - return action.payload - default: - return state - } -} +export const defaultSearchPattern = "" +export const searchPattern = createReducer( + defaultSearchPattern, + on(setSearchPattern, setState(defaultSearchPattern)), + on(setStandard, () => defaultSearchPattern) +) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.selector.ts index bb772cd65e..acc72b6263 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/searchPattern/searchPattern.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const searchPatternSelector = (state: CcState) => state.dynamicSettings.searchPattern +export const searchPatternSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.searchPattern) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.actions.ts b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.actions.ts index ccc6656fd2..d4b4a1d78b 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.actions.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.actions.ts @@ -1,22 +1,4 @@ -import { Action } from "redux" +import { createAction, props } from "@ngrx/store" import { SortingOption } from "../../../../codeCharta.model" -export enum SortingOptionActions { - SET_SORTING_OPTION = "SET_SORTING_OPTION" -} - -export interface SetSortingOptionAction extends Action { - type: SortingOptionActions.SET_SORTING_OPTION - payload: SortingOption -} - -export type SortingOptionAction = SetSortingOptionAction - -export function setSortingOption(sortingOption: SortingOption = defaultSortingOption): SetSortingOptionAction { - return { - type: SortingOptionActions.SET_SORTING_OPTION, - payload: sortingOption - } -} - -export const defaultSortingOption: SortingOption = SortingOption.NAME +export const setSortingOption = createAction("SET_SORTING_OPTION", props<{ value: SortingOption }>()) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.spec.ts b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.spec.ts index b3719e5add..32b80bae98 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.spec.ts @@ -1,27 +1,11 @@ import { sortingOption } from "./sortingOption.reducer" -import { SortingOptionAction, setSortingOption } from "./sortingOption.actions" +import { setSortingOption } from "./sortingOption.actions" import { SortingOption } from "../../../../codeCharta.model" describe("sortingOption", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = sortingOption(undefined, {} as SortingOptionAction) + it("should set new sortingOption", () => { + const result = sortingOption(SortingOption.NAME, setSortingOption({ value: SortingOption.NUMBER_OF_FILES })) - expect(result).toEqual(SortingOption.NAME) - }) - }) - - describe("Action: SET_SORTING_OPTION", () => { - it("should set new sortingOption", () => { - const result = sortingOption(SortingOption.NAME, setSortingOption(SortingOption.NUMBER_OF_FILES)) - - expect(result).toEqual(SortingOption.NUMBER_OF_FILES) - }) - - it("should set default sortingOption", () => { - const result = sortingOption(SortingOption.NUMBER_OF_FILES, setSortingOption()) - - expect(result).toEqual(SortingOption.NAME) - }) + expect(result).toEqual(SortingOption.NUMBER_OF_FILES) }) }) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.ts b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.ts index 27a54666fd..f584a08fbd 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOption.reducer.ts @@ -1,10 +1,7 @@ -import { SortingOptionAction, SortingOptionActions, setSortingOption } from "./sortingOption.actions" +import { createReducer, on } from "@ngrx/store" +import { SortingOption } from "../../../../codeCharta.model" +import { setSortingOption } from "./sortingOption.actions" +import { setState } from "../../util/setState.reducer.factory" -export function sortingOption(state = setSortingOption().payload, action: SortingOptionAction) { - switch (action.type) { - case SortingOptionActions.SET_SORTING_OPTION: - return action.payload - default: - return state - } -} +export const defaultSortingOption = SortingOption.NAME +export const sortingOption = createReducer(defaultSortingOption, on(setSortingOption, setState(defaultSortingOption))) diff --git a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOrder.selector.ts b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOrder.selector.ts index 22409c0883..ba59eb6252 100644 --- a/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOrder.selector.ts +++ b/visualization/app/codeCharta/state/store/dynamicSettings/sortingOption/sortingOrder.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { dynamicSettingsSelector } from "../dynamicSettings.selector" -export const sortingOrderSelector = (state: CcState) => state.dynamicSettings.sortingOption +export const sortingOrderSelector = createSelector(dynamicSettingsSelector, dynamicSettings => dynamicSettings.sortingOption) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.action.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.action.ts index c1a2fd94e6..613e45579a 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.action.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.action.ts @@ -1,23 +1,4 @@ -import { AttributeDescriptors, CCAction } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { AttributeDescriptors } from "../../../../codeCharta.model" -export enum AttributeDescriptorsActions { - SET_ATTRIBUTE_DESCRIPTORS = "SET_ATTRIBUTE_DESCRIPTORS" -} - -export interface SetAttributeDescriptorsAction extends CCAction { - type: AttributeDescriptorsActions.SET_ATTRIBUTE_DESCRIPTORS - payload: AttributeDescriptors -} - -export type AttributeDescriptorsAction = SetAttributeDescriptorsAction - -export function setAttributeDescriptors( - attributeDescriptors: AttributeDescriptors = defaultAttributeDescriptors -): SetAttributeDescriptorsAction { - return { - type: AttributeDescriptorsActions.SET_ATTRIBUTE_DESCRIPTORS, - payload: attributeDescriptors - } -} - -export const defaultAttributeDescriptors: AttributeDescriptors = {} +export const setAttributeDescriptors = createAction("SET_ATTRIBUTE_DESCRIPTORS", props<{ value: AttributeDescriptors }>()) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.spec.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.spec.ts index 09b21e2198..50560c7912 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.spec.ts @@ -1,30 +1,21 @@ -import { attributeDescriptors } from "./attributeDescriptors.reducer" -import { STATE } from "../../../../util/dataMocks" +import { attributeDescriptors, defaultAttributeDescriptors } from "./attributeDescriptors.reducer" import { AttributeDescriptors } from "../../../../codeCharta.model" -import { AttributeDescriptorsAction, setAttributeDescriptors } from "./attributeDescriptors.action" +import { setAttributeDescriptors } from "./attributeDescriptors.action" describe("attributeDescriptors", () => { - const defaultValue: AttributeDescriptors = {} + it("should set new attributeDescriptors", () => { + const newAttributeDescriptors: AttributeDescriptors = { + rloc: { + title: "title", + description: "description", + hintLowValue: "hintLowValue", + hintHighValue: "hintHighValue", + link: "link" + } + } - describe("Default State", () => { - it("should initialize the default state", () => { - const result = attributeDescriptors(undefined, {} as AttributeDescriptorsAction) + const result = attributeDescriptors(defaultAttributeDescriptors, setAttributeDescriptors({ value: newAttributeDescriptors })) - expect(result).toEqual(defaultValue) - }) - }) - - describe("Action: SET_ATTRIBUTE_DESCRIPTORS", () => { - it("should set new attributeDescriptors", () => { - const result = attributeDescriptors(defaultValue, setAttributeDescriptors(STATE.fileSettings.attributeDescriptors)) - - expect(result).toEqual(STATE.fileSettings.attributeDescriptors) - }) - - it("should set default attributeDescriptors", () => { - const result = attributeDescriptors(STATE.fileSettings.attributeDescriptors, setAttributeDescriptors()) - - expect(result).toEqual(defaultValue) - }) + expect(result).toEqual(newAttributeDescriptors) }) }) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.ts index e3a9e192c8..ac76c413fc 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.reducer.ts @@ -1,8 +1,10 @@ -import { AttributeDescriptorsAction, AttributeDescriptorsActions, setAttributeDescriptors } from "./attributeDescriptors.action" +import { createReducer, on } from "@ngrx/store" +import { setAttributeDescriptors } from "./attributeDescriptors.action" +import { AttributeDescriptors } from "../../../../codeCharta.model" +import { setState } from "../../util/setState.reducer.factory" -export function attributeDescriptors(state = setAttributeDescriptors().payload, action: AttributeDescriptorsAction) { - if (action.type === AttributeDescriptorsActions.SET_ATTRIBUTE_DESCRIPTORS) { - return action.payload - } - return state -} +export const defaultAttributeDescriptors: AttributeDescriptors = {} +export const attributeDescriptors = createReducer( + defaultAttributeDescriptors, + on(setAttributeDescriptors, setState(defaultAttributeDescriptors)) +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector.ts index 0c06c1c4ce..e45497fae2 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { fileSettingsSelector } from "../fileSettings.selector" -export const attributeDescriptorsSelector = (state: CcState) => state.fileSettings.attributeDescriptors +export const attributeDescriptorsSelector = createSelector(fileSettingsSelector, fileSettings => fileSettings.attributeDescriptors) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.actions.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.actions.ts index 49c41cd45d..ec3e0f1fa5 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.actions.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.actions.ts @@ -1,34 +1,12 @@ -import { AttributeTypes, CCAction, AttributeTypeValue } from "../../../../codeCharta.model" - -export enum AttributeTypesActions { - SET_ATTRIBUTE_TYPES = "SET_ATTRIBUTE_TYPES", - UPDATE_ATTRIBUTE_TYPE = "UPDATE_ATTRIBUTE_TYPE" -} - -export interface SetAttributeTypesAction extends CCAction { - type: AttributeTypesActions.SET_ATTRIBUTE_TYPES - payload: AttributeTypes -} - -export interface UpdateAttributeTypeAction extends CCAction { - type: AttributeTypesActions.UPDATE_ATTRIBUTE_TYPE - payload: { category: string; name: string; type: AttributeTypeValue } -} - -export type AttributeTypesAction = SetAttributeTypesAction | UpdateAttributeTypeAction - -export function setAttributeTypes(attributeTypes: AttributeTypes = defaultAttributeTypes): SetAttributeTypesAction { - return { - type: AttributeTypesActions.SET_ATTRIBUTE_TYPES, - payload: attributeTypes - } -} - -export function updateAttributeType(category: string, name: string, type: AttributeTypeValue): UpdateAttributeTypeAction { - return { - type: AttributeTypesActions.UPDATE_ATTRIBUTE_TYPE, - payload: { category, name, type } - } -} - -export const defaultAttributeTypes: AttributeTypes = { nodes: {}, edges: {} } +import { createAction, props } from "@ngrx/store" +import { AttributeTypes, AttributeTypeValue } from "../../../../codeCharta.model" + +export const setAttributeTypes = createAction("SET_ATTRIBUTE_TYPES", props<{ value: AttributeTypes }>()) +export const updateAttributeType = createAction( + "UPDATE_ATTRIBUTE_TYPE", + props<{ + category: keyof AttributeTypes + name: string + attributeType: AttributeTypeValue + }>() +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.spec.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.spec.ts index 0bbb6ef873..5a3f7499d9 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.spec.ts @@ -1,5 +1,5 @@ import { attributeTypes } from "./attributeTypes.reducer" -import { AttributeTypesAction, setAttributeTypes, updateAttributeType } from "./attributeTypes.actions" +import { setAttributeTypes, updateAttributeType } from "./attributeTypes.actions" import { STATE } from "../../../../util/dataMocks" import { AttributeTypes, AttributeTypeValue } from "../../../../codeCharta.model" @@ -9,35 +9,15 @@ describe("attributeTypes", () => { edges: {} } - describe("Default State", () => { - it("should initialize the default state", () => { - const result = attributeTypes(undefined, {} as AttributeTypesAction) - - expect(result).toEqual(defaultValue) - }) - }) - describe("Action: SET_ATTRIBUTE_TYPES", () => { it("should set new attributeTypes", () => { - const result = attributeTypes(defaultValue, setAttributeTypes(STATE.fileSettings.attributeTypes)) + const result = attributeTypes(defaultValue, setAttributeTypes({ value: STATE.fileSettings.attributeTypes })) expect(result).toEqual(STATE.fileSettings.attributeTypes) }) - - it("should set default attributeTypes", () => { - const result = attributeTypes(STATE.fileSettings.attributeTypes, setAttributeTypes()) - - expect(result).toEqual(defaultValue) - }) }) describe("Action: UPDATE_ATTRIBUTE_TYPE", () => { - it("should set new attributeType if not existing yet", () => { - const result = attributeTypes(defaultValue, updateAttributeType("edges", "foo", AttributeTypeValue.relative)) - - expect(result).toEqual({ nodes: {}, edges: { foo: AttributeTypeValue.relative } }) - }) - it("should update existing", () => { const currentState = { nodes: { foo: AttributeTypeValue.relative }, @@ -48,7 +28,10 @@ describe("attributeTypes", () => { edges: { foo: AttributeTypeValue.relative, bar: AttributeTypeValue.absolute } } - const result = attributeTypes(currentState, updateAttributeType("edges", "foo", AttributeTypeValue.relative)) + const result = attributeTypes( + currentState, + updateAttributeType({ category: "edges", name: "foo", attributeType: AttributeTypeValue.relative }) + ) expect(result).toEqual(expected) }) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.ts index 786e1c5298..420c09a519 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.reducer.ts @@ -1,20 +1,14 @@ -import { AttributeTypesAction, AttributeTypesActions, setAttributeTypes, UpdateAttributeTypeAction } from "./attributeTypes.actions" +import { setAttributeTypes, updateAttributeType } from "./attributeTypes.actions" import { AttributeTypes } from "../../../../codeCharta.model" +import { createReducer, on } from "@ngrx/store" +import { setState } from "../../util/setState.reducer.factory" -export function attributeTypes(state = setAttributeTypes().payload, action: AttributeTypesAction) { - switch (action.type) { - case AttributeTypesActions.SET_ATTRIBUTE_TYPES: - return action.payload - case AttributeTypesActions.UPDATE_ATTRIBUTE_TYPE: - return updateAttributeType(state, action) - default: - return state - } -} - -function updateAttributeType(state: AttributeTypes, action: UpdateAttributeTypeAction): AttributeTypes { - return { +export const defaultAttributeTypes: AttributeTypes = { nodes: {}, edges: {} } +export const attributeTypes = createReducer( + defaultAttributeTypes, + on(setAttributeTypes, setState(defaultAttributeTypes)), + on(updateAttributeType, (state, action) => ({ ...state, - [action.payload.category]: { ...state[action.payload.category], [action.payload.name]: action.payload.type } - } -} + [action.category]: { ...state[action.category], [action.name]: action.attributeType } + })) +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.selector.ts index 7e97221f37..c8bc6fd4fd 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/attributeTypes/attributeTypes.selector.ts @@ -1,3 +1,4 @@ -import { CcState } from "../../store" +import { createSelector } from "@ngrx/store" +import { fileSettingsSelector } from "../fileSettings.selector" -export const attributeTypesSelector = (state: CcState) => state.fileSettings.attributeTypes +export const attributeTypesSelector = createSelector(fileSettingsSelector, fileSettings => fileSettings.attributeTypes) diff --git a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts index 23f27640a2..c61569acc7 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts @@ -1,78 +1,11 @@ -import { BlacklistItem, CCAction } from "../../../../codeCharta.model" - -export enum BlacklistActions { - ADD_BLACKLIST_ITEM = "ADD_BLACKLIST_ITEM", - REMOVE_BLACKLIST_ITEM = "REMOVE_BLACKLIST_ITEM", - SET_BLACKLIST = "SET_BLACKLIST", - ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP = "ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP", - ADD_BLACKLIST_ITEMS = "ADD_BLACKLIST_ITEMS" -} - -export interface AddBlacklistAction extends CCAction { - type: BlacklistActions.ADD_BLACKLIST_ITEM - payload: BlacklistItem -} - -export interface AddBlacklistItemsIfNotResultsInEmptyMapAction extends CCAction { - type: BlacklistActions.ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP - payload: BlacklistItem[] -} - -export interface AddBlacklistItemsAction extends CCAction { - type: BlacklistActions.ADD_BLACKLIST_ITEMS - payload: BlacklistItem[] -} - -export interface RemoveBlacklistAction extends CCAction { - type: BlacklistActions.REMOVE_BLACKLIST_ITEM - payload: BlacklistItem -} - -export interface SetBlacklistAction extends CCAction { - type: BlacklistActions.SET_BLACKLIST - payload: BlacklistItem[] -} - -export type BlacklistAction = - | AddBlacklistAction - | RemoveBlacklistAction - | SetBlacklistAction - | AddBlacklistItemsAction - | AddBlacklistItemsIfNotResultsInEmptyMapAction - -export function addBlacklistItem(item: BlacklistItem): AddBlacklistAction { - return { - type: BlacklistActions.ADD_BLACKLIST_ITEM, - payload: item - } -} - -export function addBlacklistItemsIfNotResultsInEmptyMap(items: BlacklistItem[]): AddBlacklistItemsIfNotResultsInEmptyMapAction { - return { - type: BlacklistActions.ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP, - payload: items - } -} - -export function addBlacklistItems(items: BlacklistItem[]): AddBlacklistItemsAction { - return { - type: BlacklistActions.ADD_BLACKLIST_ITEMS, - payload: items - } -} - -export function removeBlacklistItem(item: BlacklistItem): RemoveBlacklistAction { - return { - type: BlacklistActions.REMOVE_BLACKLIST_ITEM, - payload: item - } -} - -export function setBlacklist(blacklist: BlacklistItem[] = defaultBlacklist): SetBlacklistAction { - return { - type: BlacklistActions.SET_BLACKLIST, - payload: blacklist - } -} - -export const defaultBlacklist: BlacklistItem[] = [] +import { createAction, props } from "@ngrx/store" +import { BlacklistItem } from "../../../../codeCharta.model" + +export const setBlacklist = createAction("SET_BLACKLIST", props<{ value: BlacklistItem[] }>()) +export const addBlacklistItem = createAction("ADD_BLACKLIST_ITEM", props<{ item: BlacklistItem }>()) +export const addBlacklistItems = createAction("ADD_BLACKLIST_ITEMS", props<{ items: BlacklistItem[] }>()) +export const removeBlacklistItem = createAction("REMOVE_BLACKLIST_ITEM", props<{ item: BlacklistItem }>()) +export const addBlacklistItemsIfNotResultsInEmptyMap = createAction( + "ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP", + props<{ items: BlacklistItem[] }>() +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts index 2a52f63e27..9c06f4a2d5 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts @@ -1,21 +1,13 @@ -import { addBlacklistItem, BlacklistAction, setBlacklist, removeBlacklistItem, addBlacklistItems } from "./blacklist.actions" +import { addBlacklistItem, setBlacklist, removeBlacklistItem, addBlacklistItems } from "./blacklist.actions" import { blacklist } from "./blacklist.reducer" import { BlacklistItem } from "../../../../codeCharta.model" describe("blacklist", () => { const item: BlacklistItem = { type: "flatten", path: "foo/bar" } - describe("Default State", () => { - it("should initialize the default state", () => { - const result = blacklist(undefined, {} as BlacklistAction) - - expect(result).toEqual([]) - }) - }) - describe("Action: ADD_BLACKLIST_ITEM", () => { it("should add a blacklist item to the blacklist", () => { - const result = blacklist([], addBlacklistItem(item)) + const result = blacklist([], addBlacklistItem({ item })) expect(result).toEqual([item]) }) @@ -26,7 +18,7 @@ describe("blacklist", () => { const existingItem: BlacklistItem = { type: "flatten", path: "foo/bar" } const result = blacklist( [existingItem], - addBlacklistItems([existingItem, { type: "flatten", path: "foo/bar2" }, { type: "flatten", path: "foo/bar2" }]) + addBlacklistItems({ items: [existingItem, { type: "flatten", path: "foo/bar2" }, { type: "flatten", path: "foo/bar2" }] }) ) expect(result).toEqual([existingItem, { type: "flatten", path: "foo/bar2" }]) @@ -35,7 +27,7 @@ describe("blacklist", () => { describe("Action: REMOVE_BLACKLIST_ITEM", () => { it("should remove a blacklist item, that is in the list", () => { - const result = blacklist([item], removeBlacklistItem(item)) + const result = blacklist([item], removeBlacklistItem({ item })) expect(result).toEqual([]) }) @@ -43,15 +35,9 @@ describe("blacklist", () => { describe("Action: SET_BLACKLIST", () => { it("should set new blacklist", () => { - const result = blacklist([], setBlacklist([item, item])) + const result = blacklist([], setBlacklist({ value: [item, item] })) expect(result).toEqual([item, item]) }) - - it("should set default blacklist", () => { - const result = blacklist([item, item], setBlacklist()) - - expect(result).toEqual([]) - }) }) }) diff --git a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts index 384244ac46..5a2dbd3afb 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts @@ -1,17 +1,14 @@ -import { BlacklistAction, BlacklistActions, setBlacklist } from "./blacklist.actions" -import { addItemsToArray, addItemToArray, removeItemFromArray } from "../../../../util/reduxHelper" +import { addBlacklistItem, addBlacklistItems, removeBlacklistItem, setBlacklist } from "./blacklist.actions" +import { addItemsToArray, addItemToArray, removeItemFromArray } from "../../../../util/arrayHelper" +import { createReducer, on } from "@ngrx/store" +import { BlacklistItem } from "../../../../codeCharta.model" +import { setState } from "../../util/setState.reducer.factory" -export function blacklist(state = setBlacklist().payload, action: BlacklistAction) { - switch (action.type) { - case BlacklistActions.ADD_BLACKLIST_ITEM: - return addItemToArray(state, action.payload) - case BlacklistActions.ADD_BLACKLIST_ITEMS: - return addItemsToArray(state, action.payload) - case BlacklistActions.REMOVE_BLACKLIST_ITEM: - return removeItemFromArray(state, action.payload) - case BlacklistActions.SET_BLACKLIST: - return action.payload - default: - return state - } -} +export const defaultBlacklist: BlacklistItem[] = [] +export const blacklist = createReducer( + defaultBlacklist, + on(setBlacklist, setState(defaultBlacklist)), + on(addBlacklistItem, (state, action) => addItemToArray(state, action.item)), + on(addBlacklistItems, (state, action) => addItemsToArray(state, action.items)), + on(removeBlacklistItem, (state, action) => removeItemFromArray(state, action.item)) +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.selector.ts index aba39ae701..360894cc15 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/blacklist/blacklist.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { fileSettingsSelector } from "../fileSettings.selector" -export const blacklistSelector = createSelector([fileSettingsSelector], fileSettings => fileSettings.blacklist) +export const blacklistSelector = createSelector(fileSettingsSelector, fileSettings => fileSettings.blacklist) diff --git a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.actions.ts b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.actions.ts index 71c20c4b9a..30145b3ee5 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.actions.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.actions.ts @@ -1,47 +1,6 @@ -import { CCAction, Edge } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { Edge } from "../../../../codeCharta.model" -export enum EdgesActions { - SET_EDGES = "SET_EDGES", - ADD_EDGE = "ADD_EDGE", - REMOVE_EDGE = "REMOVE_EDGE" -} - -export interface SetEdgesAction extends CCAction { - type: EdgesActions.SET_EDGES - payload: Edge[] -} - -export interface AddEdgeAction extends CCAction { - type: EdgesActions.ADD_EDGE - payload: Edge -} - -export interface RemoveEdgeAction extends CCAction { - type: EdgesActions.REMOVE_EDGE - payload: Edge -} - -export type EdgesAction = SetEdgesAction | AddEdgeAction | RemoveEdgeAction - -export function setEdges(edges: Edge[] = defaultEdges): SetEdgesAction { - return { - type: EdgesActions.SET_EDGES, - payload: edges - } -} - -export function addEdge(edge: Edge): AddEdgeAction { - return { - type: EdgesActions.ADD_EDGE, - payload: edge - } -} - -export function removeEdge(edge: Edge): RemoveEdgeAction { - return { - type: EdgesActions.REMOVE_EDGE, - payload: edge - } -} - -export const defaultEdges: Edge[] = [] +export const setEdges = createAction("SET_EDGES", props<{ value: Edge[] }>()) +export const addEdge = createAction("ADD_EDGE", props<{ edge: Edge }>()) +export const removeEdge = createAction("REMOVE_EDGE", props<{ edge: Edge }>()) diff --git a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.spec.ts b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.spec.ts index 437a96f7f9..ac2dc8cb43 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.spec.ts @@ -1,33 +1,19 @@ import { edges } from "./edges.reducer" -import { addEdge, EdgesAction, removeEdge, setEdges } from "./edges.actions" +import { addEdge, removeEdge, setEdges } from "./edges.actions" import { VALID_EDGE } from "../../../../util/dataMocks" describe("edges", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = edges(undefined, {} as EdgesAction) - - expect(result).toEqual([]) - }) - }) - describe("Action: SET_EDGES", () => { it("should set new edges", () => { - const result = edges([], setEdges([VALID_EDGE])) + const result = edges([], setEdges({ value: [VALID_EDGE] })) expect(result).toEqual([VALID_EDGE]) }) - - it("should set new edges", () => { - const result = edges([VALID_EDGE], setEdges()) - - expect(result).toEqual([]) - }) }) describe("Action: ADD_EDGE", () => { it("should add an edge", () => { - const result = edges([], addEdge(VALID_EDGE)) + const result = edges([], addEdge({ edge: VALID_EDGE })) expect(result).toEqual([VALID_EDGE]) }) @@ -35,7 +21,7 @@ describe("edges", () => { describe("Action: REMOVE_EDGE", () => { it("should remove an edge", () => { - const result = edges([VALID_EDGE], removeEdge(VALID_EDGE)) + const result = edges([VALID_EDGE], removeEdge({ edge: VALID_EDGE })) expect(result).toEqual([]) }) diff --git a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.ts index 6ecc426770..afc39b1176 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.reducer.ts @@ -1,15 +1,13 @@ -import { EdgesAction, EdgesActions, setEdges } from "./edges.actions" -import { addItemToArray, removeItemFromArray } from "../../../../util/reduxHelper" +import { addEdge, removeEdge, setEdges } from "./edges.actions" +import { addItemToArray, removeItemFromArray } from "../../../../util/arrayHelper" +import { createReducer, on } from "@ngrx/store" +import { Edge } from "../../../../codeCharta.model" +import { setState } from "../../util/setState.reducer.factory" -export function edges(state = setEdges().payload, action: EdgesAction) { - switch (action.type) { - case EdgesActions.SET_EDGES: - return action.payload - case EdgesActions.ADD_EDGE: - return addItemToArray(state, action.payload) - case EdgesActions.REMOVE_EDGE: - return removeItemFromArray(state, action.payload) - default: - return state - } -} +export const defaultEdges: Edge[] = [] +export const edges = createReducer( + defaultEdges, + on(setEdges, setState(defaultEdges)), + on(addEdge, (state, action) => addItemToArray(state, action.edge)), + on(removeEdge, (state, action) => removeItemFromArray(state, action.edge)) +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.selector.ts index c37448cc11..caa3fbe059 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/edges/edges.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/edges/edges.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { fileSettingsSelector } from "../fileSettings.selector" -export const edgesSelector = createSelector([fileSettingsSelector], fileSettings => fileSettings.edges) +export const edgesSelector = createSelector(fileSettingsSelector, fileSettings => fileSettings.edges) diff --git a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.actions.ts b/visualization/app/codeCharta/state/store/fileSettings/fileSettings.actions.ts deleted file mode 100644 index 8510146c8b..0000000000 --- a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.actions.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CCAction, FileSettings, RecursivePartial } from "../../../codeCharta.model" - -import { defaultAttributeTypes } from "./attributeTypes/attributeTypes.actions" -import { defaultAttributeDescriptors } from "./attributeDescriptors/attributeDescriptors.action" -import { defaultBlacklist } from "./blacklist/blacklist.actions" -import { defaultEdges } from "./edges/edges.actions" -import { defaultMarkedPackages } from "./markedPackages/markedPackages.actions" - -export enum FileSettingsActions { - SET_FILE_SETTINGS = "SET_FILE_SETTINGS" -} - -export interface SetFileSettingsAction extends CCAction { - type: FileSettingsActions.SET_FILE_SETTINGS - payload: RecursivePartial -} - -export type FileSettingsAction = SetFileSettingsAction - -export function setFileSettings(fileSettings: RecursivePartial = defaultFileSettings): FileSettingsAction { - return { - type: FileSettingsActions.SET_FILE_SETTINGS, - payload: fileSettings - } -} - -export const defaultFileSettings: FileSettings = { - attributeTypes: defaultAttributeTypes, - attributeDescriptors: defaultAttributeDescriptors, - blacklist: defaultBlacklist, - edges: defaultEdges, - markedPackages: defaultMarkedPackages -} diff --git a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/fileSettings.reducer.ts index 47f820f1b6..c41d8998a4 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/fileSettings.reducer.ts @@ -1,11 +1,11 @@ -import { markedPackages } from "./markedPackages/markedPackages.reducer" -import { edges } from "./edges/edges.reducer" -import { attributeTypes } from "./attributeTypes/attributeTypes.reducer" -import { blacklist } from "./blacklist/blacklist.reducer" -import { combineReducers } from "redux" -import { attributeDescriptors } from "./attributeDescriptors/attributeDescriptors.reducer" +import { defaultMarkedPackages, markedPackages } from "./markedPackages/markedPackages.reducer" +import { defaultEdges, edges } from "./edges/edges.reducer" +import { attributeTypes, defaultAttributeTypes } from "./attributeTypes/attributeTypes.reducer" +import { blacklist, defaultBlacklist } from "./blacklist/blacklist.reducer" +import { attributeDescriptors, defaultAttributeDescriptors } from "./attributeDescriptors/attributeDescriptors.reducer" +import { combineReducers } from "@ngrx/store" -const fileSettings = combineReducers({ +export const fileSettings = combineReducers({ markedPackages, edges, attributeTypes, @@ -13,4 +13,10 @@ const fileSettings = combineReducers({ blacklist }) -export default fileSettings +export const defaultFileSettings = { + markedPackages: defaultMarkedPackages, + edges: defaultEdges, + attributeTypes: defaultAttributeTypes, + attributeDescriptors: defaultAttributeDescriptors, + blacklist: defaultBlacklist +} diff --git a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/fileSettings.selector.ts index 8ede6296bb..0a663bc89f 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/fileSettings.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/fileSettings.selector.ts @@ -1,3 +1,3 @@ -import { CcState } from "../store" +import { CcState } from "../../../codeCharta.model" export const fileSettingsSelector = (state: CcState) => state.fileSettings diff --git a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.actions.ts b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.actions.ts index bd00dd3664..4c9e515250 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.actions.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.actions.ts @@ -1,47 +1,6 @@ -import { CCAction, CodeMapNode, MarkedPackage } from "../../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { MarkedPackage } from "../../../../codeCharta.model" -export enum MarkedPackagesActions { - SET_MARKED_PACKAGES = "SET_MARKED_PACKAGES", - MARK_PACKAGE = "MARK_PACKAGE", - UNMARK_PACKAGE = "UNMARK_PACKAGE" -} - -export interface MarkPackagesAction extends CCAction { - type: MarkedPackagesActions.MARK_PACKAGE - payload: MarkedPackage[] -} - -export interface SetMarkedPackagesAction extends CCAction { - type: MarkedPackagesActions.SET_MARKED_PACKAGES - payload: MarkedPackage[] -} - -export interface UnmarkPackageAction extends CCAction { - type: MarkedPackagesActions.UNMARK_PACKAGE - payload: CodeMapNode["path"] -} - -export type MarkedPackagesAction = SetMarkedPackagesAction | UnmarkPackageAction | MarkPackagesAction - -export function markPackages(packagesToBeMarked: MarkedPackage[]): MarkPackagesAction { - return { - type: MarkedPackagesActions.MARK_PACKAGE, - payload: packagesToBeMarked - } -} - -export function setMarkedPackages(markedPackages: MarkedPackage[] = defaultMarkedPackages): SetMarkedPackagesAction { - return { - type: MarkedPackagesActions.SET_MARKED_PACKAGES, - payload: markedPackages - } -} - -export function unmarkPackage(node: Pick): UnmarkPackageAction { - return { - type: MarkedPackagesActions.UNMARK_PACKAGE, - payload: node.path - } -} - -export const defaultMarkedPackages: MarkedPackage[] = [] +export const setMarkedPackages = createAction("SET_MARKED_PACKAGES", props<{ value: MarkedPackage[] }>()) +export const markPackages = createAction("MARK_PACKAGES", props<{ packages: MarkedPackage[] }>()) +export const unmarkPackage = createAction("UNMARK_PACKAGE", props<{ path: string }>()) diff --git a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.spec.ts b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.spec.ts index eeae26dbaf..8cc771c922 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.spec.ts @@ -1,28 +1,14 @@ import { markedPackages } from "./markedPackages.reducer" -import { MarkedPackagesAction, setMarkedPackages, markPackages, unmarkPackage } from "./markedPackages.actions" +import { setMarkedPackages, markPackages, unmarkPackage } from "./markedPackages.actions" import { MARKED_PACKAGES } from "../../../../util/dataMocks" describe("markedPackages", () => { - describe("Default State", () => { - it("should initialize the default state", () => { - const result = markedPackages(undefined, {} as MarkedPackagesAction) - - expect(result).toEqual([]) - }) - }) - describe("Action: SET_MARKED_PACKAGES", () => { it("should set new markedPackages", () => { - const result = markedPackages([], setMarkedPackages(MARKED_PACKAGES)) + const result = markedPackages([], setMarkedPackages({ value: MARKED_PACKAGES })) expect(result).toEqual(MARKED_PACKAGES) }) - - it("should set default markedPackages", () => { - const result = markedPackages(MARKED_PACKAGES, setMarkedPackages()) - - expect(result).toEqual([]) - }) }) describe("Action: UNMARK_PACKAGE", () => { @@ -39,18 +25,24 @@ describe("markedPackages", () => { describe("Action: MARK_PACKAGES", () => { it("should add a package", () => { - const result = markedPackages([MARKED_PACKAGES[0]], markPackages(MARKED_PACKAGES.slice(1))) + const result = markedPackages([MARKED_PACKAGES[0]], markPackages({ packages: MARKED_PACKAGES.slice(1) })) expect(result).toEqual(MARKED_PACKAGES) }) it("should remove the children of a marked package if children marked color is the same", () => { - const result = markedPackages([{ path: "/root/child", color: "#000000" }], markPackages([{ path: "/root", color: "#000000" }])) + const result = markedPackages( + [{ path: "/root/child", color: "#000000" }], + markPackages({ packages: [{ path: "/root", color: "#000000" }] }) + ) expect(result.length).toBe(1) expect(result[0]).toEqual({ path: "/root", color: "#000000" }) }) it("should not remove the children of a marked package if color is different", () => { - const result = markedPackages([{ path: "/root/child", color: "#000000" }], markPackages([{ path: "/root", color: "#ffffff" }])) + const result = markedPackages( + [{ path: "/root/child", color: "#000000" }], + markPackages({ packages: [{ path: "/root", color: "#ffffff" }] }) + ) expect(result.length).toBe(2) expect(result[0]).toEqual({ path: "/root/child", color: "#000000" }) expect(result[1]).toEqual({ path: "/root", color: "#ffffff" }) @@ -62,7 +54,7 @@ describe("markedPackages", () => { { path: "/root", color: "#ffffff" }, { path: "/root/child", color: "#000000" } ], - markPackages([{ path: "/root", color: "#333333" }]) + markPackages({ packages: [{ path: "/root", color: "#333333" }] }) ) expect(result.length).toBe(2) expect(result[0]).toEqual({ path: "/root", color: "#333333" }) diff --git a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.ts b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.ts index 569c922fdf..d121312975 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.reducer.ts @@ -1,29 +1,29 @@ -import { MarkedPackagesAction, MarkedPackagesActions, setMarkedPackages } from "./markedPackages.actions" -import { removeEntryAtIndexFromArray } from "../../../../util/reduxHelper" +import { markPackages, setMarkedPackages, unmarkPackage } from "./markedPackages.actions" +import { removeEntryAtIndexFromArray } from "../../../../util/arrayHelper" import { addMarkedPackage } from "./util/addMarkedPackage" import { findIndexOfMarkedPackageOrParent } from "./util/findIndexOfMarkedPackageOrParent" +import { createReducer, on } from "@ngrx/store" +import { MarkedPackage } from "../../../../codeCharta.model" +import { setState } from "../../util/setState.reducer.factory" -export function markedPackages(state = setMarkedPackages().payload, action: MarkedPackagesAction) { - switch (action.type) { - case MarkedPackagesActions.SET_MARKED_PACKAGES: - return action.payload - case MarkedPackagesActions.UNMARK_PACKAGE: { - const indexOfPackageToBeUnmarked = findIndexOfMarkedPackageOrParent(state, action.payload) - if (indexOfPackageToBeUnmarked !== -1) { - return removeEntryAtIndexFromArray(state, indexOfPackageToBeUnmarked) - } - return state - } - case MarkedPackagesActions.MARK_PACKAGE: { - const markedPackagesMap = new Map(state.map(entry => [entry.path, entry])) +export const defaultMarkedPackages: MarkedPackage[] = [] +export const markedPackages = createReducer( + defaultMarkedPackages, + on(setMarkedPackages, setState(defaultMarkedPackages)), + on(markPackages, (state, action) => { + const markedPackagesMap = new Map(state.map(entry => [entry.path, entry])) - for (const markedPackage of action.payload) { - addMarkedPackage(markedPackagesMap, markedPackage) - } + for (const markedPackage of action.packages) { + addMarkedPackage(markedPackagesMap, markedPackage) + } - return [...markedPackagesMap.values()] + return [...markedPackagesMap.values()] + }), + on(unmarkPackage, (state, action) => { + const indexOfPackageToBeUnmarked = findIndexOfMarkedPackageOrParent(state, action.path) + if (indexOfPackageToBeUnmarked !== -1) { + return removeEntryAtIndexFromArray(state, indexOfPackageToBeUnmarked) } - default: - return state - } -} + return state + }) +) diff --git a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.selector.ts b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.selector.ts index 453a7eab8d..f481d0ec83 100644 --- a/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.selector.ts +++ b/visualization/app/codeCharta/state/store/fileSettings/markedPackages/markedPackages.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { fileSettingsSelector } from "../fileSettings.selector" -export const markedPackagesSelector = createSelector([fileSettingsSelector], fileSettings => fileSettings.markedPackages) +export const markedPackagesSelector = createSelector(fileSettingsSelector, fileSettings => fileSettings.markedPackages) diff --git a/visualization/app/codeCharta/state/store/files/files.actions.ts b/visualization/app/codeCharta/state/store/files/files.actions.ts index 23fa745b46..ab22da9289 100644 --- a/visualization/app/codeCharta/state/store/files/files.actions.ts +++ b/visualization/app/codeCharta/state/store/files/files.actions.ts @@ -1,160 +1,28 @@ -import { CCAction, CCFile } from "../../../codeCharta.model" +import { createAction, props } from "@ngrx/store" +import { CCFile } from "../../../codeCharta.model" import { FileState } from "../../../model/files/files" -export enum FilesSelectionActions { - SET_STANDARD = "SET_STANDARD", - SET_STANDARD_BY_NAMES = "SET_STANDARD_BY_NAMES", - INVERT_STANDARD = "INVERT_STANDARD", - SET_ALL = "SET_ALL", - SET_DELTA = "SET_DELTA", - SET_DELTA_REFERENCE = "SET_DELTA_REFERENCE", - SET_DELTA_COMPARISON = "SET_DELTA_COMPARISON", - SWITCH_REFERENCE_AND_COMPARISON = "SWITCH_REFERENCE_AND_COMPARISON", - SET_FILES = "SET_FILES" -} - -export enum NewFilesImportedActions { - ADD_FILE = "ADD_FILE", - REMOVE_FILE = "REMOVE_FILE" -} - -export interface SetFilesAction extends CCAction { - type: FilesSelectionActions.SET_FILES - payload: FileState[] -} - -export interface RemoveFileAction extends CCAction { - type: NewFilesImportedActions.REMOVE_FILE - payload: string -} - -export interface AddFileAction extends CCAction { - type: NewFilesImportedActions.ADD_FILE - payload: CCFile -} - -export interface SetStandardAction extends CCAction { - type: FilesSelectionActions.SET_STANDARD - payload: CCFile[] -} - -export interface SetStandardByNamesAction extends CCAction { - type: FilesSelectionActions.SET_STANDARD_BY_NAMES - payload: string[] -} - -export interface InvertStandardAction extends CCAction { - type: FilesSelectionActions.INVERT_STANDARD -} - -export interface SetAllAction extends CCAction { - type: FilesSelectionActions.SET_ALL -} - -export interface SetDeltaAction extends CCAction { - type: FilesSelectionActions.SET_DELTA - payload: { referenceFile: CCFile; comparisonFile: CCFile } -} - -export interface SetDeltaReferenceAction extends CCAction { - type: FilesSelectionActions.SET_DELTA_REFERENCE - payload: CCFile -} - -export interface SetDeltaComparisonAction extends CCAction { - type: FilesSelectionActions.SET_DELTA_COMPARISON - payload: CCFile -} - -export interface SwitchReferenceAndComparisonAction extends CCAction { - type: FilesSelectionActions.SWITCH_REFERENCE_AND_COMPARISON -} - -export type FilesAction = - | SetFilesAction - | AddFileAction - | RemoveFileAction - | SetStandardAction - | SetStandardByNamesAction - | InvertStandardAction - | SetAllAction - | SetDeltaAction - | SetDeltaReferenceAction - | SetDeltaComparisonAction - | SwitchReferenceAndComparisonAction - -export function setFiles(files: FileState[] = defaultFiles): SetFilesAction { - return { - type: FilesSelectionActions.SET_FILES, - payload: files - } -} - -export function addFile(file: CCFile): AddFileAction { - return { - type: NewFilesImportedActions.ADD_FILE, - payload: file - } -} - -export function removeFile(fileName: string): RemoveFileAction { - return { - type: NewFilesImportedActions.REMOVE_FILE, - payload: fileName - } -} - -export function setStandard(files: CCFile[]): SetStandardAction { - return { - type: FilesSelectionActions.SET_STANDARD, - payload: files - } -} - -export function setStandardByNames(fileNames: string[]): SetStandardByNamesAction { - return { - type: FilesSelectionActions.SET_STANDARD_BY_NAMES, - payload: fileNames - } -} - -export function invertStandard(): InvertStandardAction { - return { - type: FilesSelectionActions.INVERT_STANDARD - } -} - -export function setAll(): SetAllAction { - return { - type: FilesSelectionActions.SET_ALL - } -} - -export function setDelta(referenceFile: CCFile, comparisonFile?: CCFile): SetDeltaAction { - return { - type: FilesSelectionActions.SET_DELTA, - payload: { referenceFile, comparisonFile } - } -} - -export function setDeltaReference(file: CCFile): SetDeltaReferenceAction { - return { - type: FilesSelectionActions.SET_DELTA_REFERENCE, - payload: file - } -} - -export function setDeltaComparison(file: CCFile): SetDeltaComparisonAction { - return { - type: FilesSelectionActions.SET_DELTA_COMPARISON, - payload: file - } -} - -export function switchReferenceAndComparison(): SwitchReferenceAndComparisonAction { - return { - type: FilesSelectionActions.SWITCH_REFERENCE_AND_COMPARISON - } -} - -export const defaultFiles: FileState[] = [] +export const setFiles = createAction("SET_FILES", props<{ value: FileState[] }>()) +export const addFile = createAction("ADD_FILE", props<{ file: CCFile }>()) +export const removeFile = createAction("REMOVE_FILE", props<{ fileName: string }>()) +export const setStandard = createAction("SET_STANDARD", props<{ files: CCFile[] }>()) +export const setStandardByNames = createAction("SET_STANDARD_BY_NAMES", props<{ fileNames: string[] }>()) +export const setAll = createAction("SET_ALL") +export const invertStandard = createAction("INVERT_STANDARD") +export const switchReferenceAndComparison = createAction("SWITCH_REFERENCE_AND_COMPARISON") +export const setDeltaComparison = createAction("SET_DELTA_COMPARISON", props<{ file: CCFile }>()) +export const setDeltaReference = createAction("SET_DELTA_REFERENCE", props<{ file: CCFile }>()) +export const setDelta = createAction("SET_DELTA", props<{ referenceFile: CCFile; comparisonFile: CCFile }>()) +export const fileActions = [ + setFiles, + addFile, + removeFile, + setStandard, + setStandardByNames, + setAll, + invertStandard, + switchReferenceAndComparison, + setDeltaComparison, + setDeltaReference, + setDelta +] diff --git a/visualization/app/codeCharta/state/store/files/files.reducer.spec.ts b/visualization/app/codeCharta/state/store/files/files.reducer.spec.ts index 14d344f198..9d8eb37bc9 100644 --- a/visualization/app/codeCharta/state/store/files/files.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/files/files.reducer.spec.ts @@ -1,8 +1,5 @@ import { addFile, - defaultFiles, - FilesAction, - FilesSelectionActions, invertStandard, removeFile, setAll, @@ -15,52 +12,32 @@ import { switchReferenceAndComparison } from "./files.actions" import { TEST_DELTA_MAP_A, TEST_DELTA_MAP_B } from "../../../util/dataMocks" -import files from "./files.reducer" import { isDeltaState, isPartialState } from "../../../model/files/files.helper" import { FileSelectionState, FileState } from "../../../model/files/files" import { clone } from "../../../util/clone" -import { isActionOfType } from "../../../util/reduxHelper" +import { files } from "./files.reducer" describe("files", () => { let state: FileState[] = [] beforeEach(() => { - state = [] - state = files(state, addFile(TEST_DELTA_MAP_A)) - state = files(state, addFile(TEST_DELTA_MAP_B)) - }) - - describe("Default State", () => { - it("should initialize the default state", () => { - const result = files(undefined, {} as FilesAction) - - expect(result).toEqual(defaultFiles) - }) + state = files([], addFile({ file: TEST_DELTA_MAP_A })) + state = files(state, addFile({ file: TEST_DELTA_MAP_B })) }) describe("Action: SET_FILES", () => { it("should set new files", () => { const newFiles: FileState[] = [{ file: TEST_DELTA_MAP_A, selectedAs: FileSelectionState.Partial }] - const result = files(state, setFiles(newFiles)) + const result = files(state, setFiles({ value: newFiles })) expect(result).toEqual(newFiles) }) - - it("should set default files", () => { - const result = files(state, setFiles()) - - expect(result).toEqual(defaultFiles) - }) - - it("should be a file selection action, as file selections changes when all files are set", () => { - expect(isActionOfType(setFiles().type, FilesSelectionActions)).toBe(true) - }) }) describe("Action: SET_DELTA", () => { it("should select a file as reference and another as comparison", () => { - const result = files(state, setDelta(TEST_DELTA_MAP_A, TEST_DELTA_MAP_B)) + const result = files(state, setDelta({ referenceFile: TEST_DELTA_MAP_A, comparisonFile: TEST_DELTA_MAP_B })) expect(isDeltaState(result)).toBeTruthy() }) @@ -68,7 +45,7 @@ describe("files", () => { describe("Action: SET_STANDARD", () => { it("should select two files to view in multiple mode", () => { - const result = files(state, setStandard([TEST_DELTA_MAP_A, TEST_DELTA_MAP_B])) + const result = files(state, setStandard({ files: [TEST_DELTA_MAP_A, TEST_DELTA_MAP_B] })) expect(isPartialState(result)).toBeTruthy() }) @@ -76,7 +53,10 @@ describe("files", () => { describe("Action: SET_STANDARD_BY_NAMES", () => { it("should select two files by name to view in multiple mode", () => { - const result = files(state, setStandardByNames([TEST_DELTA_MAP_A.fileMeta.fileName, TEST_DELTA_MAP_B.fileMeta.fileName])) + const result = files( + state, + setStandardByNames({ fileNames: [TEST_DELTA_MAP_A.fileMeta.fileName, TEST_DELTA_MAP_B.fileMeta.fileName] }) + ) expect(isPartialState(result)).toBeTruthy() }) @@ -84,7 +64,7 @@ describe("files", () => { describe("Action: REMOVE_FILE", () => { it("should remove a file", () => { - const result = files(state, removeFile(TEST_DELTA_MAP_A.fileMeta.fileName)) + const result = files(state, removeFile({ fileName: TEST_DELTA_MAP_A.fileMeta.fileName })) expect(result[0].file).toEqual(TEST_DELTA_MAP_B) expect(result.length).toBe(1) @@ -92,7 +72,7 @@ describe("files", () => { it("should select first file as partial when there is no other file selected", () => { state[1].selectedAs = FileSelectionState.None - const result = files(state, removeFile(state[0].file.fileMeta.fileName)) + const result = files(state, removeFile({ fileName: state[0].file.fileMeta.fileName })) expect(result.length).toBe(1) expect(result[0].selectedAs).toBe(FileSelectionState.Partial) }) @@ -112,7 +92,7 @@ describe("files", () => { it("should set delta reference file", () => { state[0].selectedAs = FileSelectionState.Partial state[1].selectedAs = FileSelectionState.Partial - const result = files(state, setDeltaReference(state[0].file)) + const result = files(state, setDeltaReference({ file: state[0].file })) expect(result[0].selectedAs).toBe(FileSelectionState.Reference) expect(result[1].selectedAs).toBe(FileSelectionState.None) }) @@ -122,7 +102,7 @@ describe("files", () => { state[1].selectedAs = FileSelectionState.Comparison state[2] = { file: clone(state[1].file), selectedAs: FileSelectionState.None } state[2].file.fileMeta.fileChecksum += "1" - const result = files(state, setDeltaReference(state[2].file)) + const result = files(state, setDeltaReference({ file: state[2].file })) expect(result[0].selectedAs).toBe(FileSelectionState.None) expect(result[1].selectedAs).toBe(FileSelectionState.Comparison) expect(result[2].selectedAs).toBe(FileSelectionState.Reference) @@ -133,7 +113,7 @@ describe("files", () => { it("should set delta comparison file", () => { state[0].selectedAs = FileSelectionState.Partial state[1].selectedAs = FileSelectionState.Reference - const result = files(state, setDeltaComparison(state[0].file)) + const result = files(state, setDeltaComparison({ file: state[0].file })) expect(result[0].selectedAs).toBe(FileSelectionState.Comparison) expect(result[1].selectedAs).toBe(FileSelectionState.Reference) }) @@ -143,7 +123,7 @@ describe("files", () => { state[1].selectedAs = FileSelectionState.Comparison state[2] = { file: clone(state[1].file), selectedAs: FileSelectionState.None } state[2].file.fileMeta.fileChecksum += "1" - const result = files(state, setDeltaComparison(state[2].file)) + const result = files(state, setDeltaComparison({ file: state[2].file })) expect(result[0].selectedAs).toBe(FileSelectionState.Reference) expect(result[1].selectedAs).toBe(FileSelectionState.None) expect(result[2].selectedAs).toBe(FileSelectionState.Comparison) diff --git a/visualization/app/codeCharta/state/store/files/files.reducer.ts b/visualization/app/codeCharta/state/store/files/files.reducer.ts index 2978d3ebb4..e1e61ed304 100644 --- a/visualization/app/codeCharta/state/store/files/files.reducer.ts +++ b/visualization/app/codeCharta/state/store/files/files.reducer.ts @@ -1,44 +1,49 @@ -import { FilesAction, FilesSelectionActions, NewFilesImportedActions, setFiles } from "./files.actions" +import { + addFile, + invertStandard, + removeFile, + setAll, + setDelta, + setDeltaComparison, + setDeltaReference, + setFiles, + setStandard, + setStandardByNames, + switchReferenceAndComparison +} from "./files.actions" import { CCFile } from "../../../codeCharta.model" import { FileSelectionState, FileState } from "../../../model/files/files" import { isEqual } from "../../../model/files/files.helper" +import { createReducer, on } from "@ngrx/store" +import { setState } from "../util/setState.reducer.factory" -export default function files(state = setFiles().payload, action: FilesAction) { - switch (action.type) { - case FilesSelectionActions.SET_FILES: - return action.payload - case NewFilesImportedActions.ADD_FILE: - return [...state, { file: action.payload, selectedAs: FileSelectionState.None }] - case NewFilesImportedActions.REMOVE_FILE: - return removeFile(state, action.payload) - case FilesSelectionActions.SET_DELTA: - return setDelta(state, action.payload.referenceFile, action.payload.comparisonFile) - case FilesSelectionActions.SET_DELTA_REFERENCE: - return setDeltaReference(state, action.payload) - case FilesSelectionActions.SET_DELTA_COMPARISON: - return setDeltaComparison(state, action.payload) - case FilesSelectionActions.SWITCH_REFERENCE_AND_COMPARISON: - return switchReferenceAndComparison(state) - case FilesSelectionActions.SET_STANDARD: - return setStandardByNames( - state, - action.payload.map(x => x.fileMeta.fileName) - ) - case FilesSelectionActions.SET_STANDARD_BY_NAMES: - return setStandardByNames(state, action.payload) - case FilesSelectionActions.INVERT_STANDARD: - return state.map(fileState => ({ - ...fileState, - selectedAs: fileState.selectedAs === FileSelectionState.Partial ? FileSelectionState.None : FileSelectionState.Partial - })) - case FilesSelectionActions.SET_ALL: - return state.map(fileState => ({ ...fileState, selectedAs: FileSelectionState.Partial })) - default: - return state - } -} +export const defaultFiles: FileState[] = [] +export const files = createReducer( + defaultFiles, + on(setFiles, setState(defaultFiles)), + on(addFile, (state, action) => [...state, { file: action.file, selectedAs: FileSelectionState.None }]), + on(removeFile, (state, action) => removeFileFromState(state, action.fileName)), + on(setDelta, (state, action) => setDeltaState(state, action.referenceFile, action.comparisonFile)), + on(setDeltaReference, (state, action) => setDeltaReferenceState(state, action.file)), + on(setDeltaComparison, (state, action) => setDeltaComparisonState(state, action.file)), + on(switchReferenceAndComparison, state => switchReferenceAndComparisonState(state)), + on(setStandard, (state, action) => + setStandardByNamesState( + state, + action.files.map(x => x.fileMeta.fileName) + ) + ), + on(setStandardByNames, (state, action) => setStandardByNamesState(state, action.fileNames)), + on(invertStandard, state => + state.map(fileState => ({ + ...fileState, + selectedAs: fileState.selectedAs === FileSelectionState.Partial ? FileSelectionState.None : FileSelectionState.Partial + })) + ), + on(setAll, state => state.map(fileState => ({ ...fileState, selectedAs: FileSelectionState.Partial }))) +) -function removeFile(state: FileState[], fileName: string) { +function removeFileFromState(state: FileState[], fileName: string): FileState[] { const newState = state.filter(fileState => fileState.file.fileMeta.fileName !== fileName) const isAnyFileSelected = newState.some(fileState => fileState.selectedAs === FileSelectionState.Partial) if (!isAnyFileSelected) { @@ -50,7 +55,7 @@ function removeFile(state: FileState[], fileName: string) { return newState } -function setDelta(state: FileState[], reference: CCFile, comparison?: CCFile) { +function setDeltaState(state: FileState[], reference: CCFile, comparison?: CCFile): FileState[] { return state.map(file => { if (isEqual(file.file, reference)) { return { ...file, selectedAs: FileSelectionState.Reference } @@ -62,7 +67,7 @@ function setDelta(state: FileState[], reference: CCFile, comparison?: CCFile) { }) } -function setDeltaReference(state: FileState[], reference: CCFile) { +function setDeltaReferenceState(state: FileState[], reference: CCFile): FileState[] { return state.map(file => { if (isEqual(file.file, reference)) { return { ...file, selectedAs: FileSelectionState.Reference } @@ -74,7 +79,7 @@ function setDeltaReference(state: FileState[], reference: CCFile) { }) } -function setDeltaComparison(state: FileState[], comparison: CCFile) { +function setDeltaComparisonState(state: FileState[], comparison: CCFile): FileState[] { return state.map(file => { if (file.file === comparison) { return { ...file, selectedAs: FileSelectionState.Comparison } @@ -86,7 +91,7 @@ function setDeltaComparison(state: FileState[], comparison: CCFile) { }) } -function switchReferenceAndComparison(state: FileState[]) { +function switchReferenceAndComparisonState(state: FileState[]): FileState[] { return state.map(file => { if (file.selectedAs === FileSelectionState.Reference) { return { ...file, selectedAs: FileSelectionState.Comparison } @@ -98,7 +103,7 @@ function switchReferenceAndComparison(state: FileState[]) { }) } -function setStandardByNames(state: FileState[], partialFileNames: string[]): FileState[] { +function setStandardByNamesState(state: FileState[], partialFileNames: string[]): FileState[] { return state.map(fileState => ({ ...fileState, selectedAs: partialFileNames.includes(fileState.file.fileMeta.fileName) ? FileSelectionState.Partial : FileSelectionState.None diff --git a/visualization/app/codeCharta/state/store/files/files.selector.ts b/visualization/app/codeCharta/state/store/files/files.selector.ts index e1ce107e11..a9784a0d51 100644 --- a/visualization/app/codeCharta/state/store/files/files.selector.ts +++ b/visualization/app/codeCharta/state/store/files/files.selector.ts @@ -1,3 +1,3 @@ -import { CcState } from "../store" +import { CcState } from "../../../codeCharta.model" export const filesSelector = (state: CcState) => state.files diff --git a/visualization/app/codeCharta/state/store/state.actions.ts b/visualization/app/codeCharta/state/store/state.actions.ts index b1310baabb..5bae8f846e 100644 --- a/visualization/app/codeCharta/state/store/state.actions.ts +++ b/visualization/app/codeCharta/state/store/state.actions.ts @@ -1,39 +1,8 @@ -import { CCAction, RecursivePartial, State } from "../../codeCharta.model" +import { Action, createAction, props } from "@ngrx/store" +import { RecursivePartial, CcState } from "../../codeCharta.model" -import { defaultAppSettings } from "./appSettings/appSettings.actions" -import { defaultFileSettings } from "./fileSettings/fileSettings.actions" -import { defaultDynamicSettings } from "./dynamicSettings/dynamicSettings.actions" -import { defaultFiles } from "./files/files.actions" -import { defaultHoveredNodeId } from "./appStatus/hoveredNodeId/hoveredNodeId.actions" -import { defaultSelectedBuildingId } from "./appStatus/selectedBuildingId/selectedBuildingId.actions" -import { defaultRightClickedNodeData } from "./appStatus/rightClickedNodeData/rightClickedNodeData.actions" +export const setState = createAction("SET_STATE", props<{ value: RecursivePartial }>()) -export enum StateActions { - SET_STATE = "SET_STATE" -} - -export interface SetStateAction extends CCAction { - type: StateActions.SET_STATE - payload: RecursivePartial -} - -export type StateAction = SetStateAction - -export function setState(state: RecursivePartial = defaultState): StateAction { - return { - type: StateActions.SET_STATE, - payload: state - } -} - -export const defaultState: State = { - appSettings: defaultAppSettings, - fileSettings: defaultFileSettings, - dynamicSettings: defaultDynamicSettings, - files: defaultFiles, - appStatus: { - hoveredNodeId: defaultHoveredNodeId, - selectedBuildingId: defaultSelectedBuildingId, - rightClickedNodeData: defaultRightClickedNodeData - } +export function isSetStateAction(action: Action): action is ReturnType { + return action.type === setState.type } diff --git a/visualization/app/codeCharta/state/store/state.manager.ts b/visualization/app/codeCharta/state/store/state.manager.ts new file mode 100644 index 0000000000..86c61c95fd --- /dev/null +++ b/visualization/app/codeCharta/state/store/state.manager.ts @@ -0,0 +1,70 @@ +import { appSettings, defaultAppSettings } from "./appSettings/appSettings.reducer" +import { defaultFileSettings, fileSettings } from "./fileSettings/fileSettings.reducer" +import { defaultDynamicSettings, dynamicSettings } from "./dynamicSettings/dynamicSettings.reducer" +import { defaultFiles, files } from "./files/files.reducer" +import { appStatus, defaultAppStatus } from "./appStatus/appStatus.reducer" +import { ActionReducer } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" +import { isSetStateAction } from "./state.actions" +import { clone } from "../../util/clone" + +export const appReducers = { + fileSettings, + appSettings, + dynamicSettings, + files, + appStatus +} +export const defaultState: CcState = { + fileSettings: defaultFileSettings, + appSettings: defaultAppSettings, + dynamicSettings: defaultDynamicSettings, + files: defaultFiles, + appStatus: defaultAppStatus +} + +export const setStateMiddleware = + (reducer: ActionReducer): ActionReducer => + (state, action) => { + if (isSetStateAction(action)) { + const newState = clone(state) + return _applyPartialState(newState, action.value) + } + return reducer(state, action) + } + +const objectWithDynamicKeysInStore = new Set([ + "fileSettings.attributeTypes", + "fileSettings.attributeDescriptors", + "fileSettings.blacklist", + "fileSettings.edges", + "fileSettings.markedPackages", + "dynamicSettings.focusedNodePath", + "files" // ToDo; this should be a Map with an unique id +]) + +export function _applyPartialState(applyTo: T, toBeApplied: unknown, composedPath = []): T { + for (const [key, value] of Object.entries(toBeApplied)) { + if (value === null || value === undefined) { + continue + } + + if (!isKeyOf(applyTo, key)) { + continue + } + + const newComposedPath = [...composedPath, key] + const composedJoinedPath = newComposedPath.join(".") + + applyTo[key] = + typeof value !== "object" || objectWithDynamicKeysInStore.has(composedJoinedPath) + ? value + : _applyPartialState(applyTo[key], value, newComposedPath) + } + + return applyTo +} + +function isKeyOf(of: T, key: PropertyKey): key is keyof T { + return Object.prototype.hasOwnProperty.call(of, key) +} diff --git a/visualization/app/codeCharta/state/store/state.reducer.spec.ts b/visualization/app/codeCharta/state/store/state.reducer.spec.ts index 171266c8b5..c69a7f55ba 100644 --- a/visualization/app/codeCharta/state/store/state.reducer.spec.ts +++ b/visualization/app/codeCharta/state/store/state.reducer.spec.ts @@ -1,25 +1,19 @@ -import { TestBed } from "@angular/core/testing" -import { AttributeTypeValue, RecursivePartial, State } from "../../codeCharta.model" -import rootReducer from "./state.reducer" -import { defaultState, setState } from "./state.actions" +import { AttributeTypeValue } from "../../codeCharta.model" +import { _applyPartialState, defaultState } from "./state.manager" import { expect } from "@jest/globals" -import { defaultInvertArea } from "./appSettings/invertArea/invertArea.actions" import { clone } from "../../util/clone" -import { Store } from "../angular-redux/store" -import { marginSelector } from "./dynamicSettings/margin/margin.selector" -import { defaultMargin } from "./dynamicSettings/margin/margin.actions" -describe("rootReducer", () => { +describe("_applyPartialState", () => { it("should update partial state", () => { - const partialState: RecursivePartial = { + const partialState = { appSettings: { invertArea: true } } - const newState = rootReducer(clone(defaultState), setState(partialState)) + const newState = _applyPartialState(clone(defaultState), partialState) - expect(newState.appSettings.invertArea).not.toBe(defaultInvertArea) + expect(newState.appSettings.invertArea).toBe(true) expect(newState.appSettings.experimentalFeaturesEnabled).toBe(defaultState.appSettings.experimentalFeaturesEnabled) }) @@ -28,15 +22,15 @@ describe("rootReducer", () => { dynamicSettings: { notValidKey: "doesn't exist" } - } as RecursivePartial + } - const newState = rootReducer(clone(defaultState), setState(partialState)) + const newState = _applyPartialState(clone(defaultState), partialState) expect(newState.dynamicSettings["notValidKey"]).toBeUndefined() }) it("should update partial state with objects that have dynamic keys ", () => { - const partialState: RecursivePartial = { + const partialState = { fileSettings: { attributeTypes: { nodes: { @@ -52,7 +46,7 @@ describe("rootReducer", () => { } } - const newState = rootReducer(clone(defaultState), setState(partialState)) + const newState = _applyPartialState(clone(defaultState), partialState) expect(newState.fileSettings.attributeTypes.nodes["rloc"]).toBe("absolute") expect(newState.fileSettings.blacklist).toEqual([ @@ -62,21 +56,4 @@ describe("rootReducer", () => { } ]) }) - - it("should return a new reference of every (nested) object, so that selectors trigger again", () => { - const store = TestBed.inject(Store) - const partialState = { - dynamicSettings: { - margin: 20 - } - } as RecursivePartial - - const marginChangedSpy = jest.fn() - store.select(marginSelector).subscribe(marginChangedSpy) - store.dispatch(setState(partialState)) - - expect(marginChangedSpy).toHaveBeenCalledTimes(2) - expect(marginChangedSpy.mock.calls[0][0]).toBe(defaultMargin) - expect(marginChangedSpy.mock.calls[1][0]).toBe(20) - }) }) diff --git a/visualization/app/codeCharta/state/store/state.reducer.ts b/visualization/app/codeCharta/state/store/state.reducer.ts deleted file mode 100644 index ea38e36a56..0000000000 --- a/visualization/app/codeCharta/state/store/state.reducer.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Action, combineReducers } from "redux" - -import appSettings from "./appSettings/appSettings.reducer" -import fileSettings from "./fileSettings/fileSettings.reducer" -import dynamicSettings from "./dynamicSettings/dynamicSettings.reducer" -import files from "./files/files.reducer" -import appStatus from "./appStatus/appStatus.reducer" -import { SetStateAction, StateActions } from "./state.actions" -import { State } from "../../codeCharta.model" -import { clone } from "../../util/clone" - -const appReducer = combineReducers({ - fileSettings, - appSettings, - dynamicSettings, - files, - appStatus -}) - -const rootReducer = (state: State, action: Action) => { - if (isSetStateAction(action)) { - const newState = clone(state) - return applyPartialState(newState, action.payload) - } - - return appReducer(state, action) -} - -export default rootReducer - -function isSetStateAction(action: Action): action is SetStateAction { - return action.type === StateActions.SET_STATE -} - -const objectWithDynamicKeysInStore = new Set([ - "fileSettings.attributeTypes", - "fileSettings.attributeDescriptors", - "fileSettings.blacklist", - "fileSettings.edges", - "fileSettings.markedPackages", - "dynamicSettings.focusedNodePath", - "files" // ToDo; this should be a Map with an unique id -]) - -function applyPartialState(applyTo: T, toBeApplied: unknown, composedPath = []): T { - for (const [key, value] of Object.entries(toBeApplied)) { - if (value === null || value === undefined) { - continue - } - - if (!isKeyOf(applyTo, key)) { - continue - } - - const newComposedPath = [...composedPath, key] - const composedJoinedPath = newComposedPath.join(".") - - applyTo[key] = - typeof value !== "object" || objectWithDynamicKeysInStore.has(composedJoinedPath) - ? value - : applyPartialState(applyTo[key], value, newComposedPath) - } - - return applyTo -} - -function isKeyOf(of: T, key: PropertyKey): key is keyof T { - return Object.prototype.hasOwnProperty.call(of, key) -} diff --git a/visualization/app/codeCharta/state/store/store.spec.ts b/visualization/app/codeCharta/state/store/store.spec.ts deleted file mode 100644 index ceda8d5341..0000000000 --- a/visualization/app/codeCharta/state/store/store.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Subject } from "rxjs" -import { EffectsModule } from "../angular-redux/effects/effects.module" -import { Store } from "./store" - -describe("plain redux store", () => { - beforeEach(() => { - EffectsModule.actions$ = new Subject() - }) - - afterEach(() => { - EffectsModule.actions$.complete() - }) - - it("should push a new event into actions$ for making EffectsModule work", () => { - const subscription = jest.fn() - EffectsModule.actions$.subscribe(subscription) - - Store.dispatch({ type: "something" }) - - expect(subscription).toHaveBeenCalledWith({ type: "something" }) - }) -}) diff --git a/visualization/app/codeCharta/state/store/store.ts b/visualization/app/codeCharta/state/store/store.ts deleted file mode 100644 index aeb526f097..0000000000 --- a/visualization/app/codeCharta/state/store/store.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Action, createStore } from "redux" -import { EffectsModule } from "../angular-redux/effects/effects.module" - -import rootReducer from "./state.reducer" - -type CcStore = ReturnType -export type CcState = ReturnType - -export class Store { - private static _store: CcStore - - private static createStore() { - return createStore(rootReducer) - } - - private static initialize() { - Store._store = Store.createStore() - const originalDispatch = Store._store.dispatch - // @ts-ignore - Store._store.dispatch = function (action: Action) { - originalDispatch(action) - EffectsModule.actions$.next(action) - return action - } - } - - static get store() { - if (!Store._store) { - Store.initialize() - } - return Store._store - } - - static dispatch(action: Action) { - Store.store.dispatch(action) - } -} diff --git a/visualization/app/codeCharta/state/store/util/setState.reducer.factory.spec.ts b/visualization/app/codeCharta/state/store/util/setState.reducer.factory.spec.ts new file mode 100644 index 0000000000..3711956abb --- /dev/null +++ b/visualization/app/codeCharta/state/store/util/setState.reducer.factory.spec.ts @@ -0,0 +1,24 @@ +import { mergeState, setState } from "./setState.reducer.factory" + +describe("setState.reducer.factory", () => { + describe("setState", () => { + it("should return default state when action payload is undefined", () => { + expect(setState(2)(undefined, { type: "generic", value: undefined })).toBe(2) + }) + + it("should return value of action", () => { + expect(setState(2)(undefined, { type: "generic", value: 3 })).toBe(3) + }) + }) + + describe("mergeState", () => { + const defaultState: { a: string; b: string } = { a: "a", b: "b" } + it("should return default state when action payload is undefined", () => { + expect(mergeState(defaultState)(defaultState, { type: "generic", value: undefined })).toBe(defaultState) + }) + + it("should merge in value of action", () => { + expect(mergeState(defaultState)(defaultState, { type: "generic", value: { a: "A" } })).toEqual({ a: "A", b: "b" }) + }) + }) +}) diff --git a/visualization/app/codeCharta/state/store/util/setState.reducer.factory.ts b/visualization/app/codeCharta/state/store/util/setState.reducer.factory.ts new file mode 100644 index 0000000000..a44a7b3035 --- /dev/null +++ b/visualization/app/codeCharta/state/store/util/setState.reducer.factory.ts @@ -0,0 +1,17 @@ +/** + * Most of CodeCharta's action will reset when action's payload is undefined. + * E.g., this has currently an effect when applying a scenario without map colors, + * to ensure that it will have default colors. + */ + +import { Action } from "@ngrx/store" + +export const setState = + (defaultValue: T) => + (_state: T, action: Action & { value: T }) => + action.value === undefined ? defaultValue : action.value + +export const mergeState = + (defaultValue: T) => + (state: T, action: Action & { value: Partial }): T => + action.value === undefined ? defaultValue : { ...state, ...action.value } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.spec.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.spec.ts index a331c28b12..8d24e57413 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.spec.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.spec.ts @@ -1,50 +1,61 @@ import { TestBed } from "@angular/core/testing" import { render } from "@testing-library/angular" -import { klona } from "klona" +import { provideMockStore, MockStore } from "@ngrx/store/testing" import { expect } from "@jest/globals" -import { TEST_NODE_FOLDER, TEST_NODE_LEAF, TEST_ATTRIBUTE_DESCRIPTORS } from "../../util/dataMocks" +import { TEST_NODE_LEAF, TEST_ATTRIBUTE_DESCRIPTORS, TEST_NODE_FOLDER } from "../../util/dataMocks" import { selectedNodeSelector } from "../../state/selectors/selectedNode.selector" import { AttributeSideBarComponent } from "./attributeSideBar.component" import { AttributeSideBarModule } from "./attributeSideBar.module" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" +import { primaryMetricNamesSelector } from "../../state/selectors/primaryMetrics/primaryMetricNames.selector" +import { attributeDescriptorsSelector } from "../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" +import { CodeMapNode } from "../../codeCharta.model" +import { klona } from "klona" +import { accumulatedDataSelector } from "../../state/selectors/accumulatedData/accumulatedData.selector" +import { mapColorsSelector } from "../../state/store/appSettings/mapColors/mapColors.selector" +import { defaultMapColors } from "../../state/store/appSettings/mapColors/mapColors.reducer" +import { primaryMetricsSelector } from "../../state/selectors/primaryMetrics/primaryMetrics.selector" +import { attributeTypesSelector } from "../../state/store/fileSettings/attributeTypes/attributeTypes.selector" +import { defaultAttributeTypes } from "../../state/store/fileSettings/attributeTypes/attributeTypes.reducer" +import { showAttributeTypeSelectorSelector } from "./util/showAttributeTypeSelector.selector" -jest.mock("../../state/selectors/selectedNode.selector", () => ({ - selectedNodeSelector: jest.fn() -})) -const mockedSelectedNodeSelector = selectedNodeSelector as jest.Mock - -const selectedMetricNames = { - areaMetric: "a", - heightMetric: "a", - colorMetric: "a", - edgeMetric: "c" -} - -jest.mock("../../state/selectors/primaryMetrics/primaryMetricNames.selector", () => ({ - primaryMetricNamesSelector: jest.fn(() => selectedMetricNames) -})) - -jest.mock("../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector", () => ({ - attributeDescriptorsSelector: jest.fn(() => TEST_ATTRIBUTE_DESCRIPTORS) -})) +let selectedMetricNames describe("AttributeSideBarComponent", () => { beforeEach(() => { + selectedMetricNames = { + areaMetric: "a", + heightMetric: "a", + colorMetric: "a", + edgeMetric: "c" + } TestBed.configureTestingModule({ imports: [AttributeSideBarModule], - providers: [{ provide: IsAttributeSideBarVisibleService, useValue: { isOpen: true } }] + providers: [ + { provide: IsAttributeSideBarVisibleService, useValue: { isOpen: true } }, + provideMockStore({ + selectors: [ + { selector: primaryMetricNamesSelector, value: selectedMetricNames }, + { selector: showAttributeTypeSelectorSelector, value: true }, + { selector: attributeDescriptorsSelector, value: TEST_ATTRIBUTE_DESCRIPTORS }, + { selector: attributeTypesSelector, value: defaultAttributeTypes }, + { selector: selectedNodeSelector, value: null }, + { selector: accumulatedDataSelector, value: {} }, + { selector: mapColorsSelector, value: defaultMapColors }, + { selector: primaryMetricsSelector, value: { edge: {}, color: {}, height: {}, area: {} } } + ] + }) + ] }) }) it("should display side bar if no building is selected (for opening / closing transition effect)", async () => { - mockedSelectedNodeSelector.mockImplementationOnce(() => {}) const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) expect(container.querySelector(".side-bar-container")).not.toBe(null) }) it("should hide side bar if side bar is closed", async () => { - mockedSelectedNodeSelector.mockImplementation(() => klona(TEST_NODE_LEAF)) const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true, componentProviders: [{ provide: IsAttributeSideBarVisibleService, useValue: { isOpen: false } }] @@ -54,12 +65,10 @@ describe("AttributeSideBarComponent", () => { }) it("should render correctly with selected building", async () => { - mockedSelectedNodeSelector.mockImplementation(() => { - const selectedNode = klona(TEST_NODE_LEAF) - selectedNode.deltas = undefined - return selectedNode - }) - const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const selectedNode = klona(TEST_NODE_LEAF) + selectedNode.deltas = undefined + mockSelectedNode(selectedNode as unknown as CodeMapNode, detectChanges) const isSideBarOpen = container.querySelector(".side-bar-container.expanded") !== null expect(isSideBarOpen).toBe(true) @@ -69,42 +78,13 @@ describe("AttributeSideBarComponent", () => { const pathName = container.querySelector("cc-node-path").textContent expect(pathName).toMatch("/root/big leaf") - - const firstPrimaryMetricEntry = container.querySelector("cc-attribute-side-bar-primary-metric").textContent - const expectedPrimaryMetricTextContent = "20a" - expect(firstPrimaryMetricEntry).toMatch(expectedPrimaryMetricTextContent) - - const expectedSecondaryMetricTextContent = "15b" - const isSecondaryMetricInPrimaryMetricSection = container - .querySelector("cc-attribute-side-bar-primary-metric") - .textContent.includes(expectedSecondaryMetricTextContent) - expect(isSecondaryMetricInPrimaryMetricSection).toBe(false) - const firstSecondaryMetricEntry = container.querySelector("cc-attribute-side-bar-secondary-metrics").textContent - expect(firstSecondaryMetricEntry).toMatch(expectedSecondaryMetricTextContent) - - expect(isAttributeTypeSelectorShown(container)).toBe(false) - }) - - it("should display deltas if node has delta values", async () => { - mockedSelectedNodeSelector.mockImplementation(() => klona(TEST_NODE_LEAF)) - const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) - const firstPrimaryMetricEntry = container.querySelector("cc-attribute-side-bar-primary-metric").textContent - const expectedPrimaryMetricTextContent = /20\s+Δ1.0\s+a/ - expect(firstPrimaryMetricEntry).toMatch(expectedPrimaryMetricTextContent) - - const expectedSecondaryMetricTextContent = /15\s+Δ2.0\s+b/ - const firstSecondaryMetricEntry = container.querySelector("cc-attribute-side-bar-secondary-metrics").textContent - expect(firstSecondaryMetricEntry).toMatch(expectedSecondaryMetricTextContent) }) it("should display attribute type selectors for folders", async () => { - mockedSelectedNodeSelector.mockImplementation(() => { - const node = klona(TEST_NODE_FOLDER) - node["children"] = [{}] - return node - }) - - const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const selectedNode = klona(TEST_NODE_FOLDER) + selectedNode["children"] = [{}] + mockSelectedNode(selectedNode as unknown as CodeMapNode, detectChanges) const attributeTypeSelectorWithinPrimaryMetrics = container.querySelectorAll( "cc-attribute-side-bar-primary-metrics cc-attribute-type-selector" @@ -117,18 +97,13 @@ describe("AttributeSideBarComponent", () => { }) it("should contain 'no edge metric available' note", async () => { - mockedSelectedNodeSelector.mockImplementation(() => { - const node = klona(TEST_NODE_FOLDER) - node["children"] = [{}] - return node - }) - selectedMetricNames.edgeMetric = undefined - - const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const selectedNode = klona(TEST_NODE_FOLDER) + selectedNode["children"] = [{}] + mockSelectedNode(selectedNode as unknown as CodeMapNode, detectChanges) const primaryMetricsWithoutEdgeMetric = container.querySelectorAll("cc-attribute-side-bar-primary-metrics td") - // if this turns out to be flaky, iterate through all results expect(primaryMetricsWithoutEdgeMetric[3].textContent === "No edge metric available") }) @@ -138,15 +113,31 @@ describe("AttributeSideBarComponent", () => { selectedMetricNames.colorMetric = "someColor" selectedMetricNames.edgeMetric = "someEdge" - mockedSelectedNodeSelector.mockImplementation(() => { - const node = klona(TEST_NODE_FOLDER) - node["children"] = [{}] - node["attributes"] = { a: 3, b: 1, c: 4, someColor: 10 } - node["edgeAttributes"] = { someEdge: { incoming: 20, outgoing: 60 } } - return node + const { container, detectChanges } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + + const store = TestBed.inject(MockStore) + store.overrideSelector(primaryMetricsSelector, { + area: { name: "a", value: 3, descriptors: { ...TEST_ATTRIBUTE_DESCRIPTORS.a, key: "a" } }, + height: { name: "b", value: 1, descriptors: { ...TEST_ATTRIBUTE_DESCRIPTORS.b, key: "b" } }, + color: { + name: "someColor", + value: 10, + descriptors: { key: "someColor", description: "", hintHighValue: "", hintLowValue: "", link: "", title: "" } + }, + edge: { + name: "a", + incoming: 20, + outgoing: 60, + descriptors: { key: "someEdge", description: "", hintHighValue: "", hintLowValue: "", link: "", title: "" } + } }) - const { container } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true }) + const selectedNode = klona(TEST_NODE_FOLDER) + selectedNode["children"] = [{}] + selectedNode["attributes"] = { a: 3, b: 1, c: 4, someColor: 10 } + selectedNode["edgeAttributes"] = { someEdge: { incoming: 20, outgoing: 60 } } + mockSelectedNode(selectedNode as unknown as CodeMapNode, detectChanges) + const attributeTypeSelectorWithinPrimaryMetrics = container.querySelectorAll("cc-attribute-side-bar-primary-metrics td") const attributeTypeSelectorWithinSecondaryMetrics = container.querySelectorAll("cc-attribute-side-bar-secondary-metrics tr") expect(attributeTypeSelectorWithinPrimaryMetrics[0].getAttribute("title")).toBe("a_testTitle (a):\na_testDescription") @@ -159,6 +150,9 @@ describe("AttributeSideBarComponent", () => { }) }) -function isAttributeTypeSelectorShown(container: Element) { - return container.querySelector("cc-attribute-type-selector") !== null +function mockSelectedNode(node: CodeMapNode, detectChanges: () => void) { + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.refreshState() + detectChanges() } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.ts index 514fa8d216..cf6ce4f3b2 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.ts @@ -1,10 +1,11 @@ import { map } from "rxjs" import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { selectedNodeSelector } from "../../state/selectors/selectedNode.selector" import { accumulatedDataSelector } from "../../state/selectors/accumulatedData/accumulatedData.selector" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-attribute-side-bar", @@ -16,5 +17,5 @@ export class AttributeSideBarComponent { selectedNode$ = this.store.select(selectedNodeSelector) fileName$ = this.store.select(accumulatedDataSelector).pipe(map(accumulatedData => accumulatedData.unifiedFileMeta?.fileName ?? "")) - constructor(public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, private store: Store) {} + constructor(public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/attributeSideBarHeaderSection.component.spec.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/attributeSideBarHeaderSection.component.spec.ts index 27406008ce..61c15baf07 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/attributeSideBarHeaderSection.component.spec.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/attributeSideBarHeaderSection.component.spec.ts @@ -1,19 +1,22 @@ import { TestBed } from "@angular/core/testing" import { render } from "@testing-library/angular" +import { provideMockStore } from "@ngrx/store/testing" import { CodeMapNode } from "../../../codeCharta.model" import { AttributeSideBarModule } from "../attributeSideBar.module" import { AttributeSideBarHeaderSectionComponent } from "./attributeSideBarHeaderSection.component" +import { IsAttributeSideBarVisibleService } from "../../../services/isAttributeSideBarVisible.service" describe("attributeSideBarHeaderSection", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AttributeSideBarModule] + imports: [AttributeSideBarModule], + providers: [{ provide: IsAttributeSideBarVisibleService, useValue: { isOpen: true } }, provideMockStore()] }) }) it("should have file link when given node has a link", async () => { const { container } = await render(AttributeSideBarHeaderSectionComponent, { - excludeComponentDeclaration: true, + providers: [{ provide: IsAttributeSideBarVisibleService, useValue: { isOpen: true } }], componentProperties: { node: { name: "myNode", children: [{}], path: "./myNode.ts", link: "myNode.com" } as CodeMapNode, fileName: "myNode.ts" diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/fileCountSelector.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/fileCountSelector.ts index a44d33a5ab..f7c2148c25 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/fileCountSelector.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/fileCountSelector.ts @@ -1,6 +1,6 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" import { selectedNodeSelector } from "../../../../state/selectors/selectedNode.selector" import { CodeMapNode, FileCount } from "../../../../codeCharta.model" +import { createSelector } from "@ngrx/store" export const getFileCount = (node?: Pick): FileCount => { if (!node) { @@ -15,4 +15,4 @@ export const getFileCount = (node?: Pick ({ - selectedNodeSelector: jest.fn() -})) -jest.mock("../../../../state/selectors/isDeltaState.selector", () => ({ - isDeltaStateSelector: jest.fn() -})) - -const selectedNodeSelectorMock = selectedNodeSelector as jest.Mock -const isDeltaStateSelectorMock = isDeltaStateSelector as jest.Mock +import { TestBed } from "@angular/core/testing" describe("nodePathComponent", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ + selectors: [ + { selector: selectedNodeSelector, value: null }, + { selector: isDeltaStateSelector, value: false } + ] + }) + ] + }) + }) + it("should display an empty p tag, if no building is selected", async () => { const { container } = await render(NodePathComponent, { componentProperties: { node: undefined } }) const pTag = container.querySelector("p") @@ -23,10 +28,13 @@ describe("nodePathComponent", () => { }) it("should display only node path, when a file is selected", async () => { - const node = { path: "some/file.ts" } - selectedNodeSelectorMock.mockImplementation(() => node) + const node = { path: "some/file.ts" } as CodeMapNode + const { container, detectChanges } = await render(NodePathComponent, { componentProperties: { node } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.refreshState() + detectChanges() - const { container } = await render(NodePathComponent, { componentProperties: { node } }) expect(container.textContent).toContain("some/file.ts") }) @@ -39,10 +47,12 @@ describe("nodePathComponent", () => { added: 1, removed: 2 } - } - selectedNodeSelectorMock.mockImplementation(() => node) - - const { container } = await render(NodePathComponent, { componentProperties: { node } }) + } as unknown as CodeMapNode + const { container, detectChanges } = await render(NodePathComponent, { componentProperties: { node } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.refreshState() + detectChanges() expect(container.textContent.replace(/\s+/g, " ")).toContain("some/folder ( 2 files )") }) @@ -57,14 +67,17 @@ describe("nodePathComponent", () => { removed: 2, changed: 3 } - } - isDeltaStateSelectorMock.mockImplementationOnce(() => true) - selectedNodeSelectorMock.mockImplementation(() => node) - - const { container } = await render(NodePathComponent, { componentProperties: { node } }) + } as unknown as CodeMapNode + const { container, detectChanges } = await render(NodePathComponent, { componentProperties: { node } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.overrideSelector(isDeltaStateSelector, true) + store.refreshState() + detectChanges() expect(container.textContent.replace(/\s+/g, " ")).toContain("some/folder ( 2 files | Δ1 | Δ-2 | Δ3)") }) + it("should display amount of files with correct english grammar, when an empty folder is selected and delta mode is enabled", async () => { const node = { children: [{}] as CodeMapNode[], @@ -75,14 +88,17 @@ describe("nodePathComponent", () => { removed: 2, changed: 0 } - } - isDeltaStateSelectorMock.mockImplementationOnce(() => true) - selectedNodeSelectorMock.mockImplementation(() => node) - - const { container } = await render(NodePathComponent, { componentProperties: { node } }) + } as unknown as CodeMapNode + const { container, detectChanges } = await render(NodePathComponent, { componentProperties: { node } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.overrideSelector(isDeltaStateSelector, true) + store.refreshState() + detectChanges() expect(container.textContent).toContain(" 0 files ") // because "zero file" is not grammatically correct }) + it("should display amount of files with correct english grammar, when a folder with 1 file is selected and delta mode is enabled", async () => { const node = { children: [{}] as CodeMapNode[], @@ -92,11 +108,13 @@ describe("nodePathComponent", () => { added: 1, removed: 0 } - } - isDeltaStateSelectorMock.mockImplementationOnce(() => true) - selectedNodeSelectorMock.mockImplementation(() => node) - - const { container } = await render(NodePathComponent, { componentProperties: { node } }) + } as unknown as CodeMapNode + const { container, detectChanges } = await render(NodePathComponent, { componentProperties: { node } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(selectedNodeSelector, node) + store.overrideSelector(isDeltaStateSelector, true) + store.refreshState() + detectChanges() expect(container.textContent).toContain(" 1 file ") // because "one files" is not grammatically correct }) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/nodePath.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/nodePath.component.ts index 6380231b2e..c8f11ebee6 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/nodePath.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/nodePath.component.ts @@ -1,7 +1,7 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { Store } from "../../../../state/angular-redux/store" -import { CodeMapNode, FileCount } from "../../../../codeCharta.model" +import { CodeMapNode, FileCount, CcState } from "../../../../codeCharta.model" import { isDeltaStateSelector } from "../../../../state/selectors/isDeltaState.selector" import { fileCountSelector } from "./fileCountSelector" @@ -15,7 +15,7 @@ export class NodePathComponent { fileCount$: Observable isDeltaMode$: Observable - constructor(store: Store) { + constructor(store: Store) { this.fileCount$ = store.select(fileCountSelector) this.isDeltaMode$ = store.select(isDeltaStateSelector) } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.ts index 6a339cb1f1..4fe208e9c3 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.ts @@ -1,6 +1,7 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { Store } from "../../../../state/angular-redux/store" +import { CcState } from "../../../../codeCharta.model" import { Metric } from "../../util/metric" import { showAttributeTypeSelectorSelector } from "../../util/showAttributeTypeSelector.selector" @@ -15,7 +16,7 @@ export class AttributeSideBarPrimaryMetricComponent { @Input() metric: Metric showAttributeTypeSelector$: Observable - constructor(store: Store) { + constructor(store: Store) { this.showAttributeTypeSelector$ = store.select(showAttributeTypeSelectorSelector) } } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.ts index 19a6f7e3cc..9e0ad3776f 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.ts @@ -1,9 +1,10 @@ import { Component, ViewEncapsulation } from "@angular/core" import { Observable } from "rxjs" -import { Store } from "../../../state/angular-redux/store" import { showAttributeTypeSelectorSelector } from "../util/showAttributeTypeSelector.selector" import { PrimaryMetrics, primaryMetricsSelector } from "../../../state/selectors/primaryMetrics/primaryMetrics.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-attribute-side-bar-primary-metrics", @@ -14,7 +15,7 @@ export class AttributeSideBarPrimaryMetricsComponent { primaryMetrics$: Observable showAttributeTypeSelector$: Observable - constructor(store: Store) { + constructor(store: Store) { this.primaryMetrics$ = store.select(primaryMetricsSelector) this.showAttributeTypeSelector$ = store.select(showAttributeTypeSelectorSelector) } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.ts index f226b279a4..43cba1273d 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.ts @@ -1,7 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" +import { CcState } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" import { Metric } from "../util/metric" import { showAttributeTypeSelectorSelector } from "../util/showAttributeTypeSelector.selector" import { showDeltaValueSelector } from "../util/showDeltaValueSelector" @@ -17,7 +18,7 @@ export class AttributeSideBarSecondaryMetricsComponent { showAttributeTypeSelector$: Observable showDeltaValue$: Observable - constructor(store: Store) { + constructor(store: Store) { this.secondaryMetrics$ = store.select(secondaryMetricsSelector) this.showAttributeTypeSelector$ = store.select(showAttributeTypeSelectorSelector) this.showDeltaValue$ = store.select(showDeltaValueSelector) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.ts index 5ee81247b0..49eb25223a 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.ts @@ -1,11 +1,10 @@ import { CodeMapNode, PrimaryMetrics, AttributeDescriptors } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { primaryMetricNamesSelector } from "../../../state/selectors/primaryMetrics/primaryMetricNames.selector" import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector" -import { CcState } from "../../../state/store/store" import { Metric } from "../util/metric" import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" import { getMetricDescriptors } from "../util/metricDescriptors" +import { createSelector } from "@ngrx/store" export const _calculateSecondaryMetrics = ( primaryMetrics: PrimaryMetrics, @@ -28,7 +27,9 @@ export const _calculateSecondaryMetrics = ( })) } -export const secondaryMetricsSelector: (state: CcState) => Metric[] = createSelector( - [primaryMetricNamesSelector, attributeDescriptorsSelector, selectedNodeSelector], +export const secondaryMetricsSelector = createSelector( + primaryMetricNamesSelector, + attributeDescriptorsSelector, + selectedNodeSelector, _calculateSecondaryMetrics ) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts index 33b369a6c6..d44d766bf2 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts @@ -2,23 +2,22 @@ import { TestBed } from "@angular/core/testing" import { render, screen, fireEvent } from "@testing-library/angular" import { AttributeTypeSelectorModule } from "./attributeTypeSelector.module" -import { Store } from "../../../state/store/store" +import { provideMockStore } from "@ngrx/store/testing" + import { AttributeTypeSelectorComponent } from "./attributeTypeSelector.component" import { AttributeTypeValue } from "../../../codeCharta.model" -import { setAttributeTypes } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.actions" +import { attributeTypesSelector } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.selector" describe("attributeTypeSelector", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AttributeTypeSelectorModule] + imports: [AttributeTypeSelectorModule], + providers: [ + provideMockStore({ + selectors: [{ selector: attributeTypesSelector, value: { nodes: { rloc: AttributeTypeValue.absolute } } }] + }) + ] }) - - Store["initialize"]() - Store.store.dispatch( - setAttributeTypes({ - nodes: { rloc: AttributeTypeValue.absolute } - }) - ) }) it("should update to median", async () => { diff --git a/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.ts index 3673b0f40a..0897209054 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.ts @@ -1,7 +1,7 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" -import { AttributeTypes, AttributeTypeValue } from "../../../codeCharta.model" +import { Store } from "@ngrx/store" +import { AttributeTypes, AttributeTypeValue, CcState } from "../../../codeCharta.model" import { updateAttributeType } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.actions" -import { Store } from "../../../state/angular-redux/store" import { attributeTypesSelector } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.selector" @Component({ @@ -16,7 +16,7 @@ export class AttributeTypeSelectorComponent { attributeTypes$ = this.store.select(attributeTypesSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} setToAbsolute() { this.setAttributeType(AttributeTypeValue.absolute) @@ -27,6 +27,12 @@ export class AttributeTypeSelectorComponent { } private setAttributeType(attributeTypeValue: AttributeTypeValue) { - this.store.dispatch(updateAttributeType(this.metricType, this.metricName, attributeTypeValue)) + this.store.dispatch( + updateAttributeType({ + category: this.metricType, + name: this.metricName, + attributeType: attributeTypeValue + }) + ) } } diff --git a/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.spec.ts b/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.spec.ts index bbf49c4bba..cd3c91709e 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.spec.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.spec.ts @@ -1,17 +1,13 @@ import { render, screen } from "@testing-library/angular" -import { idToNodeSelector } from "../../../state/selectors/accumulatedData/idToNode.selector" -import { Store } from "../../../state/store/store" import { ColorConverter } from "../../../util/color/colorConverter" import { MetricDeltaSelectedComponent } from "./metricDeltaSelected.component" - -jest.mock("../../../state/selectors/accumulatedData/idToNode.selector", () => ({ - idToNodeSelector: jest.fn() -})) -const mockedIdToNodeSelector = jest.mocked(idToNodeSelector) -jest.mock("../../../state/store/appStatus/selectedBuildingId/selectedBuildingId.selector", () => ({ - selectedBuildingIdSelector: () => 0 -})) +import { TestBed } from "@angular/core/testing" +import { provideMockStore, MockStore } from "@ngrx/store/testing" +import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector" +import { CodeMapNode } from "../../../codeCharta.model" +import { defaultMapColors } from "../../../state/store/appSettings/mapColors/mapColors.reducer" +import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/mapColors.selector" describe("MetricDeltaSelectedComponent", () => { const areColorsEqual = (hex: string, styleColor: string) => { @@ -20,54 +16,64 @@ describe("MetricDeltaSelectedComponent", () => { return formattedHex === formattedStyleColor } + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ + selectors: [ + { selector: selectedNodeSelector, value: null }, + { selector: mapColorsSelector, value: defaultMapColors } + ] + }) + ] + }) + }) + it("should not show, if there is no delta value", async () => { await render(MetricDeltaSelectedComponent) expect(screen.queryByText(/Δ/)).toBe(null) }) it("should show in positive delta color when selected building has a positive delta value", async () => { - mockIdToNodeSelector({ rloc: 2 }) - - await render(MetricDeltaSelectedComponent, { + const { detectChanges } = await render(MetricDeltaSelectedComponent, { componentProperties: { metricName: "rloc" } }) + const store = TestBed.inject(MockStore) + mockSelectedNode(store, detectChanges, { rloc: 2 }) const metricDeltaSelectedDomNode = screen.queryByText(/Δ2/) expect(metricDeltaSelectedDomNode).toBeTruthy() - expect(areColorsEqual(Store.store.getState().appSettings.mapColors.positiveDelta, metricDeltaSelectedDomNode.style.color)).toBe( - true - ) + expect(areColorsEqual(defaultMapColors.positiveDelta, metricDeltaSelectedDomNode.style.color)).toBe(true) }) it("should show in negative delta color when selected building has a negative delta value", async () => { - mockIdToNodeSelector({ rloc: -2 }) - - await render(MetricDeltaSelectedComponent, { + const { detectChanges } = await render(MetricDeltaSelectedComponent, { componentProperties: { metricName: "rloc" } }) + const store = TestBed.inject(MockStore) + mockSelectedNode(store, detectChanges, { rloc: -2 }) const metricDeltaSelectedDomNode = screen.queryByText(/Δ-2/) expect(metricDeltaSelectedDomNode).toBeTruthy() - expect(areColorsEqual(Store.store.getState().appSettings.mapColors.negativeDelta, metricDeltaSelectedDomNode.style.color)).toBe( - true - ) + expect(areColorsEqual(defaultMapColors.negativeDelta, metricDeltaSelectedDomNode.style.color)).toBe(true) }) it("should update when its metricName changes", async () => { - mockIdToNodeSelector({ rloc: 2, mcc: 4 }) - - const { change } = await render(MetricDeltaSelectedComponent, { + const { change, detectChanges } = await render(MetricDeltaSelectedComponent, { componentProperties: { metricName: "rloc" } }) + const store = TestBed.inject(MockStore) + mockSelectedNode(store, detectChanges, { rloc: 2, mcc: 4 }) + expect(screen.queryByText(/Δ2/)).toBeTruthy() await change({ metricName: "mcc" }) expect(screen.queryByText(/Δ4/)).toBeTruthy() }) - function mockIdToNodeSelector(deltas: Record) { - const idToNode = new Map() - idToNode.set(0, { id: 0, deltas }) - mockedIdToNodeSelector.mockImplementation(() => idToNode) + function mockSelectedNode(store: MockStore, detectChanges: () => void, deltas: Record) { + store.overrideSelector(selectedNodeSelector, { deltas } as unknown as CodeMapNode) + store.refreshState() + detectChanges() } }) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.ts b/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.ts index 7bda061d45..3bb1c017eb 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.ts @@ -1,8 +1,8 @@ import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { MapColors, CodeMapNode } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { MapColors, CodeMapNode, CcState } from "../../../codeCharta.model" import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector" import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/mapColors.selector" @@ -17,7 +17,7 @@ export class MetricDeltaSelectedComponent implements OnInit { selectedNode$: Observable mapColors$: Observable - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.selectedNode$ = this.store.select(selectedNodeSelector) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/util/metricDescriptors.ts b/visualization/app/codeCharta/ui/attributeSideBar/util/metricDescriptors.ts index dc0d24f213..3cce91663a 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/util/metricDescriptors.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/util/metricDescriptors.ts @@ -10,7 +10,7 @@ export type MetricDescriptors = { link: string } -export function getMetricDescriptors(metricKey: string, attributeDescriptors: AttributeDescriptors): MetricDescriptors { +export function getMetricDescriptors(metricKey: string, attributeDescriptors?: AttributeDescriptors): MetricDescriptors { return { key: metricKey, title: getMetricTitle(metricKey, attributeDescriptors), diff --git a/visualization/app/codeCharta/ui/attributeSideBar/util/showAttributeTypeSelector.selector.ts b/visualization/app/codeCharta/ui/attributeSideBar/util/showAttributeTypeSelector.selector.ts index 7606c92b46..fa398e7a26 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/util/showAttributeTypeSelector.selector.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/util/showAttributeTypeSelector.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector" import { isLeaf, MaybeLeaf } from "../../../util/codeMapHelper" export const _shouldShowAttributeType = (node?: MaybeLeaf) => node && !isLeaf(node) -export const showAttributeTypeSelectorSelector = createSelector([selectedNodeSelector], _shouldShowAttributeType) +export const showAttributeTypeSelectorSelector = createSelector(selectedNodeSelector, _shouldShowAttributeType) diff --git a/visualization/app/codeCharta/ui/attributeSideBar/util/showDeltaValueSelector.ts b/visualization/app/codeCharta/ui/attributeSideBar/util/showDeltaValueSelector.ts index 7daf40ddb4..7f071fe661 100644 --- a/visualization/app/codeCharta/ui/attributeSideBar/util/showDeltaValueSelector.ts +++ b/visualization/app/codeCharta/ui/attributeSideBar/util/showDeltaValueSelector.ts @@ -1,7 +1,7 @@ +import { createSelector } from "@ngrx/store" import { Node } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector" export const _shouldShowDeltaValue = (node?: Pick) => Boolean(node?.deltas) -export const showDeltaValueSelector = createSelector([selectedNodeSelector], _shouldShowDeltaValue) +export const showDeltaValueSelector = createSelector(selectedNodeSelector, _shouldShowDeltaValue) diff --git a/visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.render.service.spec.ts.snap b/visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.render.service.spec.ts.snap index 62d82a745b..a694f98e15 100644 --- a/visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.render.service.spec.ts.snap +++ b/visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.render.service.spec.ts.snap @@ -33,7 +33,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": 462.6132614803888, }, "path": "/root", - "visible": true, + "visible": false, "width": 950.151015307185, "x0": 0, "y0": 0, @@ -71,7 +71,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": 453.01326148038873, }, "path": "/root/big leaf", - "visible": true, + "visible": false, "width": 395.87550765359254, "x0": 19.200000000000003, "y0": 19.200000000000003, @@ -108,7 +108,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": 453.01326148038873, }, "path": "/root/Parent Leaf", - "visible": true, + "visible": false, "width": 395.8755076535925, "x0": 434.27550765359257, "y0": 19.200000000000003, @@ -146,7 +146,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": -87.31734770392224, }, "path": "/root/Parent Leaf/small leaf", - "visible": true, + "visible": false, "width": 281.67550765359243, "x0": 453.4755076535926, "y0": 38.400000000000006, @@ -184,7 +184,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": 510.35458762842757, }, "path": "/root/Parent Leaf/other small leaf", - "visible": true, + "visible": false, "width": 281.67550765359243, "x0": 453.4755076535926, "y0": 306.16530459215556, @@ -221,7 +221,7 @@ exports[`codeMapRenderService getNodes should get Nodes as array 1`] = ` "z": 671.351015307185, }, "path": "/root/Parent Leaf/empty folder", - "visible": true, + "visible": false, "width": 281.67550765359243, "x0": 453.4755076535926, "y0": 921.351015307185, diff --git a/visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.arrow.service.spec.ts.snap b/visualization/app/codeCharta/ui/codeMap/arrow/__snapshots__/codeMap.arrow.service.spec.ts.snap similarity index 100% rename from visualization/app/codeCharta/ui/codeMap/__snapshots__/codeMap.arrow.service.spec.ts.snap rename to visualization/app/codeCharta/ui/codeMap/arrow/__snapshots__/codeMap.arrow.service.spec.ts.snap diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.spec.ts similarity index 86% rename from visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.spec.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.spec.ts index 35aea1a4d8..3f936438a0 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.spec.ts @@ -1,8 +1,7 @@ -import "../../codeCharta.module" -import "./codeMap.module" import { TestBed } from "@angular/core/testing" +import { StoreModule, Store, State } from "@ngrx/store" import { CodeMapArrowService } from "./codeMap.arrow.service" -import { ThreeSceneService } from "./threeViewer/threeSceneService" +import { ThreeSceneService } from "../threeViewer/threeSceneService" import { Object3D, Vector3 } from "three" import { CODE_MAP_BUILDING, @@ -12,41 +11,36 @@ import { VALID_EDGES_DECORATED, CODE_MAP_BUILDING_WITH_INCOMING_EDGE_NODE, CODE_MAP_BUILDING_WITH_OUTGOING_EDGE_NODE -} from "../../util/dataMocks" -import { Node } from "../../codeCharta.model" -import { ColorConverter } from "../../util/color/colorConverter" -import { setScaling } from "../../state/store/appSettings/scaling/scaling.actions" -import { setEdges } from "../../state/store/fileSettings/edges/edges.actions" -import { setHeightMetric } from "../../state/store/dynamicSettings/heightMetric/heightMetric.actions" -import { CodeMapMesh } from "./rendering/codeMapMesh" -import { toggleEdgeMetricVisible } from "../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" -import { wait } from "../../util/testUtils/wait" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" -import { IdToBuildingService } from "../../services/idToBuilding/idToBuilding.service" +} from "../../../util/dataMocks" +import { CcState, Node } from "../../../codeCharta.model" +import { ColorConverter } from "../../../util/color/colorConverter" +import { setScaling } from "../../../state/store/appSettings/scaling/scaling.actions" +import { setEdges } from "../../../state/store/fileSettings/edges/edges.actions" +import { setHeightMetric } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.actions" +import { CodeMapMesh } from "../rendering/codeMapMesh" +import { toggleEdgeMetricVisible } from "../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" +import { wait } from "../../../util/testUtils/wait" +import { IdToBuildingService } from "../../../services/idToBuilding/idToBuilding.service" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" +import { clone } from "../../../util/clone" describe("CodeMapArrowService", () => { let codeMapArrowService: CodeMapArrowService let threeSceneService: ThreeSceneService - let store: Store - let state: State + let store: Store + let state: State let idToBuildingService: IdToBuildingService beforeEach(() => { - restartSystem() - rebuildService() - }) - - function restartSystem() { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) threeSceneService = TestBed.inject(ThreeSceneService) store = TestBed.inject(Store) state = TestBed.inject(State) idToBuildingService = TestBed.inject(IdToBuildingService) - } - - function rebuildService() { codeMapArrowService = new CodeMapArrowService(store, state, threeSceneService, idToBuildingService) - } + }) function withMockedThreeSceneService() { threeSceneService = codeMapArrowService["threeSceneService"] = jest.fn().mockReturnValue({ @@ -88,7 +82,7 @@ describe("CodeMapArrowService", () => { describe("Arrow Behaviour when selecting and hovering a building", () => { it("should only highlight small leaf when big leaf is selected", async () => { - store.dispatch(setEdges(VALID_EDGES_DECORATED)) + store.dispatch(setEdges({ value: VALID_EDGES_DECORATED })) const nodes: Node[] = [ CODE_MAP_BUILDING_WITH_OUTGOING_EDGE_NODE.node, CODE_MAP_BUILDING_WITH_INCOMING_EDGE_NODE.node, @@ -96,7 +90,7 @@ describe("CodeMapArrowService", () => { ] threeSceneService["mapMesh"] = new CodeMapMesh(nodes, state.getValue(), false) codeMapArrowService.addEdgePreview(nodes) - store.dispatch(setHeightMetric("mcc")) + store.dispatch(setHeightMetric({ value: "mcc" })) threeSceneService.selectBuilding(CODE_MAP_BUILDING_WITH_OUTGOING_EDGE_NODE) codeMapArrowService.onBuildingHovered(CODE_MAP_BUILDING_WITH_OUTGOING_EDGE_NODE) @@ -228,9 +222,9 @@ describe("CodeMapArrowService", () => { expect(codeMapArrowService["map"].size).toEqual(0) }) it("when targetNode is invalid then it should not call preview mode", () => { - const invalidEdge = VALID_EDGES_DECORATED + const invalidEdge = clone(VALID_EDGES_DECORATED) invalidEdge[0].toNodeName = "invalid" - store.dispatch(setEdges(invalidEdge)) + store.dispatch(setEdges({ value: invalidEdge })) const nodes: Node[] = [CODE_MAP_BUILDING_WITH_OUTGOING_EDGE_NODE.node] codeMapArrowService.addEdgePreview(nodes) @@ -238,9 +232,9 @@ describe("CodeMapArrowService", () => { expect(codeMapArrowService["previewMode"]).not.toHaveBeenCalled() }) it("when originNodeName is invalid then it should not call preview mode", () => { - const invalidEdge = VALID_EDGES_DECORATED + const invalidEdge = clone(VALID_EDGES_DECORATED) invalidEdge[0].fromNodeName = "invalid" - store.dispatch(setEdges(invalidEdge)) + store.dispatch(setEdges({ value: invalidEdge })) const nodes: Node[] = [CODE_MAP_BUILDING_WITH_INCOMING_EDGE_NODE.node] codeMapArrowService.addEdgePreview(nodes) @@ -294,7 +288,7 @@ describe("CodeMapArrowService", () => { describe("scale", () => { it("should set the scale of all arrows to x, y and z", () => { setupArrows() - store.dispatch(setScaling(new Vector3(1, 2, 3))) + store.dispatch(setScaling({ value: new Vector3(1, 2, 3) })) codeMapArrowService.scale() diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.ts b/visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.ts similarity index 92% rename from visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.ts index c3ef3123f3..82fc6e573e 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.arrow.service.ts +++ b/visualization/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.ts @@ -1,15 +1,15 @@ import { Injectable, OnDestroy } from "@angular/core" -import { ThreeSceneService } from "./threeViewer/threeSceneService" -import { Node, EdgeVisibility } from "../../codeCharta.model" +import { ThreeSceneService } from "../threeViewer/threeSceneService" +import { Node, EdgeVisibility, CcState } from "../../../codeCharta.model" import { ArrowHelper, BufferGeometry, CubicBezierCurve3, Line, LineBasicMaterial, Object3D, Vector3 } from "three" -import { ColorConverter } from "../../util/color/colorConverter" -import { CodeMapBuilding } from "./rendering/codeMapBuilding" -import { IdToBuildingService } from "../../services/idToBuilding/idToBuilding.service" +import { ColorConverter } from "../../../util/color/colorConverter" +import { CodeMapBuilding } from "../rendering/codeMapBuilding" +import { IdToBuildingService } from "../../../services/idToBuilding/idToBuilding.service" import { tap } from "rxjs" -import { hoveredNodeIdSelector } from "../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" -import { debounce } from "../../util/debounce" +import { hoveredNodeIdSelector } from "../../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector" +import { debounce } from "../../../util/debounce" +import { Store, State } from "@ngrx/store" +import { edgeVisibilitySelector } from "./utils/edgeVisibility.selector" @Injectable({ providedIn: "root" }) export class CodeMapArrowService implements OnDestroy { @@ -36,8 +36,8 @@ export class CodeMapArrowService implements OnDestroy { .subscribe() constructor( - private store: Store, - private state: State, + private store: Store, + private state: State, private threeSceneService: ThreeSceneService, private idToBuildingService: IdToBuildingService ) { @@ -109,7 +109,7 @@ export class CodeMapArrowService implements OnDestroy { this.map = this.getNodesAsMap(nodes) - const { edges } = this.state.getValue().fileSettings + const edges = edgeVisibilitySelector(this.state.getValue()) for (const edge of edges) { const originNode = this.map.get(edge.fromNodeName) diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/edgePreviewNodes.selector.spec.ts b/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgePreviewNodes.selector.spec.ts similarity index 100% rename from visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/edgePreviewNodes.selector.spec.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/utils/edgePreviewNodes.selector.spec.ts diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/edgePreviewNodes.selector.ts b/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgePreviewNodes.selector.ts similarity index 57% rename from visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/edgePreviewNodes.selector.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/utils/edgePreviewNodes.selector.ts index 7a215fcecf..e664bc3ec9 100644 --- a/visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/edgePreviewNodes.selector.ts +++ b/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgePreviewNodes.selector.ts @@ -1,11 +1,13 @@ -import { createSelector } from "../../../angular-redux/createSelector" -import { NodeEdgeMetricsMap } from "../../../selectors/accumulatedData/metricData/edgeMetricData.calculator" -import { metricDataSelector } from "../../../selectors/accumulatedData/metricData/metricData.selector" -import { amountOfEdgePreviewsSelector } from "../../../store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector" -import { edgeMetricSelector } from "../../../store/dynamicSettings/edgeMetric/edgeMetric.selector" +import { createSelector } from "@ngrx/store" +import { NodeEdgeMetricsMap } from "../../../../state/selectors/accumulatedData/metricData/edgeMetricData.calculator" +import { amountOfEdgePreviewsSelector } from "../../../../state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector" +import { edgeMetricSelector } from "../../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" +import { metricDataSelector } from "../../../../state/selectors/accumulatedData/metricData/metricData.selector" export const edgePreviewNodesSelector = createSelector( - [metricDataSelector, edgeMetricSelector, amountOfEdgePreviewsSelector], + metricDataSelector, + edgeMetricSelector, + amountOfEdgePreviewsSelector, (metricData, edgeMetric, amountOfEdgePreviews) => new Set(_getNodesWithHighestValue(metricData.nodeEdgeMetricsMap, edgeMetric, amountOfEdgePreviews)) ) diff --git a/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgeVisibility.selector.ts b/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgeVisibility.selector.ts new file mode 100644 index 0000000000..94cd3d6d0e --- /dev/null +++ b/visualization/app/codeCharta/ui/codeMap/arrow/utils/edgeVisibility.selector.ts @@ -0,0 +1,17 @@ +import { createSelector } from "@ngrx/store" +import { edgeMetricSelector } from "../../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" +import { edgePreviewNodesSelector } from "./edgePreviewNodes.selector" +import { edgesSelector } from "../../../../state/store/fileSettings/edges/edges.selector" +import { clone } from "../../../../util/clone" +import { setEdgeVisibility } from "./setEdgeVisibility" + +export const edgeVisibilitySelector = createSelector( + edgePreviewNodesSelector, + edgesSelector, + edgeMetricSelector, + (edgePreviewNodes, edges, edgeMetric) => { + const edgeVisibility = clone(edges) + setEdgeVisibility(edgePreviewNodes, edgeVisibility, edgeMetric) + return edgeVisibility + } +) diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/setEdgeVisibility.spec.ts b/visualization/app/codeCharta/ui/codeMap/arrow/utils/setEdgeVisibility.spec.ts similarity index 100% rename from visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/setEdgeVisibility.spec.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/utils/setEdgeVisibility.spec.ts diff --git a/visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/setEdgeVisibility.ts b/visualization/app/codeCharta/ui/codeMap/arrow/utils/setEdgeVisibility.ts similarity index 100% rename from visualization/app/codeCharta/state/effects/updateEdgePreviews/utils/setEdgeVisibility.ts rename to visualization/app/codeCharta/ui/codeMap/arrow/utils/setEdgeVisibility.ts diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.component.spec.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.component.spec.ts index 0891995417..006ce17967 100755 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.component.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.component.spec.ts @@ -1,11 +1,12 @@ import { ElementRef } from "@angular/core" import { Subject } from "rxjs" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" -import { Store } from "../../state/angular-redux/store" import { sharpnessModeSelector } from "../../state/store/appSettings/sharpnessMode/sharpnessMode.selector" import { CodeMapComponent } from "./codeMap.component" import { CodeMapMouseEventService } from "./codeMap.mouseEvent.service" import { ThreeViewerService } from "./threeViewer/threeViewer.service" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" describe("CodeMapComponent", () => { let mockedThreeViewService: ThreeViewerService @@ -21,7 +22,7 @@ describe("CodeMapComponent", () => { return jest.fn() } } - } as unknown as Store + } as unknown as Store beforeEach(() => { mockedThreeViewService = { init: jest.fn(), restart: jest.fn() } as unknown as ThreeViewerService diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.component.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.component.ts index ec2fc72dca..c64fe335ab 100755 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.component.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.component.ts @@ -1,11 +1,12 @@ import { Component, AfterViewInit, ElementRef, OnDestroy, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { isLoadingFileSelector } from "../../state/store/appSettings/isLoadingFile/isLoadingFile.selector" import { ThreeViewerService } from "./threeViewer/threeViewer.service" import { sharpnessModeSelector } from "../../state/store/appSettings/sharpnessMode/sharpnessMode.selector" import { CodeMapMouseEventService } from "./codeMap.mouseEvent.service" import { skip, tap } from "rxjs" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-code-map", @@ -28,7 +29,7 @@ export class CodeMapComponent implements AfterViewInit, OnDestroy { constructor( public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, - private store: Store, + private store: Store, private threeViewerService: ThreeViewerService, private codeMapMouseEventService: CodeMapMouseEventService, private elementReference: ElementRef diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.spec.ts index 06f77b7299..d2e26c3c5f 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.spec.ts @@ -2,7 +2,7 @@ import "./codeMap.module" import "../../codeCharta.module" import { TestBed } from "@angular/core/testing" import { CodeMapLabelService } from "./codeMap.label.service" -import { Node } from "../../codeCharta.model" +import { CcState, Node } from "../../codeCharta.model" import { BoxGeometry, BufferGeometry, @@ -24,13 +24,12 @@ import { setHeightMetric } from "../../state/store/dynamicSettings/heightMetric/ import { setShowMetricLabelNameValue } from "../../state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions" import { setShowMetricLabelNodeName } from "../../state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions" import { ThreeOrbitControlsService } from "./threeViewer/threeOrbitControls.service" -import { State } from "../../state/angular-redux/state" -import { Store } from "../../state/angular-redux/store" -import { Store as PlainStore } from "../../state/store/store" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" describe("CodeMapLabelService", () => { - let state: State - let store: Store + let state: State + let store: Store let threeCameraService: ThreeCameraService let threeSceneService: ThreeSceneService let codeMapLabelService: CodeMapLabelService @@ -50,7 +49,9 @@ describe("CodeMapLabelService", () => { }) function restartSystem() { - PlainStore["initialize"]() + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) store = TestBed.inject(Store) state = TestBed.inject(State) @@ -155,14 +156,14 @@ describe("CodeMapLabelService", () => { describe("addLeafLabel", () => { beforeEach(() => { - store.dispatch(setAmountOfTopLabels(1)) - store.dispatch(setHeightMetric("mcc")) + store.dispatch(setAmountOfTopLabels({ value: 1 })) + store.dispatch(setHeightMetric({ value: "mcc" })) codeMapLabelService["nodeHeight"] = 0 }) it("should add label if node has a height attribute mentioned in renderSettings", () => { - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: true })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -172,8 +173,8 @@ describe("CodeMapLabelService", () => { it("should add label even if node has a height of value 0", () => { sampleLeaf.attributes = { mcc: 0 } - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: true })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -181,8 +182,8 @@ describe("CodeMapLabelService", () => { }) it("should calculate correct height without delta with node name only", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -191,8 +192,8 @@ describe("CodeMapLabelService", () => { }) it("should calculate correct height without delta with metric values only", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -201,12 +202,12 @@ describe("CodeMapLabelService", () => { }) it("should use node height value if nodeHeight is greater than the nodes height ", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService["nodeHeight"] = 100 - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -217,8 +218,8 @@ describe("CodeMapLabelService", () => { it("should use the nodes actual height if its greater then nodeHeight", () => { codeMapLabelService["nodeHeight"] = 10 - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -227,8 +228,8 @@ describe("CodeMapLabelService", () => { }) it("should calculate correct height without delta for two line label: node name and metric value", () => { - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: true })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -237,8 +238,8 @@ describe("CodeMapLabelService", () => { }) it("should use the nodes actual height if its greater then nodeHeight and update nodeHeight correctly", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeafDelta, 0) @@ -248,8 +249,8 @@ describe("CodeMapLabelService", () => { }) it("should use highestNodeInSet if its greater then nodes actual height and nodeHeight and should update nodeHeight correctly", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeafDelta, 20) @@ -261,16 +262,16 @@ describe("CodeMapLabelService", () => { it("should use the updated and stored value for nodeHeight when adding a new, smaller node", () => { codeMapLabelService["nodeHeight"] = 10 - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeafDelta, 0) const positionSampleDeltaLeaf: Vector3 = codeMapLabelService["labels"][0].sprite.position expect(positionSampleDeltaLeaf.y).toBe(179.75) - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) const positionSampleLeafWithAppliedDeltaNodeHeight: Vector3 = codeMapLabelService["labels"][0].sprite.position @@ -278,8 +279,8 @@ describe("CodeMapLabelService", () => { }) it("should set the text correctly, creating a two line label", () => { - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: true })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -288,8 +289,8 @@ describe("CodeMapLabelService", () => { }) it("should set the text correctly, creating a one line label", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -302,8 +303,8 @@ describe("CodeMapLabelService", () => { const SY = 2 const SZ = 3 - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: true })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -317,7 +318,7 @@ describe("CodeMapLabelService", () => { const scaledLabelA = codeMapLabelService["labels"][0] const scaledLabelB = codeMapLabelService["labels"][1] - store.dispatch(setScaling(new Vector3(SX, SY, SZ))) + store.dispatch(setScaling({ value: new Vector3(SX, SY, SZ) })) const expectedScaledSpritePositions = new Vector3(originalSpritePositionsA.x * SX, 232.25, originalSpritePositionsA.z * SZ) @@ -340,48 +341,48 @@ describe("CodeMapLabelService", () => { }) it("scaling labels from a factor bigger to factor smaller then 1.0 should scale positions correctly", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) codeMapLabelService.addLeafLabel(sampleLeaf, 0) - store.dispatch(setScaling(new Vector3(1, 2, 1))) + store.dispatch(setScaling({ value: new Vector3(1, 2, 1) })) codeMapLabelService.scale() const positionWithoutDelta: Vector3 = codeMapLabelService["labels"][0].sprite.position expect(positionWithoutDelta.y).toBe(202.25) - store.dispatch(setScaling(new Vector3(1, 0.5, 1))) + store.dispatch(setScaling({ value: new Vector3(1, 0.5, 1) })) codeMapLabelService.scale() expect(positionWithoutDelta.y).toBe(149) }) it("scaling labels from a factor smaller to factor bigger then 1.0 should scale positions correctly", () => { - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) codeMapLabelService.addLeafLabel(sampleLeaf, 0) - store.dispatch(setScaling(new Vector3(1, 0.5, 1))) + store.dispatch(setScaling({ value: new Vector3(1, 0.5, 1) })) codeMapLabelService.scale() const positionWithoutDelta: Vector3 = codeMapLabelService["labels"][0].sprite.position expect(positionWithoutDelta.y).toBe(149) - store.dispatch(setScaling(new Vector3(1, 2, 1))) + store.dispatch(setScaling({ value: new Vector3(1, 2, 1) })) codeMapLabelService.scale() expect(positionWithoutDelta.y).toBe(202.25) }) it("should apply scaling factor to a newly created label", () => { - store.dispatch(setScaling(new Vector3(1, 2, 1))) + store.dispatch(setScaling({ value: new Vector3(1, 2, 1) })) - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) @@ -415,12 +416,12 @@ describe("CodeMapLabelService", () => { return generated } it("should clear label for the correct node only", () => { - store.dispatch(setAmountOfTopLabels(2)) - store.dispatch(setHeightMetric("mcc")) + store.dispatch(setAmountOfTopLabels({ value: 2 })) + store.dispatch(setHeightMetric({ value: "mcc" })) codeMapLabelService.dispose = jest.fn() - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) codeMapLabelService.addLeafLabel(otherSampleLeaf, 0) @@ -439,11 +440,11 @@ describe("CodeMapLabelService", () => { }) it("should not clear if no label exists for a given node", () => { - store.dispatch(setAmountOfTopLabels(2)) - store.dispatch(setHeightMetric("mcc")) + store.dispatch(setAmountOfTopLabels({ value: 2 })) + store.dispatch(setHeightMetric({ value: "mcc" })) - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(true)) + store.dispatch(setShowMetricLabelNameValue({ value: false })) + store.dispatch(setShowMetricLabelNodeName({ value: true })) codeMapLabelService.addLeafLabel(sampleLeaf, 0) threeSceneService.labels.children.length = 2 diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.ts index 59bb5391ba..abf405c2e9 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.label.service.ts @@ -1,12 +1,13 @@ import { Sprite, Vector3, Box3, Sphere, LineBasicMaterial, Line, BufferGeometry, LinearFilter, Texture, SpriteMaterial, Color } from "three" -import { LayoutAlgorithm, Node } from "../../codeCharta.model" +import { LayoutAlgorithm, Node, CcState } from "../../codeCharta.model" import { ThreeOrbitControlsService } from "./threeViewer/threeOrbitControls.service" import { ThreeCameraService } from "./threeViewer/threeCamera.service" import { ThreeSceneService } from "./threeViewer/threeSceneService" import { ColorConverter } from "../../util/color/colorConverter" -import { State } from "../../state/angular-redux/state" import { Injectable } from "@angular/core" import { treeMapSize } from "../../util/algorithm/treeMapLayout/treeMapHelper" +import { State } from "@ngrx/store" +import { defaultMapColors } from "../../state/store/appSettings/mapColors/mapColors.reducer" interface InternalLabel { sprite: Sprite @@ -19,7 +20,7 @@ interface InternalLabel { @Injectable({ providedIn: "root" }) export class CodeMapLabelService { private labels: InternalLabel[] - private mapLabelColors = this.state.getValue().appSettings.mapColors.labelColorAndAlpha + private mapLabelColors = defaultMapColors.labelColorAndAlpha private LABEL_COLOR_RGB = ColorConverter.convertHexToRgba(this.mapLabelColors.rgb) private LABEL_WIDTH_DIVISOR = 2100 // empirically gathered private LABEL_HEIGHT_DIVISOR = 35 // empirically gathered @@ -33,7 +34,7 @@ export class CodeMapLabelService { private nodeHeight = 0 constructor( - private state: State, + private state: State, private threeCameraService: ThreeCameraService, private threeSceneService: ThreeSceneService, private threeOrbitControlsService: ThreeOrbitControlsService diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.spec.ts index a14a4943da..09e36058bf 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.spec.ts @@ -6,23 +6,19 @@ import { ThreeRendererService } from "./threeViewer/threeRenderer.service" import { ViewCubeMouseEventsService } from "../viewCube/viewCube.mouseEvents.service" import { CodeMapBuilding } from "./rendering/codeMapBuilding" import { CODE_MAP_BUILDING, CONSTANT_HIGHLIGHT, TEST_FILE_WITH_PATHS, TEST_NODES } from "../../util/dataMocks" -import { BlacklistItem, CodeMapNode, Node } from "../../codeCharta.model" +import { BlacklistItem, CcState, CodeMapNode, Node } from "../../codeCharta.model" import { NodeDecorator } from "../../util/nodeDecorator" import { klona } from "klona" import { CodeMapLabelService } from "./codeMap.label.service" import { CodeMapMesh } from "./rendering/codeMapMesh" import { BufferGeometry, Material, Object3D, Raycaster, Vector3 } from "three" import { ThreeViewerService } from "./threeViewer/threeViewer.service" -import { setShowMetricLabelNameValue } from "../../state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions" -import { setShowMetricLabelNodeName } from "../../state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions" import { idToNodeSelector } from "../../state/selectors/accumulatedData/idToNode.selector" import { IdToBuildingService } from "../../services/idToBuilding/idToBuilding.service" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" -import { - RightClickedNodeDataActions, - setRightClickedNodeData -} from "../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" +import { setRightClickedNodeData } from "../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" +import { State, Store } from "@ngrx/store" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { defaultState } from "../../state/store/state.manager" jest.mock("../../state/selectors/accumulatedData/idToNode.selector", () => ({ idToNodeSelector: jest.fn() @@ -34,8 +30,8 @@ describe("codeMapMouseEventService", () => { let threeCameraService: ThreeCameraService let threeRendererService: ThreeRendererService let threeSceneService: ThreeSceneService - let store: Store - let state: State + let store: Store + let state: State let codeMapLabelService: CodeMapLabelService let viewCubeMouseEventsService: ViewCubeMouseEventsService let threeViewerService: ThreeViewerService @@ -63,6 +59,9 @@ describe("codeMapMouseEventService", () => { }) function restartSystem() { + TestBed.configureTestingModule({ + providers: [provideMockStore(), { provide: State, useValue: { getValue: () => defaultState } }] + }) threeCameraService = TestBed.inject(ThreeCameraService) threeRendererService = TestBed.inject(ThreeRendererService) threeSceneService = TestBed.inject(ThreeSceneService) @@ -80,7 +79,7 @@ describe("codeMapMouseEventService", () => { threeSceneService.getHighlightedBuilding = jest.fn().mockReturnValue(CODE_MAP_BUILDING) threeSceneService.getConstantHighlight = jest.fn().mockReturnValue(new Map()) - store = TestBed.inject(Store) + store = TestBed.inject(MockStore) state = TestBed.inject(State) threeViewerService = TestBed.inject(ThreeViewerService) viewCubeMouseEventsService = { @@ -390,7 +389,7 @@ describe("codeMapMouseEventService", () => { it("should un-highlight the building, when no intersection was found and a building is hovered", () => { codeMapMouseEventService["modifiedLabel"] = null codeMapMouseEventService["highlightedInTreeView"] = null - codeMapMouseEventService["threeSceneService"].getHighlightedBuilding = () => ({ node: { id: 1 } } as CodeMapBuilding) + codeMapMouseEventService["threeSceneService"].getHighlightedBuilding = () => ({ id: 1 } as CodeMapBuilding) codeMapMouseEventService.updateHovering() expect(threeSceneService.clearHighlight).toHaveBeenCalled() @@ -592,9 +591,11 @@ describe("codeMapMouseEventService", () => { expect(dispatchSpy).toHaveBeenCalledWith( setRightClickedNodeData({ - nodeId: 1, - xPositionOfRightClickEvent: 0, - yPositionOfRightClickEvent: 1 + value: { + nodeId: 1, + xPositionOfRightClickEvent: 0, + yPositionOfRightClickEvent: 1 + } }) ) }) @@ -609,7 +610,7 @@ describe("codeMapMouseEventService", () => { expect(dispatchSpy).not.toHaveBeenCalledWith( expect.objectContaining({ - type: RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA + type: "SET_RIGHT_CLICKED_NODE_DATA" }) ) }) @@ -623,7 +624,7 @@ describe("codeMapMouseEventService", () => { expect(dispatchSpy).not.toHaveBeenCalledWith( expect.objectContaining({ - type: RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA + type: "SET_RIGHT_CLICKED_NODE_DATA" }) ) }) @@ -827,20 +828,6 @@ describe("codeMapMouseEventService", () => { it("should call addLeafLabel on codeMapLabelService with temporary label name even when both label options are set to false", () => { threeSceneService.getLabelForHoveredNode = jest.fn() codeMapLabelService.addLeafLabel = jest.fn() - store.dispatch(setShowMetricLabelNameValue(false)) - store.dispatch(setShowMetricLabelNodeName(false)) - - codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding, null) - - expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled() - expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(codeMapBuilding.node, 0, true) - }) - - it("should not generate names in temporary Label when metric option is set to true and name is set to false", () => { - threeSceneService.getLabelForHoveredNode = jest.fn() - codeMapLabelService.addLeafLabel = jest.fn() - store.dispatch(setShowMetricLabelNameValue(true)) - store.dispatch(setShowMetricLabelNodeName(false)) codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding, null) diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts index ee431cdb00..76a9f38d8e 100755 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts @@ -2,7 +2,7 @@ import { Injectable, OnDestroy } from "@angular/core" import { ThreeCameraService } from "./threeViewer/threeCamera.service" import { CodeMapBuilding } from "./rendering/codeMapBuilding" import { ViewCubeMouseEventsService } from "../viewCube/viewCube.mouseEvents.service" -import { BlacklistItem } from "../../codeCharta.model" +import { BlacklistItem, CcState } from "../../codeCharta.model" import { ThreeSceneService } from "./threeViewer/threeSceneService" import { ThreeRendererService } from "./threeViewer/threeRenderer.service" import { isPathHiddenOrExcluded } from "../../util/codeMapHelper" @@ -15,12 +15,11 @@ import { setRightClickedNodeData } from "../../state/store/appStatus/rightClicke import { idToNodeSelector } from "../../state/selectors/accumulatedData/idToNode.selector" import { IdToBuildingService } from "../../services/idToBuilding/idToBuilding.service" import { hoveredNodeIdSelector } from "../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector" -import { tap, distinctUntilChanged } from "rxjs" -import { Store } from "../../state/angular-redux/store" +import { tap } from "rxjs" import { visibleFileStatesSelector } from "../../state/selectors/visibleFileStates.selector" import { blacklistSelector } from "../../state/store/fileSettings/blacklist/blacklist.selector" -import { State } from "../../state/angular-redux/state" import { debounce } from "../../util/debounce" +import { Store, State } from "@ngrx/store" interface Coordinates { x: number @@ -64,12 +63,11 @@ export class CodeMapMouseEventService implements OnDestroy { this.store .select(hoveredNodeIdSelector) .pipe( - distinctUntilChanged(), tap(hoveredNodeId => { if (hoveredNodeId !== null) { this.hoverNode(hoveredNodeId) } else { - this.unhoverNode() + this.unhoverNode(false) } }) ) @@ -80,8 +78,8 @@ export class CodeMapMouseEventService implements OnDestroy { private threeCameraService: ThreeCameraService, private threeRendererService: ThreeRendererService, private threeSceneService: ThreeSceneService, - private store: Store, - private state: State, + private store: Store, + private state: State, private codeMapLabelService: CodeMapLabelService, private viewCubeMouseEvents: ViewCubeMouseEventsService, private threeViewerService: ThreeViewerService, @@ -116,18 +114,19 @@ export class CodeMapMouseEventService implements OnDestroy { if (this.isGrabbingOrMoving()) { return } + const { buildings } = this.threeSceneService.getMapMesh().getMeshDescription() for (const building of buildings) { if (building.node.id === id) { - this.hoverBuilding(building) + this.hoverBuilding(building, false) break } } this.threeRendererService.render() } - unhoverNode() { - this.unhoverBuilding() + unhoverNode(updateStore = true) { + this.unhoverBuilding(updateStore) this.threeRendererService.render() } @@ -216,7 +215,7 @@ export class CodeMapMouseEventService implements OnDestroy { const from = this.threeSceneService.getHighlightedBuilding() const to = this.intersectedBuilding - if (from !== to) { + if (from?.id !== to?.id) { if (this.temporaryLabelForBuilding !== null) { this.codeMapLabelService.clearTemporaryLabel(this.temporaryLabelForBuilding) this.temporaryLabelForBuilding = null @@ -235,7 +234,6 @@ export class CodeMapMouseEventService implements OnDestroy { } } } - this.threeRendererService.render() } private drawTemporaryLabelFor(codeMapBuilding: CodeMapBuilding, labels: Object3D[]) { @@ -341,9 +339,11 @@ export class CodeMapMouseEventService implements OnDestroy { if (this.intersectedBuilding && !this.hasMouseMovedMoreThanThreePixels(this.mouseOnLastClick)) { this.store.dispatch( setRightClickedNodeData({ - nodeId: this.intersectedBuilding.node.id, - xPositionOfRightClickEvent: this.mouse.x, - yPositionOfRightClickEvent: this.mouse.y + value: { + nodeId: this.intersectedBuilding.node.id, + xPositionOfRightClickEvent: this.mouse.x, + yPositionOfRightClickEvent: this.mouse.y + } }) ) } @@ -378,7 +378,7 @@ export class CodeMapMouseEventService implements OnDestroy { return this.isGrabbing || this.isMoving } - private hoverBuilding(hoveredBuilding: CodeMapBuilding) { + private hoverBuilding(hoveredBuilding: CodeMapBuilding, updateStore = true) { CodeMapMouseEventService.changeCursorIndicator(CursorType.Pointer) const idToNode = idToNodeSelector(this.state.getValue()) @@ -390,7 +390,9 @@ export class CodeMapMouseEventService implements OnDestroy { } } this.threeSceneService.highlightBuildings() - this.store.dispatch(setHoveredNodeId(hoveredBuilding.node.id)) + if (updateStore) { + this.store.dispatch(setHoveredNodeId({ value: hoveredBuilding.node.id })) + } } private transformHTMLToSceneCoordinates(): Coordinates { @@ -406,7 +408,7 @@ export class CodeMapMouseEventService implements OnDestroy { return { x, y } } - private unhoverBuilding() { + private unhoverBuilding(updateStore = true) { if (!this.isGrabbingOrMoving()) { CodeMapMouseEventService.changeCursorIndicator(CursorType.Default) } @@ -417,6 +419,8 @@ export class CodeMapMouseEventService implements OnDestroy { this.threeSceneService.clearHighlight() } - this.store.dispatch(setHoveredNodeId(null)) + if (updateStore) { + this.store.dispatch(setHoveredNodeId({ value: null })) + } } } diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.spec.ts index b8a8343754..c3eda40519 100644 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.spec.ts @@ -2,8 +2,8 @@ import { TestBed } from "@angular/core/testing" import { CodeMapRenderService } from "./codeMap.render.service" import { ThreeSceneService } from "./threeViewer/threeSceneService" import { CodeMapLabelService } from "./codeMap.label.service" -import { CodeMapArrowService } from "./codeMap.arrow.service" -import { Node, CodeMapNode, colorLabelOptions } from "../../codeCharta.model" +import { CodeMapArrowService } from "./arrow/codeMap.arrow.service" +import { Node, CodeMapNode, ColorLabelOptions, CcState } from "../../codeCharta.model" import { COLOR_TEST_NODES, DEFAULT_STATE, @@ -20,16 +20,15 @@ import { NodeDecorator } from "../../util/nodeDecorator" import { Object3D, Vector3 } from "three" import { setState } from "../../state/store/state.actions" import { setEdges } from "../../state/store/fileSettings/edges/edges.actions" -import { unfocusNode } from "../../state/store/dynamicSettings/focusedNodePath/focusedNodePath.actions" import { setShowMetricLabelNodeName } from "../../state/store/appSettings/showMetricLabelNodeName/showMetricLabelNodeName.actions" import { setShowMetricLabelNameValue } from "../../state/store/appSettings/showMetricLabelNameValue/showMetricLabelNameValue.actions" import { klona } from "klona" import { ThreeStatsService } from "./threeViewer/threeStats.service" import { setColorLabels } from "../../state/store/appSettings/colorLabels/colorLabels.actions" import { CodeMapMouseEventService } from "./codeMap.mouseEvent.service" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" const mockedMetricDataSelector = metricDataSelector as unknown as jest.Mock jest.mock("../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ @@ -37,8 +36,8 @@ jest.mock("../../state/selectors/accumulatedData/metricData/metricData.selector" })) describe("codeMapRenderService", () => { - let store: Store - let state: State + let store: Store + let state: State let codeMapRenderService: CodeMapRenderService let threeSceneService: ThreeSceneService let codeMapLabelService: CodeMapLabelService @@ -59,6 +58,9 @@ describe("codeMapRenderService", () => { }) function restartSystem() { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) store = TestBed.inject(Store) state = TestBed.inject(State) codeMapLabelService = TestBed.inject(CodeMapLabelService) @@ -71,8 +73,7 @@ describe("codeMapRenderService", () => { map = klona(TEST_FILE_WITH_PATHS.map) NodeDecorator.decorateMap(map, { nodeMetricData: METRIC_DATA, edgeMetricData: [] }, []) NodeDecorator.decorateParentNodesWithAggregatedAttributes(map, false, DEFAULT_STATE.fileSettings.attributeTypes) - store.dispatch(setState(STATE)) - store.dispatch(unfocusNode()) + store.dispatch(setState({ value: STATE })) mockedMetricDataSelector.mockImplementation(() => ({ nodeMetricData: METRIC_DATA, edgeMetricData: [] @@ -165,7 +166,6 @@ describe("codeMapRenderService", () => { expect(codeMapRenderService["setNewMapMesh"]).toHaveBeenCalledWith(nodes, expect.any(Array)) expect(codeMapRenderService["setLabels"]).toHaveBeenCalled() expect(codeMapRenderService["setArrows"]).toHaveBeenCalled() - expect(codeMapRenderService["scaleMap"]).toHaveBeenCalled() }) it("should call getNodesMatchingColorSelector", () => { @@ -252,8 +252,8 @@ describe("codeMapRenderService", () => { }) it("should not generate labels when showMetricLabelNodeName and showMetricLabelNameValue are both false", () => { - store.dispatch(setShowMetricLabelNodeName(false)) - store.dispatch(setShowMetricLabelNameValue(false)) + store.dispatch(setShowMetricLabelNodeName({ value: false })) + store.dispatch(setShowMetricLabelNameValue({ value: false })) codeMapRenderService["setLabels"](nodes) @@ -261,31 +261,27 @@ describe("codeMapRenderService", () => { }) it("should not generate labels for flattened nodes", () => { - nodes[0].flat = true - - codeMapRenderService["getNodes"] = jest.fn().mockReturnValue(nodes) + codeMapRenderService["getNodes"] = () => [{ ...TEST_NODE_ROOT, flat: true }] codeMapRenderService.render(null) - expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledTimes(2) + expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledTimes(0) }) it("should generate labels for not-flattened nodes", () => { - nodes[0].flat = false - codeMapRenderService["getNodes"] = jest.fn().mockReturnValue(nodes) codeMapRenderService.render(null) - expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledTimes(4) + expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledTimes(2) }) it("should generate labels for color if option is toggled on", () => { - const colorLabelsNegative: colorLabelOptions = { + const colorLabelsNegative: ColorLabelOptions = { positive: false, negative: true, neutral: false } - store.dispatch(setColorLabels(colorLabelsNegative)) + store.dispatch(setColorLabels({ value: colorLabelsNegative })) codeMapRenderService["getNodesMatchingColorSelector"](COLOR_TEST_NODES) codeMapRenderService["setLabels"](COLOR_TEST_NODES) @@ -293,13 +289,13 @@ describe("codeMapRenderService", () => { }) it("should generate labels for multiple colors if corresponding options are toggled on", () => { - const colorLabelsPosNeut: colorLabelOptions = { + const colorLabelsPosNeut: ColorLabelOptions = { positive: true, negative: false, neutral: true } - store.dispatch(setColorLabels(colorLabelsPosNeut)) + store.dispatch(setColorLabels({ value: colorLabelsPosNeut })) codeMapRenderService["getNodesMatchingColorSelector"](COLOR_TEST_NODES) codeMapRenderService["setLabels"](COLOR_TEST_NODES) @@ -323,7 +319,7 @@ describe("codeMapRenderService", () => { }) it("should call codeMapArrowService.addEdgeArrows", () => { - store.dispatch(setEdges(VALID_EDGES)) + store.dispatch(setEdges({ value: VALID_EDGES })) codeMapRenderService["setArrows"](sortedNodes) diff --git a/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.ts b/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.ts index 73e3b3605e..42327e376f 100755 --- a/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.ts +++ b/visualization/app/codeCharta/ui/codeMap/codeMap.render.service.ts @@ -3,17 +3,16 @@ import { CodeMapMesh } from "./rendering/codeMapMesh" import { createTreemapNodes } from "../../util/algorithm/treeMapLayout/treeMapGenerator" import { CodeMapLabelService } from "./codeMap.label.service" import { ThreeSceneService } from "./threeViewer/threeSceneService" -import { CodeMapArrowService } from "./codeMap.arrow.service" -import { CodeMapNode, LayoutAlgorithm, Node } from "../../codeCharta.model" +import { CodeMapArrowService } from "./arrow/codeMap.arrow.service" +import { CodeMapNode, LayoutAlgorithm, Node, CcState } from "../../codeCharta.model" import { isDeltaState } from "../../model/files/files.helper" import { StreetLayoutGenerator } from "../../util/algorithm/streetLayout/streetLayoutGenerator" import { ThreeStatsService } from "./threeViewer/threeStats.service" import { CodeMapMouseEventService } from "./codeMap.mouseEvent.service" -import { Store } from "../../state/angular-redux/store" import { isLoadingFileSelector } from "../../state/store/appSettings/isLoadingFile/isLoadingFile.selector" import { Subscription, tap } from "rxjs" -import { State } from "../../state/angular-redux/state" import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" +import { Store, State } from "@ngrx/store" @Injectable({ providedIn: "root" }) export class CodeMapRenderService implements OnDestroy { @@ -26,8 +25,8 @@ export class CodeMapRenderService implements OnDestroy { private subscription: Subscription constructor( - private store: Store, - private state: State, + private store: Store, + private state: State, private threeSceneService: ThreeSceneService, private codeMapLabelService: CodeMapLabelService, private codeMapArrowService: CodeMapArrowService, @@ -60,11 +59,10 @@ export class CodeMapRenderService implements OnDestroy { this.getNodesMatchingColorSelector(this.unflattenedNodes) this.setLabels(this.unflattenedNodes) this.setArrows(visibleSortedNodes) - this.scaleMap() } private setNewMapMesh(allMeshNodes, visibleSortedNodes) { - const state = this.state.getValue() + const state = this.state.getValue() as CcState const mapMesh = new CodeMapMesh(visibleSortedNodes, state, isDeltaState(state.files)) this.threeSceneService.setMapMesh(allMeshNodes, mapMesh) } @@ -79,7 +77,7 @@ export class CodeMapRenderService implements OnDestroy { } private getNodes(map: CodeMapNode) { - const state = this.state.getValue() + const state = this.state.getValue() as CcState const nodeMetricData = metricDataSelector(state).nodeMetricData const { appSettings: { layoutAlgorithm }, diff --git a/visualization/app/codeCharta/ui/codeMap/rendering/codeMapGeometricDescription.ts b/visualization/app/codeCharta/ui/codeMap/rendering/codeMapGeometricDescription.ts index 0e8d6620c6..9a598e8e38 100644 --- a/visualization/app/codeCharta/ui/codeMap/rendering/codeMapGeometricDescription.ts +++ b/visualization/app/codeCharta/ui/codeMap/rendering/codeMapGeometricDescription.ts @@ -1,6 +1,6 @@ import { CodeMapBuilding } from "./codeMapBuilding" import { Vector3, Ray, Box3 } from "three" -import { Scaling } from "../../../state/store/appSettings/scaling/scaling.actions" +import { Scaling } from "../../../codeCharta.model" export class CodeMapGeometricDescription { private _buildings: CodeMapBuilding[] // todo tk: depending on how many buildings, refactor this to { [node.path]: node } might give `this.getBuildingByPath` a performance boost diff --git a/visualization/app/codeCharta/ui/codeMap/rendering/codeMapMesh.ts b/visualization/app/codeCharta/ui/codeMap/rendering/codeMapMesh.ts index 87700d2d3e..203a45212a 100644 --- a/visualization/app/codeCharta/ui/codeMap/rendering/codeMapMesh.ts +++ b/visualization/app/codeCharta/ui/codeMap/rendering/codeMapMesh.ts @@ -2,10 +2,9 @@ import { CodeMapShaderStrings } from "./shaders/loaders/codeMapShaderStrings" import { GeometryGenerator } from "./geometryGenerator" import { CodeMapGeometricDescription } from "./codeMapGeometricDescription" import { CodeMapBuilding } from "./codeMapBuilding" -import { Node, State } from "../../../codeCharta.model" +import { Node, Scaling, CcState } from "../../../codeCharta.model" import { BufferAttribute, Camera, Mesh, Ray, ShaderMaterial, UniformsLib, UniformsUtils, Vector3 } from "three" import { TreeMapHelper, treeMapSize } from "../../../util/algorithm/treeMapLayout/treeMapHelper" -import { Scaling } from "../../../state/store/appSettings/scaling/scaling.actions" export interface MousePos { x: number @@ -24,7 +23,7 @@ export class CodeMapMesh { private mapGeomDesc: CodeMapGeometricDescription private nodes: Node[] - constructor(nodes: Node[], state: State, isDeltaState: boolean) { + constructor(nodes: Node[], state: CcState, isDeltaState: boolean) { this.initMaterial() this.geomGen = new GeometryGenerator() @@ -79,7 +78,7 @@ export class CodeMapMesh { highlightBuilding( highlightedBuildings: CodeMapBuilding[], selected: CodeMapBuilding, - state: State, + state: CcState, constantHighlight: Map ) { const highlightBuildingMap = TreeMapHelper.buildingArrayToMap(highlightedBuildings) @@ -109,7 +108,7 @@ export class CodeMapMesh { this.updateVertices() } - private adjustSurroundingBuildingColors(highlighted: CodeMapBuilding[], building: CodeMapBuilding, state: State) { + private adjustSurroundingBuildingColors(highlighted: CodeMapBuilding[], building: CodeMapBuilding, state: CcState) { if (state.appSettings.isPresentationMode) { const distance = highlighted[0].getCenterPoint(treeMapSize).distanceTo(building.getCenterPoint(treeMapSize)) this.decreaseLightnessByDistance(building, distance) @@ -118,7 +117,7 @@ export class CodeMapMesh { } } - private initDeltaColorsOnMesh(state: State) { + private initDeltaColorsOnMesh(state: CcState) { if (this.mapGeomDesc.buildings[0]?.node.deltas) { for (const building of this.mapGeomDesc.buildings) { this.setNewDeltaColor(building, state) @@ -128,7 +127,7 @@ export class CodeMapMesh { } } - private setNewDeltaColor(building: CodeMapBuilding, state: State) { + private setNewDeltaColor(building: CodeMapBuilding, state: CcState) { const { appSettings: { mapColors }, dynamicSettings: { heightMetric } diff --git a/visualization/app/codeCharta/ui/codeMap/rendering/geometryGenerator.ts b/visualization/app/codeCharta/ui/codeMap/rendering/geometryGenerator.ts index 74cbdb3d1c..304a8392b4 100644 --- a/visualization/app/codeCharta/ui/codeMap/rendering/geometryGenerator.ts +++ b/visualization/app/codeCharta/ui/codeMap/rendering/geometryGenerator.ts @@ -1,4 +1,4 @@ -import { Node, State } from "../../../codeCharta.model" +import { Node, CcState } from "../../../codeCharta.model" import { CodeMapGeometricDescription } from "./codeMapGeometricDescription" import { addBoxToVertexData, IntermediateVertexData, BoxMeasures } from "./geometryGenerationHelper" import { ColorConverter } from "../../../util/color/colorConverter" @@ -16,7 +16,7 @@ export class GeometryGenerator { private floorGradient: string[] private materials: Material[] - build(nodes: Node[], material: Material, state: State, isDeltaState: boolean): BuildResult { + build(nodes: Node[], material: Material, state: CcState, isDeltaState: boolean): BuildResult { const desc = new CodeMapGeometricDescription(treeMapSize) this.floorGradient = ColorConverter.gradient("#333333", "#DDDDDD", this.getMaxNodeDepth(nodes)) @@ -97,7 +97,7 @@ export class GeometryGenerator { node: Node, index: number, desc: CodeMapGeometricDescription, - state: State, + state: CcState, isDeltaState: boolean ) { const measures = this.mapNodeToLocalBox(node) diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeOrbitControls.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeOrbitControls.service.spec.ts index 2d135b6e52..63be0bafad 100644 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeOrbitControls.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeOrbitControls.service.spec.ts @@ -1,4 +1,5 @@ import { TestBed } from "@angular/core/testing" +import { StoreModule } from "@ngrx/store" import { ThreeOrbitControlsService } from "./threeOrbitControls.service" import { ThreeCameraService } from "./threeCamera.service" import { ThreeSceneService } from "./threeSceneService" @@ -6,6 +7,7 @@ import { BoxGeometry, Group, Mesh, PerspectiveCamera, Vector3 } from "three" import type { OrbitControls } from "three/examples/jsm/controls/OrbitControls" import { ThreeRendererService } from "./threeRenderer.service" import { wait } from "../../../util/testUtils/wait" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" describe("ThreeOrbitControlsService", () => { let threeOrbitControlsService: ThreeOrbitControlsService @@ -16,6 +18,9 @@ describe("ThreeOrbitControlsService", () => { let vector: Vector3 beforeEach(() => { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) restartSystem() rebuildService() withMockedThreeCameraService() diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.spec.ts index d9d4a316a5..a73922c1c9 100644 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.spec.ts @@ -1,15 +1,16 @@ import { TestBed } from "@angular/core/testing" import { Camera, Scene, Vector2, WebGLRenderer } from "three" +import { Store, StoreModule } from "@ngrx/store" // eslint-disable-next-line no-duplicate-imports import * as three from "three" import { WEBGL } from "three/examples/jsm/WebGL" import { SharpnessMode } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" import { setSharpnessMode } from "../../../state/store/appSettings/sharpnessMode/sharpnessMode.actions" import { CustomComposer } from "../rendering/postprocessor/customComposer" import { ThreeRendererService } from "./threeRenderer.service" import * as composer from "../rendering/postprocessor/customComposer" import { setIsWhiteBackground } from "../../../state/store/appSettings/isWhiteBackground/isWhiteBackground.actions" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" describe("threeRendererService", () => { let threeRendererService: ThreeRendererService @@ -17,12 +18,12 @@ describe("threeRendererService", () => { const setFXAA = (value: boolean) => { ThreeRendererService.enableFXAA = value - store.dispatch(setSharpnessMode(value ? SharpnessMode.PixelRatioFXAA : SharpnessMode.Standard)) + store.dispatch(setSharpnessMode({ value: value ? SharpnessMode.PixelRatioFXAA : SharpnessMode.Standard })) } const setPixelRatio = (value: boolean) => { ThreeRendererService.setPixelRatio = value - store.dispatch(setSharpnessMode(value ? SharpnessMode.PixelRatioFXAA : SharpnessMode.Standard)) + store.dispatch(setSharpnessMode({ value: value ? SharpnessMode.PixelRatioFXAA : SharpnessMode.Standard })) } const setWebGl2 = value => { @@ -40,7 +41,8 @@ describe("threeRendererService", () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [ThreeRendererService, Store] + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })], + providers: [ThreeRendererService] }) store = TestBed.inject(Store) @@ -128,14 +130,14 @@ describe("threeRendererService", () => { }) it("should ignore background updates before it was initialized", () => { - store.dispatch(setIsWhiteBackground(true)) + store.dispatch(setIsWhiteBackground({ value: true })) expect(threeRendererService["setBackgroundColorToState"]).not.toHaveBeenCalled() }) it("should set its background color within init and subscribe to updates", () => { threeRendererService.init(10, 20, new Scene(), new Camera()) expect(threeRendererService["setBackgroundColorToState"]).toHaveBeenCalledTimes(1) - store.dispatch(setIsWhiteBackground(false)) + store.dispatch(setIsWhiteBackground({ value: true })) expect(threeRendererService["setBackgroundColorToState"]).toHaveBeenCalledTimes(2) }) }) @@ -192,7 +194,7 @@ describe("threeRendererService", () => { it("should call initComposer when enableFXAA is true", () => { threeRendererService["initComposer"] = jest.fn() - store.dispatch(setSharpnessMode(SharpnessMode.PixelRatioFXAA)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.PixelRatioFXAA })) threeRendererService["initGL"](1, 1) expect(threeRendererService["initComposer"]).toHaveBeenCalled() @@ -200,7 +202,7 @@ describe("threeRendererService", () => { it("should not call initComposer when enableFXAA is false", () => { threeRendererService["initComposer"] = jest.fn() - store.dispatch(setSharpnessMode(SharpnessMode.Standard)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.Standard })) threeRendererService["initGL"](1, 1) expect(threeRendererService["initComposer"]).not.toHaveBeenCalled() @@ -209,7 +211,7 @@ describe("threeRendererService", () => { describe("setGLOptions", () => { it("should call and set the standard options", () => { - store.dispatch(setSharpnessMode(SharpnessMode.Standard)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.Standard })) threeRendererService["setGLOptions"]() @@ -219,7 +221,7 @@ describe("threeRendererService", () => { }) it("should call and set the pixel ration with no AA options", () => { - store.dispatch(setSharpnessMode(SharpnessMode.PixelRatioNoAA)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.PixelRatioNoAA })) threeRendererService["setGLOptions"]() @@ -229,7 +231,7 @@ describe("threeRendererService", () => { }) it("should call and set the pixel ration with FXAA options", () => { - store.dispatch(setSharpnessMode(SharpnessMode.PixelRatioFXAA)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.PixelRatioFXAA })) threeRendererService["setGLOptions"]() @@ -239,7 +241,7 @@ describe("threeRendererService", () => { }) it("should call and set the pixel ration with AA options", () => { - store.dispatch(setSharpnessMode(SharpnessMode.PixelRatioAA)) + store.dispatch(setSharpnessMode({ value: SharpnessMode.PixelRatioAA })) threeRendererService["setGLOptions"]() diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.ts index bc443109eb..d32edc3bcc 100644 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeRenderer.service.ts @@ -4,11 +4,10 @@ import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass" import { WEBGL } from "three/examples/jsm/WebGL" import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass" import { CustomComposer } from "../rendering/postprocessor/customComposer" -import { Store } from "../../../state/angular-redux/store" -import { State } from "../../../state/angular-redux/state" import { isWhiteBackgroundSelector } from "../../../state/store/appSettings/isWhiteBackground/isWhiteBackground.selector" -import { SharpnessMode } from "../../../codeCharta.model" +import { SharpnessMode, CcState } from "../../../codeCharta.model" import { fxaaShaderStrings } from "../rendering/shaders/loaders/fxaaShaderStrings" +import { Store, State } from "@ngrx/store" @Injectable({ providedIn: "root" }) export class ThreeRendererService { @@ -37,7 +36,7 @@ export class ThreeRendererService { scene: Scene camera: Camera - constructor(private store: Store, private state: State) {} + constructor(private store: Store, private state: State) {} init(containerWidth: number, containerHeight: number, scene: Scene, camera: Camera) { this.scene = scene diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.spec.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.spec.ts index ee49256b52..72a3ca2048 100644 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.spec.ts @@ -1,3 +1,4 @@ +import { Store, State, StoreModule } from "@ngrx/store" import { CODE_MAP_BUILDING, CODE_MAP_BUILDING_TS_NODE, @@ -10,17 +11,16 @@ import { import { CodeMapBuilding } from "../rendering/codeMapBuilding" import { ThreeSceneService } from "./threeSceneService" import { CodeMapMesh } from "../rendering/codeMapMesh" -import { CodeMapNode, LayoutAlgorithm } from "../../../codeCharta.model" +import { CcState, CodeMapNode, LayoutAlgorithm } from "../../../codeCharta.model" import { setScaling } from "../../../state/store/appSettings/scaling/scaling.actions" import { Box3, BufferGeometry, Group, Material, Matrix4, Object3D, Raycaster, Vector3 } from "three" import { setLayoutAlgorithm } from "../../../state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions" import { FloorLabelDrawer } from "./floorLabels/floorLabelDrawer" import { idToNodeSelector } from "../../../state/selectors/accumulatedData/idToNode.selector" import { TestBed } from "@angular/core/testing" -import { State } from "../../../state/angular-redux/state" import { IdToBuildingService } from "../../../services/idToBuilding/idToBuilding.service" -import { Store } from "../../../state/angular-redux/store" import { setEnableFloorLabels } from "../../../state/store/appSettings/enableFloorLabels/enableFloorLabels.actions" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" jest.mock("../../../state/selectors/accumulatedData/idToNode.selector", () => ({ idToNodeSelector: jest.fn() @@ -29,13 +29,14 @@ const mockedIdToNodeSelector = jest.mocked(idToNodeSelector) describe("ThreeSceneService", () => { let threeSceneService: ThreeSceneService - let state: State + let state: State let idToBuildingService: IdToBuildingService - let store: Store + let store: Store beforeEach(() => { TestBed.configureTestingModule({ - providers: [ThreeSceneService] + providers: [ThreeSceneService], + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] }) state = TestBed.inject(State) @@ -387,7 +388,7 @@ describe("ThreeSceneService", () => { } const scaling = new Vector3(1, 2, 3) - store.dispatch(setScaling(scaling)) + store.dispatch(setScaling({ value: scaling })) threeSceneService.scaleHeight() @@ -404,7 +405,7 @@ describe("ThreeSceneService", () => { } const scaling = new Vector3(1, 2, 3) - store.dispatch(setScaling(scaling)) + store.dispatch(setScaling({ value: scaling })) threeSceneService["mapMesh"].setScale = jest.fn() threeSceneService.scaleHeight() @@ -427,10 +428,10 @@ describe("ThreeSceneService", () => { const originalGetRootNode = threeSceneService["getRootNode"] threeSceneService["getRootNode"] = getRootNodeMock - store.dispatch(setLayoutAlgorithm(LayoutAlgorithm.StreetMap)) + store.dispatch(setLayoutAlgorithm({ value: LayoutAlgorithm.StreetMap })) threeSceneService.setMapMesh([], new CodeMapMesh(TEST_NODES, state.getValue(), false)) - store.dispatch(setLayoutAlgorithm(LayoutAlgorithm.TreeMapStreet)) + store.dispatch(setLayoutAlgorithm({ value: LayoutAlgorithm.TreeMapStreet })) threeSceneService.setMapMesh([], new CodeMapMesh(TEST_NODES, state.getValue(), false)) expect(getRootNodeMock).not.toHaveBeenCalled() @@ -438,7 +439,7 @@ describe("ThreeSceneService", () => { threeSceneService["getRootNode"] = originalGetRootNode - store.dispatch(setLayoutAlgorithm(LayoutAlgorithm.SquarifiedTreeMap)) + store.dispatch(setLayoutAlgorithm({ value: LayoutAlgorithm.SquarifiedTreeMap })) threeSceneService.setMapMesh(TEST_NODES, new CodeMapMesh(TEST_NODES, state.getValue(), false)) expect(floorLabelDrawerSpy).toHaveBeenCalled() @@ -448,7 +449,7 @@ describe("ThreeSceneService", () => { threeSceneService["notifyMapMeshChanged"] = jest.fn() const floorLabelDrawerSpy = jest.spyOn(FloorLabelDrawer.prototype, "draw").mockReturnValue([]) - store.dispatch(setLayoutAlgorithm(LayoutAlgorithm.SquarifiedTreeMap)) + store.dispatch(setLayoutAlgorithm({ value: LayoutAlgorithm.SquarifiedTreeMap })) threeSceneService.setMapMesh([TEST_NODE_LEAF], new CodeMapMesh(TEST_NODES, state.getValue(), false)) expect(floorLabelDrawerSpy).not.toHaveBeenCalled() @@ -458,7 +459,7 @@ describe("ThreeSceneService", () => { threeSceneService["notifyMapMeshChanged"] = jest.fn() const floorLabelDrawerSpy = jest.spyOn(FloorLabelDrawer.prototype, "draw").mockReturnValue([]) - store.dispatch(setEnableFloorLabels(false)) + store.dispatch(setEnableFloorLabels({ value: false })) threeSceneService.setMapMesh([TEST_NODE_LEAF], new CodeMapMesh(TEST_NODES, state.getValue(), false)) expect(floorLabelDrawerSpy).not.toHaveBeenCalled() diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.ts index 1bd98e1116..3d9fb1f328 100755 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeSceneService.ts @@ -1,7 +1,7 @@ import { AmbientLight, Box3, BufferGeometry, DirectionalLight, Group, Line, Material, Object3D, Raycaster, Scene, Vector3 } from "three" import { CodeMapMesh } from "../rendering/codeMapMesh" import { CodeMapBuilding } from "../rendering/codeMapBuilding" -import { CodeMapNode, LayoutAlgorithm, Node } from "../../../codeCharta.model" +import { CodeMapNode, LayoutAlgorithm, Node, CcState } from "../../../codeCharta.model" import { hierarchy } from "d3-hierarchy" import { ColorConverter } from "../../../util/color/colorConverter" import { FloorLabelDrawer } from "./floorLabels/floorLabelDrawer" @@ -11,11 +11,10 @@ import { IdToBuildingService } from "../../../services/idToBuilding/idToBuilding import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/mapColors.selector" import { ThreeRendererService } from "./threeRenderer.service" import { Injectable, OnDestroy } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" -import { defaultMapColors } from "../../../state/store/appSettings/mapColors/mapColors.actions" -import { State } from "../../../state/angular-redux/state" +import { defaultMapColors } from "../../../state/store/appSettings/mapColors/mapColors.reducer" import { treeMapSize } from "../../../util/algorithm/treeMapLayout/treeMapHelper" import { EventEmitter } from "../../../util/EventEmitter" +import { Store, State } from "@ngrx/store" type BuildingSelectedEvents = { onBuildingSelected: (data: { building: CodeMapBuilding }) => void @@ -55,8 +54,8 @@ export class ThreeSceneService implements OnDestroy { }) constructor( - private store: Store, - private state: State, + private store: Store, + private state: State, private idToBuilding: IdToBuildingService, private threeRendererService: ThreeRendererService ) { @@ -113,7 +112,7 @@ export class ThreeSceneService implements OnDestroy { } highlightBuildings() { - const state = this.state.getValue() + const state = this.state.getValue() as CcState this.getMapMesh().highlightBuilding(this.highlighted, this.selected, state, this.constantHighlight) if (this.mapGeometry.children[0]) { this.highlightMaterial(this.mapGeometry.children[0]["material"]) @@ -193,7 +192,7 @@ export class ThreeSceneService implements OnDestroy { selectBuilding(building: CodeMapBuilding) { // TODO: This check shouldn't be necessary. When investing into model we should investigate why and remove the need. if (building.id !== this.selected?.id) { - this.store.dispatch(setSelectedBuildingId(building.node.id)) + this.store.dispatch(setSelectedBuildingId({ value: building.node.id })) } this.getMapMesh().selectBuilding(building, this.folderLabelColorSelected) @@ -368,7 +367,7 @@ export class ThreeSceneService implements OnDestroy { clearSelection() { if (this.selected) { this.getMapMesh().clearSelection(this.selected) - this.store.dispatch(setSelectedBuildingId(null)) + this.store.dispatch(setSelectedBuildingId({ value: null })) this.eventEmitter.emit("onBuildingDeselected") } diff --git a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeViewer.service.spec.ts b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeViewer.service.spec.ts index d0bcb9dcc9..98dfaf4afc 100644 --- a/visualization/app/codeCharta/ui/codeMap/threeViewer/threeViewer.service.spec.ts +++ b/visualization/app/codeCharta/ui/codeMap/threeViewer/threeViewer.service.spec.ts @@ -1,4 +1,6 @@ import { TestBed } from "@angular/core/testing" +import { provideMockStore } from "@ngrx/store/testing" +import { State } from "@ngrx/store" import { ThreeSceneService } from "./threeSceneService" import { ThreeCameraService } from "./threeCamera.service" import { ThreeOrbitControlsService } from "./threeOrbitControls.service" @@ -20,6 +22,9 @@ describe("ThreeViewerService", () => { let element: Element beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore(), { provide: State, useValue: {} }] + }) restartSystem() rebuildService() withMockedElement() diff --git a/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.spec.ts b/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.spec.ts index fefb9c83e1..0ab5acbfa9 100644 --- a/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.spec.ts +++ b/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.spec.ts @@ -1,20 +1,27 @@ import { TestBed } from "@angular/core/testing" +import { provideMockStore } from "@ngrx/store/testing" import { render, screen } from "@testing-library/angular" import { ColorPickerForMapColorComponent } from "./colorPickerForMapColor.component" import { ColorPickerForMapColorModule } from "./colorPickerForMapColor.module" - -jest.mock("../../state/store/appSettings/mapColors/mapColors.selector", () => ({ - mapColorsSelector: () => ({ positive: "#ffffff" }) -})) -jest.mock("../../state/store/dynamicSettings/colorRange/colorRange.selector", () => ({ - colorRangeSelector: () => ({ from: 21 }) -})) +import { mapColorsSelector } from "../../state/store/appSettings/mapColors/mapColors.selector" +import { defaultMapColors } from "../../state/store/appSettings/mapColors/mapColors.reducer" +import { colorRangeSelector } from "../../state/store/dynamicSettings/colorRange/colorRange.selector" +import { selectedColorMetricDataSelector } from "../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" describe("colorPickerForMapColor", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ColorPickerForMapColorModule] + imports: [ColorPickerForMapColorModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: mapColorsSelector, value: defaultMapColors }, + { selector: colorRangeSelector, value: { from: 21, to: 100 } }, + { selector: selectedColorMetricDataSelector, value: { minValue: 0, maxValue: 100 } } + ] + }) + ] }) }) diff --git a/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.ts b/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.ts index 93db742952..ace09b12c8 100644 --- a/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.ts +++ b/visualization/app/codeCharta/ui/colorPickerForMapColor/colorPickerForMapColor.component.ts @@ -1,7 +1,7 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" -import { MapColors } from "../../codeCharta.model" -import { Store } from "../../state/angular-redux/store" +import { MapColors, CcState } from "../../codeCharta.model" import { selectedColorMetricDataSelector } from "../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" import { setMapColors } from "../../state/store/appSettings/mapColors/mapColors.actions" import { mapColorsSelector } from "../../state/store/appSettings/mapColors/mapColors.selector" @@ -19,12 +19,12 @@ export class ColorPickerForMapColorComponent { colorRange$ = this.store.select(colorRangeSelector) nodeMetricRange$ = this.store.select(selectedColorMetricDataSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleColorChange(newHexColor: string) { this.store.dispatch( setMapColors({ - [this.mapColorFor]: newHexColor + value: { [this.mapColorFor]: newHexColor } }) ) } diff --git a/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.spec.ts b/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.spec.ts index e8ae0ff2e4..83a6d3821c 100644 --- a/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.spec.ts +++ b/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.spec.ts @@ -1,7 +1,9 @@ -import { State } from "../../state/angular-redux/state" +import { State } from "@ngrx/store" import { CopyToClipboardService } from "./copyToClipboard.service" import { buildTextOfFiles } from "./util/clipboardString" import { getFilenamesWithHighestMetrics } from "./util/getFilenamesWithHighestMetrics" +import { CcState } from "../../codeCharta.model" + let service: CopyToClipboardService jest.mock("./util/clipboardString", () => { return { buildTextOfFiles: jest.fn().mockReturnValue("Magic Monday") } @@ -9,14 +11,14 @@ jest.mock("./util/clipboardString", () => { jest.mock("./util/getFilenamesWithHighestMetrics", () => { return { getFilenamesWithHighestMetrics: jest.fn() } }) + describe("CopyToClipboardService", () => { beforeEach(() => { - const stateStub = {} as unknown as State + const stateStub = {} as unknown as State service = new CopyToClipboardService(stateStub) service["getUnifiedMapNode"] = jest.fn() - - jest.clearAllMocks() }) + describe("getClipboardText", () => { it("should call functions to convert state and to build text", () => { const stateConverterMock = getFilenamesWithHighestMetrics diff --git a/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.ts b/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.ts index e191133384..3236cf3ffd 100644 --- a/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.ts +++ b/visualization/app/codeCharta/ui/copyToClipboardButton/copyToClipboard.service.ts @@ -1,12 +1,13 @@ import { Injectable } from "@angular/core" -import { State } from "../../state/angular-redux/state" +import { State } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" import { accumulatedDataSelector } from "../../state/selectors/accumulatedData/accumulatedData.selector" import { buildTextOfFiles } from "./util/clipboardString" import { getFilenamesWithHighestMetrics } from "./util/getFilenamesWithHighestMetrics" @Injectable() export class CopyToClipboardService { - constructor(private state: State) {} + constructor(private state: State) {} private getUnifiedMapNode() { const { unifiedMapNode } = accumulatedDataSelector(this.state.getValue()) diff --git a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigButton.component.spec.ts b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigButton.component.spec.ts index 1193467506..5741f5e723 100644 --- a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigButton.component.spec.ts @@ -1,4 +1,5 @@ import { TestBed } from "@angular/core/testing" +import { State } from "@ngrx/store" import { AddCustomConfigButtonModule } from "./addCustomConfigButton.module" import { render, screen } from "@testing-library/angular" import { AddCustomConfigButtonComponent } from "./addCustomConfigButton.component" @@ -9,6 +10,7 @@ import { ThreeCameraService } from "../../codeMap/threeViewer/threeCamera.servic import { ThreeOrbitControlsService } from "../../codeMap/threeViewer/threeOrbitControls.service" import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed" import { MatDialogHarness } from "@angular/material/dialog/testing" +import { defaultState } from "../../../state/store/state.manager" describe("addCustomConfigButtonComponent", () => { beforeEach(async () => { @@ -16,7 +18,8 @@ describe("addCustomConfigButtonComponent", () => { imports: [AddCustomConfigButtonModule], providers: [ { provide: ThreeCameraService, useValue: { camera: { position: new Vector3(0, 300, 1000) } } }, - { provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(0, 0, 0) } } } + { provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(0, 0, 0) } } }, + { provide: State, useValue: { getValue: () => defaultState } } ] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.component.ts b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.component.ts index d37b1dcffb..f5d0a3e629 100644 --- a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.component.ts +++ b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.component.ts @@ -2,10 +2,11 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core" import { UntypedFormControl, Validators, AbstractControl, ValidatorFn } from "@angular/forms" import { CustomConfigHelper } from "../../../../util/customConfigHelper" import { buildCustomConfigFromState } from "../../../../util/customConfigBuilder" -import { State } from "../../../../state/angular-redux/state" import { ThreeCameraService } from "../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../codeMap/threeViewer/threeOrbitControls.service" import { VisibleFilesBySelectionMode, visibleFilesBySelectionModeSelector } from "../../visibleFilesBySelectionMode.selector" +import { CcState } from "../../../../codeCharta.model" +import { State } from "@ngrx/store" @Component({ templateUrl: "./addCustomConfigDialog.component.html", @@ -17,7 +18,7 @@ export class AddCustomConfigDialogComponent implements OnInit { customConfigNote: string constructor( - private state: State, + private state: State, private threeCameraService: ThreeCameraService, private threeOrbitControlsService: ThreeOrbitControlsService ) {} diff --git a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.spec.ts b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.spec.ts index 3e4f19cd9e..516af058d6 100644 --- a/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/addCustomConfigButton/addCustomConfigDialog/addCustomConfigDialog.spec.ts @@ -8,6 +8,9 @@ import { Vector3 } from "three" import { ThreeCameraService } from "../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../codeMap/threeViewer/threeOrbitControls.service" import { MatDialog } from "@angular/material/dialog" +import { provideMockStore } from "@ngrx/store/testing" +import { defaultState } from "../../../../state/store/state.manager" +import { State } from "@ngrx/store" describe("addCustomConfigDialogComponent", () => { jest.spyOn(CustomConfigHelper, "getConfigNameSuggestionByFileState").mockReturnValue("new custom view name") @@ -19,7 +22,9 @@ describe("addCustomConfigDialogComponent", () => { providers: [ { provide: MatDialog, useValue: mockedDialog }, { provide: ThreeCameraService, useValue: { camera: { position: new Vector3(0, 300, 1000) } } }, - { provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(0, 0, 0) } } } + { provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(0, 0, 0) } } }, + provideMockStore(), + { provide: State, useValue: { getValue: () => defaultState } } ] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigHelper.service.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigHelper.service.ts index 0b3b1c5a7e..03ed69af1b 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigHelper.service.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigHelper.service.ts @@ -2,9 +2,10 @@ import { combineLatest, map } from "rxjs" import { CustomConfigHelper } from "../../util/customConfigHelper" import { getDownloadableCustomConfigs } from "./downloadCustomConfigsButton/getDownloadableCustomConfigs" import { Injectable } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { getCustomConfigItemGroups } from "./customConfigList/getCustomConfigItemGroups" import { visibleFilesBySelectionModeSelector } from "./visibleFilesBySelectionMode.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Injectable() export class CustomConfigHelperService { @@ -18,5 +19,5 @@ export class CustomConfigHelperService { CustomConfigHelper.customConfigChange$ ]).pipe(map(([visibleFilesBySelectionMode]) => getCustomConfigItemGroups(visibleFilesBySelectionMode))) - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.spec.ts index be067860b6..d7f96f7abf 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.spec.ts @@ -3,6 +3,8 @@ import { CustomConfigMapSelectionMode } from "../../../../model/customConfig/cus import * as getMissingCustomConfigModeAndMaps from "./getMissingCustomConfigModeAndMaps" import { CustomConfig2ApplicableColor } from "./customConfig2ApplicableColor.pipe" +import { CcState } from "../../../../codeCharta.model" +import { State } from "@ngrx/store" describe("customConfig2ApplicableColorPipe", () => { const customConfigItem = { @@ -12,6 +14,7 @@ describe("customConfig2ApplicableColorPipe", () => { ]), mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE } as CustomConfigItem + const state = { getValue: jest.fn() } as unknown as State it("should transform black color", () => { jest.spyOn(getMissingCustomConfigModeAndMaps, "getMissingCustomConfigModeAndMaps").mockImplementation(() => ({ @@ -19,7 +22,7 @@ describe("customConfig2ApplicableColorPipe", () => { mapNames: [] })) - expect(new CustomConfig2ApplicableColor({ getValue: jest.fn() }).transform(customConfigItem)).toBe("rgba(0, 0, 0, 0.87)") + expect(new CustomConfig2ApplicableColor(state).transform(customConfigItem)).toBe("rgba(0, 0, 0, 0.87)") }) it("should transform grey color", () => { @@ -28,6 +31,6 @@ describe("customConfig2ApplicableColorPipe", () => { mapNames: ["file2"] })) - expect(new CustomConfig2ApplicableColor({ getValue: jest.fn() }).transform(customConfigItem)).toBe("rgb(204, 204, 204)") + expect(new CustomConfig2ApplicableColor(state).transform(customConfigItem)).toBe("rgb(204, 204, 204)") }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.ts index 09e12f58ef..8ea4f2963a 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableColor.pipe.ts @@ -1,14 +1,15 @@ import { Pipe, PipeTransform } from "@angular/core" -import { State } from "../../../../state/angular-redux/state" +import { State } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" import { CustomConfigItem } from "../../customConfigs.component" import { getMissingCustomConfigModeAndMaps } from "./getMissingCustomConfigModeAndMaps" @Pipe({ name: "customConfig2ApplicableColor" }) export class CustomConfig2ApplicableColor implements PipeTransform { - constructor(private state: State) {} + constructor(private state: State) {} transform(customConfig: CustomConfigItem): string { - const { mapSelectionMode, mapNames } = getMissingCustomConfigModeAndMaps(customConfig, this.state) + const { mapSelectionMode, mapNames } = getMissingCustomConfigModeAndMaps(customConfig, this.state.getValue()) return mapNames.length > 0 || mapSelectionMode.length > 0 ? "rgb(204, 204, 204)" : "rgba(0, 0, 0, 0.87)" } } diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.spec.ts index e97fce8015..87f1b78f41 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.spec.ts @@ -1,8 +1,10 @@ import { CustomConfigItem } from "../../customConfigs.component" import { CustomConfigMapSelectionMode } from "../../../../model/customConfig/customConfig.api.model" import * as getMissingCustomConfigModeAndMaps from "./getMissingCustomConfigModeAndMaps" -import { Store as PlainStore } from "../../../../state/store/store" import { CustomConfig2ApplicableMessage } from "./customConfig2ApplicableMessage.pipe" +import { defaultState } from "../../../../state/store/state.manager" +import { State } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" describe("customConfig2ApplicableMessage", () => { const customConfigItem = { @@ -12,6 +14,7 @@ describe("customConfig2ApplicableMessage", () => { ]), mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE } as CustomConfigItem + const state = { getValue: () => defaultState } as State it("should return 'Apply Custom View' message when there is no map selection mode difference and maps are not missing", () => { jest.spyOn(getMissingCustomConfigModeAndMaps, "getMissingCustomConfigModeAndMaps").mockImplementation(() => ({ @@ -19,9 +22,7 @@ describe("customConfig2ApplicableMessage", () => { mapNames: [] })) - expect(new CustomConfig2ApplicableMessage({ getValue: PlainStore.store.getState }).transform(customConfigItem)).toBe( - "Apply Custom View" - ) + expect(new CustomConfig2ApplicableMessage(state).transform(customConfigItem)).toBe("Apply Custom View") }) it("should show the map selection mode required to be totally clickable when the mode differs from the custom config", () => { @@ -30,7 +31,7 @@ describe("customConfig2ApplicableMessage", () => { mapNames: [] })) - expect(new CustomConfig2ApplicableMessage({ getValue: PlainStore.store.getState }).transform(customConfigItem)).toBe( + expect(new CustomConfig2ApplicableMessage(state).transform(customConfigItem)).toBe( "This view is partially applicable. To complete your view, please switch to the DELTA mode." ) }) @@ -41,7 +42,7 @@ describe("customConfig2ApplicableMessage", () => { mapNames: ["file1"] })) - expect(new CustomConfig2ApplicableMessage({ getValue: PlainStore.store.getState }).transform(customConfigItem)).toBe( + expect(new CustomConfig2ApplicableMessage(state).transform(customConfigItem)).toBe( "To fulfill your view, please select the following map(s): file1." ) }) @@ -52,7 +53,7 @@ describe("customConfig2ApplicableMessage", () => { mapNames: ["file1"] })) - expect(new CustomConfig2ApplicableMessage({ getValue: PlainStore.store.getState }).transform(customConfigItem)).toBe( + expect(new CustomConfig2ApplicableMessage(state).transform(customConfigItem)).toBe( "This view is partially applicable. To complete your view, please switch to the STANDARD mode and select the following map(s): file1." ) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.ts index a3cade4367..05417ab4c5 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfig2ApplicableMessage.pipe.ts @@ -1,14 +1,15 @@ import { Pipe, PipeTransform } from "@angular/core" +import { State } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" import { CustomConfigItem } from "../../customConfigs.component" -import { State } from "../../../../state/angular-redux/state" import { getMissingCustomConfigModeAndMaps } from "./getMissingCustomConfigModeAndMaps" @Pipe({ name: "customConfig2ApplicableMessage" }) export class CustomConfig2ApplicableMessage implements PipeTransform { - constructor(private state: State) {} + constructor(private state: State) {} transform(customConfig: CustomConfigItem): string { - const { mapSelectionMode, mapNames } = getMissingCustomConfigModeAndMaps(customConfig, this.state) + const { mapSelectionMode, mapNames } = getMissingCustomConfigModeAndMaps(customConfig, this.state.getValue()) if (mapNames.length > 0 && mapSelectionMode.length > 0) { return `This view is partially applicable. To complete your view, please switch to the ${mapSelectionMode} mode and select the following map(s): ${mapNames.join( diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.component.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.component.ts index 307866a0a2..c3c8447a36 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.component.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.component.ts @@ -1,9 +1,9 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" import { CustomConfigItem } from "../../../customConfigs.component" import { CustomConfigHelper } from "../../../../../util/customConfigHelper" -import { Store } from "../../../../../state/angular-redux/store" import { ThreeCameraService } from "../../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../../codeMap/threeViewer/threeOrbitControls.service" +import { Store } from "@ngrx/store" @Component({ selector: "cc-apply-custom-config-button", diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.spec.ts index bf8d6d06fd..bc01c3b90a 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigDescription/applyCustomConfigButton.spec.ts @@ -8,6 +8,9 @@ import { ThreeCameraService } from "../../../../codeMap/threeViewer/threeCamera. import { ThreeOrbitControlsService } from "../../../../codeMap/threeViewer/threeOrbitControls.service" import { CUSTOM_CONFIG_ITEM_GROUPS } from "../../../../../util/dataMocks" import { CustomConfigHelper } from "../../../../../util/customConfigHelper" +import { provideMockStore } from "@ngrx/store/testing" +import { State } from "@ngrx/store" +import { defaultState } from "../../../../../state/store/state.manager" describe("applyCustomConfigButtonComponent", () => { beforeEach(() => { @@ -15,7 +18,9 @@ describe("applyCustomConfigButtonComponent", () => { imports: [CustomConfigsModule], providers: [ { provide: ThreeCameraService, useValue: {} }, - { provide: ThreeOrbitControlsService, useValue: {} } + { provide: ThreeOrbitControlsService, useValue: {} }, + provideMockStore(), + { provide: State, useValue: { getValue: () => defaultState } } ] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.spec.ts index fed9ed670e..1f9afe4741 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.spec.ts @@ -11,12 +11,9 @@ import { expect } from "@jest/globals" import { CustomConfigMapSelectionMode } from "../../../../model/customConfig/customConfig.api.model" import { visibleFilesBySelectionModeSelector } from "../../visibleFilesBySelectionMode.selector" import { MatDialog, MatDialogRef } from "@angular/material/dialog" - -jest.mock("../../visibleFilesBySelectionMode.selector", () => ({ - visibleFilesBySelectionModeSelector: jest.fn() -})) - -const mockedVisibleFilesBySelectionModeSelector = visibleFilesBySelectionModeSelector as jest.Mock +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { State } from "@ngrx/store" +import { defaultState } from "../../../../state/store/state.manager" describe("customConfigItemGroupComponent", () => { let mockedDialog = { open: jest.fn() } @@ -32,21 +29,27 @@ describe("customConfigItemGroupComponent", () => { { provide: MatDialogRef, useValue: mockedDialogReference }, { provide: MatDialog, useValue: mockedDialog }, { provide: ThreeCameraService, useValue: {} }, - { provide: ThreeOrbitControlsService, useValue: {} } + { provide: ThreeOrbitControlsService, useValue: {} }, + provideMockStore({ + selectors: [ + { + selector: visibleFilesBySelectionModeSelector, + value: { + mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE, + assignedMaps: new Map([ + ["md5_fileB", "fileB"], + ["md5_fileC", "fileC"] + ]) + } + } + ] + }), + { provide: State, useValue: { getValue: () => defaultState } } ] }) }) it("should apply a custom Config and close custom config dialog", async () => { - mockedVisibleFilesBySelectionModeSelector.mockImplementation(() => { - return { - mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE, - assignedMaps: new Map([ - ["md5_fileB", "fileB"], - ["md5_fileC", "fileC"] - ]) - } - }) CustomConfigHelper.applyCustomConfig = jest.fn() const customConfigItemGroups = new Map([["File_B_File_C_STANDARD", CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD")]]) await render(CustomConfigItemGroupComponent, { @@ -62,15 +65,6 @@ describe("customConfigItemGroupComponent", () => { }) it("should remove a custom Config and not close custom config dialog", async () => { - mockedVisibleFilesBySelectionModeSelector.mockImplementation(() => { - return { - mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE, - assignedMaps: new Map([ - ["md5_fileB", "fileB"], - ["md5_fileC", "fileC"] - ]) - } - }) CustomConfigHelper.deleteCustomConfig = jest.fn() const customConfigItemGroups = new Map([["File_B_File_C_STANDARD", CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD")]]) await render(CustomConfigItemGroupComponent, { @@ -86,15 +80,6 @@ describe("customConfigItemGroupComponent", () => { }) it("should apply a custom config and close custom config dialog when clicking on config name", async () => { - mockedVisibleFilesBySelectionModeSelector.mockImplementation(() => { - return { - mapSelectionMode: CustomConfigMapSelectionMode.MULTIPLE, - assignedMaps: new Map([ - ["md5_fileB", "fileB"], - ["md5_fileC", "fileC"] - ]) - } - }) const customConfigItemGroups = new Map([["File_B_File_C_STANDARD", CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD")]]) await render(CustomConfigItemGroupComponent, { excludeComponentDeclaration: true, @@ -111,17 +96,18 @@ describe("customConfigItemGroupComponent", () => { }) it("should show tooltip with missing maps and correct selection mode if selected custom config is not fully applicable", async () => { - mockedVisibleFilesBySelectionModeSelector.mockImplementation(() => { - return { - mapSelectionMode: CustomConfigMapSelectionMode.DELTA, - assignedMaps: new Map([["md5_fileB", "fileB"]]) - } - }) const customConfigItemGroups = new Map([["File_B_File_C_STANDARD", CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD")]]) - await render(CustomConfigItemGroupComponent, { + const { rerender } = await render(CustomConfigItemGroupComponent, { excludeComponentDeclaration: true, componentProperties: { customConfigItemGroups } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(visibleFilesBySelectionModeSelector, { + mapSelectionMode: CustomConfigMapSelectionMode.DELTA, + assignedMaps: new Map([["md5_fileB", "fileB"]]) + }) + store.refreshState() + await rerender({ componentProperties: { customConfigItemGroups } }) const applyCustomConfigButton = screen.getAllByText("mcc")[0].closest("button") @@ -136,20 +122,22 @@ describe("customConfigItemGroupComponent", () => { it("should not be clickable for non-applicable custom configs, but can still change notes of custom configs", async () => { CustomConfigHelper.applyCustomConfig = jest.fn() CustomConfigHelper.applyCustomConfig = jest.fn() - mockedVisibleFilesBySelectionModeSelector.mockImplementation(() => { - return { - mapSelectionMode: CustomConfigMapSelectionMode.DELTA, - assignedMaps: new Map([["md5_fileA", "fileA"]]) - } - }) CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD").hasApplicableItems = false CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD").customConfigItems[0].isApplicable = false CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD").customConfigItems[1].isApplicable = false const customConfigItemGroups = new Map([["File_B_File_C_STANDARD", CUSTOM_CONFIG_ITEM_GROUPS.get("File_B_File_C_STANDARD")]]) - await render(CustomConfigItemGroupComponent, { + const { rerender } = await render(CustomConfigItemGroupComponent, { excludeComponentDeclaration: true, componentProperties: { customConfigItemGroups } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(visibleFilesBySelectionModeSelector, { + mapSelectionMode: CustomConfigMapSelectionMode.DELTA, + assignedMaps: new Map([["md5_fileA", "fileA"]]) + }) + store.refreshState() + await rerender({ componentProperties: { customConfigItemGroups } }) + const editNoteArea = screen.getAllByTitle("Edit/View Note")[0] as HTMLButtonElement const applyCustomConfigButton = screen.getAllByText("mcc")[0].closest("button") as HTMLButtonElement diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.ts index 056857d087..080b0bbfdc 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/customConfigItemGroup.component.ts @@ -1,9 +1,9 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" import { CustomConfigHelper } from "../../../../util/customConfigHelper" import { CustomConfigItemGroup } from "../../customConfigs.component" -import { Store } from "../../../../state/angular-redux/store" import { ThreeCameraService } from "../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../codeMap/threeViewer/threeOrbitControls.service" +import { Store } from "@ngrx/store" @Component({ selector: "cc-custom-config-item-group", diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.spec.ts index 1f1f68289f..bccd1c3bfb 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.spec.ts @@ -1,9 +1,9 @@ import { getMissingCustomConfigModeAndMaps } from "./getMissingCustomConfigModeAndMaps" import { CustomConfigMapSelectionMode } from "../../../../model/customConfig/customConfig.api.model" import { CustomConfigItem } from "../../customConfigs.component" -import { Store as PlainStore } from "../../../../state/store/store" import { expect } from "@jest/globals" import { visibleFilesBySelectionModeSelector } from "../../visibleFilesBySelectionMode.selector" +import { defaultState } from "../../../../state/store/state.manager" jest.mock("../../visibleFilesBySelectionMode.selector", () => ({ visibleFilesBySelectionModeSelector: jest.fn() @@ -30,7 +30,7 @@ describe("getMissingCustomConfigModeAndMaps", () => { } }) - const missingModeAndMaps = getMissingCustomConfigModeAndMaps(customConfigItem, { getValue: PlainStore.store.getState }) + const missingModeAndMaps = getMissingCustomConfigModeAndMaps(customConfigItem, defaultState) expect(missingModeAndMaps).toEqual({ mapSelectionMode: "", mapNames: [] }) }) @@ -43,7 +43,7 @@ describe("getMissingCustomConfigModeAndMaps", () => { } }) - const missingModeAndMaps = getMissingCustomConfigModeAndMaps(customConfigItem, { getValue: PlainStore.store.getState }) + const missingModeAndMaps = getMissingCustomConfigModeAndMaps(customConfigItem, defaultState) expect(missingModeAndMaps).toEqual({ mapSelectionMode: "STANDARD", mapNames: ["file1"] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.ts index 986c7821bc..055c1c5b8e 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigItemGroup/getMissingCustomConfigModeAndMaps.ts @@ -1,5 +1,5 @@ +import { CcState } from "../../../../codeCharta.model" import { CustomConfigItem } from "../../customConfigs.component" -import { State } from "../../../../state/angular-redux/state" import { visibleFilesBySelectionModeSelector } from "../../visibleFilesBySelectionMode.selector" type MissingCustomConfigsProperties = { @@ -7,8 +7,8 @@ type MissingCustomConfigsProperties = { mapNames: string[] } -export function getMissingCustomConfigModeAndMaps(configItem: CustomConfigItem, state: State): MissingCustomConfigsProperties { - const { mapSelectionMode, assignedMaps } = visibleFilesBySelectionModeSelector(state.getValue()) +export function getMissingCustomConfigModeAndMaps(configItem: CustomConfigItem, state: CcState): MissingCustomConfigsProperties { + const { mapSelectionMode, assignedMaps } = visibleFilesBySelectionModeSelector(state) const mapNames = [] for (const checksum of configItem.assignedMaps.keys()) { diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigList.component.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigList.component.spec.ts index c12c039a03..aa0cb052ea 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigList.component.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigList/customConfigList.component.spec.ts @@ -1,5 +1,6 @@ -import { Store } from "../../../state/store/store" import { TestBed } from "@angular/core/testing" +import { provideMockStore } from "@ngrx/store/testing" +import { State } from "@ngrx/store" import { CustomConfigsModule } from "../customConfigs.module" import { CustomConfigListComponent } from "./customConfigList.component" import { render, screen } from "@testing-library/angular" @@ -15,6 +16,7 @@ import { ThreeOrbitControlsService } from "../../codeMap/threeViewer/threeOrbitC import userEvent from "@testing-library/user-event" import { expect } from "@jest/globals" import { MatDialog } from "@angular/material/dialog" +import { defaultState } from "../../../state/store/state.manager" const mockedCustomConfigHelperService = { customConfigItemGroups$: of({ @@ -29,7 +31,6 @@ describe("customConfigListComponent", () => { beforeEach(() => { mockedDialog = { open: jest.fn() } - Store["initialize"]() TestBed.configureTestingModule({ imports: [CustomConfigsModule], providers: [ @@ -37,7 +38,9 @@ describe("customConfigListComponent", () => { { provide: CustomConfigHelperService, useValue: mockedCustomConfigHelperService }, { provide: ThreeSceneService, useValue: {} }, { provide: ThreeCameraService, useValue: {} }, - { provide: ThreeOrbitControlsService, useValue: {} } + { provide: ThreeOrbitControlsService, useValue: {} }, + provideMockStore(), + { provide: State, useValue: { getValue: () => defaultState } } ] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/customConfigs.component.spec.ts b/visualization/app/codeCharta/ui/customConfigs/customConfigs.component.spec.ts index b7e7521782..557b1c28d8 100644 --- a/visualization/app/codeCharta/ui/customConfigs/customConfigs.component.spec.ts +++ b/visualization/app/codeCharta/ui/customConfigs/customConfigs.component.spec.ts @@ -1,4 +1,4 @@ -import { Store } from "../../state/store/store" +import { provideMockStore } from "@ngrx/store/testing" import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { CustomConfigsComponent } from "./customConfigs.component" @@ -13,10 +13,9 @@ describe("CustomConfigsComponent", () => { beforeEach(() => { mockedDialog = { open: jest.fn() } - Store["initialize"]() TestBed.configureTestingModule({ imports: [CustomConfigsModule], - providers: [{ provide: MatDialog, useValue: mockedDialog }] + providers: [{ provide: MatDialog, useValue: mockedDialog }, provideMockStore()] }) }) diff --git a/visualization/app/codeCharta/ui/customConfigs/visibleFilesBySelectionMode.selector.ts b/visualization/app/codeCharta/ui/customConfigs/visibleFilesBySelectionMode.selector.ts index 1e4a7ed6cd..727366c4aa 100644 --- a/visualization/app/codeCharta/ui/customConfigs/visibleFilesBySelectionMode.selector.ts +++ b/visualization/app/codeCharta/ui/customConfigs/visibleFilesBySelectionMode.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../state/angular-redux/createSelector" import { visibleFileStatesSelector } from "../../state/selectors/visibleFileStates.selector" import { CustomConfig, CustomConfigMapSelectionMode, MapNamesByChecksum } from "../../model/customConfig/customConfig.api.model" import { FileSelectionState, FileState } from "../../model/files/files" +import { createSelector } from "@ngrx/store" export type VisibleFilesBySelectionMode = Pick @@ -17,4 +17,4 @@ export const _getVisibleFilesBySelectionMode = (fileStates: FileState[]): Visibl return { mapSelectionMode, assignedMaps } } -export const visibleFilesBySelectionModeSelector = createSelector([visibleFileStatesSelector], _getVisibleFilesBySelectionMode) +export const visibleFilesBySelectionModeSelector = createSelector(visibleFileStatesSelector, _getVisibleFilesBySelectionMode) diff --git a/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.spec.ts b/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.spec.ts index 4baaa0d079..7fc7467506 100644 --- a/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.spec.ts @@ -1,4 +1,5 @@ import { TestBed } from "@angular/core/testing" +import { State } from "@ngrx/store" import { Export3DMapButtonComponent } from "./export3DMapButton.component" import { fireEvent, render, screen } from "@testing-library/angular" import { Export3DMapButtonModule } from "./export3DMapButton.module" @@ -30,7 +31,10 @@ describe("Export3DMapButtonComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [Export3DMapButtonModule], - providers: [{ provide: ThreeSceneService, useValue: { getMapMesh: () => ({ getThreeMesh: jest.fn() }) } }] + providers: [ + { provide: ThreeSceneService, useValue: { getMapMesh: () => ({ getThreeMesh: jest.fn() }) } }, + { provide: State, useValue: { getValue: () => ({}) } } + ] }) }) diff --git a/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.ts b/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.ts index 76b5045c45..78fc2dcfb0 100644 --- a/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.ts +++ b/visualization/app/codeCharta/ui/export3DMapButton/export3DMapButton.component.ts @@ -7,7 +7,8 @@ import { isDeltaState } from "../../model/files/files.helper" import { accumulatedDataSelector } from "../../state/selectors/accumulatedData/accumulatedData.selector" import { filesSelector } from "../../state/store/files/files.selector" import { Mesh } from "three" -import { State } from "../../state/angular-redux/state" +import { State } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-export-threed-map-button", @@ -16,7 +17,7 @@ import { State } from "../../state/angular-redux/state" }) export class Export3DMapButtonComponent { private exporter = new STLExporter() - constructor(private state: State, private threeSceneService: ThreeSceneService) {} + constructor(private state: State, private threeSceneService: ThreeSceneService) {} downloadStlFile() { const files = filesSelector(this.state.getValue()) diff --git a/visualization/app/codeCharta/ui/fileExtensionBar/distributionMetricChooser/distributionMetricChooser.component.ts b/visualization/app/codeCharta/ui/fileExtensionBar/distributionMetricChooser/distributionMetricChooser.component.ts index 1148c5a251..e92d4e9a73 100644 --- a/visualization/app/codeCharta/ui/fileExtensionBar/distributionMetricChooser/distributionMetricChooser.component.ts +++ b/visualization/app/codeCharta/ui/fileExtensionBar/distributionMetricChooser/distributionMetricChooser.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { setDistributionMetric } from "../../../state/store/dynamicSettings/distributionMetric/distributionMetric.actions" import { distributionMetricSelector } from "../../../state/store/dynamicSettings/distributionMetric/distributionMetric.selector" @@ -11,9 +12,9 @@ import { distributionMetricSelector } from "../../../state/store/dynamicSettings export class DistributionMetricChooserComponent { distributionMetric$ = this.store.select(distributionMetricSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleDistributionMetricChanged(value: string) { - this.store.dispatch(setDistributionMetric(value)) + this.store.dispatch(setDistributionMetric({ value })) } } diff --git a/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.spec.ts b/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.spec.ts index 9caba31e50..e50d2a8667 100644 --- a/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.spec.ts +++ b/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.spec.ts @@ -1,21 +1,15 @@ import { TestBed } from "@angular/core/testing" +import { provideMockStore } from "@ngrx/store/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { CODE_MAP_BUILDING_TS_NODE } from "../../util/dataMocks" import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService" import { FileExtensionBarComponent } from "./fileExtensionBar.component" import { FileExtensionBarModule } from "./fileExtensionBar.module" - -jest.mock("./selectors/metricDistribution.selector", () => ({ - metricDistributionSelector: () => [ - { - fileExtension: "ts", - absoluteMetricValue: 1120, - relativeMetricValue: 100, - color: "hsl(111, 40%, 50%)" - } - ] -})) +import { metricDistributionSelector } from "./selectors/metricDistribution.selector" +import { distributionMetricSelector } from "../../state/store/dynamicSettings/distributionMetric/distributionMetric.selector" +import { defaultDistributionMetric } from "../../state/store/dynamicSettings/distributionMetric/distributionMetric.reducer" +import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" describe("fileExtensionBarComponent", () => { beforeEach(() => { @@ -33,7 +27,24 @@ describe("fileExtensionBarComponent", () => { addBuildingToHighlightingList: jest.fn(), highlightBuildings: jest.fn() } - } + }, + provideMockStore({ + selectors: [ + { + selector: metricDistributionSelector, + value: [ + { + fileExtension: "ts", + absoluteMetricValue: 1120, + relativeMetricValue: 100, + color: "hsl(111, 40%, 50%)" + } + ] + }, + { selector: distributionMetricSelector, value: defaultDistributionMetric }, + { selector: metricDataSelector, value: { nodeMetricData: [] } } + ] + }) ] }) }) diff --git a/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts b/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts index 52bea2064c..fc57b11f39 100644 --- a/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts +++ b/visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts @@ -2,7 +2,8 @@ import { Component, ViewEncapsulation } from "@angular/core" import { MetricDistribution, FileExtensionCalculator } from "./selectors/fileExtensionCalculator" import { metricDistributionSelector } from "./selectors/metricDistribution.selector" import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService" -import { Store } from "../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-file-extension-bar", @@ -15,7 +16,7 @@ export class FileExtensionBarComponent { showDetails = false metricDistribution: MetricDistribution[] - constructor(private store: Store, private threeSceneService: ThreeSceneService) { + constructor(private store: Store, private threeSceneService: ThreeSceneService) { this.store.select(metricDistributionSelector).subscribe(metricDistribution => { this.metricDistribution = metricDistribution }) diff --git a/visualization/app/codeCharta/ui/fileExtensionBar/selectors/metricDistribution.selector.ts b/visualization/app/codeCharta/ui/fileExtensionBar/selectors/metricDistribution.selector.ts index 8eaa3cfb31..6cddc9f600 100644 --- a/visualization/app/codeCharta/ui/fileExtensionBar/selectors/metricDistribution.selector.ts +++ b/visualization/app/codeCharta/ui/fileExtensionBar/selectors/metricDistribution.selector.ts @@ -1,11 +1,11 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { accumulatedDataSelector } from "../../../state/selectors/accumulatedData/accumulatedData.selector" import { distributionMetricSelector } from "../../../state/store/dynamicSettings/distributionMetric/distributionMetric.selector" -import { CcState } from "../../../state/store/store" -import { FileExtensionCalculator, MetricDistribution } from "./fileExtensionCalculator" +import { FileExtensionCalculator } from "./fileExtensionCalculator" -export const metricDistributionSelector: (state: CcState) => MetricDistribution[] = createSelector( - [accumulatedDataSelector, distributionMetricSelector], +export const metricDistributionSelector = createSelector( + accumulatedDataSelector, + distributionMetricSelector, (accumulatedData, distributionMetric) => FileExtensionCalculator.getMetricDistribution(accumulatedData.unifiedMapNode, distributionMetric) ) diff --git a/visualization/app/codeCharta/ui/filePanel/filePanel.component.spec.ts b/visualization/app/codeCharta/ui/filePanel/filePanel.component.spec.ts index 503533f265..29dea5ba2c 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanel.component.spec.ts @@ -3,29 +3,31 @@ import { TestBed } from "@angular/core/testing" import { FilePanelModule } from "./filePanel.module" import { render } from "@testing-library/angular" import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector" - -jest.mock("../../state/selectors/isDeltaState.selector", () => ({ - isDeltaStateSelector: jest.fn() -})) -const mockedIsDeltaStateSelector = jest.mocked(isDeltaStateSelector) +import { provideMockStore } from "@ngrx/store/testing" +import { State } from "@ngrx/store" describe("filePanelComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [FilePanelModule] + imports: [FilePanelModule], + providers: [{ provide: State, useValue: {} }] }) }) it("should render delta-selector when in delta mode", async () => { - mockedIsDeltaStateSelector.mockReturnValue(true) - const { container } = await render(FilePanelComponent, { excludeComponentDeclaration: true }) + const { container } = await render(FilePanelComponent, { + excludeComponentDeclaration: true, + providers: [provideMockStore({ selectors: [{ selector: isDeltaStateSelector, value: true }] })] + }) expect(container.querySelector("cc-file-panel-delta-selector")).not.toBe(null) expect(container.querySelector("cc-file-panel-file-selector")).toBe(null) }) it("should render file-selector when not in delta mode", async () => { - mockedIsDeltaStateSelector.mockReturnValue(false) - const { container } = await render(FilePanelComponent, { excludeComponentDeclaration: true }) + const { container } = await render(FilePanelComponent, { + excludeComponentDeclaration: true, + providers: [provideMockStore({ selectors: [{ selector: isDeltaStateSelector, value: false }] })] + }) expect(container.querySelector("cc-file-panel-file-selector")).not.toBe(null) expect(container.querySelector("cc-file-panel-delta-selector")).toBe(null) }) diff --git a/visualization/app/codeCharta/ui/filePanel/filePanel.component.ts b/visualization/app/codeCharta/ui/filePanel/filePanel.component.ts index 55ba9d3e0d..c96404d9c5 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanel.component.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanel.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector" @Component({ @@ -11,5 +12,5 @@ import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selecto export class FilePanelComponent { isDeltaState$ = this.store.select(isDeltaStateSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts b/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts index 3c09e46d4b..1a1f85a964 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts @@ -1,8 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { map } from "rxjs" -import { CCFile } from "../../../codeCharta.model" +import { CCFile, CcState } from "../../../codeCharta.model" import { FileSelectionState } from "../../../model/files/files" -import { Store } from "../../../state/angular-redux/store" import { referenceFileSelector } from "../../../state/selectors/referenceFile/referenceFile.selector" import { setDeltaComparison, setDeltaReference, switchReferenceAndComparison } from "../../../state/store/files/files.actions" import { filesSelector } from "../../../state/store/files/files.selector" @@ -21,14 +21,14 @@ export class FilePanelDeltaSelectorComponent { possibleComparisonFiles$ = this.files$.pipe(map(files => files.filter(file => file.selectedAs !== FileSelectionState.Reference))) pictogramBackground$ = this.store.select(pictogramBackgroundSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleDeltaReferenceFileChange(file: CCFile) { - this.store.dispatch(setDeltaReference(file)) + this.store.dispatch(setDeltaReference({ file })) } handleDeltaComparisonFileChange(file: CCFile) { - this.store.dispatch(setDeltaComparison(file)) + this.store.dispatch(setDeltaComparison({ file })) } switchReferenceAndComparison() { diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/pictogramBackground.selector.ts b/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/pictogramBackground.selector.ts index 051eeebb51..22d90deb2f 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/pictogramBackground.selector.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelDeltaSelector/pictogramBackground.selector.ts @@ -1,8 +1,8 @@ +import { createSelector } from "@ngrx/store" import { MapColors } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/mapColors.selector" export const _mapColors2pictogramColors = (mapColors: Pick) => `linear-gradient(${mapColors.positiveDelta} 50%, ${mapColors.negativeDelta} 50%)` -export const pictogramBackgroundSelector = createSelector([mapColorsSelector], _mapColors2pictogramColors) +export const pictogramBackgroundSelector = createSelector(mapColorsSelector, _mapColors2pictogramColors) diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.spec.ts b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.spec.ts index 0eafa71827..030b33944c 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.spec.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.spec.ts @@ -1,21 +1,23 @@ import { TestBed } from "@angular/core/testing" import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/angular" import { FileSelectionState } from "../../../model/files/files" -import { Store } from "../../../state/angular-redux/store" import { addFile, invertStandard, setStandard } from "../../../state/store/files/files.actions" import { TEST_FILE_DATA } from "../../../util/dataMocks" import { FilePanelModule } from "../filePanel.module" import { FilePanelFileSelectorComponent } from "./filePanelFileSelector.component" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" +import { Store, StoreModule } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" describe("filePanelFileSelectorComponent", () => { it("should reset selected files to selected in store when closing with zero selections", async () => { const { detectChanges, fixture } = await render(FilePanelFileSelectorComponent, { - imports: [FilePanelModule], + imports: [FilePanelModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })], excludeComponentDeclaration: true }) const store = TestBed.inject(Store) - store.dispatch(addFile(TEST_FILE_DATA)) - store.dispatch(setStandard([TEST_FILE_DATA])) + store.dispatch(addFile({ file: TEST_FILE_DATA })) + store.dispatch(setStandard({ files: [TEST_FILE_DATA] })) detectChanges() expect(fixture.componentInstance["selectedFilesInUI"].length).toBe(1) expect(fixture.componentInstance["selectedFilesInUI"][0]).toEqual(TEST_FILE_DATA) @@ -44,7 +46,7 @@ describe("filePanelFileSelectorComponent", () => { const mockedStore = createMockedStore() const component = new FilePanelFileSelectorComponent(mockedStore) component.handleSelectedFilesChanged([TEST_FILE_DATA]) - expect(mockedStore.dispatch).toHaveBeenCalledWith(setStandard([TEST_FILE_DATA])) + expect(mockedStore.dispatch).toHaveBeenCalledWith(setStandard({ files: [TEST_FILE_DATA] })) }) }) @@ -80,6 +82,6 @@ describe("filePanelFileSelectorComponent", () => { return { dispatch: jest.fn(), select: () => ({ subscribe: jest.fn() }) - } as unknown as Store + } as unknown as Store } }) diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts index 37687386da..d36a1106fa 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts @@ -1,9 +1,9 @@ import { Component, OnDestroy, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { filesSelector } from "../../../state/store/files/files.selector" import { invertStandard, setAll, setStandard } from "../../../state/store/files/files.actions" -import { CCFile } from "../../../codeCharta.model" +import { CCFile, CcState } from "../../../codeCharta.model" import { FileSelectionState, FileState } from "../../../model/files/files" +import { Store } from "@ngrx/store" @Component({ selector: "cc-file-panel-file-selector", @@ -21,7 +21,7 @@ export class FilePanelFileSelectorComponent implements OnDestroy { this.selectedFilesInUI = this.selectedFilesInStore }) - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnDestroy(): void { this.filesSubscription.unsubscribe() @@ -30,7 +30,7 @@ export class FilePanelFileSelectorComponent implements OnDestroy { handleSelectedFilesChanged(selectedFiles: CCFile[]) { this.selectedFilesInUI = selectedFiles if (selectedFiles.length > 0) { - this.store.dispatch(setStandard(selectedFiles)) + this.store.dispatch(setStandard({ files: selectedFiles })) } } diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/removeFileButton/removeFileButton.component.ts b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/removeFileButton/removeFileButton.component.ts index 4cfb195419..3b8093cb5b 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/removeFileButton/removeFileButton.component.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelFileSelector/removeFileButton/removeFileButton.component.ts @@ -1,5 +1,5 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../../state/angular-redux/store" +import { Store } from "@ngrx/store" import { removeFile } from "../../../../state/store/files/files.actions" @Component({ @@ -12,8 +12,8 @@ export class RemoveFileButtonComponent { constructor(private store: Store) {} - onRemoveFile(filename: string, $event: MouseEvent) { - this.store.dispatch(removeFile(filename)) + onRemoveFile(fileName: string, $event: MouseEvent) { + this.store.dispatch(removeFile({ fileName })) $event.stopPropagation() $event.preventDefault() diff --git a/visualization/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts b/visualization/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts index 968bfdd852..e4301ec8d6 100644 --- a/visualization/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts +++ b/visualization/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { isDeltaStateSelector } from "../../../state/selectors/isDeltaState.selector" import { FileSelectionModeService } from "../fileSelectionMode.service" @@ -11,5 +12,5 @@ import { FileSelectionModeService } from "../fileSelectionMode.service" export class FilePanelStateButtonsComponent { isDeltaState$ = this.store.select(isDeltaStateSelector) - constructor(private store: Store, public fileSelectionModeService: FileSelectionModeService) {} + constructor(private store: Store, public fileSelectionModeService: FileSelectionModeService) {} } diff --git a/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.spec.ts b/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.spec.ts index 3321289729..0ae0acb9c4 100644 --- a/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.spec.ts +++ b/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.spec.ts @@ -1,52 +1,56 @@ import { TestBed } from "@angular/core/testing" import { FileSelectionState } from "../../model/files/files" -import { State } from "../../state/angular-redux/state" -import { Store } from "../../state/angular-redux/store" import { referenceFileSelector } from "../../state/selectors/referenceFile/referenceFile.selector" import { addFile, removeFile, setDelta, setStandard } from "../../state/store/files/files.actions" -import { Store as PlainStore } from "../../state/store/store" import { TEST_FILE_DATA, TEST_FILE_DATA_JAVA } from "../../util/dataMocks" import { FileSelectionModeService } from "./fileSelectionMode.service" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" +import { CcState } from "../../codeCharta.model" describe("FileSelectionModeService", () => { let fileSelectionModeService: FileSelectionModeService + let store: Store + let state: State beforeEach(() => { - PlainStore["initialize"]() - PlainStore.dispatch(addFile(TEST_FILE_DATA)) - PlainStore.dispatch(addFile(TEST_FILE_DATA_JAVA)) - PlainStore.dispatch(setStandard([TEST_FILE_DATA])) + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] + }) + store = TestBed.inject(Store) + state = TestBed.inject(State) + store.dispatch(addFile({ file: TEST_FILE_DATA })) + store.dispatch(addFile({ file: TEST_FILE_DATA_JAVA })) + store.dispatch(setStandard({ files: [TEST_FILE_DATA] })) - const store = TestBed.inject(Store) - const state = TestBed.inject(State) fileSelectionModeService = new FileSelectionModeService(store, state) }) it("should set first selected file as reference, when there was no reference file before", () => { fileSelectionModeService.toggle() - expect(referenceFileSelector(PlainStore.store.getState())).toBe(TEST_FILE_DATA) + expect(referenceFileSelector(state.getValue())).toBe(TEST_FILE_DATA) }) it("should restore previous files on toggle", () => { - let fileStates = PlainStore.store.getState().files + let fileStates = state.getValue().files expect(fileStates[0].selectedAs).toBe(FileSelectionState.Partial) expect(fileStates[1].selectedAs).toBe(FileSelectionState.None) fileSelectionModeService.toggle() - PlainStore.dispatch(setDelta(TEST_FILE_DATA_JAVA, TEST_FILE_DATA)) + store.dispatch(setDelta({ referenceFile: TEST_FILE_DATA_JAVA, comparisonFile: TEST_FILE_DATA })) fileSelectionModeService.toggle() - fileStates = PlainStore.store.getState().files + fileStates = state.getValue().files expect(fileStates[0].selectedAs).toBe(FileSelectionState.Partial) expect(fileStates[1].selectedAs).toBe(FileSelectionState.None) }) it("should not restore a removed file when toggling back to delta mode", () => { fileSelectionModeService.toggle() - PlainStore.dispatch(setDelta(TEST_FILE_DATA_JAVA, TEST_FILE_DATA)) + store.dispatch(setDelta({ referenceFile: TEST_FILE_DATA_JAVA, comparisonFile: TEST_FILE_DATA })) fileSelectionModeService.toggle() - PlainStore.dispatch(removeFile(TEST_FILE_DATA_JAVA.fileMeta.fileName)) + store.dispatch(removeFile({ fileName: TEST_FILE_DATA_JAVA.fileMeta.fileName })) fileSelectionModeService.toggle() - expect(referenceFileSelector(PlainStore.store.getState())).toBe(TEST_FILE_DATA) + expect(referenceFileSelector(state.getValue())).toBe(TEST_FILE_DATA) }) }) diff --git a/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.ts b/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.ts index 22464beff6..f05d9134af 100644 --- a/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.ts +++ b/visualization/app/codeCharta/ui/filePanel/fileSelectionMode.service.ts @@ -1,9 +1,9 @@ import { Injectable, OnDestroy } from "@angular/core" +import { Store, State } from "@ngrx/store" import { pairwise, tap, filter } from "rxjs" +import { CcState } from "../../codeCharta.model" import { FileSelectionState, FileState } from "../../model/files/files" import { isDeltaState, isEqual } from "../../model/files/files.helper" -import { State } from "../../state/angular-redux/state" -import { Store } from "../../state/angular-redux/store" import { setDelta, setFiles } from "../../state/store/files/files.actions" import { filesSelector } from "../../state/store/files/files.selector" @@ -22,7 +22,7 @@ export class FileSelectionModeService implements OnDestroy { ) .subscribe() - constructor(private store: Store, private state: State) {} + constructor(private store: Store, private state: State) {} ngOnDestroy(): void { this.subscription.unsubscribe() @@ -43,9 +43,9 @@ export class FileSelectionModeService implements OnDestroy { this.lastSetFilesOfPreviousMode.find(file => file.selectedAs === FileSelectionState.Reference) ?? existingFiles.find(file => file.selectedAs === FileSelectionState.Partial) const comparisonFile = this.lastSetFilesOfPreviousMode.find(file => file.selectedAs === FileSelectionState.Comparison) - this.store.dispatch(setDelta(referenceFile.file, comparisonFile?.file)) + this.store.dispatch(setDelta({ referenceFile: referenceFile.file, comparisonFile: comparisonFile?.file })) } else { - this.store.dispatch(setFiles(this.lastSetFilesOfPreviousMode)) + this.store.dispatch(setFiles({ value: this.lastSetFilesOfPreviousMode })) } } diff --git a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.spec.ts b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.spec.ts index aae3c4f7c1..9d9f25d395 100644 --- a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.spec.ts +++ b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.spec.ts @@ -2,35 +2,33 @@ import { TestBed } from "@angular/core/testing" import { render } from "@testing-library/angular" import { expect } from "@jest/globals" import { LegendMarkedPackagesComponent } from "./legendMarkedPackages.component" - import { LegendMarkedPackagesModule } from "./legendMarkedPackages.module" import { legendMarkedPackagesSelector } from "./legendMarkedPackages.selector" - -jest.mock("./legendMarkedPackages.selector", () => ({ - legendMarkedPackagesSelector: jest.fn() -})) -const mockedLegendMarkedPackagesSelector = legendMarkedPackagesSelector as jest.Mock +import { MockStore, provideMockStore } from "@ngrx/store/testing" describe("LegendMarkedPackages", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [LegendMarkedPackagesModule] + imports: [LegendMarkedPackagesModule], + providers: [provideMockStore({ selectors: [{ selector: legendMarkedPackagesSelector, value: {} }] })] }) }) it("shouldn't display anything if there are no marked packages", async () => { - mockedLegendMarkedPackagesSelector.mockImplementation(() => ({})) const { container } = await render(LegendMarkedPackagesComponent, { excludeComponentDeclaration: true }) expect(container.textContent).toBe("") }) it("should display color pickers for each marked package, sorted by first marked path", async () => { - mockedLegendMarkedPackagesSelector.mockImplementation(() => ({ + const { container, detectChanges } = await render(LegendMarkedPackagesComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) + store.overrideSelector(legendMarkedPackagesSelector, { "#ffffff": ["/blackMarked/whiteMarked"], "#000000": ["/blackMarked"] - })) - const { container } = await render(LegendMarkedPackagesComponent, { excludeComponentDeclaration: true }) + }) + store.refreshState() + detectChanges() expect(container.querySelectorAll("cc-labelled-color-picker").length).toBe(2) expect(container.querySelectorAll("cc-labelled-color-picker")[0].textContent).toMatch("/blackMarked") diff --git a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.ts b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.ts index 212265239a..94680d2f69 100644 --- a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.ts +++ b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.component.ts @@ -1,10 +1,10 @@ import { Component, ViewEncapsulation } from "@angular/core" import { Observable, map } from "rxjs" import { KeyValue } from "@angular/common" - -import { Store } from "../../../state/angular-redux/store" import { legendMarkedPackagesSelector, MarkedPackagesMap } from "./legendMarkedPackages.selector" import { markPackages } from "../../../state/store/fileSettings/markedPackages/markedPackages.actions" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" type MarkedPackagesMapKeyValue = KeyValue @@ -18,19 +18,16 @@ export class LegendMarkedPackagesComponent { markedPackagesMap$: Observable hasMarkedPackages$: Observable - constructor(private store: Store) { + constructor(private store: Store) { this.markedPackagesMap$ = store.select(legendMarkedPackagesSelector) this.hasMarkedPackages$ = this.markedPackagesMap$.pipe(map(markedPackagesMap => Object.keys(markedPackagesMap).length > 0)) } handleColorChange(newHexColor: string, paths: string[]) { this.store.dispatch( - markPackages( - paths.map(path => ({ - color: newHexColor, - path - })) - ) + markPackages({ + packages: paths.map(path => ({ color: newHexColor, path })) + }) ) } diff --git a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.selector.ts b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.selector.ts index 7c23314d8a..23ca57fd34 100644 --- a/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.selector.ts +++ b/visualization/app/codeCharta/ui/legendPanel/legendMarkedPackages/legendMarkedPackages.selector.ts @@ -1,21 +1,18 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { markedPackagesSelector } from "../../../state/store/fileSettings/markedPackages/markedPackages.selector" -import { CcState } from "../../../state/store/store" type Path = string export type MarkedPackagesMap = { [color: string]: Path[] } -export const legendMarkedPackagesSelector: (state: CcState) => MarkedPackagesMap = createSelector( - [markedPackagesSelector], - markedPackages => - // eslint-disable-next-line unicorn/prefer-object-from-entries - markedPackages.reduce((accumulator, { color, path }) => { - if (!Object.prototype.hasOwnProperty.call(accumulator, color)) { - accumulator[color] = [] - } - accumulator[color].push(path) - return accumulator - }, {}) +export const legendMarkedPackagesSelector = createSelector(markedPackagesSelector, markedPackages => + // eslint-disable-next-line unicorn/prefer-object-from-entries + markedPackages.reduce((accumulator, { color, path }) => { + if (!Object.prototype.hasOwnProperty.call(accumulator, color)) { + accumulator[color] = [] + } + accumulator[color].push(path) + return accumulator + }, {}) ) diff --git a/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.spec.ts b/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.spec.ts index ead2d18cc7..ef9a6a7c52 100755 --- a/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.spec.ts @@ -5,29 +5,41 @@ import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selecto import { LegendPanelComponent } from "./legendPanel.component" import { LegendPanelModule } from "./legendPanel.module" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" - -jest.mock("../../state/store/dynamicSettings/heightMetric/heightMetric.selector", () => ({ - heightMetricSelector: () => "mcc" -})) -jest.mock("../../state/store/dynamicSettings/areaMetric/areaMetric.selector", () => ({ - areaMetricSelector: () => "loc" -})) -jest.mock("../../state/store/dynamicSettings/colorMetric/colorMetric.selector", () => ({ - colorMetricSelector: () => "rloc" -})) -jest.mock("../../state/store/dynamicSettings/colorRange/colorRange.selector", () => ({ - colorRangeSelector: () => ({ from: 21, to: 42, max: 9001 }) -})) - -const mockedIsDeltaStateSelector = isDeltaStateSelector as jest.Mock -jest.mock("../../state/selectors/isDeltaState.selector", () => ({ - isDeltaStateSelector: jest.fn() -})) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { heightMetricSelector } from "../../state/store/dynamicSettings/heightMetric/heightMetric.selector" +import { areaMetricSelector } from "../../state/store/dynamicSettings/areaMetric/areaMetric.selector" +import { colorMetricSelector } from "../../state/store/dynamicSettings/colorMetric/colorMetric.selector" +import { colorRangeSelector } from "../../state/store/dynamicSettings/colorRange/colorRange.selector" +import { State } from "@ngrx/store" +import { mapColorsSelector } from "../../state/store/appSettings/mapColors/mapColors.selector" +import { defaultMapColors } from "../../state/store/appSettings/mapColors/mapColors.reducer" +import { legendHeightMetricSelector } from "./selectors/legendHeightMetric.selector" +import { legendAreaMetricSelector } from "./selectors/legendAreaMetric.selector" +import { legendColorMetricSelector } from "./selectors/legendColorMetric.selector" +import { selectedColorMetricDataSelector } from "../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" +import { getMetricDescriptors } from "../attributeSideBar/util/metricDescriptors" describe("LegendPanelController", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [LegendPanelModule] + imports: [LegendPanelModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: heightMetricSelector, value: "mcc" }, + { selector: legendHeightMetricSelector, value: getMetricDescriptors("mcc") }, + { selector: areaMetricSelector, value: "loc" }, + { selector: legendAreaMetricSelector, value: getMetricDescriptors("loc") }, + { selector: colorMetricSelector, value: "rloc" }, + { selector: legendColorMetricSelector, value: getMetricDescriptors("rloc") }, + { selector: colorRangeSelector, value: { from: 21, to: 42, max: 9001 } }, + { selector: isDeltaStateSelector, value: true }, + { selector: mapColorsSelector, value: defaultMapColors }, + { selector: selectedColorMetricDataSelector, value: {} } + ] + }), + { provide: State, useValue: {} } + ] }) }) @@ -46,8 +58,11 @@ describe("LegendPanelController", () => { }) it("should display legend for single mode", async () => { - mockedIsDeltaStateSelector.mockImplementation(() => false) - const { container } = await render(LegendPanelComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(LegendPanelComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) + store.overrideSelector(isDeltaStateSelector, false) + store.refreshState() + detectChanges() fireEvent.click(screen.getByTitle("Show panel")) const areDeltaEntriesShown = screen.queryAllByText("delta", { exact: false }).length > 0 @@ -60,7 +75,6 @@ describe("LegendPanelController", () => { }) it("should display legend for delta mode", async () => { - mockedIsDeltaStateSelector.mockImplementation(() => true) const { container } = await render(LegendPanelComponent, { excludeComponentDeclaration: true }) fireEvent.click(screen.getByTitle("Show panel")) diff --git a/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.ts b/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.ts index 97219bf680..1bd88f936d 100755 --- a/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.ts +++ b/visualization/app/codeCharta/ui/legendPanel/legendPanel.component.ts @@ -1,11 +1,12 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector" import { legendColorMetricSelector } from "./selectors/legendColorMetric.selector" import { legendHeightMetricSelector } from "./selectors/legendHeightMetric.selector" import { legendAreaMetricSelector } from "./selectors/legendAreaMetric.selector" import { legendEdgeMetricSelector } from "./selectors/legendEdgeMetric.selector" import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-legend-panel", @@ -21,7 +22,7 @@ export class LegendPanelComponent { colorMetric$ = this.store.select(legendColorMetricSelector) edgeMetric$ = this.store.select(legendEdgeMetricSelector) - constructor(public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, private store: Store) {} + constructor(public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, private store: Store) {} toggleIsLegendVisible() { this.isLegendVisible = !this.isLegendVisible diff --git a/visualization/app/codeCharta/ui/legendPanel/selectors/legendAreaMetric.selector.ts b/visualization/app/codeCharta/ui/legendPanel/selectors/legendAreaMetric.selector.ts index db30003526..e9de511108 100644 --- a/visualization/app/codeCharta/ui/legendPanel/selectors/legendAreaMetric.selector.ts +++ b/visualization/app/codeCharta/ui/legendPanel/selectors/legendAreaMetric.selector.ts @@ -1,10 +1,10 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" -import { CcState } from "../../../state/store/store" -import { getMetricDescriptors, MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" +import { getMetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" -export const legendAreaMetricSelector: (state: CcState) => MetricDescriptors = createSelector( - [areaMetricSelector, attributeDescriptorsSelector], +export const legendAreaMetricSelector = createSelector( + areaMetricSelector, + attributeDescriptorsSelector, (areaMetric, attributeDescriptors) => getMetricDescriptors(areaMetric, attributeDescriptors) ) diff --git a/visualization/app/codeCharta/ui/legendPanel/selectors/legendColorMetric.selector.ts b/visualization/app/codeCharta/ui/legendPanel/selectors/legendColorMetric.selector.ts index 9108d5da3b..5a2734e942 100644 --- a/visualization/app/codeCharta/ui/legendPanel/selectors/legendColorMetric.selector.ts +++ b/visualization/app/codeCharta/ui/legendPanel/selectors/legendColorMetric.selector.ts @@ -1,10 +1,10 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" import { colorMetricSelector } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.selector" -import { CcState } from "../../../state/store/store" -import { getMetricDescriptors, MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" +import { getMetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" +import { createSelector } from "@ngrx/store" -export const legendColorMetricSelector: (state: CcState) => MetricDescriptors = createSelector( - [colorMetricSelector, attributeDescriptorsSelector], +export const legendColorMetricSelector = createSelector( + colorMetricSelector, + attributeDescriptorsSelector, (colorMetric, attributeDescriptors) => getMetricDescriptors(colorMetric, attributeDescriptors) ) diff --git a/visualization/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.ts b/visualization/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.ts index d86bd38e6f..157cfa2e59 100644 --- a/visualization/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.ts +++ b/visualization/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.ts @@ -1,10 +1,9 @@ import { EdgeMetricData } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { edgeMetricSelector } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" -import { CcState } from "../../../state/store/store" -import { getMetricDescriptors, MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" +import { getMetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" +import { createSelector } from "@ngrx/store" export const _getLegendEdgeMetric = (edgeMetric: string, edgeMetricDatas: EdgeMetricData[], attributeDescriptors) => { const edgeMetricData = edgeMetricDatas.find(someEdgeMetricData => { @@ -18,7 +17,9 @@ export const _getLegendEdgeMetric = (edgeMetric: string, edgeMetricDatas: EdgeMe return getMetricDescriptors(edgeMetric, attributeDescriptors) } -export const legendEdgeMetricSelector: (state: CcState) => MetricDescriptors | undefined = createSelector( - [edgeMetricSelector, metricDataSelector, attributeDescriptorsSelector], +export const legendEdgeMetricSelector = createSelector( + edgeMetricSelector, + metricDataSelector, + attributeDescriptorsSelector, (edgeMetric, metricData, attributeDescriptors) => _getLegendEdgeMetric(edgeMetric, metricData.edgeMetricData, attributeDescriptors) ) diff --git a/visualization/app/codeCharta/ui/legendPanel/selectors/legendHeightMetric.selector.ts b/visualization/app/codeCharta/ui/legendPanel/selectors/legendHeightMetric.selector.ts index ecdbf50d49..30916f5039 100644 --- a/visualization/app/codeCharta/ui/legendPanel/selectors/legendHeightMetric.selector.ts +++ b/visualization/app/codeCharta/ui/legendPanel/selectors/legendHeightMetric.selector.ts @@ -1,10 +1,10 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" import { heightMetricSelector } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.selector" -import { CcState } from "../../../state/store/store" -import { getMetricDescriptors, MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" +import { getMetricDescriptors } from "../../attributeSideBar/util/metricDescriptors" import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector" +import { createSelector } from "@ngrx/store" -export const legendHeightMetricSelector: (state: CcState) => MetricDescriptors = createSelector( - [heightMetricSelector, attributeDescriptorsSelector], +export const legendHeightMetricSelector = createSelector( + heightMetricSelector, + attributeDescriptorsSelector, (heightMetric, attributeDescriptors) => getMetricDescriptors(heightMetric, attributeDescriptors) ) diff --git a/visualization/app/codeCharta/ui/loadingFileProgressSpinner/loadingFileProgressSpinner.component.ts b/visualization/app/codeCharta/ui/loadingFileProgressSpinner/loadingFileProgressSpinner.component.ts index 85d98c6721..988dc1b012 100644 --- a/visualization/app/codeCharta/ui/loadingFileProgressSpinner/loadingFileProgressSpinner.component.ts +++ b/visualization/app/codeCharta/ui/loadingFileProgressSpinner/loadingFileProgressSpinner.component.ts @@ -1,6 +1,7 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { Store } from "../../state/angular-redux/store" +import { CcState } from "../../codeCharta.model" import { isLoadingFileSelector } from "../../state/store/appSettings/isLoadingFile/isLoadingFile.selector" @Component({ @@ -12,7 +13,7 @@ import { isLoadingFileSelector } from "../../state/store/appSettings/isLoadingFi export class LoadingFileProgressSpinnerComponent { isLoadingFile$: Observable - constructor(store: Store) { + constructor(store: Store) { this.isLoadingFile$ = store.select(isLoadingFileSelector) } } diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.spec.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.spec.ts index 8de24c4d69..acf014ee3a 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.spec.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.spec.ts @@ -5,21 +5,29 @@ import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { MetricChooserComponent } from "./metricChooser.component" import { MetricChooserModule } from "./metricChooser.module" - -jest.mock("../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ - metricDataSelector: () => ({ - nodeMetricData: [ - { name: "aMetric", maxValue: 1 }, - { name: "bMetric", maxValue: 2 }, - { name: "cMetric", maxValue: 3 } - ] - }) -})) +import { provideMockStore } from "@ngrx/store/testing" +import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" describe("metricChooserComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MetricChooserModule] + imports: [MetricChooserModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: metricDataSelector, + value: { + nodeMetricData: [ + { name: "aMetric", maxValue: 1 }, + { name: "bMetric", maxValue: 2 }, + { name: "cMetric", maxValue: 3 } + ] + } + } + ] + }) + ] }) }) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.ts index 895bb44155..d955d96be5 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooser.component.ts @@ -1,9 +1,9 @@ import { Component, ElementRef, Input, OnInit, ViewChild, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { map, Observable } from "rxjs" -import { EdgeMetricData, NodeMetricData } from "../../codeCharta.model" +import { EdgeMetricData, NodeMetricData, CcState } from "../../codeCharta.model" import { metricTitles } from "../../util/metric/metricTitles" import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" +import { Store } from "@ngrx/store" type MetricChooserType = "node" | "edge" @@ -24,7 +24,7 @@ export class MetricChooserComponent implements OnInit { metricData$: Observable metricDataDescription: Map = metricTitles - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.metricData$ = this.store diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeType.selector.spec.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeType.selector.spec.ts index bd97845639..e581995fd3 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeType.selector.spec.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeType.selector.spec.ts @@ -1,31 +1,27 @@ import { AttributeTypeValue } from "../../../codeCharta.model" -import { setAreaMetric } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.actions" -import { setEdgeMetric } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.actions" -import { setAttributeTypes } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.actions" -import { Store } from "../../../state/store/store" +import { defaultState } from "../../../state/store/state.manager" +import { clone } from "../../../util/clone" import { createAttributeTypeSelector } from "./createAttributeTypeSelector.selector" describe("createAttributeTypeSelector", () => { - beforeEach(() => { - Store["initialize"]() - }) - it("should default to 'Σ'", () => { const attributeTypeSelector = createAttributeTypeSelector("nodes", "areaMetric") - expect(attributeTypeSelector(Store.store.getState())).toBe("Σ") + expect(attributeTypeSelector(defaultState)).toBe("Σ") }) it("should read nodes", () => { - Store.store.dispatch(setAttributeTypes({ nodes: { rloc: AttributeTypeValue.relative } })) - Store.store.dispatch(setAreaMetric("rloc")) + const state = clone(defaultState) + state.fileSettings.attributeTypes = { nodes: { rloc: AttributeTypeValue.relative } } + state.dynamicSettings.areaMetric = "rloc" const attributeTypeSelector = createAttributeTypeSelector("nodes", "areaMetric") - expect(attributeTypeSelector(Store.store.getState())).toBe("x͂") + expect(attributeTypeSelector(state)).toBe("x͂") }) it("should read edges", () => { - Store.store.dispatch(setAttributeTypes({ edges: { avgCommit: AttributeTypeValue.relative } })) - Store.store.dispatch(setEdgeMetric("avgCommit")) + const state = clone(defaultState) + state.fileSettings.attributeTypes = { edges: { avgCommit: AttributeTypeValue.relative } } + state.dynamicSettings.edgeMetric = "avgCommit" const attributeTypeSelector = createAttributeTypeSelector("edges", "edgeMetric") - expect(attributeTypeSelector(Store.store.getState())).toBe("x͂") + expect(attributeTypeSelector(state)).toBe("x͂") }) }) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeTypeSelector.selector.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeTypeSelector.selector.ts index 3f137d6bbc..f2c85bb29f 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeTypeSelector.selector.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/createAttributeTypeSelector.selector.ts @@ -1,10 +1,10 @@ +import { createSelector } from "@ngrx/store" import { AttributeTypes, PrimaryMetrics } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { primaryMetricNamesSelector } from "../../../state/selectors/primaryMetrics/primaryMetricNames.selector" import { attributeTypesSelector } from "../../../state/store/fileSettings/attributeTypes/attributeTypes.selector" export const createAttributeTypeSelector = (metricType: keyof AttributeTypes, metricFor: keyof PrimaryMetrics) => - createSelector([primaryMetricNamesSelector, attributeTypesSelector], (primaryMetricNames, attributeTypes) => { + createSelector(primaryMetricNamesSelector, attributeTypesSelector, (primaryMetricNames, attributeTypes) => { const metricName = primaryMetricNames[metricFor] return attributeTypes[metricType][metricName] === "relative" ? "x͂" : "Σ" }) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/isHoveredNodeALeaf.selector.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/isHoveredNodeALeaf.selector.ts index fc625805c7..1296743a84 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/isHoveredNodeALeaf.selector.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/isHoveredNodeALeaf.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" import { isLeaf } from "../../../util/codeMapHelper" export const _isHoveredNodeALeaf = hoveredNode => hoveredNode && isLeaf(hoveredNode) -export const isHoveredNodeALeafSelector = createSelector([hoveredNodeSelector], _isHoveredNodeALeaf) +export const isHoveredNodeALeafSelector = createSelector(hoveredNodeSelector, _isHoveredNodeALeaf) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.spec.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.spec.ts index c566f48f56..8d7173b2e9 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.spec.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.spec.ts @@ -1,23 +1,27 @@ import { render } from "@testing-library/angular" import { isHoveredNodeALeafSelector } from "./isHoveredNodeALeaf.selector" import { MetricChooserTypeHoveredComponent } from "./metricChooserTypeHovered.component" - -jest.mock("./isHoveredNodeALeaf.selector", () => ({ - isHoveredNodeALeafSelector: jest.fn() -})) -const mockedIsHoveredNodeALeafSelector = jest.mocked(isHoveredNodeALeafSelector) +import { TestBed } from "@angular/core/testing" +import { MockStore, provideMockStore } from "@ngrx/store/testing" describe("metricChooserTypeHovered", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ selectors: [{ selector: isHoveredNodeALeafSelector, value: true }] })] + }) + }) it("should be hidden, when hovered node is a leaf", async () => { - mockedIsHoveredNodeALeafSelector.mockImplementation(() => true) const { container } = await render(MetricChooserTypeHoveredComponent) expect(container.querySelector("span").hidden).toBe(true) }) it("should not be hidden, when hovered node is a folder", async () => { - mockedIsHoveredNodeALeafSelector.mockImplementation(() => false) - const { container } = await render(MetricChooserTypeHoveredComponent) + const { container, detectChanges } = await render(MetricChooserTypeHoveredComponent) + const store = TestBed.inject(MockStore) + store.overrideSelector(isHoveredNodeALeafSelector, false) + store.refreshState() + detectChanges() expect(container.querySelector("span").hidden).toBe(false) }) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.ts index 485e0f4e9d..1f01df5b84 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserTypeHovered/metricChooserTypeHovered.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { AttributeTypes, PrimaryMetrics } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { AttributeTypes, PrimaryMetrics, CcState } from "../../../codeCharta.model" import { createAttributeTypeSelector } from "./createAttributeTypeSelector.selector" import { isHoveredNodeALeafSelector } from "./isHoveredNodeALeaf.selector" @@ -17,7 +17,7 @@ export class MetricChooserTypeHoveredComponent implements OnInit { isHoveredNodeALeaf$: Observable attributeType$: Observable - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.isHoveredNodeALeaf$ = this.store.select(isHoveredNodeALeafSelector) diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.spec.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.spec.ts index a0b2cbbe01..c961b4021d 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.spec.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.spec.ts @@ -4,27 +4,31 @@ import { CodeMapNode } from "../../../codeCharta.model" import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" import { MetricChooserValueHoveredComponent } from "./metricChooserValueHovered.component" import { MetricChooserValueHoveredModule } from "./metricChooserValueHovered.module" - -jest.mock("../../../state/selectors/primaryMetrics/primaryMetricNames.selector", () => ({ - primaryMetricNamesSelector: () => ({ - areaMetric: "rloc", - heightMetric: "mcc" - }) -})) -jest.mock("../../../state/selectors/hoveredNode.selector", () => ({ - hoveredNodeSelector: jest.fn() -})) -const mockedHoveredNodeSelector = jest.mocked(hoveredNodeSelector) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { primaryMetricNamesSelector } from "../../../state/selectors/primaryMetrics/primaryMetricNames.selector" describe("metricChooserValueHoveredComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MetricChooserValueHoveredModule] + imports: [MetricChooserValueHoveredModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: primaryMetricNamesSelector, + value: { + areaMetric: "rloc", + heightMetric: "mcc" + } + }, + { selector: hoveredNodeSelector, value: null } + ] + }) + ] }) }) it("should display nothing when there is no hovered node", async () => { - mockedHoveredNodeSelector.mockImplementation(() => undefined) const { container } = await render(MetricChooserValueHoveredComponent, { excludeComponentDeclaration: true, componentProperties: { metricFor: "areaMetric" } @@ -33,27 +37,30 @@ describe("metricChooserValueHoveredComponent", () => { }) it("should display attribute value", async () => { - mockedHoveredNodeSelector.mockImplementation(() => ({ attributes: { rloc: 42 } } as unknown as CodeMapNode)) - await render(MetricChooserValueHoveredComponent, { + const { detectChanges } = await render(MetricChooserValueHoveredComponent, { excludeComponentDeclaration: true, componentProperties: { metricFor: "areaMetric" } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(hoveredNodeSelector, { attributes: { rloc: 42 } } as unknown as CodeMapNode) + store.refreshState() + detectChanges() expect(screen.queryByText("42")).not.toBe(null) expect(screen.queryByText("Δ")).toBe(null) }) it("should display zero height delta value in grey", async () => { - mockedHoveredNodeSelector.mockImplementation( - () => - ({ - attributes: { mcc: 42 }, - deltas: { mcc: 0 } - } as unknown as CodeMapNode) - ) - const { container } = await render(MetricChooserValueHoveredComponent, { + const { container, detectChanges } = await render(MetricChooserValueHoveredComponent, { excludeComponentDeclaration: true, componentProperties: { metricFor: "heightMetric" } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(hoveredNodeSelector, { + attributes: { mcc: 42 }, + deltas: { mcc: 0 } + } as unknown as CodeMapNode) + store.refreshState() + detectChanges() expect(screen.queryByText("Δ0")).not.toBe(null) const deltaContainer = container.querySelector(".rounded-box.value") as HTMLElement @@ -61,17 +68,17 @@ describe("metricChooserValueHoveredComponent", () => { }) it("should display positive height delta value in green", async () => { - mockedHoveredNodeSelector.mockImplementation( - () => - ({ - attributes: { mcc: 42 }, - deltas: { mcc: 21 } - } as unknown as CodeMapNode) - ) - const { container } = await render(MetricChooserValueHoveredComponent, { + const { container, detectChanges } = await render(MetricChooserValueHoveredComponent, { excludeComponentDeclaration: true, componentProperties: { metricFor: "heightMetric" } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(hoveredNodeSelector, { + attributes: { mcc: 42 }, + deltas: { mcc: 21 } + } as unknown as CodeMapNode) + store.refreshState() + detectChanges() expect(screen.queryByText("Δ21")).not.toBe(null) const deltaContainer = container.querySelector(".rounded-box.value") as HTMLElement @@ -79,17 +86,17 @@ describe("metricChooserValueHoveredComponent", () => { }) it("should display negative height delta value in red", async () => { - mockedHoveredNodeSelector.mockImplementation( - () => - ({ - attributes: { mcc: 42 }, - deltas: { mcc: -1 } - } as unknown as CodeMapNode) - ) - const { container } = await render(MetricChooserValueHoveredComponent, { + const { container, detectChanges } = await render(MetricChooserValueHoveredComponent, { excludeComponentDeclaration: true, componentProperties: { metricFor: "heightMetric" } }) + const store = TestBed.inject(MockStore) + store.overrideSelector(hoveredNodeSelector, { + attributes: { mcc: 42 }, + deltas: { mcc: -1 } + } as unknown as CodeMapNode) + store.refreshState() + detectChanges() expect(screen.queryByText("Δ-1")).not.toBe(null) const deltaContainer = container.querySelector(".rounded-box.value") as HTMLElement diff --git a/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.ts b/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.ts index 1f0b352ba8..03d58e24da 100644 --- a/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.ts +++ b/visualization/app/codeCharta/ui/metricChooser/metricChooserValueHovered/metricChooserValueHovered.component.ts @@ -1,7 +1,7 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { CodeMapNode, PrimaryMetrics } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { CodeMapNode, PrimaryMetrics, CcState } from "../../../codeCharta.model" import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" import { primaryMetricNamesSelector } from "../../../state/selectors/primaryMetrics/primaryMetricNames.selector" @@ -16,7 +16,7 @@ export class MetricChooserValueHoveredComponent { hoveredNode$: Observable primaryMetricNames$: Observable - constructor(store: Store) { + constructor(store: Store) { this.primaryMetricNames$ = store.select(primaryMetricNamesSelector) this.hoveredNode$ = store.select(hoveredNodeSelector) } diff --git a/visualization/app/codeCharta/ui/resetSettingsButton/getPartialDefaultState.ts b/visualization/app/codeCharta/ui/resetSettingsButton/getPartialDefaultState.ts index 76ea940afd..4ec27a16a4 100644 --- a/visualization/app/codeCharta/ui/resetSettingsButton/getPartialDefaultState.ts +++ b/visualization/app/codeCharta/ui/resetSettingsButton/getPartialDefaultState.ts @@ -1,9 +1,8 @@ -import { RecursivePartial, Settings } from "../../codeCharta.model" -import { defaultState } from "../../state/store/state.actions" +import { RecursivePartial, Settings, CcState } from "../../codeCharta.model" import { convertToVectors } from "../../util/settingsHelper" import { codeMapNodesSelector } from "../../state/selectors/accumulatedData/codeMapNodes.selector" -import { CcState } from "../../state/store/store" import { getNumberOfTopLabels } from "../../state/effects/updateVisibleTopLabels/getNumberOfTopLabels" +import { defaultState } from "../../state/store/state.manager" const APP_SETTINGS_AMOUNT_OF_TOP_LABELS = "appSettings.amountOfTopLabels" diff --git a/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.spec.ts b/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.spec.ts index 5b240dac37..294d49c1d2 100755 --- a/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.spec.ts @@ -2,16 +2,20 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { Vector3 } from "three" -import { Store } from "../../state/angular-redux/store" import { setState } from "../../state/store/state.actions" import { ResetSettingsButtonComponent } from "./resetSettingsButton.component" +import { State, Store } from "@ngrx/store" +import { defaultState } from "../../state/store/state.manager" describe("resetSettingsButtonComponent", () => { const mockedStore = { dispatch: jest.fn() } beforeEach(() => { mockedStore.dispatch = jest.fn() TestBed.configureTestingModule({ - providers: [{ provide: Store, useValue: mockedStore }] + providers: [ + { provide: Store, useValue: mockedStore }, + { provide: State, useValue: { getValue: () => defaultState } } + ] }) }) @@ -25,7 +29,7 @@ describe("resetSettingsButtonComponent", () => { await userEvent.click(screen.getByRole("button")) expect(mockedStore.dispatch).toHaveBeenCalledWith( - setState({ appSettings: { mapColors: { selected: "#EB8319" }, scaling: new Vector3(1, 1, 1) } }) + setState({ value: { appSettings: { mapColors: { selected: "#EB8319" }, scaling: new Vector3(1, 1, 1) } } }) ) }) diff --git a/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.ts b/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.ts index e79c18f80b..db8bd55888 100755 --- a/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.ts +++ b/visualization/app/codeCharta/ui/resetSettingsButton/resetSettingsButton.component.ts @@ -1,8 +1,8 @@ -import { setState } from "../../state/store/state.actions" -import { getPartialDefaultState } from "./getPartialDefaultState" import { Component, Input, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" -import { State } from "../../state/angular-redux/state" +import { Store, State } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" +import { getPartialDefaultState } from "./getPartialDefaultState" +import { setState } from "../../state/store/state.actions" @Component({ selector: "cc-reset-settings-button", @@ -16,11 +16,11 @@ export class ResetSettingsButtonComponent { @Input() label?: string @Input() callback?: () => void - constructor(private store: Store, private state: State) {} + constructor(private store: Store, private state: State) {} applyDefaultSettings() { const partialDefaultState = getPartialDefaultState(this.settingsKeys, this.state.getValue()) - this.store.dispatch(setState(partialDefaultState)) + this.store.dispatch(setState({ value: partialDefaultState })) if (this.callback) { this.callback() diff --git a/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.spec.ts index 93e49dfa9c..c2ace34ee9 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.spec.ts @@ -2,30 +2,38 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { expect } from "@jest/globals" import userEvent from "@testing-library/user-event" -import { setAreaMetric } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.actions" -import { Store } from "../../../state/store/store" import { AreaMetricChooserComponent } from "./areaMetricChooser.component" import { AreaMetricChooserModule } from "./areaMetricChooser.module" - -jest.mock("../../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ - metricDataSelector: () => ({ - nodeMetricData: [ - { name: "aMetric", maxValue: 1 }, - { name: "bMetric", maxValue: 2 } - ], - edgeMetricData: [] - }) -})) +import { provideMockStore } from "@ngrx/store/testing" +import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" +import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" +import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" describe("areaMetricChooserComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AreaMetricChooserModule] + imports: [AreaMetricChooserModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: metricDataSelector, + value: { + nodeMetricData: [ + { name: "aMetric", maxValue: 1 }, + { name: "bMetric", maxValue: 2 } + ] + } + }, + { selector: areaMetricSelector, value: "aMetric" }, + { selector: hoveredNodeSelector, value: null } + ] + }) + ] }) }) it("should be a select for area metric", async () => { - Store.dispatch(setAreaMetric("aMetric")) await render(AreaMetricChooserComponent, { excludeComponentDeclaration: true }) await userEvent.click(await screen.findByText("aMetric (1)")) diff --git a/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.ts b/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.ts index 0865a6b2a4..3fe123597e 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { setAreaMetric } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.actions" import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" @@ -11,9 +12,9 @@ import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMet export class AreaMetricChooserComponent { areaMetric$ = this.store.select(areaMetricSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleAreaMetricChanged(value: string) { - this.store.dispatch(setAreaMetric(value)) + this.store.dispatch(setAreaMetric({ value })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.spec.ts index cad1235b87..3cab88af4d 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.spec.ts @@ -3,16 +3,16 @@ import { TestBed } from "@angular/core/testing" import { MatInputHarness } from "@angular/material/input/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" -import { State } from "../../../state/angular-redux/state" -import { CcState, Store } from "../../../state/store/store" import { AreaSettingsPanelComponent } from "./areaSettingsPanel.component" import { AreaSettingsPanelModule } from "./areaSettingsPanel.module" +import { State, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" +import { CcState } from "../../../codeCharta.model" describe("AreaSettingsPanelComponent", () => { beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ - imports: [AreaSettingsPanelModule] + imports: [AreaSettingsPanelModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] }) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.ts b/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.ts index 8b59981b03..5fe6a9c93c 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/areaSettingsPanel/areaSettingsPanel.component.ts @@ -1,5 +1,4 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { marginSelector } from "../../../state/store/dynamicSettings/margin/margin.selector" import { setMargin } from "../../../state/store/dynamicSettings/margin/margin.actions" import { MatCheckboxChange } from "@angular/material/checkbox" @@ -8,6 +7,8 @@ import { enableFloorLabelsSelector } from "../../../state/store/appSettings/enab import { invertAreaSelector } from "../../../state/store/appSettings/invertArea/invertArea.selector" import { debounce } from "../../../util/debounce" import { setInvertArea } from "../../../state/store/appSettings/invertArea/invertArea.actions" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-area-settings-panel", @@ -22,17 +23,17 @@ export class AreaSettingsPanelComponent { enableFloorLabels$ = this.store.select(enableFloorLabelsSelector) isInvertedArea$ = this.store.select(invertAreaSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} applyDebouncedMargin = debounce((margin: number) => { - this.store.dispatch(setMargin(margin)) + this.store.dispatch(setMargin({ value: margin })) }, AreaSettingsPanelComponent.DEBOUNCE_TIME) setEnableFloorLabel(event: MatCheckboxChange) { - this.store.dispatch(setEnableFloorLabels(event.checked)) + this.store.dispatch(setEnableFloorLabels({ value: event.checked })) } toggleInvertingArea(event: MatCheckboxChange) { - this.store.dispatch(setInvertArea(event.checked)) + this.store.dispatch(setInvertArea({ value: event.checked })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/artificialIntelligence.component.ts b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/artificialIntelligence.component.ts index ea2b6f03c6..592c9843dd 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/artificialIntelligence.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/artificialIntelligence.component.ts @@ -1,6 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" -import { debounceTime, identity, map } from "rxjs" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { artificialIntelligenceSelector } from "./selectors/artificialIntelligence.selector" @Component({ @@ -10,7 +10,7 @@ import { artificialIntelligenceSelector } from "./selectors/artificialIntelligen encapsulation: ViewEncapsulation.None }) export class ArtificialIntelligenceComponent { - data$ = this.store.select(identity).pipe(debounceTime(10), map(artificialIntelligenceSelector)) + data$ = this.store.select(artificialIntelligenceSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/selectors/artificialIntelligence.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/selectors/artificialIntelligence.selector.ts index 105313f843..c7099574e1 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/selectors/artificialIntelligence.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/selectors/artificialIntelligence.selector.ts @@ -17,10 +17,9 @@ import { hierarchy } from "d3-hierarchy" import { BlacklistItem, CodeMapNode, NodeType } from "../../../../codeCharta.model" import { getMostFrequentLanguage } from "./util/mainProgrammingLanguageHelper" import { isPathBlacklisted } from "../../../../util/codeMapHelper" -import { createSelector } from "../../../../state/angular-redux/createSelector" import { blacklistSelector } from "../../../../state/store/fileSettings/blacklist/blacklist.selector" -import { CcState } from "../../../../state/store/store" import { AccumulatedData, accumulatedDataSelector } from "../../../../state/selectors/accumulatedData/accumulatedData.selector" +import { createSelector } from "@ngrx/store" export type ArtificialIntelligenceData = { analyzedProgrammingLanguage: string @@ -96,7 +95,4 @@ function isFileValid(node: CodeMapNode, fileExtension: string) { ) } -export const artificialIntelligenceSelector: (state: CcState) => ArtificialIntelligenceData = createSelector( - [accumulatedDataSelector, blacklistSelector], - calculate -) +export const artificialIntelligenceSelector = createSelector(accumulatedDataSelector, blacklistSelector, calculate) diff --git a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.spec.ts index 6f7f2a20a0..b5f2f323d9 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.spec.ts @@ -1,12 +1,12 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" -import { Store } from "../../../../state/angular-redux/store" import { setColorMetric } from "../../../../state/store/dynamicSettings/colorMetric/colorMetric.actions" import { setColorRange } from "../../../../state/store/dynamicSettings/colorRange/colorRange.actions" import { setHeightMetric } from "../../../../state/store/dynamicSettings/heightMetric/heightMetric.actions" import { ArtificialIntelligenceModule } from "../artificialIntelligence.module" import { SuspiciousMetricComponent } from "./suspiciousMetrics.component" +import { Store } from "@ngrx/store" describe("SuspiciousMetricsComponent", () => { beforeEach(() => { @@ -129,9 +129,9 @@ describe("SuspiciousMetricsComponent", () => { await userEvent.click(screen.getByText("Suspicious MCC Files"), undefined) const store = TestBed.inject(Store) - expect(store.dispatch).toHaveBeenCalledWith(setHeightMetric("mcc")) - expect(store.dispatch).toHaveBeenCalledWith(setColorMetric("mcc")) - expect(store.dispatch).toHaveBeenCalledWith(setColorRange({ from: 10, to: 22 })) + expect(store.dispatch).toHaveBeenCalledWith(setHeightMetric({ value: "mcc" })) + expect(store.dispatch).toHaveBeenCalledWith(setColorMetric({ value: "mcc" })) + expect(store.dispatch).toHaveBeenCalledWith(setColorRange({ value: { from: 10, to: 22 } })) }) }) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.ts b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.ts index c1c0ad9981..56495992e2 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/artificialIntelligence/suspiciousMetrics/suspiciousMetrics.component.ts @@ -1,7 +1,8 @@ import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { dequal } from "dequal" -import { Store } from "../../../../state/angular-redux/store" -import { defaultMapColors, setMapColors } from "../../../../state/store/appSettings/mapColors/mapColors.actions" +import { setMapColors } from "../../../../state/store/appSettings/mapColors/mapColors.actions" +import { defaultMapColors } from "../../../../state/store/appSettings/mapColors/mapColors.reducer" import { setAreaMetric } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.actions" import { setColorMetric } from "../../../../state/store/dynamicSettings/colorMetric/colorMetric.actions" import { setColorRange } from "../../../../state/store/dynamicSettings/colorRange/colorRange.actions" @@ -31,20 +32,21 @@ export class SuspiciousMetricComponent implements OnChanges { } applySuspiciousMetric(metric: MetricSuggestionParameters, markOutlier: boolean) { - this.store.dispatch(setAreaMetric(AREA_METRIC)) - this.store.dispatch(setHeightMetric(metric.metric)) - this.store.dispatch(setColorMetric(metric.metric)) + this.store.dispatch(setAreaMetric({ value: AREA_METRIC })) + this.store.dispatch(setHeightMetric({ value: metric.metric })) + this.store.dispatch(setColorMetric({ value: metric.metric })) this.store.dispatch( setColorRange({ - from: metric.from, - to: metric.to + value: { from: metric.from, to: metric.to } }) ) this.store.dispatch( setMapColors({ - positive: markOutlier ? "#ffffff" : defaultMapColors.positive, - neutral: markOutlier ? "#ffffff" : defaultMapColors.neutral, - negative: markOutlier ? "#A900C0" : defaultMapColors.negative + value: { + positive: markOutlier ? "#ffffff" : defaultMapColors.positive, + neutral: markOutlier ? "#ffffff" : defaultMapColors.neutral, + negative: markOutlier ? "#A900C0" : defaultMapColors.negative + } }) ) } diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.spec.ts index 887c8e38f9..5254eb4e06 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.spec.ts @@ -2,33 +2,41 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { expect } from "@jest/globals" import userEvent from "@testing-library/user-event" -import { setColorMetric } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.actions" -import { Store } from "../../../state/store/store" import { ColorMetricChooserComponent } from "./colorMetricChooser.component" import { ColorMetricChooserModule } from "./heightMetricChooser.module" -import { toggleIsColorMetricLinkedToHeightMetric } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions" - -jest.mock("../../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ - metricDataSelector: () => ({ - nodeMetricData: [ - { name: "aMetric", maxValue: 1 }, - { name: "bMetric", maxValue: 2 } - ], - edgeMetricData: [] - }) -})) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" +import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" +import { isColorMetricLinkedToHeightMetricSelector } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" +import { colorMetricSelector } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.selector" describe("colorMetricChooserComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ColorMetricChooserModule] + imports: [ColorMetricChooserModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: metricDataSelector, + value: { + nodeMetricData: [ + { name: "aMetric", maxValue: 1 }, + { name: "bMetric", maxValue: 2 } + ] + } + }, + { selector: colorMetricSelector, value: "aMetric" }, + { selector: hoveredNodeSelector, value: null }, + { selector: isColorMetricLinkedToHeightMetricSelector, value: false } + ] + }) + ] }) }) it("should be a select for color metric", async () => { const nonDisabledIconColor = "color: rgb(68, 68, 68);" - Store.dispatch(setColorMetric("aMetric")) - const { container } = await render(ColorMetricChooserComponent, { excludeComponentDeclaration: true }) expect(screen.getByRole("combobox").getAttribute("aria-disabled")).toBe("false") @@ -46,9 +54,12 @@ describe("colorMetricChooserComponent", () => { }) it("should disable metric chooser when height and color metric are linked", async () => { - Store.dispatch(toggleIsColorMetricLinkedToHeightMetric()) const disabledIconColor = "color: rgba(0, 0, 0, 0.38);" - const { container } = await render(ColorMetricChooserComponent, { excludeComponentDeclaration: true }) + const { container, detectChanges } = await render(ColorMetricChooserComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) + store.overrideSelector(isColorMetricLinkedToHeightMetricSelector, true) + store.refreshState() + detectChanges() expect(screen.getByRole("combobox").getAttribute("aria-disabled")).toBe("true") expect(container.querySelector(".fa.fa-paint-brush").getAttribute("style")).toEqual(disabledIconColor) diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.ts b/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.ts index 86d7f855f5..88bb2edab8 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.ts @@ -1,8 +1,9 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { setColorMetric } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.actions" import { colorMetricSelector } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.selector" import { isColorMetricLinkedToHeightMetricSelector } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-color-metric-chooser", @@ -15,9 +16,9 @@ export class ColorMetricChooserComponent { nonDisabledColor = "rgba(0, 0, 0, 0.38)" disabledColor = "rgba(68,68,68, 1)" - constructor(private store: Store) {} + constructor(private store: Store) {} handleColorMetricChanged(value: string) { - this.store.dispatch(setColorMetric(value)) + this.store.dispatch(setColorMetric({ value })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.html b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.html index c41ba32179..26e8e0222f 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.html +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.html @@ -1,7 +1,8 @@ diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.spec.ts index 501969b448..a67f272034 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.spec.ts @@ -1,18 +1,14 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" -import { State } from "../../../state/angular-redux/state" -import { Store } from "../../../state/angular-redux/store" import { isDeltaStateSelector } from "../../../state/selectors/isDeltaState.selector" import { setColorLabels } from "../../../state/store/appSettings/colorLabels/colorLabels.actions" -import { - defaultMapColors, - invertColorRange, - invertDeltaColors, - setMapColors -} from "../../../state/store/appSettings/mapColors/mapColors.actions" +import { invertColorRange, invertDeltaColors, setMapColors } from "../../../state/store/appSettings/mapColors/mapColors.actions" import { ColorSettingsPanelComponent } from "./colorSettingsPanel.component" import { ColorSettingsPanelModule } from "./colorSettingsPanel.module" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" +import { State, Store, StoreModule } from "@ngrx/store" +import { defaultMapColors } from "../../../state/store/appSettings/mapColors/mapColors.reducer" jest.mock("../../../state/selectors/isDeltaState.selector", () => ({ isDeltaStateSelector: jest.fn() @@ -27,7 +23,7 @@ describe("colorSettingsPanelComponent", () => { mockedIsDeltaStateSelector.mockImplementation(() => false) beforeEach(() => { TestBed.configureTestingModule({ - imports: [ColorSettingsPanelModule] + imports: [ColorSettingsPanelModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] }) }) @@ -61,7 +57,7 @@ describe("colorSettingsPanelComponent", () => { const showNegativeLabels = screen.queryAllByText("Show labels")[2] await userEvent.click(showNegativeLabels) - expect(dispatchSpy).toHaveBeenCalledWith(setColorLabels({ negative: true })) + expect(dispatchSpy).toHaveBeenCalledWith(setColorLabels({ value: { negative: true } })) }) it("should reset invert colors checkbox on resetting colors", async () => { @@ -103,9 +99,11 @@ describe("colorSettingsPanelComponent", () => { const store = TestBed.inject(Store) store.dispatch( setMapColors({ - positiveDelta: "#000000", - negativeDelta: "#000000", - selected: "#000000" + value: { + positiveDelta: "#000000", + negativeDelta: "#000000", + selected: "#000000" + } }) ) diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.ts index 4fb930af44..f8030907b0 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/colorSettingsPanel.component.ts @@ -1,6 +1,5 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { colorLabelOptions, ColorMode } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { ColorLabelOptions, ColorMode, CcState } from "../../../codeCharta.model" import { isDeltaStateSelector } from "../../../state/selectors/isDeltaState.selector" import { setColorMode } from "../../../state/store/dynamicSettings/colorMode/colorMode.actions" import { colorModeSelector } from "../../../state/store/dynamicSettings/colorMode/colorMode.selector" @@ -8,6 +7,10 @@ import { colorLabelsSelector } from "../../../state/store/appSettings/colorLabel import { MatCheckboxChange } from "@angular/material/checkbox" import { setColorLabels } from "../../../state/store/appSettings/colorLabels/colorLabels.actions" import { invertColorRange, invertDeltaColors } from "../../../state/store/appSettings/mapColors/mapColors.actions" +import { Store, State } from "@ngrx/store" +import { selectedColorMetricDataSelector } from "../../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" +import { setColorRange } from "../../../state/store/dynamicSettings/colorRange/colorRange.actions" +import { calculateInitialColorRange } from "../../../state/store/dynamicSettings/colorRange/calculateInitialColorRange" @Component({ selector: "cc-color-settings-panel", @@ -22,14 +25,14 @@ export class ColorSettingsPanelComponent { isColorRangeInverted = false areDeltaColorsInverted = false - constructor(private store: Store) {} + constructor(private store: Store, private State: State) {} handleColorModeChange(gradient: ColorMode) { - this.store.dispatch(setColorMode(gradient)) + this.store.dispatch(setColorMode({ value: gradient })) } - toggleColorLabel(change: MatCheckboxChange, colorLabelToToggle: keyof colorLabelOptions) { - this.store.dispatch(setColorLabels({ [colorLabelToToggle]: change.checked })) + toggleColorLabel(change: MatCheckboxChange, colorLabelToToggle: keyof ColorLabelOptions) { + this.store.dispatch(setColorLabels({ value: { [colorLabelToToggle]: change.checked } })) } handleIsColorRangeInvertedChange(isColorRangeInverted: boolean) { @@ -46,4 +49,9 @@ export class ColorSettingsPanelComponent { this.isColorRangeInverted = false this.areDeltaColorsInverted = false } + + resetColorRange = () => { + const selectedColorMetricData = selectedColorMetricDataSelector(this.State.getValue()) + this.store.dispatch(setColorRange({ value: calculateInitialColorRange(selectedColorMetricData) })) + } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.spec.ts index b3078f2c49..3e4e8888ac 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.spec.ts @@ -1,27 +1,40 @@ import { TestBed } from "@angular/core/testing" import { render } from "@testing-library/angular" import { setColorRange } from "../../../../state/store/dynamicSettings/colorRange/colorRange.actions" -import { Store } from "../../../../state/store/store" import { wait } from "../../../../util/testUtils/wait" import { MetricColorRangeSliderComponent } from "./metricColorRangeSlider.component" import { MetricColorRangeSliderModule } from "./metricColorRangeSlider.module" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { metricColorRangeSliderValuesSelector } from "./selectors/metricColorRangeSliderValues.selector" +import { metricColorRangeSliderColorsSelector } from "./selectors/metricColorRangeSliderColors.selector" +import { getLastAction } from "../../../../util/testUtils/store.utils" describe("MetricColorRangeSliderComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MetricColorRangeSliderModule] + imports: [MetricColorRangeSliderModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: metricColorRangeSliderValuesSelector, value: { min: 0, max: 100, from: 0, to: 100 } }, + { + selector: metricColorRangeSliderColorsSelector, + value: { leftColor: "red", middleColor: "orange", rightColor: "green" } + } + ] + }) + ] }) }) it("should update store debounced without loosing an update and track it", async () => { - const storeSpy = jest.spyOn(Store.store, "dispatch") const { fixture } = await render(MetricColorRangeSliderComponent, { excludeComponentDeclaration: true }) fixture.componentInstance.handleValueChange({ newLeftValue: 10 }) fixture.componentInstance.handleValueChange({ newRightValue: 20 }) - expect(storeSpy).toHaveBeenCalledTimes(0) + const store = TestBed.inject(MockStore) + expect(await getLastAction(store)).toEqual({ type: "@ngrx/store/init" }) await wait(400) - expect(storeSpy).toHaveBeenCalledTimes(1) - expect(storeSpy).toHaveBeenCalledWith(setColorRange({ from: 10, to: 20 })) + expect(await getLastAction(store)).toEqual(setColorRange({ value: { from: 10, to: 20 } })) }) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.ts index 21c1b4190f..0cdafd2cb2 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/metricColorRangeSlider.component.ts @@ -1,11 +1,11 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../../state/angular-redux/store" import { HandleValueChange } from "./rangeSlider/rangeSlider.component" import { setColorRange } from "../../../../state/store/dynamicSettings/colorRange/colorRange.actions" import { metricColorRangeSliderColorsSelector } from "./selectors/metricColorRangeSliderColors.selector" import { metricColorRangeSliderValuesSelector } from "./selectors/metricColorRangeSliderValues.selector" -import { ColorRange } from "../../../../codeCharta.model" +import { ColorRange, CcState } from "../../../../codeCharta.model" import { debounce } from "../../../../util/debounce" +import { Store } from "@ngrx/store" @Component({ selector: "cc-metric-color-range-slider", @@ -19,7 +19,7 @@ export class MetricColorRangeSliderComponent { private newLeftValue: null | number = null private newRightValue: null | number = null - constructor(private store: Store) {} + constructor(private store: Store) {} handleValueChange: HandleValueChange = ({ newLeftValue, newRightValue }) => { if (newLeftValue !== undefined) { @@ -39,7 +39,7 @@ export class MetricColorRangeSliderComponent { if (this.newRightValue !== null) { newColorRange.to = this.newRightValue } - this.store.dispatch(setColorRange(newColorRange)) + this.store.dispatch(setColorRange({ value: newColorRange })) this.newLeftValue = null this.newRightValue = null diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderColors.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderColors.selector.ts index e54b5ef2f2..1af9cdf91b 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderColors.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderColors.selector.ts @@ -1,8 +1,8 @@ -import { createSelector } from "../../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { isDeltaStateSelector } from "../../../../../state/selectors/isDeltaState.selector" import { mapColorsSelector } from "../../../../../state/store/appSettings/mapColors/mapColors.selector" -export const metricColorRangeSliderColorsSelector = createSelector([mapColorsSelector, isDeltaStateSelector], mapColors => ({ +export const metricColorRangeSliderColorsSelector = createSelector(mapColorsSelector, isDeltaStateSelector, mapColors => ({ leftColor: mapColors.positive, middleColor: mapColors.neutral, rightColor: mapColors.negative diff --git a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderValues.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderValues.selector.ts index c7e9356ed3..f6503badc8 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderValues.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/colorSettingsPanel/metricColorRangeSlider/selectors/metricColorRangeSliderValues.selector.ts @@ -1,9 +1,10 @@ -import { createSelector } from "../../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { selectedColorMetricDataSelector } from "../../../../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" import { colorRangeSelector } from "../../../../../state/store/dynamicSettings/colorRange/colorRange.selector" export const metricColorRangeSliderValuesSelector = createSelector( - [selectedColorMetricDataSelector, colorRangeSelector], + selectedColorMetricDataSelector, + colorRangeSelector, (colorMetricData, colorRange) => ({ min: colorMetricData.minValue, max: colorMetricData.maxValue, diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.spec.ts index ff6f41c887..73671c1f1e 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.spec.ts @@ -2,26 +2,36 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { expect } from "@jest/globals" import userEvent from "@testing-library/user-event" -import { toggleEdgeMetricVisible } from "../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" -import { setEdgeMetric } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.actions" -import { Store } from "../../../state/store/store" import { EdgeMetricChooserComponent } from "./edgeMetricChooser.component" import { EdgeMetricChooserModule } from "./edgeMetricChooser.module" - -jest.mock("../../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ - metricDataSelector: () => ({ - edgeMetricData: [ - { name: "aMetric", maxValue: 1 }, - { name: "bMetric", maxValue: 2 } - ] - }) -})) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" +import { edgeMetricSelector } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" +import { isEdgeMetricVisibleSelector } from "../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector" +import { hoveredEdgeValueSelector } from "./hoveredEdgeValue.selector" describe("edgeMetricChooserComponent", () => { beforeEach(() => { - Store.dispatch(setEdgeMetric("aMetric")) TestBed.configureTestingModule({ - imports: [EdgeMetricChooserModule] + imports: [EdgeMetricChooserModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: metricDataSelector, + value: { + edgeMetricData: [ + { name: "aMetric", maxValue: 1 }, + { name: "bMetric", maxValue: 2 } + ] + } + }, + { selector: edgeMetricSelector, value: "aMetric" }, + { selector: hoveredEdgeValueSelector, value: null }, + { selector: isEdgeMetricVisibleSelector, value: true } + ] + }) + ] }) }) @@ -44,9 +54,11 @@ describe("edgeMetricChooserComponent", () => { let metricChoser = container.querySelector("cc-metric-chooser") expect(metricChoser.classList.contains("is-edge-metric-disabled")).toBe(false) - - Store.dispatch(toggleEdgeMetricVisible()) + const store = TestBed.inject(MockStore) + store.overrideSelector(isEdgeMetricVisibleSelector, false) + store.refreshState() detectChanges() + metricChoser = container.querySelector("cc-metric-chooser") expect(metricChoser.classList.contains("is-edge-metric-disabled")).toBe(true) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.ts index ea176901c9..0151ce975c 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { isEdgeMetricVisibleSelector } from "../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector" import { setEdgeMetric } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.actions" import { edgeMetricSelector } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" @@ -16,9 +17,9 @@ export class EdgeMetricChooserComponent { hoveredEdgeValue$ = this.store.select(hoveredEdgeValueSelector) isEdgeMetricVisible$ = this.store.select(isEdgeMetricVisibleSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleEdgeMetricChanged(value: string) { - this.store.dispatch(setEdgeMetric(value)) + this.store.dispatch(setEdgeMetric({ value })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/hoveredEdgeValue.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/hoveredEdgeValue.selector.ts index c8bada3bc3..124017a91b 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/hoveredEdgeValue.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeMetricChooser/hoveredEdgeValue.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { CodeMapNode } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" import { edgeMetricSelector } from "../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" @@ -18,4 +18,4 @@ export const _formatHoveredEdgeValue = (edgeMetric: string, hoveredNode?: Pick { beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ - imports: [MaterialModule] + imports: [MaterialModule], + providers: [provideMockStore({ selectors: [{ selector: isEdgeMetricVisibleSelector, value: false }] })] }) }) it("should toggle edge metric on map on click", async () => { const { container } = await render(EdgeMetricToggleComponent) - const isEdgeMetricVisible = isEdgeMetricVisibleSelector(Store.store.getState()) const checkbox = container.querySelector("input") - - expect(checkbox.checked).toBeFalsy() + expect(checkbox.checked).toBe(true) fireEvent.click(checkbox) - - expect(checkbox.checked).toBeTruthy() - - expect(isEdgeMetricVisibleSelector(Store.store.getState())).toBe(!isEdgeMetricVisible) + const store = TestBed.inject(MockStore) + expect(await getLastAction(store)).toEqual(toggleEdgeMetricVisible()) }) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeMetricToggle/edgeMetricToggle.component.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeMetricToggle/edgeMetricToggle.component.ts index dd0af4f9c6..2381c76062 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeMetricToggle/edgeMetricToggle.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeMetricToggle/edgeMetricToggle.component.ts @@ -1,8 +1,9 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../../state/angular-redux/store" import { Observable } from "rxjs" import { isEdgeMetricVisibleSelector } from "../../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.selector" import { toggleEdgeMetricVisible } from "../../../../state/store/appSettings/isEdgeMetricVisible/isEdgeMetricVisible.actions" +import { Store } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" @Component({ selector: "cc-edge-metric-toggle", @@ -12,7 +13,7 @@ import { toggleEdgeMetricVisible } from "../../../../state/store/appSettings/isE export class EdgeMetricToggleComponent implements OnInit { isEdgeMetricVisible$: Observable - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.isEdgeMetricVisible$ = this.store.select(isEdgeMetricVisibleSelector) diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.spec.ts index 0d66c16e1d..ac5f5e9a66 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.spec.ts @@ -2,11 +2,35 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { EdgeSettingsPanelComponent } from "./edgeSettingsPanel.component" import { EdgeSettingsPanelModule } from "./edgeSettingsPanel.module" +import { provideMockStore } from "@ngrx/store/testing" +import { amountOfBuildingsWithSelectedEdgeMetricSelector } from "./selectors/amountOfBuildingsWithSelectedEdgeMetric.selector" +import { amountOfEdgePreviewsSelector } from "../../../state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector" +import { edgeHeightSelector } from "../../../state/store/appSettings/edgeHeight/edgeHeight.selector" +import { showOnlyBuildingsWithEdgesSelector } from "../../../state/store/appSettings/showOnlyBuildingsWithEdges/showOnlyBuildingsWithEdges.selector" +import { State } from "@ngrx/store" +import { colorMetricSelector } from "../../../state/store/dynamicSettings/colorMetric/colorMetric.selector" +import { colorRangeSelector } from "../../../state/store/dynamicSettings/colorRange/colorRange.selector" +import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/mapColors.selector" +import { defaultMapColors } from "../../../state/store/appSettings/mapColors/mapColors.reducer" describe("edgeSettingsPanelComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [EdgeSettingsPanelModule] + imports: [EdgeSettingsPanelModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: amountOfBuildingsWithSelectedEdgeMetricSelector, value: 10 }, + { selector: amountOfEdgePreviewsSelector, value: 10 }, + { selector: edgeHeightSelector, value: 10 }, + { selector: showOnlyBuildingsWithEdgesSelector, value: true }, + { selector: colorMetricSelector, value: "rloc" }, + { selector: colorRangeSelector, value: { from: 21, to: 42, max: 9001 } }, + { selector: mapColorsSelector, value: defaultMapColors } + ] + }), + { provide: State, useValue: {} } + ] }) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.ts index 723b833ad6..424fedd136 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/edgeSettingsPanel.component.ts @@ -1,7 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" import { MatCheckboxChange } from "@angular/material/checkbox" +import { Store } from "@ngrx/store" import { map } from "rxjs" -import { Store } from "../../../state/angular-redux/store" +import { CcState } from "../../../codeCharta.model" import { setAmountOfEdgePreviews } from "../../../state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.actions" import { amountOfEdgePreviewsSelector } from "../../../state/store/appSettings/amountOfEdgePreviews/amountOfEdgePreviews.selector" import { setEdgeHeight } from "../../../state/store/appSettings/edgeHeight/edgeHeight.actions" @@ -27,17 +28,17 @@ export class EdgeSettingsPanelComponent { edgeHeight$ = this.store.select(edgeHeightSelector) showOnlyBuildingsWithEdges$ = this.store.select(showOnlyBuildingsWithEdgesSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} applySettingsAmountOfEdgePreviews = (value: number) => { - this.store.dispatch(setAmountOfEdgePreviews(value)) + this.store.dispatch(setAmountOfEdgePreviews({ value })) } applySettingsEdgeHeight = (value: number) => { - this.store.dispatch(setEdgeHeight(value)) + this.store.dispatch(setEdgeHeight({ value })) } applyShowOnlyBuildingsWithEdges(event: MatCheckboxChange) { - this.store.dispatch(setShowOnlyBuildingsWithEdges(event.checked)) + this.store.dispatch(setShowOnlyBuildingsWithEdges({ value: event.checked })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/selectors/amountOfBuildingsWithSelectedEdgeMetric.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/selectors/amountOfBuildingsWithSelectedEdgeMetric.selector.ts index 5426528dfd..b27e0ea2b6 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/selectors/amountOfBuildingsWithSelectedEdgeMetric.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/edgeSettingsPanel/selectors/amountOfBuildingsWithSelectedEdgeMetric.selector.ts @@ -1,8 +1,9 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { metricDataSelector } from "../../../../state/selectors/accumulatedData/metricData/metricData.selector" import { edgeMetricSelector } from "../../../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector" export const amountOfBuildingsWithSelectedEdgeMetricSelector = createSelector( - [metricDataSelector, edgeMetricSelector], + metricDataSelector, + edgeMetricSelector, (metricData, edgeMetric) => metricData.nodeEdgeMetricsMap.get(edgeMetric)?.size ?? 0 ) diff --git a/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/areaMetricChooser.component.ts b/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/areaMetricChooser.component.ts index b8605d3316..5ecb2ca3e3 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/areaMetricChooser.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/areaMetricChooser.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { setHeightMetric } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.actions" import { heightMetricSelector } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.selector" @@ -11,9 +12,9 @@ import { heightMetricSelector } from "../../../state/store/dynamicSettings/heigh export class HeightMetricChooserComponent { heightMetric$ = this.store.select(heightMetricSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleHeightMetricChanged(value: string) { - this.store.dispatch(setHeightMetric(value)) + this.store.dispatch(setHeightMetric({ value })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.spec.ts index 3e9e200d36..cbc11c41d4 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.spec.ts @@ -2,30 +2,38 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { expect } from "@jest/globals" import userEvent from "@testing-library/user-event" -import { setHeightMetric } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.actions" -import { Store } from "../../../state/store/store" import { HeightMetricChooserComponent } from "./areaMetricChooser.component" import { HeightMetricChooserModule } from "./heightMetricChooser.module" - -jest.mock("../../../state/selectors/accumulatedData/metricData/metricData.selector", () => ({ - metricDataSelector: () => ({ - nodeMetricData: [ - { name: "aMetric", maxValue: 1 }, - { name: "bMetric", maxValue: 2 } - ], - edgeMetricData: [] - }) -})) +import { provideMockStore } from "@ngrx/store/testing" +import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" +import { heightMetricSelector } from "../../../state/store/dynamicSettings/heightMetric/heightMetric.selector" +import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" describe("heightMetricChooserComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [HeightMetricChooserModule] + imports: [HeightMetricChooserModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: metricDataSelector, + value: { + nodeMetricData: [ + { name: "aMetric", maxValue: 1 }, + { name: "bMetric", maxValue: 2 } + ] + } + }, + { selector: heightMetricSelector, value: "aMetric" }, + { selector: hoveredNodeSelector, value: null } + ] + }) + ] }) }) it("should be a select for height metric", async () => { - Store.dispatch(setHeightMetric("aMetric")) await render(HeightMetricChooserComponent, { excludeComponentDeclaration: true }) await userEvent.click(await screen.findByText("aMetric (1)")) diff --git a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.spec.ts index 485a46967c..940413c79d 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.spec.ts @@ -2,28 +2,32 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import { setColorLabels } from "../../../state/store/appSettings/colorLabels/colorLabels.actions" import { addFile, setDelta } from "../../../state/store/files/files.actions" -import { Store } from "../../../state/store/store" import { TEST_FILE_DATA } from "../../../util/dataMocks" import { HeightSettingsPanelComponent } from "./heightSettingsPanel.component" import { HeightSettingsPanelModule } from "./heightSettingsPanel.module" +import { Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" describe("heightSettingsPanelComponent", () => { beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ - imports: [HeightSettingsPanelModule] + imports: [HeightSettingsPanelModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] }) }) it("should disable amount of top labels slider when there are colorLabels", async () => { - Store.dispatch( + const { detectChanges } = await render(HeightSettingsPanelComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(Store) + store.dispatch( setColorLabels({ - positive: true, - negative: false, - neutral: false + value: { + positive: true, + negative: false, + neutral: false + } }) ) - await render(HeightSettingsPanelComponent, { excludeComponentDeclaration: true }) + detectChanges() const amountOfTopLabelsSlider = screen.getByTitle("Disabled because color labels are used") const matSlider = amountOfTopLabelsSlider.querySelector("mat-slider") @@ -40,9 +44,12 @@ describe("heightSettingsPanelComponent", () => { }) it("should not display invertHeight-checkbox when being in delta mode", async () => { - Store.dispatch(addFile(TEST_FILE_DATA)) - Store.dispatch(setDelta(TEST_FILE_DATA, TEST_FILE_DATA)) - await render(HeightSettingsPanelComponent, { excludeComponentDeclaration: true }) + const { detectChanges } = await render(HeightSettingsPanelComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(Store) + store.dispatch(addFile({ file: TEST_FILE_DATA })) + store.dispatch(setDelta({ referenceFile: TEST_FILE_DATA, comparisonFile: TEST_FILE_DATA })) + detectChanges() + expect(screen.queryByText("Invert Height")).toBe(null) }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.ts b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.ts index 11fcadca50..307340d941 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/heightSettingsPanel.component.ts @@ -1,5 +1,4 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { amountOfTopLabelsSelector } from "../../../state/store/appSettings/amountOfTopLabels/amountOfTopLabels.selector" import { isLabelsSliderDisabledSelector } from "./selectors/isLabelsSliderDisabled.selector" import { setAmountOfTopLabels } from "../../../state/store/appSettings/amountOfTopLabels/amountOfTopLabels.actions" @@ -14,6 +13,8 @@ import { invertHeightSelector } from "../../../state/store/appSettings/invertHei import { setInvertHeight } from "../../../state/store/appSettings/invertHeight/invertHeight.actions" import { isDeltaStateSelector } from "../../../state/selectors/isDeltaState.selector" import { debounce } from "../../../util/debounce" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-height-settings-panel", @@ -31,25 +32,25 @@ export class HeightSettingsPanelComponent { invertHeight$ = this.store.select(invertHeightSelector) isDeltaState$ = this.store.select(isDeltaStateSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} applyDebouncedTopLabels = debounce((amountOfTopLabels: number) => { - this.store.dispatch(setAmountOfTopLabels(amountOfTopLabels)) + this.store.dispatch(setAmountOfTopLabels({ value: amountOfTopLabels })) }, HeightSettingsPanelComponent.DEBOUNCE_TIME) applyDebouncedScalingY = debounce((y: number) => { - this.store.dispatch(setScaling({ y })) + this.store.dispatch(setScaling({ value: { y } })) }, HeightSettingsPanelComponent.DEBOUNCE_TIME) setShowMetricLabelNodeName(event: MatCheckboxChange) { - this.store.dispatch(setShowMetricLabelNodeName(event.checked)) + this.store.dispatch(setShowMetricLabelNodeName({ value: event.checked })) } setShowMetricLabelNameValue(event: MatCheckboxChange) { - this.store.dispatch(setShowMetricLabelNameValue(event.checked)) + this.store.dispatch(setShowMetricLabelNameValue({ value: event.checked })) } setInvertHeight(event: MatCheckboxChange) { - this.store.dispatch(setInvertHeight(event.checked)) + this.store.dispatch(setInvertHeight({ value: event.checked })) } } diff --git a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/selectors/isLabelsSliderDisabled.selector.ts b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/selectors/isLabelsSliderDisabled.selector.ts index f9a38de2db..8b8b0fe05d 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/selectors/isLabelsSliderDisabled.selector.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/heightSettingsPanel/selectors/isLabelsSliderDisabled.selector.ts @@ -1,7 +1,7 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { colorLabelsSelector } from "../../../../state/store/appSettings/colorLabels/colorLabels.selector" export const isLabelsSliderDisabledSelector = createSelector( - [colorLabelsSelector], + colorLabelsSelector, colorLabels => colorLabels.negative || colorLabels.neutral || colorLabels.positive ) diff --git a/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.spec.ts index 6e520ba461..3aabc4effc 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.spec.ts @@ -1,26 +1,35 @@ import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { LinkColorMetricToHeightMetricButtonComponent } from "./linkColorMetricToHeightMetricButton.component" -import { Store } from "../../../state/store/store" import { TestBed } from "@angular/core/testing" import { CommonModule } from "@angular/common" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { isColorMetricLinkedToHeightMetricSelector } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" +import { getLastAction } from "../../../util/testUtils/store.utils" +import { toggleIsColorMetricLinkedToHeightMetric } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions" describe("linkHeightAndColorMetricComponent", () => { beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ - imports: [CommonModule] + imports: [CommonModule], + providers: [provideMockStore({ selectors: [{ selector: isColorMetricLinkedToHeightMetricSelector, value: false }] })] }) }) it("should toggle height and color metric link on click and show associated icon", async () => { - const { container } = await render(LinkColorMetricToHeightMetricButtonComponent) + const { container, detectChanges } = await render(LinkColorMetricToHeightMetricButtonComponent) expect(container.querySelector(".fa.fa-link")).not.toBe(null) expect(container.querySelector(".fa.fa-chain-broken")).toBe(null) expect(screen.queryByText("Unlink Height and Color Metric")).toBe(null) await userEvent.click(screen.getByTitle("Link Height and Color Metric")) + const store = TestBed.inject(MockStore) + expect(await getLastAction(store)).toEqual(toggleIsColorMetricLinkedToHeightMetric()) + + store.overrideSelector(isColorMetricLinkedToHeightMetricSelector, true) + store.refreshState() + detectChanges() expect(container.querySelector(".fa.fa-chain-broken")).not.toBe(null) expect(container.querySelector(".fa.fa-link")).toBe(null) diff --git a/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.ts b/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.ts index 216bca4794..c926be350a 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/linkColorMetricToHeightMetricButton/linkColorMetricToHeightMetricButton.component.ts @@ -1,7 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { isColorMetricLinkedToHeightMetricSelector } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.selector" import { toggleIsColorMetricLinkedToHeightMetric } from "../../../state/store/appSettings/isHeightAndColorMetricLinked/isColorMetricLinkedToHeightMetric.actions" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-link-color-metric-to-height-metric-button", @@ -12,7 +13,7 @@ import { toggleIsColorMetricLinkedToHeightMetric } from "../../../state/store/ap export class LinkColorMetricToHeightMetricButtonComponent { isColorMetricLinkedToHeightMetric$ = this.store.select(isColorMetricLinkedToHeightMetricSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} toggleIsColorMetricLinkedToHeightMetric() { this.store.dispatch(toggleIsColorMetricLinkedToHeightMetric()) diff --git a/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.spec.ts index 4fc095a053..1059c69ba4 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.spec.ts @@ -9,6 +9,8 @@ import { ThreeOrbitControlsService } from "../codeMap/threeViewer/threeOrbitCont import { RibbonBarComponent } from "./ribbonBar.component" import { RibbonBarModule } from "./ribbonBar.module" import { VALID_NODE_WITH_PATH_AND_EXTENSION } from "../../util/dataMocks" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" +import { StoreModule } from "@ngrx/store" jest.mock("../../state/selectors/isDeltaState.selector", () => ({ isDeltaStateSelector: jest.fn() @@ -34,7 +36,7 @@ describe("RibbonBarComponent", () => { mockedIsDeltaStateSelector.mockImplementation(() => false) mockMetricDataSelector.mockImplementation(() => ({ edgeMetricData: [], nodeMetricData: [], nodeEdgeMetricsMap: new Map() })) TestBed.configureTestingModule({ - imports: [RibbonBarModule], + imports: [RibbonBarModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })], providers: [ { provide: ThreeCameraService, useValue: {} }, { provide: ThreeOrbitControlsService, useValue: {} } diff --git a/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.ts b/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.ts index e4a5dd1656..803096c351 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/ribbonBar.component.ts @@ -1,9 +1,10 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { experimentalFeaturesEnabledSelector } from "../../state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector" import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector" import { map } from "rxjs" import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" type PanelSelection = "NONE" | "AREA_PANEL_OPEN" | "HEIGHT_PANEL_OPEN" | "COLOR_PANEL_OPEN" | "EDGE_PANEL_OPEN" @@ -18,7 +19,7 @@ export class RibbonBarComponent implements OnInit, OnDestroy { experimentalFeaturesEnabled$ = this.store.select(experimentalFeaturesEnabledSelector) isDeltaState$ = this.store.select(isDeltaStateSelector) hasEdgeMetric$ = this.store.select(metricDataSelector).pipe(map(metricData => metricData.edgeMetricData.length > 0)) - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { document.addEventListener("mousedown", this.closePanelSelectionOnOutsideClick) diff --git a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.spec.ts index 45ab364381..81fe5136c0 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.spec.ts @@ -7,29 +7,30 @@ import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { Vector3 } from "three" import { setState } from "../../../../state/store/state.actions" -import { Store } from "../../../../state/store/store" import { SCENARIO_ATTRIBUTE_CONTENT, STATE } from "../../../../util/dataMocks" import { ThreeCameraService } from "../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../codeMap/threeViewer/threeOrbitControls.service" import { ScenarioHelper } from "../scenarioHelper" import { AddCustomScenarioComponent } from "./addCustomScenario.component" import { AddCustomScenarioModule } from "./addCustomScenario.module" +import { appReducers, setStateMiddleware } from "../../../../state/store/state.manager" +import { State, Store, StoreModule } from "@ngrx/store" describe("AddCustomScenarioComponent", () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AddCustomScenarioModule], + beforeEach(async () => { + return TestBed.configureTestingModule({ + imports: [AddCustomScenarioModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })], providers: [ { provide: ThreeCameraService, useValue: { camera: { position: new Vector3(0, 300, 1000) } } }, { provide: ThreeOrbitControlsService, useValue: { controls: { target: new Vector3(177, 0, 299) } } }, - { provide: MatDialogRef, useValue: { close: jest.fn() } } + { provide: MatDialogRef, useValue: { close: jest.fn() } }, + { provide: State, useValue: { getValue: () => STATE } } ] - }) + }).compileComponents() }) it("should enable the user to add a custom scenario, with all properties set initially", async () => { ScenarioHelper.addScenario = jest.fn() - Store.dispatch(setState(STATE)) const { fixture } = await render(AddCustomScenarioComponent, { excludeComponentDeclaration: true }) const loader = TestbedHarnessEnvironment.loader(fixture) @@ -63,8 +64,10 @@ describe("AddCustomScenarioComponent", () => { }) it("should show an error message, when no properties are selected", async () => { - Store.dispatch(setState(STATE)) - await render(AddCustomScenarioComponent, { excludeComponentDeclaration: true }) + const { detectChanges } = await render(AddCustomScenarioComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(Store) + store.dispatch(setState({ value: STATE })) + detectChanges() await userEvent.click(screen.getByText("Camera-Position")) await userEvent.click(screen.getByText("Area-Metric (rloc)")) diff --git a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.ts b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.ts index ba001c9987..f2859aa532 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/addCustomScenario.component.ts @@ -1,11 +1,12 @@ import { Component, ViewEncapsulation } from "@angular/core" import { UntypedFormControl } from "@angular/forms" -import { State } from "../../../../state/angular-redux/state" import { ScenarioHelper, ScenarioMetricProperty } from "../scenarioHelper" import { ThreeCameraService } from "../../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../../codeMap/threeViewer/threeOrbitControls.service" import { customScenarioNameValidator } from "./utils/customScenarioName.validator" import { getInitialScenarioMetricProperties } from "./utils/getInitialScenarioMetricProperties" +import { State } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" @Component({ templateUrl: "./addCustomScenario.component.html", @@ -18,7 +19,11 @@ export class AddCustomScenarioComponent { scenarioContent: ScenarioMetricProperty[] areAnyScenarioMetricPropertiesSelected = true - constructor(private state: State, threeCameraService: ThreeCameraService, threeOrbitControlsService: ThreeOrbitControlsService) { + constructor( + private state: State, + threeCameraService: ThreeCameraService, + threeOrbitControlsService: ThreeOrbitControlsService + ) { this.scenarioContent = getInitialScenarioMetricProperties(this.state.getValue(), { camera: threeCameraService.camera.position, cameraTarget: threeOrbitControlsService.controls.target diff --git a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/utils/getInitialScenarioMetricProperties.ts b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/utils/getInitialScenarioMetricProperties.ts index 2b0b966201..49e1cf7b3b 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/utils/getInitialScenarioMetricProperties.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/addCustomScenario/utils/getInitialScenarioMetricProperties.ts @@ -1,5 +1,4 @@ -import { Scenario } from "../../../../../codeCharta.model" -import { CcState } from "../../../../../state/store/store" +import { Scenario, CcState } from "../../../../../codeCharta.model" import { ScenarioMetricProperty } from "../../scenarioHelper" export const getInitialScenarioMetricProperties = (state: CcState, camera: Scenario["camera"]): ScenarioMetricProperty[] => { diff --git a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.spec.ts b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.spec.ts index 038f1a0075..a282dbd079 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.spec.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.spec.ts @@ -1,23 +1,23 @@ import { MatDialog } from "@angular/material/dialog" -import { State } from "../../../state/angular-redux/state" -import { Store } from "../../../state/angular-redux/store" import { setState } from "../../../state/store/state.actions" import { ThreeCameraService } from "../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../codeMap/threeViewer/threeOrbitControls.service" import { ErrorDialogComponent } from "../../dialogs/errorDialog/errorDialog.component" import { ScenarioService } from "./scenario.service" import { ScenarioHelper } from "./scenarioHelper" +import { State, Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" describe("scenarioService", () => { let scenarioService: ScenarioService - let mockedStore: Store + let mockedStore: Store let mockedDialog: MatDialog let mockedThreeCameraService: ThreeCameraService let mockedThreeOrbitControlsService: ThreeOrbitControlsService beforeEach(() => { - const mockedState = {} as unknown as State - mockedStore = { dispatch: jest.fn() } as unknown as Store + const mockedState = {} as unknown as State + mockedStore = { dispatch: jest.fn() } as unknown as Store mockedDialog = { open: jest.fn() } as unknown as MatDialog mockedThreeCameraService = { setPosition: jest.fn() } as unknown as ThreeCameraService mockedThreeOrbitControlsService = { setControlTarget: jest.fn() } as unknown as ThreeOrbitControlsService @@ -44,8 +44,10 @@ describe("scenarioService", () => { scenarioService.applyScenario("Scenario1") expect(mockedStore.dispatch).toHaveBeenCalledWith( setState({ - dynamicSettings: { areaMetric: "rloc", margin: 50 }, - appSettings: { edgeHeight: 42 } + value: { + dynamicSettings: { areaMetric: "rloc", margin: 50 }, + appSettings: { edgeHeight: 42 } + } }) ) expect(mockedThreeCameraService.setPosition).toHaveBeenCalledWith({ x: 1, y: 1, z: 1 }) diff --git a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.ts b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.ts index ba558a4308..023752d4d4 100644 --- a/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.ts +++ b/visualization/app/codeCharta/ui/ribbonBar/showScenariosButton/scenario.service.ts @@ -1,22 +1,21 @@ import { Injectable } from "@angular/core" import { MatDialog } from "@angular/material/dialog" -import { ColorRange, MapColors } from "../../../codeCharta.model" -import { State } from "../../../state/angular-redux/state" -import { Store } from "../../../state/angular-redux/store" +import { ColorRange, MapColors, CcState } from "../../../codeCharta.model" import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector" import { setMapColors } from "../../../state/store/appSettings/mapColors/mapColors.actions" import { setColorRange } from "../../../state/store/dynamicSettings/colorRange/colorRange.actions" -import { setState } from "../../../state/store/state.actions" import { ScenarioHelper } from "./scenarioHelper" import { ThreeCameraService } from "../../codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../../codeMap/threeViewer/threeOrbitControls.service" import { ErrorDialogComponent } from "../../dialogs/errorDialog/errorDialog.component" +import { Store, State } from "@ngrx/store" +import { setState } from "../../../state/store/state.actions" @Injectable() export class ScenarioService { constructor( - private state: State, - private store: Store, + private state: State, + private store: Store, private dialog: MatDialog, private threeCameraService: ThreeCameraService, private threeOrbitControlsService: ThreeOrbitControlsService @@ -29,9 +28,9 @@ export class ScenarioService { applyScenario(name: string) { const scenario = ScenarioHelper.scenarios.get(name) const scenarioSettings = ScenarioHelper.getScenarioSettings(scenario) - this.store.dispatch(setState(scenarioSettings)) - this.store.dispatch(setColorRange(scenarioSettings.dynamicSettings.colorRange as ColorRange)) - this.store.dispatch(setMapColors(scenarioSettings.appSettings.mapColors as MapColors)) + this.store.dispatch(setState({ value: scenarioSettings })) + this.store.dispatch(setColorRange({ value: scenarioSettings.dynamicSettings.colorRange as ColorRange })) + this.store.dispatch(setMapColors({ value: scenarioSettings.appSettings.mapColors as MapColors })) if (scenario.camera) { // @ts-ignore -- we know that it is not a partial when it is set diff --git a/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.spec.ts b/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.spec.ts index 44b0060bd3..f569bb6949 100755 --- a/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.spec.ts @@ -1,13 +1,14 @@ import { ScreenshotButtonComponent } from "./screenshotButton.component" -import { setScreenshotToClipboardEnabled } from "../../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions" import { TestBed } from "@angular/core/testing" -import { Store } from "../../state/store/store" import { render, screen } from "@testing-library/angular" import { ScreenshotButtonModule } from "./screenshotButton.module" import userEvent from "@testing-library/user-event" import { ThreeRendererService } from "../codeMap/threeViewer/threeRenderer.service" import { ThreeCameraService } from "../codeMap/threeViewer/threeCamera.service" import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { screenshotToClipboardEnabledSelector } from "../../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector" +import { State } from "@ngrx/store" describe("screenshotButtonComponent", () => { beforeEach(() => { @@ -16,13 +17,14 @@ describe("screenshotButtonComponent", () => { providers: [ { provide: ThreeCameraService, useValue: {} }, { provide: ThreeSceneService, useValue: {} }, - { provide: ThreeRendererService, useValue: {} } + { provide: ThreeRendererService, useValue: {} }, + { provide: State, useValue: {} }, + provideMockStore({ selectors: [{ selector: screenshotToClipboardEnabledSelector, value: true }] }) ] }) }) it("should copy to clipboard on click, when screenshot to clipboard is enabled", async () => { - Store.store.dispatch(setScreenshotToClipboardEnabled(true)) const { fixture } = await render(ScreenshotButtonComponent, { excludeComponentDeclaration: true }) fixture.componentInstance.makeScreenshotToClipBoard = jest.fn() @@ -31,8 +33,11 @@ describe("screenshotButtonComponent", () => { }) it("should save to file on click, when screenshot to clipboard is not enabled", async () => { - Store.store.dispatch(setScreenshotToClipboardEnabled(false)) - const { fixture } = await render(ScreenshotButtonComponent, { excludeComponentDeclaration: true }) + const { fixture, detectChanges } = await render(ScreenshotButtonComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) + store.overrideSelector(screenshotToClipboardEnabledSelector, false) + store.refreshState() + detectChanges() fixture.componentInstance.makeScreenshotToFile = jest.fn() await userEvent.click(screen.getByTitle("Export screenshot as file (Ctrl+Alt+S), copy it to clipboard by (Ctrl+Alt+F)")) diff --git a/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.ts b/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.ts index 23d7584a1a..475e26cadb 100644 --- a/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.ts +++ b/visualization/app/codeCharta/ui/screenshotButton/screenshotButton.component.ts @@ -5,10 +5,10 @@ import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService" import hotkeys from "hotkeys-js" import { Component, ViewEncapsulation } from "@angular/core" -import { State } from "../../state/angular-redux/state" -import { Store } from "../../state/angular-redux/store" import { screenshotToClipboardEnabledSelector } from "../../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector" import { ThreeRendererService } from "../codeMap/threeViewer/threeRenderer.service" +import { Store, State } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-screenshot-button", @@ -24,8 +24,8 @@ export class ScreenshotButtonComponent { private threeCameraService: ThreeCameraService, private threeSceneService: ThreeSceneService, private threeRendererService: ThreeRendererService, - private store: Store, - private state: State + private store: Store, + private state: State ) { hotkeys(this.SCREENSHOT_HOTKEY_TO_FILE, () => { this.makeScreenshotToFile() diff --git a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.spec.ts index 9c9f58d065..2120407318 100644 --- a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.spec.ts @@ -2,42 +2,59 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { MaterialModule } from "../../../../material/material.module" -import { setBlacklist } from "../../../state/store/fileSettings/blacklist/blacklist.actions" -import { Store } from "../../../state/store/store" +import { removeBlacklistItem } from "../../../state/store/fileSettings/blacklist/blacklist.actions" import { BlacklistPanelComponent } from "./blacklistPanel.component" +import { Store } from "@ngrx/store" +import { BehaviorSubject } from "rxjs" +import { BlacklistItem } from "../../../codeCharta.model" const placeholderText = "Add pattern via search or node context-menu" describe("blacklistPanel", () => { + let flattenedItems$: BehaviorSubject + let excludedItems$: BehaviorSubject + let dispatchSpy: jest.Mock + beforeEach(() => { - Store["initialize"]() + flattenedItems$ = new BehaviorSubject([]) + excludedItems$ = new BehaviorSubject([]) + dispatchSpy = jest.fn() TestBed.configureTestingModule({ - imports: [MaterialModule] + imports: [MaterialModule], + providers: [{ provide: Store, useValue: { select: () => new BehaviorSubject([]), dispatch: dispatchSpy } }] }) }) + afterEach(() => { + flattenedItems$.complete() + excludedItems$.complete() + }) + it("should have place holder texts when there are no flattened nor excluded items", async () => { await render(BlacklistPanelComponent) expect(screen.getAllByText(placeholderText).length).toBe(2) }) it("should display all flattened and excluded items in the correct section and remove an item on click", async () => { - Store.dispatch( - setBlacklist([ - { type: "flatten", path: "some/flattened/building.ts" }, - { type: "exclude", path: "some/excluded/building.ts" } - ]) - ) - await render(BlacklistPanelComponent) + const { fixture, detectChanges } = await render(BlacklistPanelComponent) + flattenedItems$.next([{ type: "flatten", path: "some/flattened/building.ts" }]) + excludedItems$.next([{ type: "exclude", path: "some/excluded/building.ts" }]) + fixture.componentInstance.flattenedItems$ = flattenedItems$ + fixture.componentInstance.excludedItems$ = excludedItems$ + detectChanges() expect(screen.queryByText(placeholderText)).toBe(null) expect(screen.getByText("some/flattened/building.ts")).not.toBe(null) expect(screen.getByText("some/excluded/building.ts")).not.toBe(null) await userEvent.click(screen.getByText("some/excluded/building.ts")) - expect(Store.store.getState().fileSettings.blacklist).not.toContainEqual({ - type: "exclude", - path: "some/excluded/building.ts" - }) + expect(dispatchSpy).toHaveBeenCalledWith( + removeBlacklistItem({ + item: { + type: "exclude", + path: "some/excluded/building.ts" + } + }) + ) }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.ts b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.ts index de432ee040..a2f11bc00c 100644 --- a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/blacklistPanel.component.ts @@ -1,6 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { BlacklistItem } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { BlacklistItem, CcState } from "../../../codeCharta.model" import { removeBlacklistItem } from "../../../state/store/fileSettings/blacklist/blacklist.actions" import { createBlacklistItemSelector } from "./createBlacklistItemSelector" @@ -14,9 +14,9 @@ export class BlacklistPanelComponent { flattenedItems$ = this.store.select(createBlacklistItemSelector("flatten")) excludedItems$ = this.store.select(createBlacklistItemSelector("exclude")) - constructor(private store: Store) {} + constructor(private store: Store) {} removeBlacklistEntry(item: BlacklistItem) { - this.store.dispatch(removeBlacklistItem(item)) + this.store.dispatch(removeBlacklistItem({ item })) } } diff --git a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/createBlacklistItemSelector.ts b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/createBlacklistItemSelector.ts index 44b667b97b..a78d03e011 100644 --- a/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/createBlacklistItemSelector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/blacklistPanel/createBlacklistItemSelector.ts @@ -1,9 +1,9 @@ +import { createSelector } from "@ngrx/store" import { BlacklistItem, BlacklistType } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { blacklistSelector } from "../../../state/store/fileSettings/blacklist/blacklist.selector" export const createBlacklistItemSelector = (type: BlacklistType) => - createSelector([blacklistSelector], blacklist => _getFilteredAndSortedItems(type, blacklist)) + createSelector(blacklistSelector, blacklist => _getFilteredAndSortedItems(type, blacklist)) export const _getFilteredAndSortedItems = (type: BlacklistType, blacklist: BlacklistItem[]) => { const excludedItems = blacklist.filter(item => item.type === type) diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeView.component.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeView.component.ts index 5fee9113c6..b1b9055e5e 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeView.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeView.component.ts @@ -1,8 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { CodeMapNode } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" +import { CodeMapNode, CcState } from "../../../codeCharta.model" import { mapTreeViewNodeSelector } from "./mapTreeViewNodeSelector/mapTreeViewNode.selector" @Component({ @@ -14,7 +14,7 @@ import { mapTreeViewNodeSelector } from "./mapTreeViewNodeSelector/mapTreeViewNo export class MapTreeViewComponent { mapTreeViewNode$: Observable - constructor(store: Store) { + constructor(store: Store) { this.mapTreeViewNode$ = store.select(mapTreeViewNodeSelector) } } diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.spec.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.spec.ts index 7a8fcc8aef..fc0eba681e 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.spec.ts @@ -1,52 +1,44 @@ -import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../../state/store/store" +import { State } from "@ngrx/store" +import { CcState, CodeMapNode } from "../../../../codeCharta.model" import * as codeMapHelper from "../../../../util/codeMapHelper" import { MapTreeViewItemIconColorPipe } from "./mapTreeViewItemIconColor.pipe" describe("MapTreeViewItemIconColorPipe", () => { - const mockState = { - dynamicSettings: { - areaMetric: "unary" - }, - fileSettings: { - markedPackages: [] - } - } - - beforeEach(() => { - jest.mock("../../../../state/store/store") - Store.store.getState = jest.fn().mockReturnValue(mockState) - }) + const state = { + getValue: () => ({ + dynamicSettings: { + areaMetric: "unary" + }, + fileSettings: { + markedPackages: [] + } + }) + } as State it("should return undefined for leaf nodes", () => { const fakeNode = { attributes: { unary: 1 } } as unknown as CodeMapNode - expect(new MapTreeViewItemIconColorPipe().transform(fakeNode)).toBe(undefined) + expect(new MapTreeViewItemIconColorPipe(state).transform(fakeNode)).toBe(undefined) }) it("should return default color if getMarkingColor returns undefined", () => { const fakeNode = { children: [{}], attributes: { unary: 1 } } as unknown as CodeMapNode jest.spyOn(codeMapHelper, "getMarkingColor").mockImplementation(() => {}) - expect(new MapTreeViewItemIconColorPipe().transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.defaultColor) + expect(new MapTreeViewItemIconColorPipe(state).transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.defaultColor) }) it("should return color of getMarkingColor", () => { const fakeNode = { children: [{}], attributes: { unary: 1 } } as unknown as CodeMapNode jest.spyOn(codeMapHelper, "getMarkingColor").mockImplementation(() => "#123456") - expect(new MapTreeViewItemIconColorPipe().transform(fakeNode)).toBe("#123456") + expect(new MapTreeViewItemIconColorPipe(state).transform(fakeNode)).toBe("#123456") }) it("should return constant gray color if node has no area metric entry", () => { const fakeNode = { children: [{}], attributes: {} } as unknown as CodeMapNode - expect(new MapTreeViewItemIconColorPipe().transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.areMetricZeroColor) + expect(new MapTreeViewItemIconColorPipe(state).transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.areMetricZeroColor) }) it("should return constant gray color if node has a value of zero for area metric entry", () => { const fakeNode = { children: [{}], attributes: { unary: 0 } } as unknown as CodeMapNode - expect(new MapTreeViewItemIconColorPipe().transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.areMetricZeroColor) - }) - - afterAll(() => { - jest.clearAllMocks() - jest.resetAllMocks() + expect(new MapTreeViewItemIconColorPipe(state).transform(fakeNode)).toBe(MapTreeViewItemIconColorPipe.areMetricZeroColor) }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.ts index 306a5dc9f0..24e06e4d52 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemIcon/mapTreeViewItemIconColor.pipe.ts @@ -1,17 +1,18 @@ import { Pipe, PipeTransform } from "@angular/core" +import { State } from "@ngrx/store" -import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../../state/store/store" +import { CodeMapNode, CcState } from "../../../../codeCharta.model" import { getMarkingColor, isLeaf } from "../../../../util/codeMapHelper" @Pipe({ name: "mapTreeViewItemIconColor", pure: false }) export class MapTreeViewItemIconColorPipe implements PipeTransform { static defaultColor = "#000000" static areMetricZeroColor = "#BDBDBD" - static store = Store.store + + constructor(private state: State) {} transform(value: CodeMapNode): string | undefined { - const { areaMetric } = MapTreeViewItemIconColorPipe.store.getState().dynamicSettings + const { areaMetric } = this.state.getValue().dynamicSettings if (!value.attributes[areaMetric]) { return MapTreeViewItemIconColorPipe.areMetricZeroColor @@ -20,7 +21,7 @@ export class MapTreeViewItemIconColorPipe implements PipeTransform { return undefined } - const markingColor = getMarkingColor(value, MapTreeViewItemIconColorPipe.store.getState().fileSettings.markedPackages) + const markingColor = getMarkingColor(value, this.state.getValue().fileSettings.markedPackages) return markingColor || MapTreeViewItemIconColorPipe.defaultColor } } diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.spec.ts index cca3be87bf..57d5953846 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.spec.ts @@ -3,15 +3,24 @@ import { render } from "@testing-library/angular" import { CodeMapNode } from "../../../../codeCharta.model" import { MapTreeViewModule } from "../mapTreeView.module" import { MapTreeViewItemNameComponent } from "./mapTreeViewItemName.component" - -jest.mock("../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector", () => ({ - areaMetricSelector: () => "rloc" -})) +import { provideMockStore } from "@ngrx/store/testing" +import { areaMetricSelector } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" +import { rootUnarySelector } from "../../../../state/selectors/accumulatedData/rootUnary.selector" +import { searchedNodePathsSelector } from "../../../../state/selectors/searchedNodes/searchedNodePaths.selector" describe("mapTreeViewItemNameComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MapTreeViewModule] + imports: [MapTreeViewModule], + providers: [ + provideMockStore({ + selectors: [ + { selector: areaMetricSelector, value: "rloc" }, + { selector: rootUnarySelector, value: 42 }, + { selector: searchedNodePathsSelector, value: new Set() } + ] + }) + ] }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.ts index 1958c34742..fc8bebc957 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewItemName/mapTreeViewItemName.component.ts @@ -1,8 +1,8 @@ import { Component, Input, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { CodeMapNode } from "../../../../codeCharta.model" -import { Store } from "../../../../state/angular-redux/store" +import { CodeMapNode, CcState } from "../../../../codeCharta.model" import { rootUnarySelector } from "../../../../state/selectors/accumulatedData/rootUnary.selector" import { searchedNodePathsSelector } from "../../../../state/selectors/searchedNodes/searchedNodePaths.selector" import { areaMetricSelector } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" @@ -22,7 +22,7 @@ export class MapTreeViewItemNameComponent { rootUnary$: Observable areaMetric$: Observable - constructor(store: Store) { + constructor(store: Store) { this.searchedNodePaths$ = store.select(searchedNodePathsSelector) this.rootUnary$ = store.select(rootUnarySelector) this.areaMetric$ = store.select(areaMetricSelector) diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts index 41ad7f1105..7d09a16853 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts @@ -3,11 +3,12 @@ import { render, screen, fireEvent } from "@testing-library/angular" import userEvent from "@testing-library/user-event" import { searchedNodePathsSelector } from "../../../../state/selectors/searchedNodes/searchedNodePaths.selector" -import { Store } from "../../../../state/store/store" import { MapTreeViewModule } from "../mapTreeView.module" import { MapTreeViewLevelComponent } from "./mapTreeViewLevel.component" import { rootNode } from "./mocks" -import { setAreaMetric } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.actions" +import { appReducers, setStateMiddleware } from "../../../../state/store/state.manager" +import { StoreModule } from "@ngrx/store" +import { areaMetricSelector } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" jest.mock("../../../../state/selectors/searchedNodes/searchedNodePaths.selector", () => ({ searchedNodePathsSelector: jest.fn( @@ -16,6 +17,11 @@ jest.mock("../../../../state/selectors/searchedNodes/searchedNodePaths.selector" })) const searchedNodePathsSelectorMock = searchedNodePathsSelector as unknown as jest.Mock> +jest.mock("../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector", () => ({ + areaMetricSelector: jest.fn(() => "unary") +})) +const areaMetricSelectorMock = areaMetricSelector as unknown as jest.Mock> + describe("mapTreeViewLevel", () => { const componentProperties = { depth: 0, @@ -23,12 +29,10 @@ describe("mapTreeViewLevel", () => { } beforeEach(() => { + areaMetricSelectorMock.mockImplementation(() => "unary") TestBed.configureTestingModule({ - imports: [MapTreeViewModule] + imports: [MapTreeViewModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })] }) - - Store["initialize"]() - Store.dispatch(setAreaMetric("unary")) }) it("should show root and first level folder and files initially", async () => { @@ -143,7 +147,7 @@ describe("mapTreeViewLevel", () => { expect(firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")).toBeTruthy() - Store.dispatch(setAreaMetric("mcc")) + areaMetricSelectorMock.mockImplementation(() => "mcc") await userEvent.hover(firstLevelFolder) expect(firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")).toBeFalsy() diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts index 5a0daf297e..4fc2fc74ab 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts @@ -1,12 +1,12 @@ import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../../state/angular-redux/store" -import { CodeMapNode } from "../../../../codeCharta.model" +import { CodeMapNode, CcState } from "../../../../codeCharta.model" import { setHoveredNodeId } from "../../../../state/store/appStatus/hoveredNodeId/hoveredNodeId.actions" import { setRightClickedNodeData } from "../../../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions" import { rightClickedNodeDataSelector } from "../../../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector" import { hoveredNodeIdSelector } from "../../../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector" import { areaMetricSelector } from "../../../../state/store/dynamicSettings/areaMetric/areaMetric.selector" +import { Store } from "@ngrx/store" @Component({ selector: "cc-map-tree-view-level", @@ -25,7 +25,7 @@ export class MapTreeViewLevelComponent implements OnInit { areMetricGreaterZero = false - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { // open root folder initially @@ -33,11 +33,11 @@ export class MapTreeViewLevelComponent implements OnInit { } onMouseEnter() { - this.store.dispatch(setHoveredNodeId(this.node.id)) + this.store.dispatch(setHoveredNodeId({ value: this.node.id })) } onMouseLeave() { - this.store.dispatch(setHoveredNodeId(null)) + this.store.dispatch(setHoveredNodeId({ value: null })) } openNodeContextMenu = $event => { @@ -54,9 +54,11 @@ export class MapTreeViewLevelComponent implements OnInit { if (this.areMetricGreaterZero) { this.store.dispatch( setRightClickedNodeData({ - nodeId: this.node.id, - xPositionOfRightClickEvent: $event.clientX, - yPositionOfRightClickEvent: $event.clientY + value: { + nodeId: this.node.id, + xPositionOfRightClickEvent: $event.clientX, + yPositionOfRightClickEvent: $event.clientY + } }) ) @@ -69,7 +71,7 @@ export class MapTreeViewLevelComponent implements OnInit { } private scrollFunction = () => { - this.store.dispatch(setRightClickedNodeData(null)) + this.store.dispatch(setRightClickedNodeData({ value: null })) document.querySelector(".tree-element-0").removeEventListener("scroll", this.scrollFunction) } } diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.spec.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.spec.ts deleted file mode 100644 index 9b38f94c8f..0000000000 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { SortingOption } from "../../../../codeCharta.model" -import { sortingOrderSelector } from "../../../../state/store/dynamicSettings/sortingOption/sortingOrder.selector" -import { Store } from "../../../../state/store/store" -import { mapTreeViewNodeSelector } from "./mapTreeViewNode.selector" - -jest.mock("../../../../state/selectors/accumulatedData/accumulatedData.selector", () => ({ - accumulatedDataSelector: () => ({ - // freeze to make sure it is not modified. We cannot test for modification, as jest always returns the untouched mock, but due to this freeze, we would get a JS runtime error leading to a test failure, - unifiedMapNode: Object.freeze({ - name: "root", - children: [ - { - name: "folder1", - type: "Folder", - attributes: { unary: 1 }, - children: [] // there should be one child in it to match its unary value but don't care for this test - }, - { - name: "folder2", - type: "Folder", - attributes: { unary: 2 }, - children: [] // there should be two children in it to match its unary value but don't care for this test - }, - { name: "a", type: "File", attributes: {} }, - { name: "b", type: "File", attributes: {} } - ] - }) - }) -})) -jest.mock("../../../../state/store/dynamicSettings/sortingOption/sortingOrder.selector", () => { - const realSelector = jest.requireActual( - "../../../../state/store/dynamicSettings/sortingOption/sortingOrder.selector" - ).sortingOrderSelector - return { - sortingOrderSelector: jest.fn().mockImplementation(realSelector) - } -}) - -describe("mapTreeViewNodeSelector", () => { - it("should sort default to ascending by name", () => { - const mapTreeViewNode = mapTreeViewNodeSelector(Store.store.getState()) - expect(mapTreeViewNode.children[0].name).toBe("folder1") - expect(mapTreeViewNode.children[1].name).toBe("folder2") - expect(mapTreeViewNode.children[2].name).toBe("a") - expect(mapTreeViewNode.children[3].name).toBe("b") - }) - - it("should sort folder ascending by unary value, meaning most children first", () => { - sortingOrderSelector["mockImplementationOnce"](() => SortingOption.NUMBER_OF_FILES) - const mapTreeViewNode = mapTreeViewNodeSelector(Store.store.getState()) - expect(mapTreeViewNode.children[0].name).toBe("folder1") - expect(mapTreeViewNode.children[1].name).toBe("folder2") - }) -}) diff --git a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.ts b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.ts index 2317b673b1..0636abeb08 100644 --- a/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/mapTreeView/mapTreeViewNodeSelector/mapTreeViewNode.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { klona } from "klona" -import { createSelector } from "../../../../state/angular-redux/createSelector" import { accumulatedDataSelector } from "../../../../state/selectors/accumulatedData/accumulatedData.selector" import { sortingOrderAscendingSelector } from "../../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector" @@ -7,7 +7,9 @@ import { sortingOrderSelector } from "../../../../state/store/dynamicSettings/so import { sortNode } from "./sortNode" export const mapTreeViewNodeSelector = createSelector( - [accumulatedDataSelector, sortingOrderSelector, sortingOrderAscendingSelector], + accumulatedDataSelector, + sortingOrderSelector, + sortingOrderAscendingSelector, (accumulatedData, sortingOrder, sortingOrderAscending) => { // use cloned map as it is sorted inline return sortNode(klona(accumulatedData.unifiedMapNode), sortingOrder, sortingOrderAscending) diff --git a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.spec.ts index c77c975d2f..f0b4173a2d 100644 --- a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.spec.ts @@ -3,19 +3,27 @@ import { render } from "@testing-library/angular" import { expect } from "@jest/globals" import { MatchingFilesCounterComponent } from "./matchingFilesCounter.component" import { MatchingFilesCounterModule } from "./matchingFilesCounter.module" - -jest.mock("./selectors/matchingFilesCounter.selector", () => ({ - matchingFilesCounterSelector: () => ({ - fileCount: "2/3", - flattenCount: "1/1", - excludeCount: "0/1" - }) -})) +import { provideMockStore } from "@ngrx/store/testing" +import { matchingFilesCounterSelector } from "./selectors/matchingFilesCounter.selector" describe("MatchingFilesCounterComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MatchingFilesCounterModule] + imports: [MatchingFilesCounterModule], + providers: [ + provideMockStore({ + selectors: [ + { + selector: matchingFilesCounterSelector, + value: { + fileCount: "2/3", + flattenCount: "1/1", + excludeCount: "0/1" + } + } + ] + }) + ] }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.ts b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.ts index 90242b0d2d..10fb6d5be9 100644 --- a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/matchingFilesCounter.component.ts @@ -1,6 +1,7 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { Store } from "../../../state/angular-redux/store" +import { CcState } from "../../../codeCharta.model" import { MatchingFilesCounter, matchingFilesCounterSelector } from "./selectors/matchingFilesCounter.selector" @Component({ @@ -12,7 +13,7 @@ import { MatchingFilesCounter, matchingFilesCounterSelector } from "./selectors/ export class MatchingFilesCounterComponent { matchingFileCounters$: Observable - constructor(store: Store) { + constructor(store: Store) { this.matchingFileCounters$ = store.select(matchingFilesCounterSelector) } } diff --git a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.spec.ts b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.spec.ts index 8bbdfd95d9..afa50418a5 100644 --- a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.spec.ts @@ -1,44 +1,21 @@ -import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model" -import { CcState } from "../../../../state/store/store" -import { matchingFilesCounterSelector } from "./matchingFilesCounter.selector" - -jest.mock("../../../../state/selectors/accumulatedData/accumulatedData.selector", () => ({ - accumulatedDataSelector: () => ({ - unifiedMapNode: { - name: "root", - type: "Folder", - path: "/root", - children: [ - { name: "big leaf", type: "File", path: "/root/big leaf", link: "https://www.google.de" }, - { - name: "Parent Leaf", - type: "Folder", - path: "/root/Parent Leaf", - children: [ - { name: "small leaf", type: "File", path: "/root/Parent Leaf/small leaf" }, - { name: "other small leaf", type: "File", path: "/root/Parent Leaf/other small leaf" } - ] - } - ] - } - }) -})) -jest.mock("../../../../state/store/dynamicSettings/searchPattern/searchPattern.selector", () => ({ - searchPatternSelector: () => "small leaf" -})) -jest.mock("../../../../state/store/fileSettings/blacklist/blacklist.selector", () => ({ - blacklistSelector: () => { - const excluded: BlacklistItem = { path: "big Leaf", type: "exclude" as BlacklistType } - const flattened: BlacklistItem = { path: "small leaf", type: "flatten" as BlacklistType } - return [excluded, flattened] - } -})) +import { NodeType, CodeMapNode, BlacklistItem } from "../../../../codeCharta.model" +import { _calculateMatchingFilesCounter } from "./matchingFilesCounter.selector" describe("matchingFilesCounterSelector", () => { it("should calculate matching files counter", () => { - // all input selectors are mocked above - const fakeState = {} as unknown as CcState - expect(matchingFilesCounterSelector(fakeState)).toEqual({ + const blacklist: BlacklistItem[] = [ + { path: "big Leaf", type: "exclude" }, + { path: "small leaf", type: "flatten" } + ] + const searchedNodes: CodeMapNode[] = [ + { name: "small leaf", type: NodeType.FILE, path: "/root/Parent Leaf/small leaf" }, + { name: "other small leaf", type: NodeType.FILE, path: "/root/Parent Leaf/other small leaf" } + ] + const codeMapNodes: CodeMapNode[] = [ + ...searchedNodes, + { name: "big leaf", type: NodeType.FILE, path: "/root/big leaf", link: "https://www.google.de" } + ] + expect(_calculateMatchingFilesCounter(searchedNodes, blacklist, codeMapNodes)).toEqual({ excludeCount: "0/1", fileCount: "2/3", flattenCount: "1/1" diff --git a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.ts b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.ts index fd9f01ccfb..a0bd2045ad 100644 --- a/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/matchingFilesCounter/selectors/matchingFilesCounter.selector.ts @@ -1,10 +1,9 @@ import { BlacklistItem, BlacklistType, CodeMapNode } from "../../../../codeCharta.model" import { searchedNodesSelector } from "../../../../state/selectors/searchedNodes/searchedNodes.selector" import { blacklistSelector } from "../../../../state/store/fileSettings/blacklist/blacklist.selector" -import { CcState } from "../../../../state/store/store" import { isLeaf, isPathBlacklisted } from "../../../../util/codeMapHelper" import { codeMapNodesSelector } from "../../../../state/selectors/accumulatedData/codeMapNodes.selector" -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" const getBlacklistedFileCount = (blacklistType: BlacklistType, nodes: CodeMapNode[], blacklist: BlacklistItem[]) => nodes.reduce((count, node) => (isPathBlacklisted(node.path, blacklist, blacklistType) ? count + 1 : count), 0) @@ -15,22 +14,26 @@ export type MatchingFilesCounter = { excludeCount: string } -export const matchingFilesCounterSelector: (state: CcState) => MatchingFilesCounter = createSelector( - [searchedNodesSelector, blacklistSelector, codeMapNodesSelector], - (searchedNodes, blacklist, allNodes) => { - const searchedNodeLeaves = searchedNodes.filter(node => isLeaf(node)) - return { - fileCount: `${searchedNodeLeaves.length}/${allNodes.length}`, - flattenCount: `${getBlacklistedFileCount("flatten", searchedNodeLeaves, blacklist)}/${getBlacklistedFileCount( - "flatten", - allNodes, - blacklist - )}`, - excludeCount: `${getBlacklistedFileCount("exclude", searchedNodeLeaves, blacklist)}/${getBlacklistedFileCount( - "exclude", - allNodes, - blacklist - )}` - } +export const _calculateMatchingFilesCounter = (searchedNodes: CodeMapNode[], blacklist: BlacklistItem[], allNodes: CodeMapNode[]) => { + const searchedNodeLeaves = searchedNodes.filter(node => isLeaf(node)) + return { + fileCount: `${searchedNodeLeaves.length}/${allNodes.length}`, + flattenCount: `${getBlacklistedFileCount("flatten", searchedNodeLeaves, blacklist)}/${getBlacklistedFileCount( + "flatten", + allNodes, + blacklist + )}`, + excludeCount: `${getBlacklistedFileCount("exclude", searchedNodeLeaves, blacklist)}/${getBlacklistedFileCount( + "exclude", + allNodes, + blacklist + )}` } +} + +export const matchingFilesCounterSelector = createSelector( + searchedNodesSelector, + blacklistSelector, + codeMapNodesSelector, + _calculateMatchingFilesCounter ) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.spec.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.spec.ts index 0dc82a4d41..1c87fdf135 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.spec.ts @@ -1,59 +1,66 @@ -import { ApplicationInitStatus } from "@angular/core" import { TestBed } from "@angular/core/testing" import { MatDialog } from "@angular/material/dialog" -import { Action } from "redux" -import { Subject } from "rxjs" -import { EffectsModule } from "../../../state/angular-redux/effects/effects.module" +import { first, Subject } from "rxjs" import { AddBlacklistItemsIfNotResultsInEmptyMapEffect } from "../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect" -import { resultsInEmptyMap } from "../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap" -import { setSearchPattern } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.actions" -import { addBlacklistItemsIfNotResultsInEmptyMap } from "../../../state/store/fileSettings/blacklist/blacklist.actions" -import { Store } from "../../../state/store/store" import { blacklistSearchPattern, BlacklistSearchPatternEffect } from "./blacklistSearchPattern.effect" - -jest.mock("../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap", () => ({ - resultsInEmptyMap: jest.fn() -})) - -const mockedResultsInEmptyMap = jest.mocked(resultsInEmptyMap) +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { searchPatternSelector } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" +import { provideMockActions } from "@ngrx/effects/testing" +import { Action } from "@ngrx/store" +import { addBlacklistItemsIfNotResultsInEmptyMap } from "../../../state/store/fileSettings/blacklist/blacklist.actions" +import { setSearchPattern } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.actions" describe("BlacklistSearchPatternEffect", () => { - const mockedDialog = { open: jest.fn() } + let effect: BlacklistSearchPatternEffect + let actions$: Subject + let doBlacklistItemsResultInEmptyMap$: Subject<{ resultsInEmptyMap: boolean }> + let store: MockStore - beforeEach(async () => { - Store["initialize"]() - mockedDialog.open = jest.fn() + beforeEach(() => { + actions$ = new Subject() + doBlacklistItemsResultInEmptyMap$ = new Subject() - EffectsModule.actions$ = new Subject() TestBed.configureTestingModule({ - imports: [EffectsModule.forRoot([BlacklistSearchPatternEffect, AddBlacklistItemsIfNotResultsInEmptyMapEffect])], - providers: [{ provide: MatDialog, useValue: mockedDialog }] + providers: [ + BlacklistSearchPatternEffect, + { provide: MatDialog, useValue: { open: jest.fn() } }, + { provide: AddBlacklistItemsIfNotResultsInEmptyMapEffect, useValue: { doBlacklistItemsResultInEmptyMap$ } }, + provideMockStore({ selectors: [{ selector: searchPatternSelector, value: "" }] }), + provideMockActions(() => actions$) + ] }) - await TestBed.inject(ApplicationInitStatus).donePromise + effect = TestBed.inject(BlacklistSearchPatternEffect) + store = TestBed.inject(MockStore) }) afterEach(() => { - EffectsModule.actions$.complete() + actions$.complete() + doBlacklistItemsResultInEmptyMap$.complete() }) it("should exclude pattern and reset search pattern", () => { - mockedResultsInEmptyMap.mockImplementation(() => false) - Store.dispatch(setSearchPattern("needle")) + store.overrideSelector(searchPatternSelector, "needle") + store.refreshState() + const dispatchSpy = jest.spyOn(store, "dispatch") - EffectsModule.actions$.next(blacklistSearchPattern("exclude")) + let firedEffect + effect.excludeSearchPattern$.pipe(first()).subscribe(event => { + firedEffect = event + }) + actions$.next(blacklistSearchPattern("exclude")) + expect(firedEffect).toEqual(addBlacklistItemsIfNotResultsInEmptyMap({ items: [{ type: "exclude", path: "*needle*" }] })) - expect(Store.store.getState().dynamicSettings.searchPattern).toBe("") - expect(Store.store.getState().fileSettings.blacklist).toEqual([{ type: "exclude", path: "*needle*" }]) + doBlacklistItemsResultInEmptyMap$.next({ resultsInEmptyMap: false }) + expect(dispatchSpy).toHaveBeenCalledWith(setSearchPattern({ value: "" })) }) - it("should not reset search pattern, when excluding from search bar failed and afterwards excluding within CodeCharta map", () => { - mockedResultsInEmptyMap.mockImplementation(() => true) - Store.dispatch(setSearchPattern("root")) - EffectsModule.actions$.next(blacklistSearchPattern("exclude")) - - mockedResultsInEmptyMap.mockImplementation(() => false) - EffectsModule.actions$.next(addBlacklistItemsIfNotResultsInEmptyMap([{ type: "exclude", path: "*needle*" }])) + it("should not reset search pattern, when excluding from search bar failed / would result in an empty map", () => { + store.overrideSelector(searchPatternSelector, "root") + store.refreshState() + const dispatchSpy = jest.spyOn(store, "dispatch") - expect(Store.store.getState().dynamicSettings.searchPattern).toBe("root") + actions$.next(blacklistSearchPattern("exclude")) + doBlacklistItemsResultInEmptyMap$.next({ resultsInEmptyMap: true }) + expect(dispatchSpy).not.toHaveBeenCalled() }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.ts index 102fafb98a..f4e274ba99 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/blacklistSearchPattern.effect.ts @@ -1,10 +1,8 @@ -import { Inject, Injectable } from "@angular/core" -import { map, filter, withLatestFrom, tap, take } from "rxjs" -import { BlacklistType } from "../../../codeCharta.model" -import { createEffect } from "../../../state/angular-redux/effects/createEffect" -import { Actions, ActionsToken } from "../../../state/angular-redux/effects/effects.module" -import { ofType } from "../../../state/angular-redux/ofType" -import { Store } from "../../../state/angular-redux/store" +import { Injectable } from "@angular/core" +import { Actions, createEffect, ofType } from "@ngrx/effects" +import { Store } from "@ngrx/store" +import { map, filter, withLatestFrom, tap, take, share } from "rxjs" +import { BlacklistType, CcState } from "../../../codeCharta.model" import { AddBlacklistItemsIfNotResultsInEmptyMapEffect } from "../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect" import { setSearchPattern } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.actions" import { searchPatternSelector } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" @@ -13,31 +11,30 @@ import { parseBlacklistItems } from "./utils/parseBlacklistItems" type BlacklistSearchPatternAction = { type: "BlacklistSearchPatternAction" - payload: { type: BlacklistType } + action: { type: BlacklistType } } export const blacklistSearchPattern = (type: BlacklistType): BlacklistSearchPatternAction => ({ type: "BlacklistSearchPatternAction", - payload: { type } + action: { type } }) @Injectable() export class BlacklistSearchPatternEffect { constructor( - @Inject(ActionsToken) private actions$: Actions, - private store: Store, + private actions$: Actions, + private store: Store, private addBlacklistItemsIfNotResultsInEmptyMapEffect: AddBlacklistItemsIfNotResultsInEmptyMapEffect ) {} - private searchPattern$ = this.store.select(searchPatternSelector) - private searchPattern2BlacklistItems$ = this.actions$.pipe( ofType("BlacklistSearchPatternAction"), - withLatestFrom(this.searchPattern$), + withLatestFrom(this.store.select(searchPatternSelector)), map(([blacklistSearchPatternAction, searchPattern]) => ({ - type: blacklistSearchPatternAction.payload.type, - blacklistItems: parseBlacklistItems(blacklistSearchPatternAction.payload.type, searchPattern) - })) + type: blacklistSearchPatternAction.action.type, + blacklistItems: parseBlacklistItems(blacklistSearchPatternAction.action.type, searchPattern) + })), + share() ) flattenSearchPattern$ = createEffect( @@ -45,8 +42,8 @@ export class BlacklistSearchPatternEffect { this.searchPattern2BlacklistItems$.pipe( filter(searchPattern2BlacklistItems => searchPattern2BlacklistItems.type === "flatten"), tap(searchPattern2BlacklistItems => { - this.store.dispatch(addBlacklistItems(searchPattern2BlacklistItems.blacklistItems)) - this.store.dispatch(setSearchPattern()) + this.store.dispatch(addBlacklistItems({ items: searchPattern2BlacklistItems.blacklistItems })) + this.store.dispatch(setSearchPattern({ value: "" })) }) ), { dispatch: false } @@ -61,12 +58,14 @@ export class BlacklistSearchPatternEffect { take(1), filter(doBlacklistItemsResultInEmptyMap => !doBlacklistItemsResultInEmptyMap.resultsInEmptyMap), tap(() => { - this.store.dispatch(setSearchPattern()) + this.store.dispatch(setSearchPattern({ value: "" })) }) ) .subscribe() }), - map(searchPattern2BlacklistItems => addBlacklistItemsIfNotResultsInEmptyMap(searchPattern2BlacklistItems.blacklistItems)) + map(searchPattern2BlacklistItems => + addBlacklistItemsIfNotResultsInEmptyMap({ items: searchPattern2BlacklistItems.blacklistItems }) + ) ) ) } diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.spec.ts index c14d7da97c..c494a8441a 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.spec.ts @@ -4,14 +4,13 @@ import { BlacklistSearchPatternEffect } from "./blacklistSearchPattern.effect" import { SearchBarComponent } from "./searchBar.component" import { SearchBarModule } from "./searchBar.module" import userEvent from "@testing-library/user-event" -import { Store as PlainStore } from "../../../state/store/store" import { searchPatternSelector } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" -import { EffectsModule } from "../../../state/angular-redux/effects/effects.module" import { AddBlacklistItemsIfNotResultsInEmptyMapEffect } from "../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect" -import { Subject } from "rxjs" -import { Action } from "redux" import { resultsInEmptyMap } from "../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap" import { MatDialog } from "@angular/material/dialog" +import { State, Store, StoreModule } from "@ngrx/store" +import { appReducers, setStateMiddleware } from "../../../state/store/state.manager" +import { EffectsModule } from "@ngrx/effects" jest.mock("../../../state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap", () => ({ resultsInEmptyMap: jest.fn() @@ -23,10 +22,9 @@ describe("cc-search-bar", () => { const mockedDialog = { open: jest.fn() } beforeEach(async () => { - PlainStore["initialize"]() - EffectsModule.actions$ = new Subject() TestBed.configureTestingModule({ imports: [ + StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] }), EffectsModule.forRoot([BlacklistSearchPatternEffect, AddBlacklistItemsIfNotResultsInEmptyMapEffect]), SearchBarModule ], @@ -34,13 +32,11 @@ describe("cc-search-bar", () => { }) }) - afterEach(() => { - EffectsModule.actions$.complete() - }) - it("should be a debounced field for search pattern with clear button if is not empty", async () => { await render(SearchBarComponent, { excludeComponentDeclaration: true }) - const dispatchSpy = jest.spyOn(PlainStore.store, "dispatch") + const store = TestBed.inject(Store) + const state = TestBed.inject(State) + const dispatchSpy = jest.spyOn(store, "dispatch") expect(screen.queryByTestId("search-bar-clear-button")).toBe(null) @@ -49,17 +45,18 @@ describe("cc-search-bar", () => { const clearButton = await screen.findByTestId("search-bar-clear-button") expect(dispatchSpy).toHaveBeenCalledTimes(1) - expect(searchPatternSelector(PlainStore.store.getState())).toBe("needle") + expect(searchPatternSelector(state.getValue())).toBe("needle") await userEvent.click(clearButton) searchField = screen.getByPlaceholderText("Search: *.js, **/app/*") expect(searchField.value).toBe("") - expect(searchPatternSelector(PlainStore.store.getState())).toBe("") + expect(searchPatternSelector(state.getValue())).toBe("") }) it("should flatten pattern", async () => { await render(SearchBarComponent, { excludeComponentDeclaration: true }) + const state = TestBed.inject(State) let searchField = screen.getByPlaceholderText("Search: *.js, **/app/*") as HTMLInputElement await userEvent.type(searchField, "needle") @@ -70,12 +67,13 @@ describe("cc-search-bar", () => { searchField = screen.getByPlaceholderText("Search: *.js, **/app/*") expect(searchField.value).toBe("") - expect(PlainStore.store.getState().fileSettings.blacklist[0]).toEqual({ type: "flatten", path: "*needle*" }) + expect(state.getValue().fileSettings.blacklist[0]).toEqual({ type: "flatten", path: "*needle*" }) }) it("should exclude pattern", async () => { mockedResultsInEmptyMap.mockImplementation(() => false) await render(SearchBarComponent, { excludeComponentDeclaration: true }) + const state = TestBed.inject(State) let searchField = screen.getByPlaceholderText("Search: *.js, **/app/*") as HTMLInputElement await userEvent.type(searchField, "needle") @@ -86,6 +84,6 @@ describe("cc-search-bar", () => { searchField = screen.getByPlaceholderText("Search: *.js, **/app/*") expect(searchField.value).toBe("") - expect(PlainStore.store.getState().fileSettings.blacklist[0]).toEqual({ type: "exclude", path: "*needle*" }) + expect(state.getValue().fileSettings.blacklist[0]).toEqual({ type: "exclude", path: "*needle*" }) }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.ts index 5e2221a3a7..6496d4ce0d 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/searchBar.component.ts @@ -1,13 +1,13 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { setSearchPattern } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.actions" import { searchPatternSelector } from "../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" import { isSearchPatternEmptySelector } from "./selectors/isSearchPatternEmpty.selector" import { isFlattenPatternDisabledSelector } from "./selectors/isFlattenPatternDisabled.selector" import { isExcludePatternDisabledSelector } from "./selectors/isExcludePatternDisabled.selector" -import { BlacklistType } from "../../../codeCharta.model" +import { BlacklistType, CcState } from "../../../codeCharta.model" import { blacklistSearchPattern } from "./blacklistSearchPattern.effect" import { debounce } from "../../../util/debounce" +import { Store } from "@ngrx/store" @Component({ selector: "cc-search-bar", @@ -22,15 +22,15 @@ export class SearchBarComponent { isExcludePatternDisabled$ = this.store.select(isExcludePatternDisabledSelector) setSearchPatternDebounced = debounce((event: Event) => this.setSearchPattern(event), 400) - constructor(private store: Store) {} + constructor(private store: Store) {} setSearchPattern(event: Event) { const eventTarget = event.target as HTMLInputElement - this.store.dispatch(setSearchPattern(eventTarget.value)) + this.store.dispatch(setSearchPattern({ value: eventTarget.value })) } resetSearchPattern() { - this.store.dispatch(setSearchPattern()) + this.store.dispatch(setSearchPattern({ value: "" })) } blacklistSearchPattern(type: BlacklistType) { diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isExcludePatternDisabled.selector.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isExcludePatternDisabled.selector.ts index f6257f1be6..00ebf1b3a2 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isExcludePatternDisabled.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isExcludePatternDisabled.selector.ts @@ -1,11 +1,13 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { searchPatternSelector } from "../../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" import { blacklistSelector } from "../../../../state/store/fileSettings/blacklist/blacklist.selector" import { isPatternBlacklisted } from "../utils/isPatternBlacklisted" import { isSearchPatternEmptySelector } from "./isSearchPatternEmpty.selector" export const isExcludePatternDisabledSelector = createSelector( - [searchPatternSelector, isSearchPatternEmptySelector, blacklistSelector], + searchPatternSelector, + isSearchPatternEmptySelector, + blacklistSelector, (searchPattern, isSearchPatternEmpty, blacklist) => { if (isSearchPatternEmpty) { return true diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isFlattenPatternDisabled.selector.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isFlattenPatternDisabled.selector.ts index 547ded7fee..be9a598e90 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isFlattenPatternDisabled.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isFlattenPatternDisabled.selector.ts @@ -1,11 +1,13 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { searchPatternSelector } from "../../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" import { blacklistSelector } from "../../../../state/store/fileSettings/blacklist/blacklist.selector" import { isPatternBlacklisted } from "../utils/isPatternBlacklisted" import { isSearchPatternEmptySelector } from "./isSearchPatternEmpty.selector" export const isFlattenPatternDisabledSelector = createSelector( - [searchPatternSelector, isSearchPatternEmptySelector, blacklistSelector], + searchPatternSelector, + isSearchPatternEmptySelector, + blacklistSelector, (searchPattern, isSearchPatternEmpty, blacklist) => { if (isSearchPatternEmpty) { return true diff --git a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isSearchPatternEmpty.selector.ts b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isSearchPatternEmpty.selector.ts index be621f3729..36069560cb 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isSearchPatternEmpty.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchBar/selectors/isSearchPatternEmpty.selector.ts @@ -1,6 +1,6 @@ -import { createSelector } from "../../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { searchPatternSelector } from "../../../../state/store/dynamicSettings/searchPattern/searchPattern.selector" export const _isSearchPatternEmpty = (searchPattern: string) => searchPattern === "" || searchPattern === "!" || searchPattern === "," -export const isSearchPatternEmptySelector = createSelector([searchPatternSelector], _isSearchPatternEmpty) +export const isSearchPatternEmptySelector = createSelector(searchPatternSelector, _isSearchPatternEmpty) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchPanel.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/searchPanel.component.spec.ts index c45f8f35c0..e739c64f65 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchPanel.component.spec.ts @@ -2,12 +2,13 @@ import { TestBed } from "@angular/core/testing" import { fireEvent, render } from "@testing-library/angular" import { SearchPanelComponent } from "./searchPanel.component" import { SearchPanelModule } from "./searchPanel.module" +import { provideMockStore } from "@ngrx/store/testing" describe("SearchPanelComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [SearchPanelModule], - providers: [SearchPanelComponent] + providers: [SearchPanelComponent, provideMockStore()] }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/hideBlacklistItemsIndicator.selector.ts b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/hideBlacklistItemsIndicator.selector.ts index 640701a2ae..03adbccf11 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/hideBlacklistItemsIndicator.selector.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/hideBlacklistItemsIndicator.selector.ts @@ -1,4 +1,4 @@ -import { createSelector } from "../../../state/angular-redux/createSelector" +import { createSelector } from "@ngrx/store" import { blacklistSelector } from "../../../state/store/fileSettings/blacklist/blacklist.selector" -export const hideBlacklistItemsIndicatorSelector = createSelector([blacklistSelector], blacklist => blacklist.length === 0) +export const hideBlacklistItemsIndicatorSelector = createSelector(blacklistSelector, blacklist => blacklist.length === 0) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.spec.ts index bec1f52054..c20f16f5b3 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.spec.ts @@ -1,19 +1,22 @@ import { render } from "@testing-library/angular" -import { addBlacklistItem } from "../../../state/store/fileSettings/blacklist/blacklist.actions" -import { Store } from "../../../state/store/store" import { SearchPanelModeSelectorComponent } from "./searchPanelModeSelector.component" +import { provideMockStore } from "@ngrx/store/testing" +import { hideBlacklistItemsIndicatorSelector } from "./hideBlacklistItemsIndicator.selector" describe("SearchPanelModeSelectorComponent", () => { it("should not show blacklist items indicator when there are no blacklist items", async () => { - const { container } = await render(SearchPanelModeSelectorComponent) + const { container } = await render(SearchPanelModeSelectorComponent, { + providers: [provideMockStore({ selectors: [{ selector: hideBlacklistItemsIndicatorSelector, value: true }] })] + }) expect(container.querySelector(".has-blacklist-items-indicator")["hidden"]).toBe(true) }) it("should show blacklist items indicator when there are blacklist items", async () => { - Store.dispatch(addBlacklistItem({ path: "something.ts", type: "exclude" })) + const { container } = await render(SearchPanelModeSelectorComponent, { + providers: [provideMockStore({ selectors: [{ selector: hideBlacklistItemsIndicatorSelector, value: false }] })] + }) - const { container } = await render(SearchPanelModeSelectorComponent) expect(container.querySelector(".has-blacklist-items-indicator")["hidden"]).toBe(false) }) }) diff --git a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.ts b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.ts index 01f1c019a6..8403de9a87 100644 --- a/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/searchPanelModeSelector/searchPanelModeSelector.component.ts @@ -1,8 +1,9 @@ import { SearchPanelMode } from "../searchPanel.component" import { Component, Input, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" import { Observable } from "rxjs" import { hideBlacklistItemsIndicatorSelector } from "./hideBlacklistItemsIndicator.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" @Component({ selector: "cc-search-panel-mode-selector", @@ -16,7 +17,7 @@ export class SearchPanelModeSelectorComponent { hideBlacklistItemsIndicator$: Observable - constructor(store: Store) { + constructor(store: Store) { this.hideBlacklistItemsIndicator$ = store.select(hideBlacklistItemsIndicatorSelector) } } diff --git a/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.spec.ts index 6a3f656dc4..3055870fb9 100644 --- a/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.spec.ts @@ -1,30 +1,27 @@ import { fireEvent, render, screen } from "@testing-library/angular" -import { Store } from "../../../state/store/store" import { sortingOrderAscendingSelector } from "../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector" import { SortingButtonComponent } from "./sortingButton.component" -import { setSortingOrderAscending } from "../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions" +import { toggleSortingOrderAscending } from "../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { TestBed } from "@angular/core/testing" describe("SortingButtonComponent", () => { - beforeEach(() => { - Store["initialize"]() - }) - it("should toggle SortingOrderAscending on click", async () => { - await render(SortingButtonComponent) - const initialSortingOrder = sortingOrderAscendingSelector(Store.store.getState()) + const { detectChanges } = await render(SortingButtonComponent, { + providers: [provideMockStore({ selectors: [{ selector: sortingOrderAscendingSelector, value: true }] })] + }) + const store = TestBed.inject(MockStore) + + expect(screen.getByTitle("Toggle sort order (currently ascending)")).toBeTruthy() + const dispatchSpy = jest.spyOn(store, "dispatch") const button = screen.getByRole("button") fireEvent.click(button) + expect(dispatchSpy).toHaveBeenCalledWith(toggleSortingOrderAscending()) - expect(sortingOrderAscendingSelector(Store.store.getState())).toBe(!initialSortingOrder) - }) - - it("should set title of button according to current sorting order", async () => { - const { detectChanges } = await render(SortingButtonComponent) - expect(screen.getByTitle("Toggle sort order (currently ascending)")).toBeTruthy() - - Store.store.dispatch(setSortingOrderAscending(false)) + store.overrideSelector(sortingOrderAscendingSelector, false) + store.refreshState() detectChanges() expect(screen.getByTitle("Toggle sort order (currently descending)")).toBeTruthy() diff --git a/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.ts b/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.ts index 7ebdc7816a..4afd4f52f0 100644 --- a/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/sortingButton/sortingButton.component.ts @@ -1,7 +1,8 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" +import { CcState } from "../../../codeCharta.model" -import { Store } from "../../../state/angular-redux/store" import { toggleSortingOrderAscending } from "../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.actions" import { sortingOrderAscendingSelector } from "../../../state/store/appSettings/sortingOrderAscending/sortingOrderAscending.selector" @@ -13,7 +14,7 @@ import { sortingOrderAscendingSelector } from "../../../state/store/appSettings/ export class SortingButtonComponent implements OnInit { sortingOrderAscending$: Observable - constructor(private store: Store) {} + constructor(private store: Store) {} ngOnInit(): void { this.sortingOrderAscending$ = this.store.select(sortingOrderAscendingSelector) diff --git a/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.spec.ts b/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.spec.ts index c345de77bc..64bcf91adf 100644 --- a/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.spec.ts +++ b/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.spec.ts @@ -3,27 +3,24 @@ import { MatSelectModule } from "@angular/material/select" import { fireEvent, render, screen, getByText, waitForElementToBeRemoved } from "@testing-library/angular" import { SortingOption } from "../../../codeCharta.model" -import { Store } from "../../../state/store/store" import { SortingOptionComponent } from "./sortingOption.component" +import { provideMockStore } from "@ngrx/store/testing" +import { sortingOrderSelector } from "../../../state/store/dynamicSettings/sortingOption/sortingOrder.selector" describe("SortingOptionComponent", () => { beforeEach(() => { - Store["initialize"]() - TestBed.configureTestingModule({ - imports: [MatSelectModule] + imports: [MatSelectModule], + providers: [provideMockStore({ selectors: [{ selector: sortingOrderSelector, value: SortingOption.NAME }] })] }) }) - it("should have an explaining title", async () => { - await render(SortingOptionComponent) - expect(await screen.findByTitle("Sort by")).toBeTruthy() - }) - it("should be a select for the sorting option", async () => { const { detectChanges } = await render(SortingOptionComponent) detectChanges() + expect(await screen.findByTitle("Sort by")).toBeTruthy() + // it has initial sorting order expect(screen.getByText("Name")).toBeTruthy() diff --git a/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.ts b/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.ts index 4b9d730cdf..be0e3d7a47 100644 --- a/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.ts +++ b/visualization/app/codeCharta/ui/searchPanel/sortingOption/sortingOption.component.ts @@ -1,9 +1,9 @@ import { Component, ViewEncapsulation } from "@angular/core" +import { Store } from "@ngrx/store" import { Observable } from "rxjs" -import { SortingOption } from "../../../codeCharta.model" +import { SortingOption, CcState } from "../../../codeCharta.model" import { setSortingOption } from "../../../state/store/dynamicSettings/sortingOption/sortingOption.actions" -import { Store } from "../../../state/angular-redux/store" import { sortingOrderSelector } from "../../../state/store/dynamicSettings/sortingOption/sortingOrder.selector" @Component({ @@ -15,7 +15,7 @@ export class SortingOptionComponent { sortingOptions = Object.values(SortingOption) selectedSortingOption$: Observable - constructor(private store: Store) { + constructor(private store: Store) { this.selectedSortingOption$ = store.select(sortingOrderSelector) } diff --git a/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadButton.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadButton.component.spec.ts index 5e45896c23..6b57512d42 100644 --- a/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadButton.component.spec.ts @@ -3,13 +3,16 @@ import { render, waitFor } from "@testing-library/angular" import { screen } from "@testing-library/dom" import userEvent from "@testing-library/user-event" import { stubDate } from "../../../../../mocks/dateMock.helper" -import { State } from "../../../state/angular-redux/state" import { FILE_META, VALID_EDGES, VALID_NODE_WITH_PATH_AND_EXTENSION } from "../../../util/dataMocks" import { FileDownloader } from "../../../util/fileDownloader" import { DownloadButtonComponent } from "./downloadButton.component" import { DownloadButtonModule } from "./downloadButton.module" +import { State } from "@ngrx/store" -const mockedAccumulatedData = {} +const mockedAccumulatedData = { + unifiedMapNode: VALID_NODE_WITH_PATH_AND_EXTENSION, + unifiedFileMeta: FILE_META +} jest.mock("../../../state/selectors/accumulatedData/accumulatedData.selector", () => ({ accumulatedDataSelector: () => mockedAccumulatedData })) @@ -27,8 +30,6 @@ describe("downloadButtonComponent", () => { } beforeEach(() => { - mockedAccumulatedData["unifiedMapNode"] = VALID_NODE_WITH_PATH_AND_EXTENSION - mockedAccumulatedData["unifiedFileMeta"] = FILE_META TestBed.configureTestingModule({ imports: [DownloadButtonModule], providers: [ diff --git a/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadDialog/downloadDialog.component.ts b/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadDialog/downloadDialog.component.ts index 9f09edc383..1d4d9c00ce 100644 --- a/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadDialog/downloadDialog.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/downloadButton/downloadDialog/downloadDialog.component.ts @@ -1,5 +1,4 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { State } from "../../../../state/angular-redux/state" import { FileDownloader } from "../../../../util/fileDownloader" import { accumulatedDataSelector } from "../../../../state/selectors/accumulatedData/accumulatedData.selector" import { FileNameHelper } from "../../../../util/fileNameHelper" @@ -11,6 +10,8 @@ import { getDownloadableProperty, getFilteredBlacklistLength } from "./util/propertyHelper" +import { State } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" @Component({ templateUrl: "./downloadDialog.component.html", @@ -21,7 +22,7 @@ export class DownloadDialogComponent { fileName: string properties: (DownloadableProperty & { change: (isSelected: boolean) => void })[] - constructor(private state: State) { + constructor(private state: State) { const stateValue = this.state.getValue() const { unifiedMapNode, unifiedFileMeta } = accumulatedDataSelector(stateValue) const { fileSettings, files } = stateValue diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.spec.ts index ca488e7736..1ea9a4f397 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.spec.ts @@ -1,28 +1,36 @@ import { TestBed } from "@angular/core/testing" import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/angular" -import { Store } from "../../../../../state/store/store" +import { provideMockStore, MockStore } from "@ngrx/store/testing" import { DisplayQualitySelectionComponent } from "./displayQualitySelection.component" import { DisplayQualitySelectionModule } from "./displayQualitySelection.module" +import { sharpnessModeSelector } from "../../../../../state/store/appSettings/sharpnessMode/sharpnessMode.selector" +import { SharpnessMode } from "../../../../../codeCharta.model" +import { getLastAction } from "../../../../../util/testUtils/store.utils" +import { setSharpnessMode } from "../../../../../state/store/appSettings/sharpnessMode/sharpnessMode.actions" describe("DisplayQualitySelectionComponent", () => { beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ - imports: [DisplayQualitySelectionModule] + imports: [DisplayQualitySelectionModule], + providers: [ + provideMockStore({ + selectors: [{ selector: sharpnessModeSelector, value: SharpnessMode.Standard }] + }) + ] }) }) it("should change display quality selection", async () => { const { detectChanges } = await render(DisplayQualitySelectionComponent, { excludeComponentDeclaration: true }) + const store = TestBed.inject(MockStore) detectChanges() const initialDisplayQualitySelection = screen.getByText("High") - expect(initialDisplayQualitySelection).not.toBe(null) fireEvent.click(initialDisplayQualitySelection) const anotherDisplayQualityOption = screen.getByText("Low") fireEvent.click(anotherDisplayQualityOption) await waitForElementToBeRemoved(() => screen.getByRole("listbox")) - expect(screen.getByText("Low")).not.toBe(null) + expect(await getLastAction(store)).toEqual(setSharpnessMode({ value: SharpnessMode.PixelRatioNoAA })) }) }) diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.ts index 0f6f95f8ee..043bfe8ce1 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/displayQualitySelection/displayQualitySelection.component.ts @@ -1,7 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { MatSelectChange } from "@angular/material/select" -import { SharpnessMode } from "../../../../../codeCharta.model" -import { Store } from "../../../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { SharpnessMode, CcState } from "../../../../../codeCharta.model" import { setSharpnessMode } from "../../../../../state/store/appSettings/sharpnessMode/sharpnessMode.actions" import { sharpnessModeSelector } from "../../../../../state/store/appSettings/sharpnessMode/sharpnessMode.selector" @@ -14,9 +13,9 @@ export class DisplayQualitySelectionComponent { sharpnessModes = Object.values(SharpnessMode) sharpnessMode$ = this.store.select(sharpnessModeSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} - handleSelectedSharpnessModeChanged(event: MatSelectChange) { - this.store.dispatch(setSharpnessMode(event.value)) + handleSelectedSharpnessModeChanged(event: { value: SharpnessMode }) { + this.store.dispatch(setSharpnessMode({ value: event.value })) } } diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.spec.ts index 640834b4b3..00dd7bf56b 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.spec.ts @@ -4,11 +4,19 @@ import userEvent from "@testing-library/user-event" import { GlobalSettingsHelper } from "../../../../util/globalSettingsHelper" import { GlobalConfigurationButtonModule } from "../globalConfigurationButton.module" import { GlobalConfigurationDialogComponent } from "./globalConfigurationDialog.component" +import { provideMockStore } from "@ngrx/store/testing" +import { isWhiteBackgroundSelector } from "../../../../state/store/appSettings/isWhiteBackground/isWhiteBackground.selector" +import { State } from "@ngrx/store" +import { defaultState } from "../../../../state/store/state.manager" describe("globalConfigurationDialogComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [GlobalConfigurationButtonModule] + imports: [GlobalConfigurationButtonModule], + providers: [ + provideMockStore({ selectors: [{ selector: isWhiteBackgroundSelector, value: false }], initialState: defaultState }), + { provide: State, useValue: {} } + ] }) }) @@ -18,8 +26,6 @@ describe("globalConfigurationDialogComponent", () => { await userEvent.click(screen.getByText("White Background")) - expect(setGlobalSettingsInLocalStorageSpy).toHaveBeenCalledWith({ - isWhiteBackground: true - }) + expect(setGlobalSettingsInLocalStorageSpy).toHaveBeenCalledWith({ isWhiteBackground: true }) }) }) diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.ts index c16842295d..371bde8269 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/globalConfigurationDialog.component.ts @@ -1,6 +1,7 @@ import { Component, ViewEncapsulation } from "@angular/core" import { MatSlideToggleChange } from "@angular/material/slide-toggle" -import { Store } from "../../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../../codeCharta.model" import { setScreenshotToClipboardEnabled } from "../../../../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions" import { screenshotToClipboardEnabledSelector } from "../../../../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.selector" import { setExperimentalFeaturesEnabled } from "../../../../state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.actions" @@ -24,30 +25,30 @@ export class GlobalConfigurationDialogComponent { hideFlatBuildings$ = this.store.select(hideFlatBuildingsSelector) resetCameraIfNewFileIsLoaded$ = this.store.select(resetCameraIfNewFileIsLoadedSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} handleResetCameraIfNewFileIsLoadedChanged(event: MatSlideToggleChange) { - this.store.dispatch(setResetCameraIfNewFileIsLoaded(event.checked)) + this.store.dispatch(setResetCameraIfNewFileIsLoaded({ value: event.checked })) GlobalSettingsHelper.setGlobalSettingsInLocalStorage({ resetCameraIfNewFileIsLoaded: event.checked }) } handleHideFlatBuildingsChanged(event: MatSlideToggleChange) { - this.store.dispatch(setHideFlatBuildings(event.checked)) + this.store.dispatch(setHideFlatBuildings({ value: event.checked })) GlobalSettingsHelper.setGlobalSettingsInLocalStorage({ hideFlatBuildings: event.checked }) } handleIsWhiteBackgroundChanged(event: MatSlideToggleChange) { - this.store.dispatch(setIsWhiteBackground(event.checked)) + this.store.dispatch(setIsWhiteBackground({ value: event.checked })) GlobalSettingsHelper.setGlobalSettingsInLocalStorage({ isWhiteBackground: event.checked }) } handleExperimentalFeaturesEnabledChanged(event: MatSlideToggleChange) { - this.store.dispatch(setExperimentalFeaturesEnabled(event.checked)) + this.store.dispatch(setExperimentalFeaturesEnabled({ value: event.checked })) GlobalSettingsHelper.setGlobalSettingsInLocalStorage({ experimentalFeaturesEnabled: event.checked }) } handleScreenshotToClipboardEnabledChanged(event: MatSlideToggleChange) { - this.store.dispatch(setScreenshotToClipboardEnabled(event.checked)) + this.store.dispatch(setScreenshotToClipboardEnabled({ value: event.checked })) GlobalSettingsHelper.setGlobalSettingsInLocalStorage({ screenshotToClipboardEnabled: event.checked }) } } diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.spec.ts index e7733164ba..427475b797 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.spec.ts @@ -2,26 +2,39 @@ import { ComponentFixture, TestBed } from "@angular/core/testing" import { screen } from "@testing-library/angular" import { LayoutAlgorithm } from "../../../../../codeCharta.model" import { setLayoutAlgorithm } from "../../../../../state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions" -import { Store } from "../../../../../state/store/store" +import { provideMockStore, MockStore } from "@ngrx/store/testing" import { MapLayoutSelectionComponent } from "./mapLayoutSelection.component" import { MapLayoutSelectionModule } from "./mapLayoutSelection.module" import { HarnessLoader } from "@angular/cdk/testing" import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed" import { MatSelectHarness } from "@angular/material/select/testing" import { MatInputHarness } from "@angular/material/input/testing" +import { layoutAlgorithmSelector } from "../../../../../state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector" +import { maxTreeMapFilesSelector } from "../../../../../state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.selector" +import { getLastAction } from "../../../../../util/testUtils/store.utils" +import { setMaxTreeMapFiles } from "../../../../../state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions" let loader: HarnessLoader let fixture: ComponentFixture describe("MapLayoutSelectionComponent", () => { + let store: MockStore beforeEach(() => { - Store["initialize"]() TestBed.configureTestingModule({ imports: [MapLayoutSelectionModule], - declarations: [MapLayoutSelectionComponent] + declarations: [MapLayoutSelectionComponent], + providers: [ + provideMockStore({ + selectors: [ + { selector: layoutAlgorithmSelector, value: LayoutAlgorithm.SquarifiedTreeMap }, + { selector: maxTreeMapFilesSelector, value: 100 } + ] + }) + ] }).compileComponents() fixture = TestBed.createComponent(MapLayoutSelectionComponent) loader = TestbedHarnessEnvironment.loader(fixture) + store = TestBed.inject(MockStore) }) it("should change map layout selection", async () => { @@ -30,7 +43,8 @@ describe("MapLayoutSelectionComponent", () => { await select.open() await select.clickOptions({ text: "StreetMap" }) - expect(await select.getValueText()).toBe("StreetMap") + + expect(await getLastAction(store)).toEqual(setLayoutAlgorithm({ value: LayoutAlgorithm.StreetMap })) }) it("should not display max tree map files slider when layout selection is NOT 'TreeMapStreet'", async () => { @@ -39,7 +53,9 @@ describe("MapLayoutSelectionComponent", () => { }) it("should display max tree map files slider when layout selection is 'TreeMapStreet'", async () => { - Store.dispatch(setLayoutAlgorithm(LayoutAlgorithm.TreeMapStreet)) + store.overrideSelector(layoutAlgorithmSelector, LayoutAlgorithm.TreeMapStreet) + store.refreshState() + fixture.detectChanges() const select = await loader.getHarness(MatSelectHarness) expect(await select.getValueText()).toBe("TreeMapStreet") expect(screen.queryByText("Maximum TreeMap Files")).not.toBe(null) @@ -48,6 +64,6 @@ describe("MapLayoutSelectionComponent", () => { expect(await input.getValue()).toBe("100") await input.setValue("42") - expect(await input.getValue()).toBe("42") + expect(await getLastAction(store)).toEqual(setMaxTreeMapFiles({ value: 42 })) }) }) diff --git a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.ts b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.ts index 1424cd385c..47a55d0636 100644 --- a/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/globalConfigurationButton/globalConfigurationDialog/mapLayoutSelection/mapLayoutSelection.component.ts @@ -1,7 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { MatSelectChange } from "@angular/material/select" -import { LayoutAlgorithm } from "../../../../../codeCharta.model" -import { Store } from "../../../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { LayoutAlgorithm, CcState } from "../../../../../codeCharta.model" import { setLayoutAlgorithm } from "../../../../../state/store/appSettings/layoutAlgorithm/layoutAlgorithm.actions" import { layoutAlgorithmSelector } from "../../../../../state/store/appSettings/layoutAlgorithm/layoutAlgorithm.selector" import { setMaxTreeMapFiles } from "../../../../../state/store/appSettings/maxTreeMapFiles/maxTreeMapFiles.actions" @@ -18,13 +17,13 @@ export class MapLayoutSelectionComponent { layoutAlgorithm$ = this.store.select(layoutAlgorithmSelector) maxTreeMapFiles$ = this.store.select(maxTreeMapFilesSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} - handleSelectedLayoutAlgorithmChanged(event: MatSelectChange) { - this.store.dispatch(setLayoutAlgorithm(event.value)) + handleSelectedLayoutAlgorithmChanged(event: { value: LayoutAlgorithm }) { + this.store.dispatch(setLayoutAlgorithm({ value: event.value })) } handleChangeMaxTreeMapFiles = debounce((maxTreeMapFiles: number) => { - this.store.dispatch(setMaxTreeMapFiles(maxTreeMapFiles)) + this.store.dispatch(setMaxTreeMapFiles({ value: maxTreeMapFiles })) }, 400) } diff --git a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.spec.ts index dd6d0d3422..b38f3f36fa 100644 --- a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.spec.ts @@ -3,11 +3,7 @@ import { render } from "@testing-library/angular" import { HoveredNodePathPanelComponent } from "./hoveredNodePathPanel.component" import { HoveredNodePathPanelModule } from "./hoveredNodePathPanel.module" import { hoveredNodePathPanelDataSelector } from "./hoveredNodePathPanelData.selector" - -jest.mock("./hoveredNodePathPanelData.selector", () => ({ - hoveredNodePathPanelDataSelector: jest.fn() -})) -const mockedHoveredNodePathPanelDataSelector = jest.mocked(hoveredNodePathPanelDataSelector) +import { provideMockStore } from "@ngrx/store/testing" describe("HoveredNodePathPanelComponent", () => { beforeEach(() => { @@ -17,17 +13,27 @@ describe("HoveredNodePathPanelComponent", () => { }) it("should be empty when there is no node hovered", async () => { - mockedHoveredNodePathPanelDataSelector.mockImplementation(() => undefined) - const { container } = await render(HoveredNodePathPanelComponent, { excludeComponentDeclaration: true }) + const { container } = await render(HoveredNodePathPanelComponent, { + excludeComponentDeclaration: true, + providers: [provideMockStore({ selectors: [{ selector: hoveredNodePathPanelDataSelector, value: undefined }] })] + }) expect(container.textContent).toBe("") }) it("should show path to a hovered file", async () => { - mockedHoveredNodePathPanelDataSelector.mockImplementation(() => ({ - path: ["root", "a.ts"], - isFile: true - })) - const { container } = await render(HoveredNodePathPanelComponent, { excludeComponentDeclaration: true }) + const { container } = await render(HoveredNodePathPanelComponent, { + excludeComponentDeclaration: true, + providers: [ + provideMockStore({ + selectors: [ + { + selector: hoveredNodePathPanelDataSelector, + value: { path: ["root", "a.ts"], isFile: true } + } + ] + }) + ] + }) const steps = container.children expect(steps.length).toBe(2) @@ -42,12 +48,19 @@ describe("HoveredNodePathPanelComponent", () => { }) it("should show path to a hovered folder", async () => { - mockedHoveredNodePathPanelDataSelector.mockImplementation(() => ({ - path: ["root"], - isFile: false - })) - const { container } = await render(HoveredNodePathPanelComponent, { excludeComponentDeclaration: true }) - + const { container } = await render(HoveredNodePathPanelComponent, { + excludeComponentDeclaration: true, + providers: [ + provideMockStore({ + selectors: [ + { + selector: hoveredNodePathPanelDataSelector, + value: { path: ["root"], isFile: false } + } + ] + }) + ] + }) const steps = container.children expect(steps.length).toBe(1) diff --git a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.ts b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.ts index 8e069c1094..47f9d507d9 100644 --- a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanel.component.ts @@ -1,5 +1,6 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { hoveredNodePathPanelDataSelector } from "./hoveredNodePathPanelData.selector" @Component({ @@ -11,5 +12,5 @@ import { hoveredNodePathPanelDataSelector } from "./hoveredNodePathPanelData.sel export class HoveredNodePathPanelComponent { hoveredNodePathPanelData$ = this.store.select(hoveredNodePathPanelDataSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanelData.selector.ts b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanelData.selector.ts index b66ad09235..44a75713a2 100644 --- a/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanelData.selector.ts +++ b/visualization/app/codeCharta/ui/toolBar/hoveredNodePathPanel/hoveredNodePathPanelData.selector.ts @@ -1,5 +1,5 @@ +import { createSelector } from "@ngrx/store" import { CodeMapNode } from "../../../codeCharta.model" -import { createSelector } from "../../../state/angular-redux/createSelector" import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector" export const _getHoveredNodePathPanelData = (hoveredNode?: Pick) => @@ -8,4 +8,4 @@ export const _getHoveredNodePathPanelData = (hoveredNode?: Pick - constructor(store: Store) { + constructor(store: Store) { this.isLoadingMap$ = store.select(isLoadingMapSelector) } } diff --git a/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.spec.ts index 21ed9c6f94..177a472036 100644 --- a/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.spec.ts @@ -1,21 +1,20 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" -import userEvent from "@testing-library/user-event" import { PresentationModeButtonComponent } from "./presentationModeButton.component" import { PresentationModeButtonModule } from "./presentationModeButton.module" +import { provideMockStore } from "@ngrx/store/testing" +import { isPresentationModeSelector } from "../../../state/store/appSettings/isPresentationMode/isPresentationMode.selector" describe("presentationModeButtonComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [PresentationModeButtonModule] + imports: [PresentationModeButtonModule], + providers: [provideMockStore({ selectors: [{ selector: isPresentationModeSelector, value: false }] })] }) }) it("should toggle presentation mode", async () => { - const { container } = await render(PresentationModeButtonComponent, { excludeComponentDeclaration: true }) + await render(PresentationModeButtonComponent, { excludeComponentDeclaration: true }) expect(screen.getByTitle("Enable flashlight hover effect")).toBeTruthy() - - await userEvent.click(container.querySelector("mat-slide-toggle label")) - expect(screen.getByTitle("Disable flashlight hover effect")).toBeTruthy() }) }) diff --git a/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.ts b/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.ts index c99a879e08..7633fe0bff 100644 --- a/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/presentationModeButton/presentationModeButton.component.ts @@ -1,6 +1,7 @@ import { Component, ViewEncapsulation } from "@angular/core" import { MatSlideToggleChange } from "@angular/material/slide-toggle" -import { Store } from "../../../state/angular-redux/store" +import { Store } from "@ngrx/store" +import { CcState } from "../../../codeCharta.model" import { setPresentationMode } from "../../../state/store/appSettings/isPresentationMode/isPresentationMode.actions" import { isPresentationModeSelector } from "../../../state/store/appSettings/isPresentationMode/isPresentationMode.selector" @@ -13,9 +14,9 @@ import { isPresentationModeSelector } from "../../../state/store/appSettings/isP export class PresentationModeButtonComponent { isPresentationModeEnabled$ = this.store.select(isPresentationModeSelector) - constructor(private readonly store: Store) {} + constructor(private readonly store: Store) {} setPresentationModeEnabled(event: MatSlideToggleChange) { - this.store.dispatch(setPresentationMode(event.checked)) + this.store.dispatch(setPresentationMode({ value: event.checked })) } } diff --git a/visualization/app/codeCharta/ui/toolBar/toolBar.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/toolBar.component.spec.ts index 3e3a574eb2..0f92340a29 100644 --- a/visualization/app/codeCharta/ui/toolBar/toolBar.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/toolBar.component.spec.ts @@ -7,6 +7,8 @@ import { ThreeRendererService } from "../codeMap/threeViewer/threeRenderer.servi import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService" import { ToolBarComponent } from "./toolBar.component" import { ToolBarModule } from "./toolBar.module" +import { appReducers, setStateMiddleware } from "../../state/store/state.manager" +import { StoreModule } from "@ngrx/store" jest.mock("../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector", () => ({ hoveredNodeIdSelector: jest.fn() @@ -16,7 +18,7 @@ const mockedHoveredNodeIdSelector = jest.mocked(hoveredNodeIdSelector) describe("ToolBarComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ToolBarModule], + imports: [ToolBarModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })], providers: [ { provide: LoadFileService, useValue: {} }, { provide: ThreeCameraService, useValue: {} }, diff --git a/visualization/app/codeCharta/ui/toolBar/toolBar.component.ts b/visualization/app/codeCharta/ui/toolBar/toolBar.component.ts index 8dbde24084..f97d7474c4 100644 --- a/visualization/app/codeCharta/ui/toolBar/toolBar.component.ts +++ b/visualization/app/codeCharta/ui/toolBar/toolBar.component.ts @@ -1,7 +1,8 @@ import { Component, ViewEncapsulation } from "@angular/core" -import { Store } from "../../state/angular-redux/store" import { hoveredNodeIdSelector } from "../../state/store/appStatus/hoveredNodeId/hoveredNodeId.selector" import { experimentalFeaturesEnabledSelector } from "../../state/store/appSettings/enableExperimentalFeatures/experimentalFeaturesEnabled.selector" +import { Store } from "@ngrx/store" +import { CcState } from "../../codeCharta.model" @Component({ selector: "cc-tool-bar", @@ -13,5 +14,5 @@ export class ToolBarComponent { hoveredNodeId$ = this.store.select(hoveredNodeIdSelector) experimentalFeaturesEnabled$ = this.store.select(experimentalFeaturesEnabledSelector) - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFiles.service.ts b/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFiles.service.ts index b1a3b7e110..36e0829f92 100644 --- a/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFiles.service.ts +++ b/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFiles.service.ts @@ -1,6 +1,6 @@ import { Injectable } from "@angular/core" +import { Store } from "@ngrx/store" import { LoadFileService } from "../../../services/loadFile/loadFile.service" -import { Store } from "../../../state/angular-redux/store" import { setIsLoadingFile } from "../../../state/store/appSettings/isLoadingFile/isLoadingFile.actions" import { setIsLoadingMap } from "../../../state/store/appSettings/isLoadingMap/isLoadingMap.actions" import { CustomConfigHelper, CUSTOM_CONFIG_FILE_EXTENSION } from "../../../util/customConfigHelper" @@ -19,8 +19,8 @@ export class UploadFilesService { ccFileInput.addEventListener("change", async () => { try { this.isUploading = true - this.store.dispatch(setIsLoadingFile(true)) - this.store.dispatch(setIsLoadingMap(true)) + this.store.dispatch(setIsLoadingFile({ value: true })) + this.store.dispatch(setIsLoadingMap({ value: true })) const plainFileContents = await Promise.all(readFiles(ccFileInput.files)) const { customConfigs, ccFiles } = this.splitCustomConfigsAndCCFiles(ccFileInput.files, plainFileContents) @@ -33,8 +33,8 @@ export class UploadFilesService { await this.loadFileService.loadFiles(ccFiles) } } catch { - this.store.dispatch(setIsLoadingFile(false)) - this.store.dispatch(setIsLoadingMap(false)) + this.store.dispatch(setIsLoadingFile({ value: false })) + this.store.dispatch(setIsLoadingMap({ value: false })) } finally { this.isUploading = false } diff --git a/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFilesButton.component.spec.ts b/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFilesButton.component.spec.ts index 2aed5000c3..d2d9dace3d 100644 --- a/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFilesButton.component.spec.ts +++ b/visualization/app/codeCharta/ui/toolBar/uploadFilesButton/uploadFilesButton.component.spec.ts @@ -1,14 +1,14 @@ import { TestBed } from "@angular/core/testing" import { render, screen } from "@testing-library/angular" -import { LoadFileService } from "../../../services/loadFile/loadFile.service" import { UploadFilesButtonComponent } from "./uploadFilesButton.component" import { UploadFilesButtonModule } from "./uploadFilesButton.module" +import { UploadFilesService } from "./uploadFiles.service" describe("uploadFilesButtonComponent", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [UploadFilesButtonModule], - providers: [{ provide: LoadFileService, useValue: {} }] + providers: [{ provide: UploadFilesService, useValue: {} }] }) }) diff --git a/visualization/app/codeCharta/ui/viewCube/viewCube.component.spec.ts b/visualization/app/codeCharta/ui/viewCube/viewCube.component.spec.ts index 26dd51a8b0..cf31e6e248 100644 --- a/visualization/app/codeCharta/ui/viewCube/viewCube.component.spec.ts +++ b/visualization/app/codeCharta/ui/viewCube/viewCube.component.spec.ts @@ -1,4 +1,3 @@ -import "./viewCube.module" import { ThreeOrbitControlsService } from "../codeMap/threeViewer/threeOrbitControls.service" import { ViewCubeMouseEventsService } from "./viewCube.mouseEvents.service" import { PerspectiveCamera } from "three/src/cameras/PerspectiveCamera" diff --git a/visualization/app/codeCharta/util/algorithm/streetLayout/streetLayoutGenerator.ts b/visualization/app/codeCharta/util/algorithm/streetLayout/streetLayoutGenerator.ts index 41da11140f..6b0d133baa 100644 --- a/visualization/app/codeCharta/util/algorithm/streetLayout/streetLayoutGenerator.ts +++ b/visualization/app/codeCharta/util/algorithm/streetLayout/streetLayoutGenerator.ts @@ -1,4 +1,4 @@ -import { CodeMapNode, Node, State, NodeMetricData, LayoutAlgorithm } from "../../../codeCharta.model" +import { CodeMapNode, Node, CcState, NodeMetricData, LayoutAlgorithm } from "../../../codeCharta.model" import BoundingBox from "./boundingBox" import VerticalStreet from "./verticalStreet" import HorizontalStreet from "./horizontalStreet" @@ -14,7 +14,7 @@ import { treeMapSize } from "../treeMapLayout/treeMapHelper" const MARGIN_SCALING_FACTOR = 0.02 const HEIGHT_SCALING_FACTOR = 0.1 export class StreetLayoutGenerator { - static createStreetLayoutNodes(map: CodeMapNode, state: State, metricData: NodeMetricData[], isDeltaState: boolean): Node[] { + static createStreetLayoutNodes(map: CodeMapNode, state: CcState, metricData: NodeMetricData[], isDeltaState: boolean): Node[] { const mapSizeResolutionScaling = getMapResolutionScaleFactor(state.files) const maxHeight = (metricData.find(x => x.name === state.dynamicSettings.heightMetric).maxValue * mapSizeResolutionScaling) / @@ -38,7 +38,7 @@ export class StreetLayoutGenerator { private static createBoxes( node: CodeMapNode, metricName: string, - state: State, + state: CcState, orientation: StreetOrientation, depth: number, maxTreeMapFiles: number diff --git a/visualization/app/codeCharta/util/algorithm/streetLayout/streetViewHelper.ts b/visualization/app/codeCharta/util/algorithm/streetLayout/streetViewHelper.ts index ee78c19335..4ded1320c4 100644 --- a/visualization/app/codeCharta/util/algorithm/streetLayout/streetViewHelper.ts +++ b/visualization/app/codeCharta/util/algorithm/streetLayout/streetViewHelper.ts @@ -1,5 +1,5 @@ import { Vector3 } from "three" -import { CodeMapNode, Node, State } from "../../../codeCharta.model" +import { CodeMapNode, Node, CcState } from "../../../codeCharta.model" import { selectedColorMetricDataSelector } from "../../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector" import { getMarkingColor, isLeaf } from "../../codeMapHelper" import { getBuildingColor, getIncomingEdgePoint, isNodeFlat, isVisible, TreeMapHelper, treeMapSize } from "../treeMapLayout/treeMapHelper" @@ -36,7 +36,7 @@ function mergeDirectories(node: CodeMapNode, metricName: string): CodeMapNode { return mergedNode } -function getHeightValue(s: State, squaredNode: CodeMapNode, maxHeight: number, flattened: boolean): number { +function getHeightValue(s: CcState, squaredNode: CodeMapNode, maxHeight: number, flattened: boolean): number { const heightValue = squaredNode.attributes[s.dynamicSettings.heightMetric] || TreeMapHelper.HEIGHT_VALUE_WHEN_METRIC_NOT_FOUND if (flattened) { @@ -48,7 +48,7 @@ function getHeightValue(s: State, squaredNode: CodeMapNode, maxHeight: number, f return heightValue } -function buildNodeFrom(layoutNode: CodeMapNode, heightScale: number, maxHeight: number, s: State, isDeltaState: boolean): Node { +function buildNodeFrom(layoutNode: CodeMapNode, heightScale: number, maxHeight: number, s: CcState, isDeltaState: boolean): Node { const isNodeLeaf = !(layoutNode.children && layoutNode.children.length > 0) const flattened: boolean = isNodeFlat(layoutNode, s) const heightValue: number = getHeightValue(s, layoutNode, maxHeight, flattened) diff --git a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts index ece78d6663..49afcd3446 100644 --- a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts +++ b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts @@ -1,4 +1,4 @@ -import { NodeMetricData, State, CodeMapNode, Node, NameDataPair } from "../../../codeCharta.model" +import { NodeMetricData, CcState, CodeMapNode, Node, NameDataPair } from "../../../codeCharta.model" import { METRIC_DATA, TEST_FILE_WITH_PATHS, @@ -16,25 +16,19 @@ import * as SquarifiedLayoutGenerator from "./treeMapGenerator" describe("treeMapGenerator", () => { let map: CodeMapNode - let state: State + let state: CcState let metricData: NodeMetricData[] let codeMapNode: CodeMapNode let isDeltaState beforeEach(() => { - restartSystem() - }) - - function restartSystem() { map = klona(TEST_FILE_WITH_PATHS.map) - const file: NameDataPair = { fileName: "someFile", fileSize: 42, content: fileWithFixedFolders } - NodeDecorator.decorateMapWithPathAttribute(getCCFile(file)) state = klona(STATE) codeMapNode = klona(VALID_NODE_WITH_PATH) metricData = klona(METRIC_DATA) isDeltaState = false state.dynamicSettings.focusedNodePath = [] - } + }) describe("create Treemap nodes", () => { it("create map with fixed root children which include dynamic folders on the one hand and fixed ones at the other", () => { @@ -105,7 +99,10 @@ describe("treeMapGenerator", () => { }) it("should build the tree map with valid coordinates using the fixed folder structure", () => { - const nodes = SquarifiedLayoutGenerator.createTreemapNodes(fileWithFixedFolders.nodes[0], state, metricData, isDeltaState) + const file: NameDataPair = { fileName: "someFile", fileSize: 42, content: fileWithFixedFolders } + const ccFile = getCCFile(file) + NodeDecorator.decorateMapWithPathAttribute(ccFile) + const nodes = SquarifiedLayoutGenerator.createTreemapNodes(ccFile.map, state, metricData, isDeltaState) expect(nodes).toMatchSnapshot() }) diff --git a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts index d0e8145124..263a6786de 100644 --- a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts +++ b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts @@ -1,6 +1,6 @@ import { hierarchy, HierarchyNode, HierarchyRectangularNode, treemap } from "d3-hierarchy" import { TreeMapHelper, treeMapSize } from "./treeMapHelper" -import { CodeMapNode, DynamicSettings, Node, NodeMetricData, State } from "../../../codeCharta.model" +import { CodeMapNode, DynamicSettings, Node, NodeMetricData, CcState } from "../../../codeCharta.model" import { getMapResolutionScaleFactor, isLeaf } from "../../codeMapHelper" export type SquarifiedTreeMap = { treeMap: HierarchyRectangularNode; height: number; width: number } @@ -11,7 +11,7 @@ const DEFAULT_PADDING_FLOOR_LABEL_FROM_LEVEL_2 = 95 const DEFAULT_ROOT_FLOOR_LABEL_SCALING = 0.035 const DEFAULT_SUB_FLOOR_LABEL_SCALING = 0.028 -export function createTreemapNodes(map: CodeMapNode, state: State, metricData: NodeMetricData[], isDeltaState: boolean): Node[] { +export function createTreemapNodes(map: CodeMapNode, state: CcState, metricData: NodeMetricData[], isDeltaState: boolean): Node[] { const mapSizeResolutionScaling = getMapResolutionScaleFactor(state.files) const maxHeight = metricData.find(x => x.name === state.dynamicSettings.heightMetric).maxValue * mapSizeResolutionScaling const maxWidth = metricData.find(x => x.name === state.dynamicSettings.areaMetric).maxValue * mapSizeResolutionScaling @@ -62,7 +62,7 @@ export function createTreemapNodes(map: CodeMapNode, state: State, metricData: N function buildSquarifiedTreeMapsForFixedFolders( hierarchyNode: HierarchyNode, - state: State, + state: CcState, scaleLength: number, scaleWidth: number, offsetX0: number, @@ -155,7 +155,7 @@ function scaleRoot(root: Node, scaleLength: number, scaleWidth: number) { root.length *= scaleLength } -function getSquarifiedTreeMap(map: CodeMapNode, state: State, mapSizeResolutionScaling: number, maxWidth: number): SquarifiedTreeMap { +function getSquarifiedTreeMap(map: CodeMapNode, state: CcState, mapSizeResolutionScaling: number, maxWidth: number): SquarifiedTreeMap { const hierarchyNode = hierarchy(map) const nodesPerSide = getEstimatedNodesPerSide(hierarchyNode) const { enableFloorLabels } = state.appSettings @@ -255,7 +255,7 @@ function isOnlyVisibleInComparisonMap(node: CodeMapNode, dynamicSettings: Dynami } // Only exported for testing. -export function calculateAreaValue(node: CodeMapNode, { dynamicSettings, appSettings }: State, maxWidth: number) { +export function calculateAreaValue(node: CodeMapNode, { dynamicSettings, appSettings }: CcState, maxWidth: number) { if (node.isExcluded) { return 0 } diff --git a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.spec.ts b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.spec.ts index 097f35f14c..1becf7e34a 100644 --- a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.spec.ts +++ b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.spec.ts @@ -1,7 +1,8 @@ import { TreeMapHelper } from "./treeMapHelper" -import { CodeMapNode, ColorMode, EdgeVisibility, NodeType, State } from "../../../codeCharta.model" +import { CodeMapNode, ColorMode, EdgeVisibility, NodeType, CcState } from "../../../codeCharta.model" import { CODE_MAP_BUILDING, STATE } from "../../dataMocks" import { HierarchyRectangularNode } from "d3-hierarchy" +import { clone } from "../../clone" jest.mock("../../../state/selectors/accumulatedData/accumulatedData.selector", () => ({ accumulatedDataSelector: () => ({ @@ -23,7 +24,7 @@ describe("TreeMapHelper", () => { describe("build node", () => { let codeMapNode: CodeMapNode let squaredNode: HierarchyRectangularNode - let state: State + let state: CcState const heightScale = 1 const maxHeight = 2000 @@ -48,7 +49,7 @@ describe("TreeMapHelper", () => { y1: 400 } as HierarchyRectangularNode - state = STATE + state = clone(STATE) state.dynamicSettings.margin = 15 state.dynamicSettings.heightMetric = "theHeight" state.appSettings.invertHeight = false @@ -73,14 +74,12 @@ describe("TreeMapHelper", () => { state.dynamicSettings.heightMetric = "theHeight" squaredNode.data.deltas[state.dynamicSettings.heightMetric] = 33 expect(buildNode()).toMatchSnapshot() - squaredNode.data.deltas = undefined }) it("given negative deltas the resulting heightDelta also should be negative", () => { squaredNode.data.deltas = {} squaredNode.data.deltas[state.dynamicSettings.heightMetric] = -33 expect(buildNode().heightDelta).toBe(-33) - squaredNode.data.deltas = undefined }) it("should set lowest possible height caused by other visible edge pairs", () => { @@ -155,7 +154,6 @@ describe("TreeMapHelper", () => { y1: 400 } as HierarchyRectangularNode - state = STATE state.dynamicSettings.margin = 15 }) @@ -232,7 +230,6 @@ describe("TreeMapHelper", () => { node.attributes = { validMetricName: 0 } - state = STATE state.dynamicSettings.colorRange.from = 5 state.dynamicSettings.colorRange.to = 10 state.dynamicSettings.colorMetric = "validMetricName" diff --git a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.ts b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.ts index fb80470ea6..ebfe9c406c 100644 --- a/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.ts +++ b/visualization/app/codeCharta/util/algorithm/treeMapLayout/treeMapHelper.ts @@ -1,5 +1,5 @@ import { getMapResolutionScaleFactor, getMarkingColor, isLeaf } from "../../codeMapHelper" -import { CodeMapNode, ColorMode, Node, State } from "../../../codeCharta.model" +import { CodeMapNode, ColorMode, Node, CcState } from "../../../codeCharta.model" import { Vector3 } from "three" import { CodeMapBuilding } from "../../../ui/codeMap/rendering/codeMapBuilding" import { HierarchyRectangularNode } from "d3-hierarchy" @@ -48,7 +48,7 @@ function buildingArrayToMap(highlighted: CodeMapBuilding[]) { return geomMap } -function buildRootFolderForFixedFolders(map: CodeMapNode, heightScale: number, state: State, isDeltaState: boolean) { +function buildRootFolderForFixedFolders(map: CodeMapNode, heightScale: number, state: CcState, isDeltaState: boolean) { const flattened = isNodeFlat(map, state) const height = FOLDER_HEIGHT const width = 100 @@ -84,7 +84,7 @@ function buildNodeFrom( squaredNode: HierarchyRectangularNode, heightScale: number, maxHeight: number, - state: State, + state: CcState, isDeltaState: boolean ): Node { const mapSizeResolutionScaling = getMapResolutionScaleFactor(state.files) @@ -127,7 +127,7 @@ function buildNodeFrom( } } -export function getHeightValue(state: State, squaredNode: HierarchyRectangularNode, maxHeight: number, flattened: boolean) { +export function getHeightValue(state: CcState, squaredNode: HierarchyRectangularNode, maxHeight: number, flattened: boolean) { const mapSizeResolutionScaling = getMapResolutionScaleFactor(state.files) if (flattened) { @@ -143,7 +143,7 @@ export function getHeightValue(state: State, squaredNode: HierarchyRectangularNo return heightValue } -export function isVisible(squaredNode: CodeMapNode, isNodeLeaf: boolean, state: State, flattened: boolean) { +export function isVisible(squaredNode: CodeMapNode, isNodeLeaf: boolean, state: CcState, flattened: boolean) { if (squaredNode.isExcluded || (isNodeLeaf && state.appSettings.hideFlatBuildings && flattened)) { return false } @@ -169,7 +169,7 @@ export function getOutgoingEdgePoint(width: number, height: number, length: numb return new Vector3(vector.x - mapSize + width / 2, vector.y + height, vector.z - mapSize + 0.75 * length) } -export function isNodeFlat(codeMapNode: CodeMapNode, state: State) { +export function isNodeFlat(codeMapNode: CodeMapNode, state: CcState) { if (codeMapNode.isFlattened) { return true } @@ -187,21 +187,21 @@ export function isNodeFlat(codeMapNode: CodeMapNode, state: State) { return false } -function nodeHasNoVisibleEdges(codeMapNode: CodeMapNode, state: State) { +function nodeHasNoVisibleEdges(codeMapNode: CodeMapNode, state: CcState) { return ( codeMapNode.edgeAttributes[state.dynamicSettings.edgeMetric] === undefined || !state.fileSettings.edges.some(edge => codeMapNode.path === edge.fromNodeName || codeMapNode.path === edge.toNodeName) ) } -function isNodeNonSearched(squaredNode: CodeMapNode, state: State) { +function isNodeNonSearched(squaredNode: CodeMapNode, state: CcState) { const searchedNodePaths = searchedNodePathsSelector(state) return !searchedNodePaths.has(squaredNode.path) } export function getBuildingColor( node: CodeMapNode, - { appSettings, dynamicSettings }: State, + { appSettings, dynamicSettings }: CcState, nodeMetricDataRange: MetricMinMax, isDeltaState: boolean, flattened: boolean diff --git a/visualization/app/codeCharta/util/reduxHelper.spec.ts b/visualization/app/codeCharta/util/arrayHelper.spec.ts similarity index 54% rename from visualization/app/codeCharta/util/reduxHelper.spec.ts rename to visualization/app/codeCharta/util/arrayHelper.spec.ts index 62bc015601..9a71b757b8 100644 --- a/visualization/app/codeCharta/util/reduxHelper.spec.ts +++ b/visualization/app/codeCharta/util/arrayHelper.spec.ts @@ -1,12 +1,10 @@ -import { addItemToArray, isActionOfType, removeItemFromArray } from "./reduxHelper" -import { ScalingActions } from "../state/store/appSettings/scaling/scaling.actions" -import { IsLoadingFileActions } from "../state/store/appSettings/isLoadingFile/isLoadingFile.actions" +import { addItemToArray, removeItemFromArray } from "./arrayHelper" function mutateObject(object: Record) { object.x = 10_000 } -describe("reduxHelper", () => { +describe("arrayHelper", () => { let object1: { x: number; y: number } let object2: { x: number; y: number } let array: { x: number; y: number }[] @@ -42,18 +40,4 @@ describe("reduxHelper", () => { ]) }) }) - - describe("isActionOfType", () => { - it("should return true if an action is part of an enum", () => { - const result = isActionOfType(ScalingActions.SET_SCALING, ScalingActions) - - expect(result).toBeTruthy() - }) - - it("should return false if an action is not part of an enum", () => { - const result = isActionOfType(IsLoadingFileActions.SET_IS_LOADING_FILE, ScalingActions) - - expect(result).toBeFalsy() - }) - }) }) diff --git a/visualization/app/codeCharta/util/reduxHelper.ts b/visualization/app/codeCharta/util/arrayHelper.ts similarity index 75% rename from visualization/app/codeCharta/util/reduxHelper.ts rename to visualization/app/codeCharta/util/arrayHelper.ts index 9a8cc7e420..5a7887327a 100644 --- a/visualization/app/codeCharta/util/reduxHelper.ts +++ b/visualization/app/codeCharta/util/arrayHelper.ts @@ -1,6 +1,5 @@ import { clone } from "./clone" import { dequal } from "dequal" -import { Action } from "redux" export function removeItemFromArray(array: T[], searchItem: T) { return array.filter(entry => !dequal(entry, searchItem)) @@ -27,14 +26,6 @@ export function addItemsToArray(array: T[], items: T[]) { return newArray } -export function isActionOfType(actionType: string, actions) { - return actions[actionType] !== undefined -} - -export function isAction(action: Action, type: string): action is T { - return action.type === type -} - function arrayContainsItem(array: T[], item: T) { return array.some(x => dequal(x, item)) } diff --git a/visualization/app/codeCharta/util/customConfigBuilder.spec.ts b/visualization/app/codeCharta/util/customConfigBuilder.spec.ts index ebd7d06a49..2a771546d2 100644 --- a/visualization/app/codeCharta/util/customConfigBuilder.spec.ts +++ b/visualization/app/codeCharta/util/customConfigBuilder.spec.ts @@ -1,7 +1,7 @@ import { Vector3 } from "three" import { buildCustomConfigFromState } from "./customConfigBuilder" import { DEFAULT_STATE } from "./dataMocks" -import { AppSettings, State } from "../codeCharta.model" +import { AppSettings, CcState } from "../codeCharta.model" import { expect } from "@jest/globals" import { CustomConfigMapSelectionMode } from "../model/customConfig/customConfig.api.model" @@ -18,7 +18,7 @@ jest.mock("../ui/customConfigs/visibleFilesBySelectionMode.selector", () => ({ describe("CustomConfigBuilder", () => { describe("buildCustomConfigFromState", () => { it("should return a new CustomConfig instance", () => { - const state: State = { ...DEFAULT_STATE, appSettings: { experimentalFeaturesEnabled: true } as AppSettings } + const state: CcState = { ...DEFAULT_STATE, appSettings: { experimentalFeaturesEnabled: true } as AppSettings } const customConfig = buildCustomConfigFromState( "testCustomConfig", diff --git a/visualization/app/codeCharta/util/customConfigBuilder.ts b/visualization/app/codeCharta/util/customConfigBuilder.ts index aa5e130cc0..bc9b07eb2e 100644 --- a/visualization/app/codeCharta/util/customConfigBuilder.ts +++ b/visualization/app/codeCharta/util/customConfigBuilder.ts @@ -1,4 +1,4 @@ -import { State, stateObjectReplacer } from "../codeCharta.model" +import { CcState, stateObjectReplacer } from "../codeCharta.model" import { CustomConfig } from "../model/customConfig/customConfig.api.model" import md5 from "md5" import { visibleFilesBySelectionModeSelector } from "../ui/customConfigs/visibleFilesBySelectionMode.selector" @@ -7,7 +7,7 @@ const CUSTOM_CONFIG_API_VERSION = "1.0.0" export function buildCustomConfigFromState( configName: string, - state: State, + state: CcState, camera: CustomConfig["camera"], note: string | undefined ): CustomConfig { @@ -120,7 +120,7 @@ function initializeFileSettings(target: CustomConfig) { } } -function deepMapOneToOther(source: State, target: T) { +function deepMapOneToOther(source: CcState, target: T) { for (const [key, value] of Object.entries(source)) { // if a property of source is missing, we don't want to copy it into target. if (!Object.prototype.hasOwnProperty.call(target, key)) { diff --git a/visualization/app/codeCharta/util/customConfigHelper.ts b/visualization/app/codeCharta/util/customConfigHelper.ts index 2b6bf3de03..84976cc971 100644 --- a/visualization/app/codeCharta/util/customConfigHelper.ts +++ b/visualization/app/codeCharta/util/customConfigHelper.ts @@ -1,4 +1,3 @@ -"use strict" import { LocalStorageCustomConfigs, stateObjectReplacer, stateObjectReviver } from "../codeCharta.model" import { CustomConfigItemGroup } from "../ui/customConfigs/customConfigs.component" import { @@ -10,12 +9,12 @@ import { } from "../model/customConfig/customConfig.api.model" import { FileNameHelper } from "./fileNameHelper" import { FileDownloader } from "./fileDownloader" -import { setState } from "../state/store/state.actions" import { ThreeCameraService } from "../ui/codeMap/threeViewer/threeCamera.service" import { ThreeOrbitControlsService } from "../ui/codeMap/threeViewer/threeOrbitControls.service" import { BehaviorSubject } from "rxjs" -import { Store } from "../state/angular-redux/store" import { VisibleFilesBySelectionMode } from "../ui/customConfigs/visibleFilesBySelectionMode.selector" +import { Store } from "@ngrx/store" +import { setState } from "../state/store/state.actions" export const CUSTOM_CONFIG_FILE_EXTENSION = ".cc.config.json" const CUSTOM_CONFIGS_LOCAL_STORAGE_VERSION = "1.0.1" @@ -197,7 +196,7 @@ export class CustomConfigHelper { threeOrbitControlsService: ThreeOrbitControlsService ) { const customConfig = this.getCustomConfigSettings(configId) - store.dispatch(setState(customConfig.stateSettings)) + store.dispatch(setState({ value: customConfig.stateSettings })) // TODO: remove this dirty timeout and set camera settings properly // This timeout is a chance that CustomConfigs for a small map can be restored and applied completely (even the camera positions) diff --git a/visualization/app/codeCharta/util/dataMocks.ts b/visualization/app/codeCharta/util/dataMocks.ts index bb1adac0fd..6c69b83ee1 100644 --- a/visualization/app/codeCharta/util/dataMocks.ts +++ b/visualization/app/codeCharta/util/dataMocks.ts @@ -21,7 +21,7 @@ import { Settings, SharpnessMode, SortingOption, - State + CcState } from "../codeCharta.model" import { CodeMapBuilding } from "../ui/codeMap/rendering/codeMapBuilding" import { Box3, Vector3 } from "three" @@ -1586,7 +1586,7 @@ export const EDGE_METRIC_DATA: EdgeMetricData[] = [ { name: "average_commits", maxValue: 20, minValue: 0 } ] -export const STATE: State = { +export const STATE: CcState = { fileSettings: { attributeTypes: { nodes: { @@ -1671,7 +1671,7 @@ export const STATE: State = { } } -export const DEFAULT_STATE: State = { +export const DEFAULT_STATE: CcState = { appSettings: { amountOfTopLabels: 1, amountOfEdgePreviews: 1, diff --git a/visualization/app/codeCharta/util/fileHelper.ts b/visualization/app/codeCharta/util/fileHelper.ts index 4b43b02e37..70a4f2c57a 100644 --- a/visualization/app/codeCharta/util/fileHelper.ts +++ b/visualization/app/codeCharta/util/fileHelper.ts @@ -2,6 +2,7 @@ import { ExportBlacklistType, ExportCCFile, ExportWrappedCCFile, OldAttributeTyp import { AttributeDescriptors, AttributeTypes, BlacklistItem, CCFile, NameDataPair } from "../codeCharta.model" import { FileSelectionState, FileState } from "../model/files/files" import md5 from "md5" +import { clone } from "./clone" export function getCCFile(file: NameDataPair): CCFile { const fileContent = file.content @@ -23,7 +24,7 @@ export function getCCFile(file: NameDataPair): CCFile { markedPackages: fileContent.markedPackages || [] } }, - map: fileContent.nodes[0] + map: clone(fileContent.nodes[0]) } } diff --git a/visualization/app/codeCharta/util/globalSettingsHelper.ts b/visualization/app/codeCharta/util/globalSettingsHelper.ts index abaac9e4dd..fa3b63314a 100644 --- a/visualization/app/codeCharta/util/globalSettingsHelper.ts +++ b/visualization/app/codeCharta/util/globalSettingsHelper.ts @@ -8,7 +8,7 @@ import { setMaxTreeMapFiles } from "../state/store/appSettings/maxTreeMapFiles/m import { setResetCameraIfNewFileIsLoaded } from "../state/store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.actions" import packageJson from "../../../package.json" import { setScreenshotToClipboardEnabled } from "../state/store/appSettings/enableClipboard/screenshotToClipboardEnabled.actions" -import { Store } from "../state/angular-redux/store" +import { Store } from "@ngrx/store" export class GlobalSettingsHelper { static readonly GLOBALSETTINGS_LOCAL_STORAGE_ELEMENT = "globalSettings" @@ -28,28 +28,28 @@ export class GlobalSettingsHelper { ).globalSettings if (appSettings.hideFlatBuildings !== globalSettings.hideFlatBuildings) { - store.dispatch(setHideFlatBuildings(globalSettings.hideFlatBuildings)) + store.dispatch(setHideFlatBuildings({ value: globalSettings.hideFlatBuildings })) } if (appSettings.isWhiteBackground !== globalSettings.isWhiteBackground) { - store.dispatch(setIsWhiteBackground(globalSettings.isWhiteBackground)) + store.dispatch(setIsWhiteBackground({ value: globalSettings.isWhiteBackground })) } if (appSettings.resetCameraIfNewFileIsLoaded !== globalSettings.resetCameraIfNewFileIsLoaded) { - store.dispatch(setResetCameraIfNewFileIsLoaded(globalSettings.resetCameraIfNewFileIsLoaded)) + store.dispatch(setResetCameraIfNewFileIsLoaded({ value: globalSettings.resetCameraIfNewFileIsLoaded })) } if (appSettings.experimentalFeaturesEnabled !== globalSettings.experimentalFeaturesEnabled) { - store.dispatch(setExperimentalFeaturesEnabled(globalSettings.experimentalFeaturesEnabled)) + store.dispatch(setExperimentalFeaturesEnabled({ value: globalSettings.experimentalFeaturesEnabled })) } if (appSettings.screenshotToClipboardEnabled !== globalSettings.screenshotToClipboardEnabled) { - store.dispatch(setScreenshotToClipboardEnabled(globalSettings.screenshotToClipboardEnabled)) + store.dispatch(setScreenshotToClipboardEnabled({ value: globalSettings.screenshotToClipboardEnabled })) } if (appSettings.layoutAlgorithm !== globalSettings.layoutAlgorithm) { - store.dispatch(setLayoutAlgorithm(globalSettings.layoutAlgorithm)) + store.dispatch(setLayoutAlgorithm({ value: globalSettings.layoutAlgorithm })) } if (appSettings.maxTreeMapFiles !== globalSettings.maxTreeMapFiles) { - store.dispatch(setMaxTreeMapFiles(globalSettings.maxTreeMapFiles)) + store.dispatch(setMaxTreeMapFiles({ value: globalSettings.maxTreeMapFiles })) } if (appSettings.sharpnessMode !== globalSettings.sharpnessMode) { - store.dispatch(setSharpnessMode(globalSettings.sharpnessMode)) + store.dispatch(setSharpnessMode({ value: globalSettings.sharpnessMode })) } } } diff --git a/visualization/app/codeCharta/util/settingsHelper.spec.ts b/visualization/app/codeCharta/util/settingsHelper.spec.ts index 0095589a7e..2c95ee552a 100644 --- a/visualization/app/codeCharta/util/settingsHelper.spec.ts +++ b/visualization/app/codeCharta/util/settingsHelper.spec.ts @@ -1,4 +1,4 @@ -import { RecursivePartial, State } from "../codeCharta.model" +import { RecursivePartial, CcState } from "../codeCharta.model" import { convertToVectors } from "./settingsHelper" import { Vector3 } from "three" @@ -11,13 +11,13 @@ describe("SettingsHelper", () => { } } - const expected: RecursivePartial = { + const expected: RecursivePartial = { appSettings: { scaling: new Vector3(1, 27, 1) } } - convertToVectors(partialState as RecursivePartial) + convertToVectors(partialState as RecursivePartial) expect(partialState).toEqual(expected) }) @@ -31,7 +31,7 @@ describe("SettingsHelper", () => { } } - const expected: RecursivePartial = { + const expected: RecursivePartial = { appSettings: { scaling: new Vector3(1, 27, 1), invertHeight: false, @@ -39,7 +39,7 @@ describe("SettingsHelper", () => { } } - convertToVectors(partialState as RecursivePartial) + convertToVectors(partialState as RecursivePartial) expect(partialState).toEqual(expected) }) diff --git a/visualization/app/codeCharta/util/testUtils/store.utils.ts b/visualization/app/codeCharta/util/testUtils/store.utils.ts new file mode 100644 index 0000000000..057a027cf2 --- /dev/null +++ b/visualization/app/codeCharta/util/testUtils/store.utils.ts @@ -0,0 +1,6 @@ +import { MockStore } from "@ngrx/store/testing" +import { firstValueFrom } from "rxjs" + +export async function getLastAction(store: MockStore) { + return firstValueFrom(store.scannedActions$) +} diff --git a/visualization/package-lock.json b/visualization/package-lock.json index e6fa45d927..675f681aec 100644 --- a/visualization/package-lock.json +++ b/visualization/package-lock.json @@ -17,6 +17,8 @@ "@angular/material": "^15.1.1", "@angular/platform-browser": "^15.1.1", "@angular/platform-browser-dynamic": "^15.1.1", + "@ngrx/effects": "^15.4.0", + "@ngrx/store": "^15.4.0", "ajv": "^6.12.6", "color-convert": "^2.0.1", "d3-hierarchy": "^2.0.0", @@ -31,7 +33,6 @@ "nw": "^0.75.0", "pako": "^2.0.4", "percent-round": "^2.2.1", - "redux": "^4.0.5", "rxjs": "^7.5.1", "shelljs": "^0.8.4", "three": "^0.126.1", @@ -2250,6 +2251,7 @@ }, "node_modules/@babel/runtime": { "version": "7.20.7", + "dev": true, "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.11" @@ -3887,6 +3889,31 @@ "tslib": "^2.1.0" } }, + "node_modules/@ngrx/effects": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.4.0.tgz", + "integrity": "sha512-/8gHhOM9aeGaw8OG2LLwi4I4p84xzG0EU9TqWrvQcW74wn8sFZONjLvUte5YOzJ5502PPFFrfXSOc+lHnVAJUA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^15.0.0", + "@ngrx/store": "15.4.0", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/store": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.4.0.tgz", + "integrity": "sha512-OvCuNBHL8mAUnRTS6QSFm+IunspsYNu2cCwDovBNn7EGhxRuGihBeNoX47jCqWPHBFtokj4BlatDfpJ/yCh4xQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^15.0.0", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, "node_modules/@ngtools/webpack": { "version": "15.1.2", "dev": true, @@ -16261,13 +16288,6 @@ "dev": true, "license": "MIT" }, - "node_modules/redux": { - "version": "4.2.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "node_modules/reflect-metadata": { "version": "0.1.13", "dev": true, @@ -16291,6 +16311,7 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.11", + "dev": true, "license": "MIT" }, "node_modules/regenerator-transform": { @@ -20494,6 +20515,7 @@ }, "@babel/runtime": { "version": "7.20.7", + "dev": true, "requires": { "regenerator-runtime": "^0.13.11" } @@ -21802,6 +21824,22 @@ "tslib": "^2.1.0" } }, + "@ngrx/effects": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.4.0.tgz", + "integrity": "sha512-/8gHhOM9aeGaw8OG2LLwi4I4p84xzG0EU9TqWrvQcW74wn8sFZONjLvUte5YOzJ5502PPFFrfXSOc+lHnVAJUA==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ngrx/store": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.4.0.tgz", + "integrity": "sha512-OvCuNBHL8mAUnRTS6QSFm+IunspsYNu2cCwDovBNn7EGhxRuGihBeNoX47jCqWPHBFtokj4BlatDfpJ/yCh4xQ==", + "requires": { + "tslib": "^2.0.0" + } + }, "@ngtools/webpack": { "version": "15.1.2", "dev": true, @@ -30114,12 +30152,6 @@ "version": "1.0.6", "dev": true }, - "redux": { - "version": "4.2.0", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, "reflect-metadata": { "version": "0.1.13", "dev": true @@ -30136,7 +30168,8 @@ } }, "regenerator-runtime": { - "version": "0.13.11" + "version": "0.13.11", + "dev": true }, "regenerator-transform": { "version": "0.15.1", diff --git a/visualization/package.json b/visualization/package.json index 2c90df9c35..5f83be803e 100644 --- a/visualization/package.json +++ b/visualization/package.json @@ -76,6 +76,8 @@ "@angular/material": "^15.1.1", "@angular/platform-browser": "^15.1.1", "@angular/platform-browser-dynamic": "^15.1.1", + "@ngrx/effects": "^15.4.0", + "@ngrx/store": "^15.4.0", "ajv": "^6.12.6", "color-convert": "^2.0.1", "d3-hierarchy": "^2.0.0", @@ -90,7 +92,6 @@ "nw": "^0.75.0", "pako": "^2.0.4", "percent-round": "^2.2.1", - "redux": "^4.0.5", "rxjs": "^7.5.1", "shelljs": "^0.8.4", "three": "^0.126.1", @@ -126,9 +127,9 @@ "jest-preset-angular": "^13.0.0", "jest-puppeteer": "^6.1.1", "lint-staged": "^13.0.0", + "marked": "^4.3.0", "nw-builder": "^3.7.4", "puppeteer": "^17.0.0", - "marked": "^4.3.0", "ts-jest": "^29.0.5", "typescript": "~4.9.4", "webpack-glsl-loader": "^1.0.1"