codecharta-visualization 1.87.1 → 1.88.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.
- package/app/app.module.ts +18 -8
- package/app/codeCharta/codeCharta.component.ts +2 -0
- package/app/codeCharta/codeCharta.model.ts +2 -0
- package/app/codeCharta/codeCharta.service.spec.ts +41 -50
- package/app/codeCharta/codeCharta.service.ts +33 -32
- package/app/codeCharta/e2e/url.e2e.ts +1 -1
- package/app/codeCharta/state/store/appStatus/appStatus.reducer.ts +3 -1
- package/app/codeCharta/state/store/appStatus/appStatus.selector.ts +3 -0
- package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts +23 -0
- package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts +15 -0
- package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts +4 -0
- package/app/codeCharta/state/store/state.actions.ts +3 -1
- package/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts +6 -8
- package/app/codeCharta/ui/customConfigs/customConfigs.component.html +9 -9
- package/app/codeCharta/ui/dialog/dialog.addCustomConfigSettings.component.html +2 -2
- package/app/codeCharta/ui/dialog/dialog.changelog.component.scss +15 -0
- package/app/codeCharta/ui/dialog/dialog.changelog.component.spec.ts +15 -15
- package/app/codeCharta/ui/dialog/dialog.changelog.component.ts +2 -1
- package/app/codeCharta/ui/dialog/dialog.service.spec.ts +68 -0
- package/app/codeCharta/ui/dialog/dialog.service.ts +38 -17
- package/app/codeCharta/ui/edgeChooser/edgeChooser.e2e.ts +3 -2
- package/app/codeCharta/ui/fileChooser/fileChooser.e2e.ts +5 -6
- package/app/codeCharta/ui/filePanel/filePanel.component.html +24 -106
- package/app/codeCharta/ui/filePanel/filePanel.component.scss +12 -57
- package/app/codeCharta/ui/filePanel/filePanel.component.spec.ts +40 -72
- package/app/codeCharta/ui/filePanel/filePanel.component.ts +29 -81
- package/app/codeCharta/ui/filePanel/filePanel.module.ts +13 -1
- package/app/codeCharta/ui/filePanel/filePanel.po.ts +6 -24
- package/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.html +23 -0
- package/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts +18 -0
- package/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.html +18 -0
- package/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts +16 -0
- package/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.html +18 -0
- package/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts +11 -0
- package/app/codeCharta/ui/mapTreeView/mapTreeView.level.e2e.ts +7 -5
- package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.html +1 -1
- package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts +6 -16
- package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts +15 -11
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.html +22 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.scss +31 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts +35 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.ts +30 -0
- package/app/codeCharta/ui/nodeContextMenu/{markFolderColorPicker/markFolderColorPicker.module.ts → markFolderRow/markFolderRow.module.ts} +4 -5
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts +17 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +29 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.spec.ts +15 -0
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.ts +9 -0
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.html +2 -15
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.scss +0 -15
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.spec.ts +10 -119
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.ts +40 -134
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.module.ts +2 -2
- package/app/codeCharta/ui/ribbonBar/ribbonBar.component.html +1 -1
- package/app/codeCharta/ui/toolBar/toolBar.component.html +1 -1
- package/app/codeCharta/ui/toolBar/toolBar.component.scss +1 -1
- package/app/codeCharta/ui/ui.ts +2 -2
- package/app/codeCharta/util/customConfigHelper.spec.ts +155 -60
- package/app/codeCharta/util/customConfigHelper.ts +33 -3
- package/app/codeCharta/util/dataMocks.ts +4 -2
- package/app/codeCharta/util/fileValidator.spec.ts +69 -182
- package/app/codeCharta/util/fileValidator.ts +61 -37
- package/dist/webpack/bundle.js +852 -485
- package/dist/webpack/bundle.js.map +1 -1
- package/package.json +1 -1
- package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.html +0 -9
- package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.scss +0 -13
- package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.ts +0 -10
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./markFolderRow.component.scss"
|
|
2
|
+
import { Component, Inject } from "@angular/core"
|
|
3
|
+
import { Store } from "../../../state/angular-redux/store"
|
|
4
|
+
import { markPackages, unmarkPackage } from "../../../state/store/fileSettings/markedPackages/markedPackages.actions"
|
|
5
|
+
import { Observable } from "rxjs"
|
|
6
|
+
import { MarkFolderItem, markFolderItemsSelector } from "./selectors/markFolderItems.selector"
|
|
7
|
+
import { Node } from "../../../codeCharta.model"
|
|
8
|
+
import { rightClickedNodeSelector } from "./selectors/rightClickedNode.selector"
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: "cc-mark-folder-row",
|
|
12
|
+
template: require("./markFolderRow.component.html")
|
|
13
|
+
})
|
|
14
|
+
export class MarkFolderRowComponent {
|
|
15
|
+
markFolderItems$: Observable<MarkFolderItem[]>
|
|
16
|
+
node$: Observable<Node>
|
|
17
|
+
|
|
18
|
+
constructor(@Inject(Store) private store: Store) {
|
|
19
|
+
this.markFolderItems$ = store.select(markFolderItemsSelector)
|
|
20
|
+
this.node$ = store.select(rightClickedNodeSelector)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
markFolder(path: string, color: string) {
|
|
24
|
+
this.store.dispatch(markPackages([{ path, color }]))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
unmarkFolder(path: string) {
|
|
28
|
+
this.store.dispatch(unmarkPackage({ path }))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { CommonModule } from "@angular/common"
|
|
2
2
|
import { NgModule } from "@angular/core"
|
|
3
|
-
|
|
4
3
|
import { ColorPickerModule } from "../../colorPicker/colorPicker.module"
|
|
5
|
-
import {
|
|
4
|
+
import { MarkFolderRowComponent } from "./markFolderRow.component"
|
|
6
5
|
|
|
7
6
|
@NgModule({
|
|
8
7
|
imports: [CommonModule, ColorPickerModule],
|
|
9
|
-
declarations: [
|
|
10
|
-
exports: [
|
|
8
|
+
declarations: [MarkFolderRowComponent],
|
|
9
|
+
exports: [MarkFolderRowComponent]
|
|
11
10
|
})
|
|
12
|
-
export class
|
|
11
|
+
export class MarkFolderRowModule {}
|
package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { _getMarkFolderItems } from "./markFolderItems.selector"
|
|
2
|
+
|
|
3
|
+
describe("markFolderItemsSelector's _getMarkFolderItems", () => {
|
|
4
|
+
it("should return all colors as unmarked if no node is given", () => {
|
|
5
|
+
expect(_getMarkFolderItems(null, ["#000000", "#ffffff"], [])).toEqual([
|
|
6
|
+
{ color: "#000000", isMarked: false },
|
|
7
|
+
{ color: "#ffffff", isMarked: false }
|
|
8
|
+
])
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it("should recognized a marked folder", () => {
|
|
12
|
+
expect(_getMarkFolderItems({ path: "/root" }, ["#000000", "#ffffff"], [{ color: "#000000", path: "/root" }])).toEqual([
|
|
13
|
+
{ color: "#000000", isMarked: true },
|
|
14
|
+
{ color: "#ffffff", isMarked: false }
|
|
15
|
+
])
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MarkedPackage, Node } from "../../../../codeCharta.model"
|
|
2
|
+
import { createSelector } from "../../../../state/angular-redux/createSelector"
|
|
3
|
+
import { mapColorsSelector } from "../../../../state/store/appSettings/mapColors/mapColors.selector"
|
|
4
|
+
import { markedPackagesSelector } from "../../../../state/store/fileSettings/markedPackages/markedPackages.selector"
|
|
5
|
+
import { findIndexOfMarkedPackageOrParent } from "../../../../state/store/fileSettings/markedPackages/util/findIndexOfMarkedPackageOrParent"
|
|
6
|
+
import { CcState } from "../../../../state/store/store"
|
|
7
|
+
import { rightClickedNodeSelector } from "./rightClickedNode.selector"
|
|
8
|
+
|
|
9
|
+
export type MarkFolderItem = {
|
|
10
|
+
color: string
|
|
11
|
+
isMarked: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const markingColorsSelector = createSelector([mapColorsSelector], mapColors => mapColors.markingColors)
|
|
15
|
+
|
|
16
|
+
export const _getMarkFolderItems = (node: Pick<Node, "path">, markingColors: string[], markedPackages: MarkedPackage[]) => {
|
|
17
|
+
if (node === null) return markingColors.map(color => ({ color, isMarked: false }))
|
|
18
|
+
|
|
19
|
+
const nodeIndexWithinMarkedPackages = findIndexOfMarkedPackageOrParent(markedPackages, node.path)
|
|
20
|
+
return markingColors.map(color => ({
|
|
21
|
+
color,
|
|
22
|
+
isMarked: nodeIndexWithinMarkedPackages !== -1 && color === markedPackages[nodeIndexWithinMarkedPackages].color
|
|
23
|
+
}))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const markFolderItemsSelector: (state: CcState) => MarkFolderItem[] = createSelector(
|
|
27
|
+
[rightClickedNodeSelector, markingColorsSelector, markedPackagesSelector],
|
|
28
|
+
_getMarkFolderItems
|
|
29
|
+
)
|
package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.spec.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CodeMapBuilding } from "../../../codeMap/rendering/codeMapBuilding"
|
|
2
|
+
import { _getNode } from "./rightClickedNode.selector"
|
|
3
|
+
|
|
4
|
+
describe("rightClickedNodeSelector's _getNode", () => {
|
|
5
|
+
it("should return null when no building was right clicked on", () => {
|
|
6
|
+
expect(_getNode(new Map(), null)).toBe(null)
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it("should return node", () => {
|
|
10
|
+
const node = { id: 1 }
|
|
11
|
+
const codeMapBuilding = { node } as CodeMapBuilding
|
|
12
|
+
const idToBuilding = new Map([[1, codeMapBuilding]])
|
|
13
|
+
expect(_getNode(idToBuilding, { nodeId: 1 })).toBe(node)
|
|
14
|
+
})
|
|
15
|
+
})
|
package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createSelector } from "../../../../state/angular-redux/createSelector"
|
|
2
|
+
import { rightClickedNodeDataSelector } from "../../../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector"
|
|
3
|
+
import { idToBuildingSelector } from "../../../../state/store/lookUp/idToBuilding/idToBuilding.selector"
|
|
4
|
+
import { CodeMapBuilding } from "../../../codeMap/rendering/codeMapBuilding"
|
|
5
|
+
|
|
6
|
+
export const _getNode = (idToBuilding: Map<number, CodeMapBuilding>, rightClickedNodeData: { nodeId: number }) =>
|
|
7
|
+
rightClickedNodeData !== null ? idToBuilding.get(rightClickedNodeData.nodeId).node : null
|
|
8
|
+
|
|
9
|
+
export const rightClickedNodeSelector = createSelector([idToBuildingSelector, rightClickedNodeDataSelector], _getNode)
|
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
<md-card id="codemap-context-menu" ng-show="$ctrl.
|
|
1
|
+
<md-card id="codemap-context-menu" ng-show="$ctrl.rightClickedNodeData !== null">
|
|
2
2
|
<div ng-if="$ctrl.nodeIsFolder()">
|
|
3
|
-
<
|
|
4
|
-
<md-button
|
|
5
|
-
ng-repeat="color in $ctrl._viewModel.markingColors track by $index"
|
|
6
|
-
ng-style="{ 'background-color': '{{ color }}' }"
|
|
7
|
-
ng-disabled="primary === color && !isPrimary"
|
|
8
|
-
ng-click="$ctrl.clickColor(color)"
|
|
9
|
-
class="colorButton"
|
|
10
|
-
title="Colorize folder"
|
|
11
|
-
>
|
|
12
|
-
<i class="fa fa-times" ng-if="$ctrl.isNodeOrParentMarked(color)"></i>
|
|
13
|
-
</md-button>
|
|
14
|
-
|
|
15
|
-
<cc-mark-folder-color-picker [mark-folder]="$ctrl.markFolder"></cc-mark-folder-color-picker>
|
|
16
|
-
</div>
|
|
3
|
+
<cc-mark-folder-row></cc-mark-folder-row>
|
|
17
4
|
<md-divider></md-divider>
|
|
18
5
|
</div>
|
|
19
6
|
|
|
@@ -36,19 +36,4 @@ node-context-menu-component {
|
|
|
36
36
|
margin-bottom: 0;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
.colorButton {
|
|
41
|
-
width: 32px !important;
|
|
42
|
-
height: 32px !important;
|
|
43
|
-
min-width: 32px !important;
|
|
44
|
-
min-height: 32px !important;
|
|
45
|
-
|
|
46
|
-
i {
|
|
47
|
-
font-size: 25px;
|
|
48
|
-
margin-left: 0;
|
|
49
|
-
margin-top: 3px;
|
|
50
|
-
color: red;
|
|
51
|
-
text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
39
|
}
|
|
@@ -9,13 +9,11 @@ import {
|
|
|
9
9
|
CONSTANT_HIGHLIGHT,
|
|
10
10
|
TEST_DELTA_MAP_A,
|
|
11
11
|
VALID_FILE_NODE_WITH_ID,
|
|
12
|
-
VALID_NODE_WITH_PATH
|
|
13
|
-
withMockedEventMethods
|
|
12
|
+
VALID_NODE_WITH_PATH
|
|
14
13
|
} from "../../util/dataMocks"
|
|
15
14
|
import { CodeMapPreRenderService } from "../codeMap/codeMap.preRender.service"
|
|
16
15
|
import { StoreService } from "../../state/store.service"
|
|
17
|
-
import {
|
|
18
|
-
import { BlacklistType, MarkedPackage, NodeType } from "../../codeCharta.model"
|
|
16
|
+
import { BlacklistType, NodeType } from "../../codeCharta.model"
|
|
19
17
|
import { addBlacklistItem } from "../../state/store/fileSettings/blacklist/blacklist.actions"
|
|
20
18
|
import { NodeDecorator } from "../../util/nodeDecorator"
|
|
21
19
|
import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService"
|
|
@@ -92,38 +90,6 @@ describe("nodeContextMenuController", () => {
|
|
|
92
90
|
})()
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
describe("constructor", () => {
|
|
96
|
-
it("should subscribe to 'show-node-context-menu' events", () => {
|
|
97
|
-
NodeContextMenuController.subscribeToShowNodeContextMenu = jest.fn()
|
|
98
|
-
|
|
99
|
-
rebuildController()
|
|
100
|
-
|
|
101
|
-
expect(NodeContextMenuController.subscribeToShowNodeContextMenu).toHaveBeenCalledWith($rootScope, nodeContextMenuController)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it("should broadcast 'show-node-context-menu' when 'show' method is called", () => {
|
|
105
|
-
withMockedEventMethods($rootScope)
|
|
106
|
-
NodeContextMenuController.broadcastShowEvent($rootScope, "somepath", "sometype", 42, 24)
|
|
107
|
-
|
|
108
|
-
expect($rootScope.$broadcast).toHaveBeenCalledWith("show-node-context-menu", {
|
|
109
|
-
path: "somepath",
|
|
110
|
-
type: "sometype",
|
|
111
|
-
x: 42,
|
|
112
|
-
y: 24
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it("should subscribe to 'on-building-right-clicked' events", () => {
|
|
117
|
-
const documentAddEventListenerSpy = jest.spyOn(document, "addEventListener")
|
|
118
|
-
rebuildController()
|
|
119
|
-
|
|
120
|
-
expect(documentAddEventListenerSpy).toHaveBeenCalledWith(
|
|
121
|
-
"building-right-clicked",
|
|
122
|
-
nodeContextMenuController.onBuildingRightClicked
|
|
123
|
-
)
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
93
|
describe("onShowNodeContextMenu", () => {
|
|
128
94
|
let mockedWheelTargetElement
|
|
129
95
|
beforeEach(() => {
|
|
@@ -137,10 +103,9 @@ describe("nodeContextMenuController", () => {
|
|
|
137
103
|
})
|
|
138
104
|
|
|
139
105
|
it("should set the correct building after some timeout", () => {
|
|
140
|
-
nodeContextMenuController.
|
|
106
|
+
nodeContextMenuController.showNodeContextMenu("/root", NodeType.FOLDER, 42, 24)
|
|
141
107
|
|
|
142
108
|
expect(nodeContextMenuController["_viewModel"].codeMapNode).toEqual(TEST_DELTA_MAP_A.map)
|
|
143
|
-
expect(nodeContextMenuController["_viewModel"].showNodeContextMenu).toBe(true)
|
|
144
109
|
expect(nodeContextMenuController.calculatePosition).toHaveBeenCalledWith(42, 24)
|
|
145
110
|
expect(nodeContextMenuController.setPosition).toHaveBeenCalledTimes(1)
|
|
146
111
|
expect(nodeContextMenuController.setPosition).toBeCalledWith(1, 2)
|
|
@@ -153,14 +118,14 @@ describe("nodeContextMenuController", () => {
|
|
|
153
118
|
})
|
|
154
119
|
|
|
155
120
|
it("should not shorten the path if it has no sub paths", () => {
|
|
156
|
-
nodeContextMenuController.
|
|
121
|
+
nodeContextMenuController.showNodeContextMenu("/root", NodeType.FOLDER, 42, 24)
|
|
157
122
|
|
|
158
123
|
expect(nodeContextMenuController["_viewModel"].nodePath).toEqual(TEST_DELTA_MAP_A.map.path)
|
|
159
124
|
expect(nodeContextMenuController["_viewModel"].lastPartOfNodePath).toBe(TEST_DELTA_MAP_A.map.path)
|
|
160
125
|
})
|
|
161
126
|
|
|
162
127
|
it("should set the complete and shortened node path", () => {
|
|
163
|
-
nodeContextMenuController.
|
|
128
|
+
nodeContextMenuController.showNodeContextMenu("/root/big leaf", NodeType.FILE, 521, 588)
|
|
164
129
|
const nodePath = TEST_DELTA_MAP_A.map.children[0].path
|
|
165
130
|
|
|
166
131
|
expect(nodeContextMenuController["_viewModel"].nodePath).toEqual(nodePath)
|
|
@@ -170,7 +135,7 @@ describe("nodeContextMenuController", () => {
|
|
|
170
135
|
it("should remove all listener on hide", () => {
|
|
171
136
|
const documentRemoveEventListenerSpy = jest.spyOn(document.body, "removeEventListener")
|
|
172
137
|
|
|
173
|
-
nodeContextMenuController.
|
|
138
|
+
nodeContextMenuController.hideNodeContextMenu()
|
|
174
139
|
|
|
175
140
|
expect(documentRemoveEventListenerSpy).toHaveBeenCalledWith(
|
|
176
141
|
"click",
|
|
@@ -293,80 +258,6 @@ describe("nodeContextMenuController", () => {
|
|
|
293
258
|
})
|
|
294
259
|
})
|
|
295
260
|
|
|
296
|
-
describe("clickColor", () => {
|
|
297
|
-
it("should call unmarkFolder, if current folder is marked with color ", () => {
|
|
298
|
-
nodeContextMenuController.isNodeOrParentMarked = jest.fn().mockReturnValue(true)
|
|
299
|
-
nodeContextMenuController.unmarkFolder = jest.fn()
|
|
300
|
-
|
|
301
|
-
nodeContextMenuController.clickColor("color")
|
|
302
|
-
|
|
303
|
-
expect(nodeContextMenuController.isNodeOrParentMarked).toHaveBeenCalledWith("color")
|
|
304
|
-
expect(nodeContextMenuController.unmarkFolder).toHaveBeenCalled()
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
it("should call markFolder, if current folder is not marked with color ", () => {
|
|
308
|
-
nodeContextMenuController.isNodeOrParentMarked = jest.fn().mockReturnValue(false)
|
|
309
|
-
nodeContextMenuController.markFolder = jest.fn()
|
|
310
|
-
|
|
311
|
-
nodeContextMenuController.clickColor("color")
|
|
312
|
-
|
|
313
|
-
expect(nodeContextMenuController.isNodeOrParentMarked).toHaveBeenCalledWith("color")
|
|
314
|
-
expect(nodeContextMenuController.markFolder).toHaveBeenCalled()
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
describe("currentFolderIsMarkedWithColor", () => {
|
|
319
|
-
it("should return false, if color is undefined", () => {
|
|
320
|
-
const result = nodeContextMenuController.isNodeOrParentMarked()
|
|
321
|
-
|
|
322
|
-
expect(result).toBeFalsy()
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
it("should return false, if color is null", () => {
|
|
326
|
-
const result = nodeContextMenuController.isNodeOrParentMarked(null)
|
|
327
|
-
|
|
328
|
-
expect(result).toBeFalsy()
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
it("should return false, if _viewModel.contextMenuBuilding is undefined", () => {
|
|
332
|
-
nodeContextMenuController["_viewModel"].codeMapNode = undefined
|
|
333
|
-
|
|
334
|
-
const result = nodeContextMenuController.isNodeOrParentMarked("color")
|
|
335
|
-
|
|
336
|
-
expect(result).toBeFalsy()
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
it("should return false, if _viewModel.contextMenuBuilding is null", () => {
|
|
340
|
-
nodeContextMenuController["_viewModel"].codeMapNode = null
|
|
341
|
-
|
|
342
|
-
const result = nodeContextMenuController.isNodeOrParentMarked("color")
|
|
343
|
-
|
|
344
|
-
expect(result).toBeFalsy()
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
it("should return true, if package is marked and matches the color", () => {
|
|
348
|
-
const markedPackages: MarkedPackage[] = [{ path: "/root", color: "color" }]
|
|
349
|
-
storeService.dispatch(setMarkedPackages(markedPackages))
|
|
350
|
-
|
|
351
|
-
nodeContextMenuController["_viewModel"].codeMapNode = VALID_NODE_WITH_PATH
|
|
352
|
-
|
|
353
|
-
const result = nodeContextMenuController.isNodeOrParentMarked("color")
|
|
354
|
-
|
|
355
|
-
expect(result).toBeTruthy()
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
it("should return false, if package is not marked and doesn't match the color of parent folder", () => {
|
|
359
|
-
const markedPackages: MarkedPackage[] = [{ path: "/root", color: "color" }]
|
|
360
|
-
storeService.dispatch(setMarkedPackages(markedPackages))
|
|
361
|
-
|
|
362
|
-
nodeContextMenuController["_viewModel"].codeMapNode = VALID_NODE_WITH_PATH
|
|
363
|
-
|
|
364
|
-
const result = nodeContextMenuController.isNodeOrParentMarked("another color")
|
|
365
|
-
|
|
366
|
-
expect(result).toBeFalsy()
|
|
367
|
-
})
|
|
368
|
-
})
|
|
369
|
-
|
|
370
261
|
describe("excludeNode", () => {
|
|
371
262
|
beforeEach(() => {
|
|
372
263
|
nodeContextMenuController["_viewModel"].codeMapNode = VALID_NODE_WITH_PATH.children[1]
|
|
@@ -442,9 +333,9 @@ describe("nodeContextMenuController", () => {
|
|
|
442
333
|
|
|
443
334
|
describe("onBodyLeftClickHideNodeContextMenu", () => {
|
|
444
335
|
it("should not hide if a click on color-picker tricker occurs", () => {
|
|
445
|
-
const broadcastHideEventSpy = jest.spyOn(
|
|
336
|
+
const broadcastHideEventSpy = jest.spyOn(nodeContextMenuController, "hideNodeContextMenu")
|
|
446
337
|
const mockedMouseEvent: any = {
|
|
447
|
-
composedPath: () => [{ nodeName: "CC-
|
|
338
|
+
composedPath: () => [{ nodeName: "CC-COLOR-PICKER" }]
|
|
448
339
|
}
|
|
449
340
|
nodeContextMenuController.onBodyLeftClickHideNodeContextMenu(mockedMouseEvent)
|
|
450
341
|
|
|
@@ -452,7 +343,7 @@ describe("nodeContextMenuController", () => {
|
|
|
452
343
|
})
|
|
453
344
|
|
|
454
345
|
it("should not hide if a click within color-picker occurs", () => {
|
|
455
|
-
const broadcastHideEventSpy = jest.spyOn(
|
|
346
|
+
const broadcastHideEventSpy = jest.spyOn(nodeContextMenuController, "hideNodeContextMenu")
|
|
456
347
|
const mockedMouseEvent: any = {
|
|
457
348
|
composedPath: () => [{ nodeName: "COLOR-CHROME" }]
|
|
458
349
|
}
|
|
@@ -462,7 +353,7 @@ describe("nodeContextMenuController", () => {
|
|
|
462
353
|
})
|
|
463
354
|
|
|
464
355
|
it("should hide if clicked somewhere but not within the color-picker", () => {
|
|
465
|
-
const broadcastHideEventSpy = jest.spyOn(
|
|
356
|
+
const broadcastHideEventSpy = jest.spyOn(nodeContextMenuController, "hideNodeContextMenu")
|
|
466
357
|
const mockedMouseEvent: any = {
|
|
467
358
|
composedPath: () => [{ nodeName: "DIV" }]
|
|
468
359
|
}
|
|
@@ -1,47 +1,35 @@
|
|
|
1
1
|
import "./nodeContextMenu.component.scss"
|
|
2
2
|
import angular, { IRootScopeService } from "angular"
|
|
3
|
-
import { BlacklistItem, BlacklistType, CodeMapNode,
|
|
3
|
+
import { BlacklistItem, BlacklistType, CodeMapNode, NodeType } from "../../codeCharta.model"
|
|
4
4
|
import { CodeMapPreRenderService } from "../codeMap/codeMap.preRender.service"
|
|
5
5
|
import { StoreService } from "../../state/store.service"
|
|
6
6
|
import { addBlacklistItem, removeBlacklistItem } from "../../state/store/fileSettings/blacklist/blacklist.actions"
|
|
7
7
|
import { CodeMapBuilding } from "../codeMap/rendering/codeMapBuilding"
|
|
8
|
-
import {
|
|
9
|
-
import { getCodeMapNodeFromPath } from "../../util/codeMapHelper"
|
|
8
|
+
import { getCodeMapNodeFromPath, isLeaf } from "../../util/codeMapHelper"
|
|
10
9
|
import { ThreeSceneService } from "../codeMap/threeViewer/threeSceneService"
|
|
11
10
|
import { DialogService } from "../dialog/dialog.service"
|
|
12
11
|
import { BlacklistService } from "../../state/store/fileSettings/blacklist/blacklist.service"
|
|
13
12
|
import { ERROR_MESSAGES } from "../../util/fileValidator"
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
13
|
+
import { Store } from "../../state/store/store"
|
|
14
|
+
import { rightClickedNodeDataSelector } from "../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector"
|
|
15
|
+
import {
|
|
16
|
+
RightClickedNodeData,
|
|
17
|
+
setRightClickedNodeData
|
|
18
|
+
} from "../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions"
|
|
17
19
|
|
|
18
20
|
export enum ClickType {
|
|
19
21
|
RightClick = 2
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface HideNodeContextMenuSubscriber {
|
|
27
|
-
onHideNodeContextMenu()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class NodeContextMenuController implements ShowNodeContextMenuSubscriber, HideNodeContextMenuSubscriber, MapColorsSubscriber {
|
|
31
|
-
private static SHOW_NODE_CONTEXT_MENU_EVENT = "show-node-context-menu"
|
|
32
|
-
private static HIDE_NODE_CONTEXT_MENU_EVENT = "hide-node-context-menu"
|
|
33
|
-
private static instance: NodeContextMenuController
|
|
24
|
+
export class NodeContextMenuController {
|
|
25
|
+
private rightClickedNodeData: RightClickedNodeData
|
|
34
26
|
|
|
35
27
|
private _viewModel: {
|
|
36
28
|
codeMapNode: CodeMapNode
|
|
37
|
-
showNodeContextMenu: boolean
|
|
38
|
-
markingColors: string[]
|
|
39
29
|
nodePath: string
|
|
40
30
|
lastPartOfNodePath: string
|
|
41
31
|
} = {
|
|
42
32
|
codeMapNode: null,
|
|
43
|
-
showNodeContextMenu: false,
|
|
44
|
-
markingColors: null,
|
|
45
33
|
nodePath: "",
|
|
46
34
|
lastPartOfNodePath: ""
|
|
47
35
|
}
|
|
@@ -57,35 +45,38 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
57
45
|
private blacklistService: BlacklistService
|
|
58
46
|
) {
|
|
59
47
|
"ngInject"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
48
|
+
Store.store.subscribe(() => {
|
|
49
|
+
const state = Store.store.getState()
|
|
50
|
+
const rightClickedNodeData = rightClickedNodeDataSelector(state)
|
|
51
|
+
if (this.rightClickedNodeData === rightClickedNodeData) return
|
|
52
|
+
|
|
53
|
+
this.rightClickedNodeData = rightClickedNodeData
|
|
54
|
+
if (rightClickedNodeData === null) {
|
|
55
|
+
this.hideNodeContextMenu()
|
|
56
|
+
} else {
|
|
57
|
+
const rightClickedNode = state.lookUp.idToNode.get(rightClickedNodeData.nodeId)
|
|
58
|
+
const nodeType = isLeaf(rightClickedNode) ? NodeType.FILE : NodeType.FOLDER
|
|
59
|
+
this.showNodeContextMenu(
|
|
60
|
+
rightClickedNode.path,
|
|
61
|
+
nodeType,
|
|
62
|
+
rightClickedNodeData.xPositionOfRightClickEvent,
|
|
63
|
+
rightClickedNodeData.yPositionOfRightClickEvent
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
74
67
|
}
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
showNodeContextMenu(path: string, nodeType: string, mouseX: number, mouseY: number) {
|
|
77
70
|
this._viewModel.codeMapNode = getCodeMapNodeFromPath(path, nodeType, this.codeMapPreRenderService.getRenderMap())
|
|
78
71
|
this._viewModel.nodePath = path
|
|
79
72
|
this._viewModel.lastPartOfNodePath = `${path.lastIndexOf("/") === 0 ? "" : "..."}${path.slice(path.lastIndexOf("/"))}`
|
|
80
73
|
|
|
81
|
-
this._viewModel.showNodeContextMenu = true
|
|
82
|
-
|
|
83
74
|
const { x, y } = this.calculatePosition(mouseX, mouseY)
|
|
84
75
|
this.setPosition(x, y)
|
|
85
76
|
|
|
86
77
|
// Add event listeners, so that opened node context menu can be closed again later
|
|
87
78
|
// when clicking (left or right button) or using the mouse wheel on the body element.
|
|
88
|
-
document.body.addEventListener("click", this.onBodyLeftClickHideNodeContextMenu,
|
|
79
|
+
document.body.addEventListener("click", this.onBodyLeftClickHideNodeContextMenu, false)
|
|
89
80
|
document.body.addEventListener("mousedown", this.onBodyRightClickHideNodeContextMenu, true)
|
|
90
81
|
document.getElementById("codeMap").addEventListener("wheel", this.onMapWheelHideNodeContextMenu, true)
|
|
91
82
|
}
|
|
@@ -94,7 +85,7 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
94
85
|
if (this.isEventFromColorPicker(mouseEvent)) return
|
|
95
86
|
|
|
96
87
|
// Just close node context menu, if you click anywhere on the map.
|
|
97
|
-
this.
|
|
88
|
+
this.hideNodeContextMenu()
|
|
98
89
|
}
|
|
99
90
|
|
|
100
91
|
onBodyRightClickHideNodeContextMenu = event => {
|
|
@@ -102,23 +93,19 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
102
93
|
// Otherwise, if mouseup would be used and you would move the map with keeping the right button pressed,
|
|
103
94
|
// the menu would not be closed.
|
|
104
95
|
if (event.button === ClickType.RightClick) {
|
|
105
|
-
this.
|
|
96
|
+
this.hideNodeContextMenu()
|
|
106
97
|
}
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
onMapWheelHideNodeContextMenu = () => {
|
|
110
101
|
// If you zoom in and out the map, the node context menu should be closed.
|
|
111
|
-
this.
|
|
102
|
+
this.hideNodeContextMenu()
|
|
112
103
|
}
|
|
113
104
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
onHideNodeContextMenu() {
|
|
119
|
-
this._viewModel.showNodeContextMenu = false
|
|
105
|
+
hideNodeContextMenu = () => {
|
|
106
|
+
this.storeService.dispatch(setRightClickedNodeData(null))
|
|
120
107
|
|
|
121
|
-
// remove event listeners registered in
|
|
108
|
+
// remove event listeners registered in showNodeContextMenu
|
|
122
109
|
document.body.removeEventListener("click", this.onBodyLeftClickHideNodeContextMenu, true)
|
|
123
110
|
document.body.removeEventListener("mousedown", this.onBodyRightClickHideNodeContextMenu, true)
|
|
124
111
|
document.getElementById("codeMap").removeEventListener("wheel", this.onMapWheelHideNodeContextMenu, true)
|
|
@@ -161,35 +148,12 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
161
148
|
|
|
162
149
|
addNodeToConstantHighlight() {
|
|
163
150
|
this.threeSceneService.addNodeAndChildrenToConstantHighlight(this._viewModel.codeMapNode)
|
|
164
|
-
this.
|
|
151
|
+
this.hideNodeContextMenu()
|
|
165
152
|
}
|
|
166
153
|
|
|
167
154
|
removeNodeFromConstantHighlight() {
|
|
168
155
|
this.threeSceneService.removeNodeAndChildrenFromConstantHighlight(this._viewModel.codeMapNode)
|
|
169
|
-
this.
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
clickColor(color: string) {
|
|
173
|
-
if (this.isNodeOrParentMarked(color)) {
|
|
174
|
-
this.unmarkFolder()
|
|
175
|
-
} else {
|
|
176
|
-
this.markFolder(color)
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
markFolder = (color: string) => {
|
|
181
|
-
this.storeService.dispatch(
|
|
182
|
-
markPackages([
|
|
183
|
-
{
|
|
184
|
-
path: this._viewModel.codeMapNode.path,
|
|
185
|
-
color
|
|
186
|
-
}
|
|
187
|
-
])
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
unmarkFolder() {
|
|
192
|
-
this.storeService.dispatch(unmarkPackage(this._viewModel.codeMapNode))
|
|
156
|
+
this.hideNodeContextMenu()
|
|
193
157
|
}
|
|
194
158
|
|
|
195
159
|
calculatePosition(mouseX: number, mouseY: number) {
|
|
@@ -206,39 +170,9 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
206
170
|
angular.element(this.$element[0].children[0]).css("left", `${x}px`)
|
|
207
171
|
}
|
|
208
172
|
|
|
209
|
-
isNodeOrParentMarked(color?: string) {
|
|
210
|
-
if (!color || !this._viewModel.codeMapNode) {
|
|
211
|
-
return false
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (this.isNodeMarked()) {
|
|
215
|
-
return this.packageMatchesColor(color)
|
|
216
|
-
}
|
|
217
|
-
return this.packageMatchesColorOfParentMP(color)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
173
|
private isEventFromColorPicker(mouseEvent: MouseEvent) {
|
|
221
174
|
const elements = mouseEvent.composedPath() as Node[]
|
|
222
|
-
return elements.some(element => element?.nodeName === "CC-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
private isNodeMarked() {
|
|
226
|
-
return this.storeService.getState().fileSettings.markedPackages.some(mp => mp.path === this._viewModel.codeMapNode.path)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private packageMatchesColor(color: string) {
|
|
230
|
-
return this.storeService
|
|
231
|
-
.getState()
|
|
232
|
-
.fileSettings.markedPackages.some(mp => mp.path === this._viewModel.codeMapNode.path && mp.color === color)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
private packageMatchesColorOfParentMP(color: string) {
|
|
236
|
-
const { markedPackages } = this.storeService.getState().fileSettings
|
|
237
|
-
const index = findIndexOfMarkedPackageOrParent(markedPackages, this._viewModel.codeMapNode.path)
|
|
238
|
-
if (index === -1) {
|
|
239
|
-
return false
|
|
240
|
-
}
|
|
241
|
-
return this.storeService.getState().fileSettings.markedPackages[index].color === color
|
|
175
|
+
return elements.some(element => element?.nodeName === "CC-COLOR-PICKER" || element?.nodeName === "COLOR-CHROME")
|
|
242
176
|
}
|
|
243
177
|
|
|
244
178
|
isNodeConstantlyHighlighted() {
|
|
@@ -255,34 +189,6 @@ export class NodeContextMenuController implements ShowNodeContextMenuSubscriber,
|
|
|
255
189
|
nodeIsFolder() {
|
|
256
190
|
return this._viewModel.codeMapNode?.children?.length > 0
|
|
257
191
|
}
|
|
258
|
-
|
|
259
|
-
static broadcastShowEvent($rootScope, path: string, type: string, x, y) {
|
|
260
|
-
const rootScope = $rootScope || NodeContextMenuController.instance.$rootScope
|
|
261
|
-
rootScope.$broadcast(NodeContextMenuController.SHOW_NODE_CONTEXT_MENU_EVENT, {
|
|
262
|
-
path,
|
|
263
|
-
type,
|
|
264
|
-
x,
|
|
265
|
-
y
|
|
266
|
-
})
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
static broadcastHideEvent($rootScope?: IRootScopeService) {
|
|
270
|
-
const rootScope = $rootScope || NodeContextMenuController.instance.$rootScope
|
|
271
|
-
rootScope.$broadcast(NodeContextMenuController.HIDE_NODE_CONTEXT_MENU_EVENT)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
static subscribeToShowNodeContextMenu($rootScope: IRootScopeService, subscriber: ShowNodeContextMenuSubscriber) {
|
|
275
|
-
$rootScope.$on(NodeContextMenuController.SHOW_NODE_CONTEXT_MENU_EVENT, (_event, data) => {
|
|
276
|
-
subscriber.onShowNodeContextMenu(data.path, data.type, data.x, data.y)
|
|
277
|
-
})
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
static subscribeToHideNodeContextMenu($rootScope: IRootScopeService, subscriber: HideNodeContextMenuSubscriber) {
|
|
281
|
-
const rootScope = $rootScope || NodeContextMenuController.instance.$rootScope
|
|
282
|
-
rootScope.$on(NodeContextMenuController.HIDE_NODE_CONTEXT_MENU_EVENT, () => {
|
|
283
|
-
subscriber.onHideNodeContextMenu()
|
|
284
|
-
})
|
|
285
|
-
}
|
|
286
192
|
}
|
|
287
193
|
|
|
288
194
|
export const nodeContextMenuComponent = {
|
|
@@ -5,11 +5,11 @@ import angular from "angular"
|
|
|
5
5
|
import { downgradeComponent } from "@angular/upgrade/static"
|
|
6
6
|
|
|
7
7
|
import { nodeContextMenuComponent } from "./nodeContextMenu.component"
|
|
8
|
-
import { MarkFolderColorPickerComponent } from "./markFolderColorPicker/markFolderColorPicker.component"
|
|
9
8
|
import { FocusButtonsComponent } from "./focusButtons/focusButtons.component"
|
|
9
|
+
import { MarkFolderRowComponent } from "./markFolderRow/markFolderRow.component"
|
|
10
10
|
|
|
11
11
|
angular
|
|
12
12
|
.module("app.codeCharta.ui.nodeContextMenu", ["app.codeCharta.state", "app.codeCharta.ui"])
|
|
13
13
|
.component(nodeContextMenuComponent.selector, nodeContextMenuComponent)
|
|
14
|
-
.directive("
|
|
14
|
+
.directive("ccMarkFolderRow", downgradeComponent({ component: MarkFolderRowComponent }))
|
|
15
15
|
.directive("ccFocusButtons", downgradeComponent({ component: FocusButtonsComponent }))
|