Skip to content

Commit 88ed1a2

Browse files
authored
Merge branch 'main' into bug/3848/gitlog-with-authors
2 parents be29405 + be979aa commit 88ed1a2

File tree

9 files changed

+124
-34
lines changed

9 files changed

+124
-34
lines changed

.github/workflows/test.yml

+11-11
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ jobs:
1616
env:
1717
working-directory: ./
1818
steps:
19-
- uses: actions/checkout@v3
19+
- uses: actions/checkout@v4
2020
- name: Setup Node.js environment
21-
uses: actions/setup-node@v3
21+
uses: actions/setup-node@v4
2222
with:
2323
node-version: '20'
2424

@@ -50,10 +50,10 @@ jobs:
5050
env:
5151
working-directory: ./visualization
5252
steps:
53-
- uses: actions/checkout@v3
53+
- uses: actions/checkout@v4
5454

5555
- name: Setup Node.js environment
56-
uses: actions/setup-node@v3
56+
uses: actions/setup-node@v4
5757
with:
5858
node-version: '20'
5959

@@ -81,7 +81,7 @@ jobs:
8181
working-directory: ${{env.working-directory}}
8282

8383
- name: Upload artifact
84-
uses: actions/upload-artifact@v3
84+
uses: actions/upload-artifact@v4
8585
with:
8686
name: coverage
8787
path: ./visualization/dist/
@@ -93,10 +93,10 @@ jobs:
9393
env:
9494
working-directory: ./visualization
9595
steps:
96-
- uses: actions/checkout@v3
96+
- uses: actions/checkout@v4
9797

9898
- name: Setup Node.js environment
99-
uses: actions/setup-node@v3
99+
uses: actions/setup-node@v4
100100
with:
101101
node-version: '20'
102102

@@ -132,12 +132,12 @@ jobs:
132132
project-directory: .
133133

134134
steps:
135-
- uses: actions/checkout@v3
135+
- uses: actions/checkout@v4
136136
with:
137137
fetch-depth: 0
138138

139139
- name: Setup Node.js environment
140-
uses: actions/setup-node@v3
140+
uses: actions/setup-node@v4
141141
with:
142142
node-version: '20'
143143

@@ -185,11 +185,11 @@ jobs:
185185
working-directory: ./visualization
186186

187187
steps:
188-
- uses: actions/checkout@v3
188+
- uses: actions/checkout@v4
189189
with:
190190
fetch-depth: 0
191191

192-
- uses: actions/download-artifact@v3
192+
- uses: actions/download-artifact@v4
193193
with:
194194
name: coverage
195195
path: ./visualization/dist/

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Compare two maps and see the delta between them. This allows you to see the chan
8484

8585
## Getting started
8686

87-
You can find our prefered way to get start
87+
You can find our preferred way to get started
8888
under [Documentation - Quick Start Guide](https://maibornwolff.github.io/codecharta/docs/overview/getting-started).
8989

9090
But if you already know what to do, here is how you install our CCSH.
@@ -99,7 +99,7 @@ $ ccsh - h
9999

100100
## Get Involved
101101

102-
Do you have a **bug**, **feature request**, or question? Please open a [a new issue](https://github.com/MaibornWolff/codecharta/issues/new).
102+
Do you have a **bug**, **feature request**, or question? Please open [a new issue](https://github.com/MaibornWolff/codecharta/issues/new).
103103
Feedback is always welcome.
104104

105105
Want **more information**? Check out our [documentation](https://maibornwolff.github.io/codecharta/)

visualization/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
1818
### Fixed 🐞
1919

2020
- Fix loading cc.json files that contain the 'authors' attribute [#3848](https://github.com/MaibornWolff/codecharta/pull/3897)
21+
- Fix applying Custom Views [#3898](https://github.com/MaibornWolff/codecharta/pull/3898)
22+
- The camera is now only reset when the area or the height of the map is changed [#3896](https://github.com/MaibornWolff/codecharta/pull/3896)
2123

2224
## [1.131.2] - 2024-12-04
2325

visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.spec.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { Action } from "@ngrx/store"
1212
import { MockStore, provideMockStore } from "@ngrx/store/testing"
1313
import { provideMockActions } from "@ngrx/effects/testing"
1414
import { LayoutAlgorithm } from "../../../codeCharta.model"
15+
import { selectorsTriggeringAutoFit } from "./selectorsTriggeringAutoFit"
16+
import { colorRangeSelector } from "../../store/dynamicSettings/colorRange/colorRange.selector"
1517

1618
describe("autoFitCodeMapOnFileSelectionChangeEffect", () => {
1719
let mockedRenderCodeMap$: Subject<unknown>
@@ -23,16 +25,18 @@ describe("autoFitCodeMapOnFileSelectionChangeEffect", () => {
2325
actions$ = new BehaviorSubject({ type: "" })
2426
mockedRenderCodeMap$ = new Subject()
2527
mockedAutoFitTo = jest.fn()
28+
const mockedSelectorsTriggeringAutoFit = selectorsTriggeringAutoFit.map(selector => {
29+
return { selector, value: [] }
30+
})
2631
TestBed.configureTestingModule({
2732
imports: [EffectsModule.forRoot([AutoFitCodeMapEffect])],
2833
providers: [
2934
{ provide: RenderCodeMapEffect, useValue: { renderCodeMap$: mockedRenderCodeMap$ } },
3035
provideMockStore({
3136
selectors: [
32-
{ selector: visibleFileStatesSelector, value: [] },
33-
{ selector: focusedNodePathSelector, value: [] },
34-
{ selector: layoutAlgorithmSelector, value: LayoutAlgorithm.StreetMap },
35-
{ selector: resetCameraIfNewFileIsLoadedSelector, value: true }
37+
...mockedSelectorsTriggeringAutoFit,
38+
{ selector: resetCameraIfNewFileIsLoadedSelector, value: true },
39+
{ selector: colorRangeSelector, value: { from: 0, to: 0 } }
3640
]
3741
}),
3842
provideMockActions(() => actions$),
@@ -71,6 +75,13 @@ describe("autoFitCodeMapOnFileSelectionChangeEffect", () => {
7175
expect(mockedAutoFitTo).not.toHaveBeenCalled()
7276
})
7377

78+
it("should do nothing when color range has changed", () => {
79+
store.overrideSelector(colorRangeSelector, { from: 1, to: 2 })
80+
store.refreshState()
81+
mockedRenderCodeMap$.next(undefined)
82+
expect(mockedAutoFitTo).not.toHaveBeenCalled()
83+
})
84+
7485
it("should auto fit map when focused node paths has changed", () => {
7586
store.overrideSelector(focusedNodePathSelector, [])
7687
store.refreshState()

visualization/app/codeCharta/state/effects/autoFitCodeMapChange/autoFitCodeMap.effect.ts

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { Injectable } from "@angular/core"
22
import { Store } from "@ngrx/store"
33
import { Actions, createEffect, ofType } from "@ngrx/effects"
4-
import { switchMap, filter, skip, take, tap, combineLatest, withLatestFrom, first } from "rxjs"
4+
import { combineLatest, filter, first, skip, switchMap, take, tap, withLatestFrom } from "rxjs"
55
import { CcState } from "../../../codeCharta.model"
66
import { ThreeMapControlsService } from "../../../ui/codeMap/threeViewer/threeMapControls.service"
7-
import { visibleFileStatesSelector } from "../../selectors/visibleFileStates/visibleFileStates.selector"
8-
import { layoutAlgorithmSelector } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.selector"
97
import { resetCameraIfNewFileIsLoadedSelector } from "../../store/appSettings/resetCameraIfNewFileIsLoaded/resetCameraIfNewFileIsLoaded.selector"
10-
import { focusedNodePathSelector } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector"
118
import { RenderCodeMapEffect } from "../renderCodeMapEffect/renderCodeMap.effect"
9+
import { selectorsTriggeringAutoFit } from "./selectorsTriggeringAutoFit"
1210

1311
@Injectable()
1412
export class AutoFitCodeMapEffect {
@@ -21,11 +19,7 @@ export class AutoFitCodeMapEffect {
2119

2220
autoFitTo$ = createEffect(
2321
() =>
24-
combineLatest([
25-
this.store.select(visibleFileStatesSelector),
26-
this.store.select(focusedNodePathSelector),
27-
this.store.select(layoutAlgorithmSelector)
28-
]).pipe(
22+
combineLatest(selectorsTriggeringAutoFit.map(selector => this.store.select(selector))).pipe(
2923
skip(1), // initial map load is already fitted
3024
withLatestFrom(this.store.select(resetCameraIfNewFileIsLoadedSelector)),
3125
filter(([, resetCameraIfNewFileIsLoaded]) => resetCameraIfNewFileIsLoaded),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { visibleFileStatesSelector } from "../../selectors/visibleFileStates/visibleFileStates.selector"
2+
import { focusedNodePathSelector } from "../../store/dynamicSettings/focusedNodePath/focusedNodePath.selector"
3+
import { layoutAlgorithmSelector } from "../../store/appSettings/layoutAlgorithm/layoutAlgorithm.selector"
4+
import { invertAreaSelector } from "../../store/appSettings/invertArea/invertArea.selector"
5+
import { marginSelector } from "../../store/dynamicSettings/margin/margin.selector"
6+
import { DefaultProjectorFn, MemoizedSelector } from "@ngrx/store"
7+
import { enableFloorLabelsSelector } from "../../store/appSettings/enableFloorLabels/enableFloorLabels.selector"
8+
import { areaMetricSelector } from "../../store/dynamicSettings/areaMetric/areaMetric.selector"
9+
import { isDeltaStateSelector } from "../../selectors/isDeltaState.selector"
10+
11+
export const selectorsTriggeringAutoFit: MemoizedSelector<any, any, DefaultProjectorFn<any>>[] = [
12+
visibleFileStatesSelector,
13+
focusedNodePathSelector,
14+
layoutAlgorithmSelector,
15+
invertAreaSelector,
16+
marginSelector,
17+
enableFloorLabelsSelector,
18+
areaMetricSelector,
19+
isDeltaStateSelector
20+
]

visualization/app/codeCharta/state/store/state.manager.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { appStatus, defaultAppStatus } from "./appStatus/appStatus.reducer"
66
import { ActionReducer } from "@ngrx/store"
77
import { CcState } from "../../codeCharta.model"
88
import { isSetStateAction } from "./state.actions"
9-
import { clone } from "../../util/clone"
109

1110
export const appReducers = {
1211
fileSettings,
@@ -26,11 +25,8 @@ export const defaultState: CcState = {
2625
export const setStateMiddleware =
2726
(reducer: ActionReducer<CcState>): ActionReducer<CcState> =>
2827
(state, action) => {
29-
if (isSetStateAction(action)) {
30-
const newState = clone(state)
31-
return _applyPartialState(newState, action.value)
32-
}
33-
return reducer(state, action)
28+
const newState = isSetStateAction(action) ? _applyPartialState({ ...state }, action.value) : state
29+
return reducer(newState, action)
3430
}
3531

3632
const objectWithDynamicKeysInStore = new Set([
@@ -59,7 +55,7 @@ export function _applyPartialState<T>(applyTo: T, toBeApplied: unknown, composed
5955
applyTo[key] =
6056
typeof value !== "object" || objectWithDynamicKeysInStore.has(composedJoinedPath)
6157
? value
62-
: _applyPartialState(applyTo[key], value, newComposedPath)
58+
: _applyPartialState({ ...applyTo[key] }, value, newComposedPath)
6359
}
6460

6561
return applyTo

visualization/app/codeCharta/util/customConfigHelper.spec.ts

+65
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import { CustomConfigItemGroup } from "../ui/customConfigs/customConfigs.compone
1111
import { klona } from "klona"
1212
import { stubDate } from "../../../mocks/dateMock.helper"
1313
import { FileDownloader } from "./fileDownloader"
14+
import { Vector3 } from "three/src/math/Vector3"
15+
import { Store } from "@ngrx/store"
16+
import { ThreeCameraService } from "../ui/codeMap/threeViewer/threeCamera.service"
17+
import { ThreeMapControlsService } from "../ui/codeMap/threeViewer/threeMapControls.service"
18+
import { ThreeRendererService } from "../ui/codeMap/threeViewer/threeRenderer.service"
19+
import { setState } from "../state/store/state.actions"
1420

1521
describe("CustomConfigHelper", () => {
1622
beforeEach(() => {
@@ -439,4 +445,63 @@ describe("CustomConfigHelper", () => {
439445
expect(FileDownloader.downloadData).toHaveBeenCalledWith("mock_serialized_config_to_be_downloaded", `${newDate}.cc.config.json`)
440446
})
441447
})
448+
449+
describe("applyCustomConfig", () => {
450+
let customConfigMock: CustomConfig
451+
let store: Store
452+
let threeCameraService: ThreeCameraService
453+
let threeOrbitControlsService: ThreeMapControlsService
454+
let threeRendererService: ThreeRendererService
455+
456+
beforeEach(() => {
457+
customConfigMock = {
458+
stateSettings: {
459+
appSettings: {},
460+
dynamicSettings: {},
461+
fileSettings: {}
462+
},
463+
camera: {
464+
camera: new Vector3(1, 2, 3),
465+
cameraTarget: new Vector3(4, 5, 6)
466+
}
467+
} as CustomConfig
468+
469+
store = {
470+
dispatch: jest.fn()
471+
} as unknown as Store
472+
473+
threeCameraService = {
474+
setPosition: jest.fn()
475+
} as unknown as ThreeCameraService
476+
477+
threeOrbitControlsService = {
478+
setControlTarget: jest.fn()
479+
} as unknown as ThreeMapControlsService
480+
481+
threeRendererService = {
482+
render: jest.fn()
483+
} as unknown as ThreeRendererService
484+
485+
jest.spyOn(CustomConfigHelper, "getCustomConfigSettings").mockReturnValue(customConfigMock)
486+
})
487+
488+
it("should dispatch stateSettings to the store", () => {
489+
CustomConfigHelper.applyCustomConfig("testId", store, threeCameraService, threeOrbitControlsService, threeRendererService)
490+
491+
expect(store.dispatch).toHaveBeenCalledWith(setState({ value: customConfigMock.stateSettings }))
492+
})
493+
494+
it("should update camera position and orbit controls target", () => {
495+
CustomConfigHelper.applyCustomConfig("testId", store, threeCameraService, threeOrbitControlsService, threeRendererService)
496+
497+
expect(threeCameraService.setPosition).toHaveBeenCalledWith(customConfigMock.camera.camera)
498+
expect(threeOrbitControlsService.setControlTarget).toHaveBeenCalledWith(customConfigMock.camera.cameraTarget)
499+
})
500+
501+
it("should trigger a render in the renderer service", () => {
502+
CustomConfigHelper.applyCustomConfig("testId", store, threeCameraService, threeOrbitControlsService, threeRendererService)
503+
504+
expect(threeRendererService.render).toHaveBeenCalled()
505+
})
506+
})
442507
})

visualization/app/codeCharta/util/customConfigHelper.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { BehaviorSubject } from "rxjs"
1515
import { VisibleFilesBySelectionMode } from "../ui/customConfigs/visibleFilesBySelectionMode.selector"
1616
import { Store } from "@ngrx/store"
1717
import { ThreeRendererService } from "../ui/codeMap/threeViewer/threeRenderer.service"
18+
import { setState } from "../state/store/state.actions"
1819

1920
export const CUSTOM_CONFIG_FILE_EXTENSION = ".cc.config.json"
2021
const CUSTOM_CONFIGS_LOCAL_STORAGE_VERSION = "1.0.1"
@@ -191,13 +192,14 @@ export class CustomConfigHelper {
191192

192193
static applyCustomConfig(
193194
configId: string,
194-
// biome-ignore lint/correctness/noUnusedVariables: <explanation>
195195
store: Store,
196196
threeCameraService: ThreeCameraService,
197197
threeOrbitControlsService: ThreeMapControlsService,
198198
threeRendererService: ThreeRendererService
199199
) {
200200
const customConfig = this.getCustomConfigSettings(configId)
201+
store.dispatch(setState({ value: customConfig.stateSettings }))
202+
201203
if (customConfig.camera) {
202204
threeCameraService.setPosition(customConfig.camera.camera)
203205
threeOrbitControlsService.setControlTarget(customConfig.camera.cameraTarget)

0 commit comments

Comments
 (0)