codecharta-visualization 1.88.0 → 1.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/app/app.module.ts +20 -10
  2. package/app/codeCharta/codeCharta.component.html +0 -2
  3. package/app/codeCharta/codeCharta.model.ts +1 -0
  4. package/app/codeCharta/services/ajs-upgraded-providers.ts +13 -0
  5. package/app/codeCharta/state/angular-redux/effects/createEffect.spec.ts +37 -0
  6. package/app/codeCharta/state/angular-redux/effects/createEffect.ts +25 -0
  7. package/app/codeCharta/state/angular-redux/effects/effects.module.ts +36 -0
  8. package/app/codeCharta/state/angular-redux/ofType.ts +11 -0
  9. package/app/codeCharta/state/angular-redux/state.ts +12 -0
  10. package/app/codeCharta/state/angular-redux/store.ts +1 -1
  11. package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts +60 -0
  12. package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts +56 -0
  13. package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap.ts +22 -0
  14. package/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.html +3 -0
  15. package/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts +26 -0
  16. package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.html +13 -0
  17. package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts +55 -0
  18. package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts +34 -0
  19. package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.module.ts +11 -0
  20. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.html +0 -0
  21. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.spec.ts +2 -2
  22. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.ts +5 -5
  23. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.module.ts +1 -1
  24. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/isNodeFocused.pipe.spec.ts +0 -0
  25. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/isNodeFocused.pipe.ts +2 -2
  26. package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.html +6 -0
  27. package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.spec.ts +64 -0
  28. package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.ts +39 -0
  29. package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.module.ts +11 -0
  30. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.html +3 -3
  31. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.scss +0 -0
  32. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts +2 -2
  33. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.ts +6 -6
  34. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.module.ts +1 -1
  35. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts +0 -0
  36. package/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +29 -0
  37. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/nodeContextMenu.e2e.ts +4 -16
  38. package/app/codeCharta/{ui → state/effects}/nodeContextMenu/nodeContextMenu.po.ts +1 -1
  39. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts +78 -0
  40. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts +72 -0
  41. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.spec.ts +11 -0
  42. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.ts +8 -0
  43. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.html +17 -0
  44. package/app/codeCharta/{ui/nodeContextMenu/nodeContextMenu.component.scss → state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.scss} +6 -11
  45. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts +49 -0
  46. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts +19 -0
  47. package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.module.ts +18 -0
  48. package/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts +32 -0
  49. package/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts +33 -0
  50. package/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts +8 -0
  51. package/app/codeCharta/state/effects/unfocusNodesOnLoadingMap.effect.spec.ts +47 -0
  52. package/app/codeCharta/state/effects/unfocusNodesOnLoadingMap.effect.ts +18 -0
  53. package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts +30 -0
  54. package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areDynamicSettingsAvailable.spec.ts +36 -0
  55. package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areDynamicSettingsAvailable.ts +10 -0
  56. package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areMetricsAvailable.spec.ts +13 -0
  57. package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areMetricsAvailable.ts +8 -0
  58. package/app/codeCharta/state/store/appSettings/appSettings.actions.ts +2 -0
  59. package/app/codeCharta/state/store/appSettings/appSettings.reducer.ts +2 -0
  60. package/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts +32 -0
  61. package/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts +26 -0
  62. package/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts +12 -0
  63. package/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts +3 -0
  64. package/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts +14 -3
  65. package/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts +41 -6
  66. package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts +33 -2
  67. package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts +17 -1
  68. package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts +3 -1
  69. package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.service.spec.ts +1 -19
  70. package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.service.ts +5 -28
  71. package/app/codeCharta/state/store/lookUp/idToNode/idToNode.selector.ts +4 -0
  72. package/app/codeCharta/state/store/lookUp/lookUp.selector.ts +3 -0
  73. package/app/codeCharta/state/store/metricData/nodeMetricData/nodeMetricData.service.ts +0 -4
  74. package/app/codeCharta/state/store/store.ts +5 -1
  75. package/app/codeCharta/state/store.service.spec.ts +20 -7
  76. package/app/codeCharta/state/store.service.ts +3 -36
  77. package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.html +3 -1
  78. package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.scss +6 -2
  79. package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.ts +1 -1
  80. package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.module.ts +3 -0
  81. package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.po.ts +4 -4
  82. package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.html +1 -0
  83. package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.scss +26 -0
  84. package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.spec.ts +29 -0
  85. package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.ts +24 -0
  86. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/aggregationType.pipe.spec.ts +19 -0
  87. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/{aggregationSymbol.pipe.ts → aggregationType.pipe.ts} +4 -4
  88. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.html +4 -12
  89. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.scss +11 -20
  90. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts +8 -15
  91. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.module.ts +2 -2
  92. package/app/codeCharta/ui/codeMap/codeMap.preRender.service.spec.ts +1 -9
  93. package/app/codeCharta/ui/codeMap/codeMap.preRender.service.ts +9 -32
  94. package/app/codeCharta/ui/dialogs/dialogs.ts +3 -0
  95. package/app/codeCharta/ui/dialogs/errorDialog/errorDialog.component.html +7 -0
  96. package/app/codeCharta/ui/dialogs/errorDialog/errorDialog.component.ts +9 -0
  97. package/app/codeCharta/ui/mapTreeView/mapTreeView.level.e2e.ts +1 -1
  98. package/app/codeCharta/ui/mapTreeView/mapTreeView.level.po.ts +1 -1
  99. package/app/codeCharta/ui/ribbonBar/ribbonBar.component.html +2 -2
  100. package/app/codeCharta/ui/ribbonBar/ribbonBar.e2e.ts +3 -3
  101. package/app/codeCharta/ui/searchBar/searchBar.component.html +5 -0
  102. package/app/codeCharta/ui/searchBar/searchBar.component.scss +11 -0
  103. package/app/codeCharta/ui/searchBar/searchBar.component.spec.ts +10 -0
  104. package/app/codeCharta/ui/searchBar/searchBar.component.ts +1 -1
  105. package/app/codeCharta/ui/sortingOption/sortingOption.component.spec.ts +1 -1
  106. package/app/codeCharta/ui/ui.ts +0 -2
  107. package/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts +1 -1
  108. package/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts +14 -7
  109. package/app/codeCharta/util/customConfigBuilder.ts +1 -0
  110. package/app/codeCharta/util/dataMocks.ts +2 -0
  111. package/app/codeCharta/util/reduxHelper.ts +11 -0
  112. package/app/material/material.module.ts +17 -1
  113. package/conf/webpack.loaders.js +4 -1
  114. package/dist/webpack/bundle.js +4582 -950
  115. package/dist/webpack/bundle.js.map +1 -1
  116. package/package.json +2 -2
  117. package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/aggregationSymbol.pipe.spec.ts +0 -19
  118. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +0 -29
  119. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.spec.ts +0 -15
  120. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.ts +0 -9
  121. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.html +0 -45
  122. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.spec.ts +0 -365
  123. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.ts +0 -198
  124. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.module.ts +0 -15
@@ -0,0 +1,8 @@
1
+ import { createSelector } from "../../angular-redux/createSelector"
2
+ import { rightClickedNodeDataSelector } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.selector"
3
+ import { idToNodeSelector } from "../../store/lookUp/idToNode/idToNode.selector"
4
+
5
+ export const rightClickedCodeMapNodeSelector = createSelector(
6
+ [rightClickedNodeDataSelector, idToNodeSelector],
7
+ (rightClickedNodeData, idToNode) => (rightClickedNodeData ? idToNode.get(rightClickedNodeData.nodeId) : null)
8
+ )
@@ -0,0 +1,47 @@
1
+ import { ApplicationInitStatus } from "@angular/core"
2
+ import { TestBed } from "@angular/core/testing"
3
+ import { Action } from "redux"
4
+ import { Subject } from "rxjs"
5
+ import { mocked } from "ts-jest/utils"
6
+
7
+ import { EffectsModule } from "../angular-redux/effects/effects.module"
8
+ import { setIsLoadingFile } from "../store/appSettings/isLoadingFile/isLoadingFile.actions"
9
+ import { unfocusAllNodes } from "../store/dynamicSettings/focusedNodePath/focusedNodePath.actions"
10
+ import { Store } from "../store/store"
11
+ import { UnfocusNodesOnLoadingMapEffect } from "./unfocusNodesOnLoadingMap.effect"
12
+
13
+ jest.mock("../store/store", () => ({
14
+ Store: {}
15
+ }))
16
+ const MockedStore = mocked(Store)
17
+
18
+ describe("UnfocusNodesOnLoadingMapEffect", () => {
19
+ beforeEach(async () => {
20
+ MockedStore.dispatch = jest.fn()
21
+
22
+ EffectsModule.actions$ = new Subject<Action>()
23
+ TestBed.configureTestingModule({
24
+ imports: [EffectsModule.forRoot([UnfocusNodesOnLoadingMapEffect])]
25
+ })
26
+ await TestBed.inject(ApplicationInitStatus).donePromise
27
+ })
28
+
29
+ afterEach(() => {
30
+ EffectsModule.actions$.complete()
31
+ })
32
+
33
+ it("should ignore a not relevant action", () => {
34
+ EffectsModule.actions$.next({ type: "whatever" })
35
+ expect(MockedStore.dispatch).not.toHaveBeenCalled()
36
+ })
37
+
38
+ it("should fire an unfocusAllNodes action after setIsLoadingFile to true", () => {
39
+ EffectsModule.actions$.next(setIsLoadingFile(true))
40
+ expect(MockedStore.dispatch).toHaveBeenCalledWith(unfocusAllNodes())
41
+ })
42
+
43
+ it("should ignore setIsLoadingFile to false", () => {
44
+ EffectsModule.actions$.next(setIsLoadingFile(false))
45
+ expect(MockedStore.dispatch).not.toHaveBeenCalled()
46
+ })
47
+ })
@@ -0,0 +1,18 @@
1
+ import { Inject } from "@angular/core"
2
+ import { filter, map } from "rxjs"
3
+ import { isAction } from "../../util/reduxHelper"
4
+ import { createEffect } from "../angular-redux/effects/createEffect"
5
+ import { Actions, ActionsToken } from "../angular-redux/effects/effects.module"
6
+ import { IsLoadingFileActions, SetIsLoadingFileAction } from "../store/appSettings/isLoadingFile/isLoadingFile.actions"
7
+ import { unfocusAllNodes } from "../store/dynamicSettings/focusedNodePath/focusedNodePath.actions"
8
+
9
+ export class UnfocusNodesOnLoadingMapEffect {
10
+ constructor(@Inject(ActionsToken) private actions$: Actions) {}
11
+
12
+ unfocusNodesOnLoadingMap$ = createEffect(() => {
13
+ return this.actions$.pipe(
14
+ filter(action => isAction<SetIsLoadingFileAction>(action, IsLoadingFileActions.SET_IS_LOADING_FILE) && action.payload === true),
15
+ map(() => unfocusAllNodes())
16
+ )
17
+ })
18
+ }
@@ -0,0 +1,30 @@
1
+ import { fileStatesAvailable } from "../../../model/files/files.helper"
2
+ import { createSelector } from "../../angular-redux/createSelector"
3
+ import { areaMetricSelector } from "../../store/dynamicSettings/areaMetric/areaMetric.selector"
4
+ import { colorMetricSelector } from "../../store/dynamicSettings/colorMetric/colorMetric.selector"
5
+ import { dynamicSettingsSelector } from "../../store/dynamicSettings/dynamicSettings.selector"
6
+ import { heightMetricSelector } from "../../store/dynamicSettings/heightMetric/heightMetric.selector"
7
+ import { filesSelector } from "../../store/files/files.selector"
8
+ import { nodeMetricDataSelector } from "../accumulatedData/metricData/nodeMetricData.selector"
9
+ import { areDynamicSettingsAvailable } from "./utils/areDynamicSettingsAvailable"
10
+ import { areMetricsAvailable } from "./utils/areMetricsAvailable"
11
+
12
+ const areFileStatesAvailableSelector = createSelector([filesSelector], files => fileStatesAvailable(files))
13
+
14
+ const areChosenMetricsAvailableSelector = createSelector(
15
+ [nodeMetricDataSelector, areaMetricSelector, colorMetricSelector, heightMetricSelector],
16
+ (nodeMetricData, areaMetric, colorMetric, heightMetric) => areMetricsAvailable(nodeMetricData, [areaMetric, colorMetric, heightMetric])
17
+ )
18
+
19
+ const areDynamicSettingsAvailableSelector = createSelector([dynamicSettingsSelector], dynamicSettings =>
20
+ areDynamicSettingsAvailable(dynamicSettings)
21
+ )
22
+
23
+ export const areAllNecessaryRenderDataAvailableSelector = createSelector(
24
+ [nodeMetricDataSelector, areFileStatesAvailableSelector, areChosenMetricsAvailableSelector, areDynamicSettingsAvailableSelector],
25
+ (nodeMetricData, areFileStatesAvailable, areChosenMetricsAvailable, areDynamicSettingsAvailable) => {
26
+ if (nodeMetricData === null || !areFileStatesAvailable || !areChosenMetricsAvailable || !areDynamicSettingsAvailable) return false
27
+
28
+ return true
29
+ }
30
+ )
@@ -0,0 +1,36 @@
1
+ import { ColorMode, DynamicSettings, SortingOption } from "../../../../codeCharta.model"
2
+ import { areDynamicSettingsAvailable } from "./areDynamicSettingsAvailable"
3
+
4
+ describe("areDynamicSettingsAvailable", () => {
5
+ it("should return false when recent files aren't set", () => {
6
+ const dynamicSettings = {
7
+ recentFiles: null
8
+ }
9
+ expect(areDynamicSettingsAvailable(dynamicSettings)).toBe(false)
10
+ })
11
+
12
+ it("should return false when colorRange.from isn't set", () => {
13
+ const dynamicSettings = {
14
+ colorRange: { from: null, to: 25, min: 0, max: 100 }
15
+ }
16
+ expect(areDynamicSettingsAvailable(dynamicSettings)).toBe(false)
17
+ })
18
+
19
+ it("should return true when everything is set", () => {
20
+ const dynamicSettings: DynamicSettings = {
21
+ colorMode: ColorMode.trueGradient,
22
+ sortingOption: SortingOption.NAME,
23
+ areaMetric: "rloc",
24
+ heightMetric: "loc",
25
+ colorMetric: "mcc",
26
+ distributionMetric: "pairingRate",
27
+ edgeMetric: "avgCommits",
28
+ focusedNodePath: [],
29
+ searchPattern: "",
30
+ margin: 2,
31
+ colorRange: { from: 0, to: 25, min: 0, max: 100 },
32
+ recentFiles: ["test.cc.json"]
33
+ }
34
+ expect(areDynamicSettingsAvailable(dynamicSettings)).toBe(true)
35
+ })
36
+ })
@@ -0,0 +1,10 @@
1
+ import { ColorRange, DynamicSettings } from "../../../../codeCharta.model"
2
+
3
+ const isDynamicSettingAvailable = (setting: null | string | number | string[] | ColorRange) => {
4
+ if (setting === null) return false
5
+ if (typeof setting !== "object") return true
6
+ return Object.values(setting).every(v => v !== null)
7
+ }
8
+
9
+ export const areDynamicSettingsAvailable = (dynamicSettings: Partial<DynamicSettings>) =>
10
+ Object.values(dynamicSettings).every(value => isDynamicSettingAvailable(value))
@@ -0,0 +1,13 @@
1
+ import { areMetricsAvailable } from "./areMetricsAvailable"
2
+
3
+ describe("areMetricsAvailable", () => {
4
+ const nodeMetricData = [{ name: "mcc" }, { name: "rloc" }]
5
+
6
+ it("should return false if some metric is not available", () => {
7
+ expect(areMetricsAvailable(nodeMetricData, ["mcc", "loc"])).toBe(false)
8
+ })
9
+
10
+ it("should return true if all metric are available", () => {
11
+ expect(areMetricsAvailable(nodeMetricData, ["mcc", "rloc"])).toBe(true)
12
+ })
13
+ })
@@ -0,0 +1,8 @@
1
+ import { NodeMetricData } from "../../../../codeCharta.model"
2
+
3
+ type NodeMetricDataName = Pick<NodeMetricData, "name">
4
+
5
+ const isMetricAvailable = (nodeMetricData: NodeMetricDataName[], metricName: string) => nodeMetricData.some(x => x.name === metricName)
6
+
7
+ export const areMetricsAvailable = (nodeMetricData: NodeMetricDataName[], metricNames: string[]) =>
8
+ metricNames.every(metric => isMetricAvailable(nodeMetricData, metric))
@@ -28,6 +28,7 @@ import { defaultLayoutAlgorithm } from "./layoutAlgorithm/layoutAlgorithm.action
28
28
  import { defaultMaxTreeMapFiles } from "./maxTreeMapFiles/maxTreeMapFiles.actions"
29
29
  import { defaultSharpnessMode } from "./sharpnessMode/sharpnessMode.actions"
30
30
  import { defaultScreenshotToClipboardEnabled } from "./enableClipboard/screenshotToClipboardEnabled.actions"
31
+ import { defaultInvertArea } from "./invertArea/invertArea.actions"
31
32
 
32
33
  export enum AppSettingsActions {
33
34
  SET_APP_SETTINGS = "SET_APP_SETTINGS"
@@ -61,6 +62,7 @@ export const defaultAppSettings: AppSettings = {
61
62
  cameraTarget: defaultCameraTarget,
62
63
  hideFlatBuildings: defaultHideFlatBuildings,
63
64
  invertHeight: defaultInvertHeight,
65
+ invertArea: defaultInvertArea,
64
66
  dynamicMargin: defaultDynamicMargin,
65
67
  isWhiteBackground: defaultIsWhiteBackground,
66
68
  mapColors: defaultMapColors,
@@ -27,6 +27,7 @@ import { layoutAlgorithm } from "./layoutAlgorithm/layoutAlgorithm.reducer"
27
27
  import { maxTreeMapFiles } from "./maxTreeMapFiles/maxTreeMapFiles.reducer"
28
28
  import { sharpnessMode } from "./sharpnessMode/sharpnessMode.reducer"
29
29
  import { screenshotToClipboardEnabled } from "./enableClipboard/screenshotToClipboardEnabled.reducer"
30
+ import { invertArea } from "./invertArea/invertArea.reducer"
30
31
 
31
32
  const appSettings = combineReducers({
32
33
  colorLabels,
@@ -45,6 +46,7 @@ const appSettings = combineReducers({
45
46
  isWhiteBackground,
46
47
  dynamicMargin,
47
48
  invertHeight,
49
+ invertArea,
48
50
  hideFlatBuildings,
49
51
  camera,
50
52
  scaling,
@@ -0,0 +1,32 @@
1
+ import { Action } from "redux"
2
+
3
+ export enum InvertAreaActions {
4
+ SET_INVERT_AREA = "SET_INVERT_AREA",
5
+ TOGGLE_INVERTING_AREA = "TOGGLE_INVERTING_AREA"
6
+ }
7
+
8
+ export interface SetInvertAreaAction extends Action {
9
+ type: InvertAreaActions.SET_INVERT_AREA
10
+ payload: boolean
11
+ }
12
+
13
+ export type InvertAreaAction = SetInvertAreaAction
14
+
15
+ export const defaultInvertArea = false
16
+
17
+ export function setInvertArea(invertArea: boolean = defaultInvertArea): SetInvertAreaAction {
18
+ return {
19
+ type: InvertAreaActions.SET_INVERT_AREA,
20
+ payload: invertArea
21
+ }
22
+ }
23
+
24
+ export interface ToggleInvertingAreaAction extends Action {
25
+ type: InvertAreaActions.TOGGLE_INVERTING_AREA
26
+ }
27
+
28
+ export function toggleInvertingArea(): ToggleInvertingAreaAction {
29
+ return {
30
+ type: InvertAreaActions.TOGGLE_INVERTING_AREA
31
+ }
32
+ }
@@ -0,0 +1,26 @@
1
+ import { invertArea } from "./invertArea.reducer"
2
+ import { InvertAreaAction, setInvertArea } from "./invertArea.actions"
3
+
4
+ describe("invertArea", () => {
5
+ describe("Default State", () => {
6
+ it("should initialize the default state", () => {
7
+ const result = invertArea(undefined, {} as InvertAreaAction)
8
+
9
+ expect(result).toBeFalsy()
10
+ })
11
+ })
12
+
13
+ describe("Action: SET_INVERT_AREA", () => {
14
+ it("should set new invertArea", () => {
15
+ const result = invertArea(false, setInvertArea(true))
16
+
17
+ expect(result).toBeTruthy()
18
+ })
19
+
20
+ it("should set default invertArea", () => {
21
+ const result = invertArea(true, setInvertArea())
22
+
23
+ expect(result).toBeFalsy()
24
+ })
25
+ })
26
+ })
@@ -0,0 +1,12 @@
1
+ import { InvertAreaAction, InvertAreaActions, setInvertArea, ToggleInvertingAreaAction } from "./invertArea.actions"
2
+
3
+ export function invertArea(state = setInvertArea().payload, action: InvertAreaAction | ToggleInvertingAreaAction) {
4
+ switch (action.type) {
5
+ case InvertAreaActions.SET_INVERT_AREA:
6
+ return action.payload
7
+ case InvertAreaActions.TOGGLE_INVERTING_AREA:
8
+ return !state
9
+ default:
10
+ return state
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ import { CcState } from "../../store"
2
+
3
+ export const invertAreaSelector = (state: CcState): boolean => state.appSettings.invertArea
@@ -1,12 +1,13 @@
1
1
  import { isLoadingMap } from "./isLoadingMap.reducer"
2
2
  import { IsLoadingMapAction, setIsLoadingMap } from "./isLoadingMap.actions"
3
+ import { setHoveredBuildingPath } from "../../appStatus/hoveredBuildingPath/hoveredBuildingPath.actions"
3
4
 
4
5
  describe("isLoadingMap", () => {
5
6
  describe("Default State", () => {
6
7
  it("should initialize the default state", () => {
7
8
  const result = isLoadingMap(undefined, {} as IsLoadingMapAction)
8
9
 
9
- expect(result).toBeTruthy()
10
+ expect(result).toBe(true)
10
11
  })
11
12
  })
12
13
 
@@ -14,13 +15,23 @@ describe("isLoadingMap", () => {
14
15
  it("should set new isLoadingMap", () => {
15
16
  const result = isLoadingMap(true, setIsLoadingMap(false))
16
17
 
17
- expect(result).toBeFalsy()
18
+ expect(result).toBe(false)
18
19
  })
19
20
 
20
21
  it("should set default isLoadingMap", () => {
21
22
  const result = isLoadingMap(false, setIsLoadingMap())
22
23
 
23
- expect(result).toBeTruthy()
24
+ expect(result).toBe(true)
25
+ })
26
+ })
27
+
28
+ describe("Other Actions to (not) set isLoadingMap to true", () => {
29
+ it("'should' set isLoadingMap to true on a random action", () => {
30
+ expect(isLoadingMap(false, { type: "any" } as unknown as IsLoadingMapAction)).toBe(true)
31
+ })
32
+
33
+ it("'should' not set isLoadingMap to true on an explicit excluded action", () => {
34
+ expect(isLoadingMap(false, setHoveredBuildingPath("/root/child") as unknown as IsLoadingMapAction)).toBe(false)
24
35
  })
25
36
  })
26
37
  })
@@ -1,10 +1,45 @@
1
+ import { isActionOfType } from "../../../../util/reduxHelper"
2
+ import { HoveredBuildingPathActions } from "../../appStatus/hoveredBuildingPath/hoveredBuildingPath.actions"
3
+ import { FocusedNodePathActions } from "../../dynamicSettings/focusedNodePath/focusedNodePath.actions"
4
+ import { SortingOptionActions } from "../../dynamicSettings/sortingOption/sortingOption.actions"
5
+ import { CameraTargetActions } from "../cameraTarget/cameraTarget.actions"
6
+ import { CameraActions } from "../../appSettings/camera/camera.actions"
7
+ import { ScreenshotToClipboardEnabledActions } from "../enableClipboard/screenshotToClipboardEnabled.actions"
8
+ import { ExperimentalFeaturesEnabledActions } from "../enableExperimentalFeatures/experimentalFeaturesEnabled.actions"
9
+ import { IsAttributeSideBarVisibleActions } from "../isAttributeSideBarVisible/isAttributeSideBarVisible.actions"
10
+ import { IsLoadingFileActions } from "../isLoadingFile/isLoadingFile.actions"
11
+ import { PresentationModeActions } from "../isPresentationMode/isPresentationMode.actions"
12
+ import { PanelSelectionActions } from "../panelSelection/panelSelection.actions"
13
+ import { SearchPanelModeActions } from "../searchPanelMode/searchPanelMode.actions"
14
+ import { SortingOrderAscendingActions } from "../sortingOrderAscending/sortingOrderAscending.actions"
1
15
  import { IsLoadingMapAction, IsLoadingMapActions, setIsLoadingMap } from "./isLoadingMap.actions"
16
+ import { IdToNodeActions } from "../../lookUp/idToNode/idToNode.actions"
17
+ import { IdToBuildingActions } from "../../lookUp/idToBuilding/idToBuilding.actions"
18
+
19
+ // Todo state actions explicit instead of excluding all others; refs #1547
20
+ const actionsToExclude = [
21
+ IsLoadingMapActions,
22
+ IsLoadingFileActions,
23
+ SortingOrderAscendingActions,
24
+ SearchPanelModeActions,
25
+ SortingOptionActions,
26
+ IsAttributeSideBarVisibleActions,
27
+ PanelSelectionActions,
28
+ PresentationModeActions,
29
+ ExperimentalFeaturesEnabledActions,
30
+ ScreenshotToClipboardEnabledActions,
31
+ HoveredBuildingPathActions,
32
+ FocusedNodePathActions,
33
+ CameraTargetActions,
34
+ CameraActions,
35
+ IdToNodeActions,
36
+ IdToBuildingActions
37
+ ]
2
38
 
3
39
  export function isLoadingMap(state = setIsLoadingMap().payload, action: IsLoadingMapAction) {
4
- switch (action.type) {
5
- case IsLoadingMapActions.SET_IS_LOADING_MAP:
6
- return action.payload
7
- default:
8
- return state
9
- }
40
+ if (action.type === IsLoadingMapActions.SET_IS_LOADING_MAP) return action.payload
41
+
42
+ if (actionsToExclude.every(excludeActions => !isActionOfType(action.type, excludeActions))) return true
43
+
44
+ return state
10
45
  }
@@ -3,7 +3,9 @@ import { BlacklistItem, CCAction } from "../../../../codeCharta.model"
3
3
  export enum BlacklistActions {
4
4
  ADD_BLACKLIST_ITEM = "ADD_BLACKLIST_ITEM",
5
5
  REMOVE_BLACKLIST_ITEM = "REMOVE_BLACKLIST_ITEM",
6
- SET_BLACKLIST = "SET_BLACKLIST"
6
+ SET_BLACKLIST = "SET_BLACKLIST",
7
+ ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP = "ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP",
8
+ ADD_BLACKLIST_ITEMS = "ADD_BLACKLIST_ITEMS"
7
9
  }
8
10
 
9
11
  export interface AddBlacklistAction extends CCAction {
@@ -11,6 +13,16 @@ export interface AddBlacklistAction extends CCAction {
11
13
  payload: BlacklistItem
12
14
  }
13
15
 
16
+ export interface AddBlacklistItemsIfNotResultsInEmptyMapAction extends CCAction {
17
+ type: BlacklistActions.ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP
18
+ payload: BlacklistItem[]
19
+ }
20
+
21
+ export interface AddBlacklistItemsAction extends CCAction {
22
+ type: BlacklistActions.ADD_BLACKLIST_ITEMS
23
+ payload: BlacklistItem[]
24
+ }
25
+
14
26
  export interface RemoveBlacklistAction extends CCAction {
15
27
  type: BlacklistActions.REMOVE_BLACKLIST_ITEM
16
28
  payload: BlacklistItem
@@ -21,7 +33,12 @@ export interface SetBlacklistAction extends CCAction {
21
33
  payload: BlacklistItem[]
22
34
  }
23
35
 
24
- export type BlacklistAction = AddBlacklistAction | RemoveBlacklistAction | SetBlacklistAction
36
+ export type BlacklistAction =
37
+ | AddBlacklistAction
38
+ | RemoveBlacklistAction
39
+ | SetBlacklistAction
40
+ | AddBlacklistItemsAction
41
+ | AddBlacklistItemsIfNotResultsInEmptyMapAction
25
42
 
26
43
  export function addBlacklistItem(item: BlacklistItem): AddBlacklistAction {
27
44
  return {
@@ -30,6 +47,20 @@ export function addBlacklistItem(item: BlacklistItem): AddBlacklistAction {
30
47
  }
31
48
  }
32
49
 
50
+ export function addBlacklistItemsIfNotResultsInEmptyMap(items: BlacklistItem[]): AddBlacklistItemsIfNotResultsInEmptyMapAction {
51
+ return {
52
+ type: BlacklistActions.ADD_BLACKLIST_ITEMS_IF_NOT_RESULTS_IN_EMPTY_MAP,
53
+ payload: items
54
+ }
55
+ }
56
+
57
+ export function addBlacklistItems(items: BlacklistItem[]): AddBlacklistItemsAction {
58
+ return {
59
+ type: BlacklistActions.ADD_BLACKLIST_ITEMS,
60
+ payload: items
61
+ }
62
+ }
63
+
33
64
  export function removeBlacklistItem(item: BlacklistItem): RemoveBlacklistAction {
34
65
  return {
35
66
  type: BlacklistActions.REMOVE_BLACKLIST_ITEM,
@@ -1,4 +1,4 @@
1
- import { addBlacklistItem, BlacklistAction, setBlacklist, removeBlacklistItem } from "./blacklist.actions"
1
+ import { addBlacklistItem, BlacklistAction, setBlacklist, removeBlacklistItem, addBlacklistItems } from "./blacklist.actions"
2
2
  import { blacklist } from "./blacklist.reducer"
3
3
  import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model"
4
4
 
@@ -21,6 +21,22 @@ describe("blacklist", () => {
21
21
  })
22
22
  })
23
23
 
24
+ describe("Action: ADD_BLACKLIST_ITEMS", () => {
25
+ it("should add all unique blacklist items to the blacklist", () => {
26
+ const existingItem: BlacklistItem = { type: BlacklistType.flatten, path: "foo/bar" }
27
+ const result = blacklist(
28
+ [existingItem],
29
+ addBlacklistItems([
30
+ existingItem,
31
+ { type: BlacklistType.flatten, path: "foo/bar2" },
32
+ { type: BlacklistType.flatten, path: "foo/bar2" }
33
+ ])
34
+ )
35
+
36
+ expect(result).toEqual([existingItem, { type: BlacklistType.flatten, path: "foo/bar2" }])
37
+ })
38
+ })
39
+
24
40
  describe("Action: REMOVE_BLACKLIST_ITEM", () => {
25
41
  it("should remove a blacklist item, that is in the list", () => {
26
42
  const result = blacklist([item], removeBlacklistItem(item))
@@ -1,10 +1,12 @@
1
1
  import { BlacklistAction, BlacklistActions, setBlacklist } from "./blacklist.actions"
2
- import { addItemToArray, removeItemFromArray } from "../../../../util/reduxHelper"
2
+ import { addItemsToArray, addItemToArray, removeItemFromArray } from "../../../../util/reduxHelper"
3
3
 
4
4
  export function blacklist(state = setBlacklist().payload, action: BlacklistAction) {
5
5
  switch (action.type) {
6
6
  case BlacklistActions.ADD_BLACKLIST_ITEM:
7
7
  return addItemToArray(state, action.payload)
8
+ case BlacklistActions.ADD_BLACKLIST_ITEMS:
9
+ return addItemsToArray(state, action.payload)
8
10
  case BlacklistActions.REMOVE_BLACKLIST_ITEM:
9
11
  return removeItemFromArray(state, action.payload)
10
12
  case BlacklistActions.SET_BLACKLIST:
@@ -2,12 +2,11 @@ import "../../../state.module"
2
2
  import { IRootScopeService } from "angular"
3
3
  import { StoreService } from "../../../store.service"
4
4
  import { getService, instantiateModule } from "../../../../../../mocks/ng.mockhelper"
5
- import * as FilesHelper from "../../../../model/files/files.helper"
6
5
  import { BlacklistService } from "./blacklist.service"
7
6
  import { BlacklistAction, BlacklistActions } from "./blacklist.actions"
8
7
  import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model"
9
8
  import { PresentationModeActions } from "../../appSettings/isPresentationMode/isPresentationMode.actions"
10
- import { FILE_STATES, withMockedEventMethods } from "../../../../util/dataMocks"
9
+ import { withMockedEventMethods } from "../../../../util/dataMocks"
11
10
  import { FilesService } from "../../files/files.service"
12
11
 
13
12
  describe("BlacklistService", () => {
@@ -67,21 +66,4 @@ describe("BlacklistService", () => {
67
66
  expect($rootScope.$broadcast).not.toHaveBeenCalled()
68
67
  })
69
68
  })
70
-
71
- describe("resultsInEmptyMap", () => {
72
- it("should return true when all files are empty", () => {
73
- jest.spyOn(FilesHelper, "getVisibleFileStates").mockReturnValue(FILE_STATES)
74
- const blacklistItem: BlacklistItem[] = [{ path: "/root", type: BlacklistType.exclude }]
75
-
76
- expect(blacklistService.resultsInEmptyMap(blacklistItem)).toBe(true)
77
- })
78
-
79
- it("should return false when files are left", () => {
80
- blacklistService.isIncludedNode = jest.fn(() => true)
81
- jest.spyOn(FilesHelper, "getVisibleFileStates").mockReturnValue(FILE_STATES)
82
- const blacklistItem: BlacklistItem[] = [{ path: "/root/Parent Leaf", type: BlacklistType.exclude }]
83
-
84
- expect(blacklistService.resultsInEmptyMap(blacklistItem)).toBe(false)
85
- })
86
- })
87
69
  })
@@ -1,14 +1,13 @@
1
1
  import { StoreService, StoreSubscriber } from "../../../store.service"
2
2
  import { IRootScopeService } from "angular"
3
- import { BlacklistItem, BlacklistType } from "../../../../codeCharta.model"
3
+ import { BlacklistItem } from "../../../../codeCharta.model"
4
4
  import { BlacklistActions, setBlacklist } from "./blacklist.actions"
5
5
  import { getMergedBlacklist } from "./blacklist.merger"
6
6
  import { FilesService, FilesSelectionSubscriber } from "../../files/files.service"
7
7
  import { isActionOfType } from "../../../../util/reduxHelper"
8
8
  import { getVisibleFiles, getVisibleFileStates, isPartialState } from "../../../../model/files/files.helper"
9
9
  import { FileState } from "../../../../model/files/files"
10
- import { hierarchy } from "d3-hierarchy"
11
- import { isLeaf, isPathBlacklisted } from "../../../../util/codeMapHelper"
10
+ import { resultsInEmptyMap } from "../../../effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap"
12
11
 
13
12
  export interface BlacklistSubscriber {
14
13
  onBlacklistChanged(blacklist: BlacklistItem[])
@@ -34,31 +33,9 @@ export class BlacklistService implements StoreSubscriber, FilesSelectionSubscrib
34
33
  }
35
34
 
36
35
  resultsInEmptyMap(blacklistItems: BlacklistItem[]) {
37
- const fileStates = getVisibleFileStates(this.storeService.getState().files)
38
- for (const { file } of fileStates) {
39
- if (!this.isEmptyFile(file, blacklistItems)) {
40
- return false
41
- }
42
- }
43
- return true
44
- }
45
-
46
- isIncludedNode(node, blacklist: Array<BlacklistItem>) {
47
- return isLeaf(node) && node.data.path && !isPathBlacklisted(node.data.path, blacklist, BlacklistType.exclude)
48
- }
49
-
50
- private isEmptyFile(file, blacklistItems: BlacklistItem[]) {
51
- const blacklist = [...this.storeService.getState().fileSettings.blacklist]
52
- for (const blacklistItem of blacklistItems) {
53
- blacklist.push(blacklistItem)
54
- }
55
-
56
- for (const node of hierarchy(file.map)) {
57
- if (this.isIncludedNode(node, blacklist)) {
58
- return false
59
- }
60
- }
61
- return true
36
+ const visibleFiles = getVisibleFileStates(this.storeService.getState().files)
37
+ const blacklist = this.storeService.getState().fileSettings.blacklist
38
+ return resultsInEmptyMap(visibleFiles, blacklist, blacklistItems)
62
39
  }
63
40
 
64
41
  private merge(files: FileState[]) {
@@ -0,0 +1,4 @@
1
+ import { createSelector } from "../../../angular-redux/createSelector"
2
+ import { lookUpSelector } from "../lookUp.selector"
3
+
4
+ export const idToNodeSelector = createSelector([lookUpSelector], lookUp => lookUp.idToNode)
@@ -0,0 +1,3 @@
1
+ import { CcState } from "../store"
2
+
3
+ export const lookUpSelector = (state: CcState) => state.lookUp
@@ -40,10 +40,6 @@ export class NodeMetricDataService implements FilesSelectionSubscriber, Blacklis
40
40
  return this.nodeMetricData.map(x => x.name)
41
41
  }
42
42
 
43
- isMetricAvailable(metricName: string) {
44
- return this.nodeMetricData.some(x => x.name === metricName)
45
- }
46
-
47
43
  getMaxValueOfMetric(metricName: string) {
48
44
  const metric = this.nodeMetricData.find(x => x.name === metricName)
49
45
  return metric?.maxValue
@@ -1,4 +1,4 @@
1
- import { createStore } from "redux"
1
+ import { Action, createStore } from "redux"
2
2
 
3
3
  import rootReducer from "./state.reducer"
4
4
 
@@ -20,4 +20,8 @@ export class Store {
20
20
  if (!Store._store) Store.initialize()
21
21
  return Store._store
22
22
  }
23
+
24
+ static dispatch(action: Action) {
25
+ Store.store.dispatch(action)
26
+ }
23
27
  }