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.
- package/app/app.module.ts +20 -10
- package/app/codeCharta/codeCharta.component.html +0 -2
- package/app/codeCharta/codeCharta.model.ts +1 -0
- package/app/codeCharta/services/ajs-upgraded-providers.ts +13 -0
- package/app/codeCharta/state/angular-redux/effects/createEffect.spec.ts +37 -0
- package/app/codeCharta/state/angular-redux/effects/createEffect.ts +25 -0
- package/app/codeCharta/state/angular-redux/effects/effects.module.ts +36 -0
- package/app/codeCharta/state/angular-redux/ofType.ts +11 -0
- package/app/codeCharta/state/angular-redux/state.ts +12 -0
- package/app/codeCharta/state/angular-redux/store.ts +1 -1
- package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.spec.ts +60 -0
- package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/addBlacklistItemsIfNotResultsInEmptyMap.effect.ts +56 -0
- package/app/codeCharta/state/effects/addBlacklistItemsIfNotResultsInEmptyMap/resultsInEmptyMap.ts +22 -0
- package/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.html +3 -0
- package/app/codeCharta/state/effects/nodeContextMenu/excludeButton/excludeButton.component.ts +26 -0
- package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.html +13 -0
- package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts +55 -0
- package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.component.ts +34 -0
- package/app/codeCharta/state/effects/nodeContextMenu/flattenButtons/flattenButtons.module.ts +11 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.html +0 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.spec.ts +2 -2
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.component.ts +5 -5
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/focusButtons.module.ts +1 -1
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/isNodeFocused.pipe.spec.ts +0 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/focusButtons/isNodeFocused.pipe.ts +2 -2
- package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.html +6 -0
- package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.spec.ts +64 -0
- package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.ts +39 -0
- package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.module.ts +11 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.html +3 -3
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.scss +0 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts +2 -2
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.ts +6 -6
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.module.ts +1 -1
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts +0 -0
- package/app/codeCharta/state/effects/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +29 -0
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/nodeContextMenu.e2e.ts +4 -16
- package/app/codeCharta/{ui → state/effects}/nodeContextMenu/nodeContextMenu.po.ts +1 -1
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.spec.ts +78 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenu.service.ts +72 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.spec.ts +11 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.ts +8 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.html +17 -0
- package/app/codeCharta/{ui/nodeContextMenu/nodeContextMenu.component.scss → state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.scss} +6 -11
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts +49 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts +19 -0
- package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.module.ts +18 -0
- package/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.spec.ts +32 -0
- package/app/codeCharta/state/effects/nodeContextMenu/openNodeContextMenu.effect.ts +33 -0
- package/app/codeCharta/state/effects/nodeContextMenu/rightClickedCodeMapNode.selector.ts +8 -0
- package/app/codeCharta/state/effects/unfocusNodesOnLoadingMap.effect.spec.ts +47 -0
- package/app/codeCharta/state/effects/unfocusNodesOnLoadingMap.effect.ts +18 -0
- package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/areAllNecessaryRenderDataAvailable.selector.ts +30 -0
- package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areDynamicSettingsAvailable.spec.ts +36 -0
- package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areDynamicSettingsAvailable.ts +10 -0
- package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areMetricsAvailable.spec.ts +13 -0
- package/app/codeCharta/state/selectors/allNecessaryRenderDataAvailable/utils/areMetricsAvailable.ts +8 -0
- package/app/codeCharta/state/store/appSettings/appSettings.actions.ts +2 -0
- package/app/codeCharta/state/store/appSettings/appSettings.reducer.ts +2 -0
- package/app/codeCharta/state/store/appSettings/invertArea/invertArea.actions.ts +32 -0
- package/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.spec.ts +26 -0
- package/app/codeCharta/state/store/appSettings/invertArea/invertArea.reducer.ts +12 -0
- package/app/codeCharta/state/store/appSettings/invertArea/invertArea.selector.ts +3 -0
- package/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.spec.ts +14 -3
- package/app/codeCharta/state/store/appSettings/isLoadingMap/isLoadingMap.reducer.ts +41 -6
- package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.actions.ts +33 -2
- package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.spec.ts +17 -1
- package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.reducer.ts +3 -1
- package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.service.spec.ts +1 -19
- package/app/codeCharta/state/store/fileSettings/blacklist/blacklist.service.ts +5 -28
- package/app/codeCharta/state/store/lookUp/idToNode/idToNode.selector.ts +4 -0
- package/app/codeCharta/state/store/lookUp/lookUp.selector.ts +3 -0
- package/app/codeCharta/state/store/metricData/nodeMetricData/nodeMetricData.service.ts +0 -4
- package/app/codeCharta/state/store/store.ts +5 -1
- package/app/codeCharta/state/store.service.spec.ts +20 -7
- package/app/codeCharta/state/store.service.ts +3 -36
- package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.html +3 -1
- package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.scss +6 -2
- package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.component.ts +1 -1
- package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.module.ts +3 -0
- package/app/codeCharta/ui/areaSettingsPanel/areaSettingsPanel.po.ts +4 -4
- package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.html +1 -0
- package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.scss +26 -0
- package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.spec.ts +29 -0
- package/app/codeCharta/ui/areaSettingsPanel/invertAreaOption/invertAreaOption.component.ts +24 -0
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/aggregationType.pipe.spec.ts +19 -0
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/{aggregationSymbol.pipe.ts → aggregationType.pipe.ts} +4 -4
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.html +4 -12
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.scss +11 -20
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.component.spec.ts +8 -15
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/attributeTypeSelector.module.ts +2 -2
- package/app/codeCharta/ui/codeMap/codeMap.preRender.service.spec.ts +1 -9
- package/app/codeCharta/ui/codeMap/codeMap.preRender.service.ts +9 -32
- package/app/codeCharta/ui/dialogs/dialogs.ts +3 -0
- package/app/codeCharta/ui/dialogs/errorDialog/errorDialog.component.html +7 -0
- package/app/codeCharta/ui/dialogs/errorDialog/errorDialog.component.ts +9 -0
- package/app/codeCharta/ui/mapTreeView/mapTreeView.level.e2e.ts +1 -1
- package/app/codeCharta/ui/mapTreeView/mapTreeView.level.po.ts +1 -1
- package/app/codeCharta/ui/ribbonBar/ribbonBar.component.html +2 -2
- package/app/codeCharta/ui/ribbonBar/ribbonBar.e2e.ts +3 -3
- package/app/codeCharta/ui/searchBar/searchBar.component.html +5 -0
- package/app/codeCharta/ui/searchBar/searchBar.component.scss +11 -0
- package/app/codeCharta/ui/searchBar/searchBar.component.spec.ts +10 -0
- package/app/codeCharta/ui/searchBar/searchBar.component.ts +1 -1
- package/app/codeCharta/ui/sortingOption/sortingOption.component.spec.ts +1 -1
- package/app/codeCharta/ui/ui.ts +0 -2
- package/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.spec.ts +1 -1
- package/app/codeCharta/util/algorithm/treeMapLayout/treeMapGenerator.ts +14 -7
- package/app/codeCharta/util/customConfigBuilder.ts +1 -0
- package/app/codeCharta/util/dataMocks.ts +2 -0
- package/app/codeCharta/util/reduxHelper.ts +11 -0
- package/app/material/material.module.ts +17 -1
- package/conf/webpack.loaders.js +4 -1
- package/dist/webpack/bundle.js +4582 -950
- package/dist/webpack/bundle.js.map +1 -1
- package/package.json +2 -2
- package/app/codeCharta/ui/attributeSideBar/attributeTypeSelector/aggregationSymbol.pipe.spec.ts +0 -19
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +0 -29
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.spec.ts +0 -15
- package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.ts +0 -9
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.html +0 -45
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.spec.ts +0 -365
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.ts +0 -198
- package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.module.ts +0 -15
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/angular"
|
|
2
|
+
import { TestBed } from "@angular/core/testing"
|
|
3
|
+
import userEvent from "@testing-library/user-event"
|
|
4
|
+
import { HighlightButtonsModule } from "./highlightButtons.module"
|
|
5
|
+
import { ThreeSceneServiceToken } from "../../../../services/ajs-upgraded-providers"
|
|
6
|
+
import { HighlightButtonsComponent } from "./highlightButtons.component"
|
|
7
|
+
import { VALID_FILE_NODE_WITH_ID as codeMapNode } from "../../../../util/dataMocks"
|
|
8
|
+
import { State } from "../../../angular-redux/state"
|
|
9
|
+
import { CodeMapNode } from "../../../../codeCharta.model"
|
|
10
|
+
|
|
11
|
+
describe("flattenButtonsComponent", () => {
|
|
12
|
+
let threeSceneService
|
|
13
|
+
let state
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
threeSceneService = createMockedThreeSceneService()
|
|
17
|
+
state = createMockedState()
|
|
18
|
+
TestBed.configureTestingModule({
|
|
19
|
+
imports: [HighlightButtonsModule],
|
|
20
|
+
providers: [
|
|
21
|
+
{ provide: ThreeSceneServiceToken, useValue: threeSceneService },
|
|
22
|
+
{ provide: State, useValue: state }
|
|
23
|
+
]
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it("should let a user permanently highlight and remove permanently highlight of a node", async () => {
|
|
28
|
+
state.getValue().lookUp.idToBuilding.set(codeMapNode.id, { id: codeMapNode.id, node: codeMapNode })
|
|
29
|
+
|
|
30
|
+
const { rerender } = await render(HighlightButtonsComponent, {
|
|
31
|
+
excludeComponentDeclaration: true,
|
|
32
|
+
componentProperties: { codeMapNode }
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(screen.queryByText("REMOVE HIGHLIGHT")).toBe(null)
|
|
36
|
+
userEvent.click(screen.getByText("KEEP HIGHLIGHT"))
|
|
37
|
+
|
|
38
|
+
rerender({ codeMapNode: null })
|
|
39
|
+
rerender({ codeMapNode })
|
|
40
|
+
|
|
41
|
+
expect(screen.queryByText("KEEP HIGHLIGHT")).toBe(null)
|
|
42
|
+
userEvent.click(screen.getByText("REMOVE HIGHLIGHT"))
|
|
43
|
+
|
|
44
|
+
rerender({ codeMapNode: null })
|
|
45
|
+
rerender({ codeMapNode })
|
|
46
|
+
|
|
47
|
+
expect(screen.queryByText("REMOVE HIGHLIGHT")).toBe(null)
|
|
48
|
+
expect(screen.queryByText("KEEP HIGHLIGHT")).not.toBe(null)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
function createMockedThreeSceneService() {
|
|
52
|
+
const highlighted = new Map()
|
|
53
|
+
return {
|
|
54
|
+
addNodeAndChildrenToConstantHighlight: (node: CodeMapNode) => highlighted.set(node.id, node),
|
|
55
|
+
removeNodeAndChildrenFromConstantHighlight: (node: CodeMapNode) => highlighted.delete(node.id),
|
|
56
|
+
getConstantHighlight: () => highlighted
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function createMockedState() {
|
|
61
|
+
const idToBuilding = new Map()
|
|
62
|
+
return { getValue: () => ({ lookUp: { idToBuilding } }) }
|
|
63
|
+
}
|
|
64
|
+
})
|
package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.component.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Component, Inject, Input, OnChanges, SimpleChanges } from "@angular/core"
|
|
2
|
+
import { CodeMapNode } from "../../../../codeCharta.model"
|
|
3
|
+
import { ThreeSceneServiceToken } from "../../../../services/ajs-upgraded-providers"
|
|
4
|
+
import { State } from "../../../angular-redux/state"
|
|
5
|
+
import { ThreeSceneService } from "../../../../ui/codeMap/threeViewer/threeSceneService"
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: "cc-highlight-buttons",
|
|
9
|
+
template: require("./highlightButtons.component.html")
|
|
10
|
+
})
|
|
11
|
+
export class HighlightButtonsComponent implements OnChanges {
|
|
12
|
+
@Input() codeMapNode: CodeMapNode
|
|
13
|
+
|
|
14
|
+
isHighlighted: boolean
|
|
15
|
+
|
|
16
|
+
constructor(@Inject(ThreeSceneServiceToken) private threeSceneService: ThreeSceneService, @Inject(State) private state: State) {}
|
|
17
|
+
|
|
18
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
19
|
+
if (changes.codeMapNode) this.isHighlighted = this.calculateIsHighlighted()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
addNodeToConstantHighlight() {
|
|
23
|
+
this.threeSceneService.addNodeAndChildrenToConstantHighlight(this.codeMapNode)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
removeNodeFromConstantHighlight() {
|
|
27
|
+
this.threeSceneService.removeNodeAndChildrenFromConstantHighlight(this.codeMapNode)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private calculateIsHighlighted() {
|
|
31
|
+
if (!this.codeMapNode) return false
|
|
32
|
+
|
|
33
|
+
const { lookUp } = this.state.getValue()
|
|
34
|
+
const codeMapBuilding = lookUp.idToBuilding.get(this.codeMapNode.id)
|
|
35
|
+
if (!codeMapBuilding) return false
|
|
36
|
+
|
|
37
|
+
return this.threeSceneService.getConstantHighlight().has(codeMapBuilding.id)
|
|
38
|
+
}
|
|
39
|
+
}
|
package/app/codeCharta/state/effects/nodeContextMenu/highlightButtons/highlightButtons.module.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CommonModule } from "@angular/common"
|
|
2
|
+
import { NgModule } from "@angular/core"
|
|
3
|
+
import { MaterialModule } from "../../../../../material/material.module"
|
|
4
|
+
import { HighlightButtonsComponent } from "./highlightButtons.component"
|
|
5
|
+
|
|
6
|
+
@NgModule({
|
|
7
|
+
imports: [CommonModule, MaterialModule],
|
|
8
|
+
declarations: [HighlightButtonsComponent],
|
|
9
|
+
exports: [HighlightButtonsComponent]
|
|
10
|
+
})
|
|
11
|
+
export class HighlightButtonsModule {}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<div class="row" *ngIf="
|
|
1
|
+
<div class="row" *ngIf="codeMapNode$ | async as codeMapNode">
|
|
2
2
|
<ng-container *ngFor="let markFolderItem of markFolderItems$ | async">
|
|
3
3
|
<button
|
|
4
4
|
[style.background-color]="markFolderItem.color"
|
|
5
|
-
(click)="markFolderItem.isMarked ? unmarkFolder(
|
|
5
|
+
(click)="markFolderItem.isMarked ? unmarkFolder(codeMapNode.path) : markFolder(codeMapNode.path, markFolderItem.color)"
|
|
6
6
|
class="colorButton"
|
|
7
7
|
title="Colorize folder"
|
|
8
8
|
>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<cc-color-picker
|
|
14
14
|
[hexColor]="'#ff0000'"
|
|
15
|
-
(onColorChange)="markFolder(
|
|
15
|
+
(onColorChange)="markFolder(codeMapNode.path, $event)"
|
|
16
16
|
[triggerTemplate]="colorPickerTriggerTemplate"
|
|
17
17
|
></cc-color-picker>
|
|
18
18
|
</div>
|
|
File without changes
|
|
@@ -3,8 +3,8 @@ import { fireEvent, render } from "@testing-library/angular"
|
|
|
3
3
|
import { MarkFolderRowComponent } from "./markFolderRow.component"
|
|
4
4
|
import { MarkFolderRowModule } from "./markFolderRow.module"
|
|
5
5
|
|
|
6
|
-
jest.mock("
|
|
7
|
-
|
|
6
|
+
jest.mock("../rightClickedCodeMapNode.selector", () => ({
|
|
7
|
+
rightClickedCodeMapNodeSelector: () => ({ path: "/root" })
|
|
8
8
|
}))
|
|
9
9
|
|
|
10
10
|
describe("markFolderRow component", () => {
|
package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.component.ts
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./markFolderRow.component.scss"
|
|
2
2
|
import { Component, Inject } from "@angular/core"
|
|
3
|
-
import { Store } from "../../../
|
|
4
|
-
import { markPackages, unmarkPackage } from "../../../
|
|
3
|
+
import { Store } from "../../../angular-redux/store"
|
|
4
|
+
import { markPackages, unmarkPackage } from "../../../store/fileSettings/markedPackages/markedPackages.actions"
|
|
5
5
|
import { Observable } from "rxjs"
|
|
6
6
|
import { MarkFolderItem, markFolderItemsSelector } from "./selectors/markFolderItems.selector"
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { CodeMapNode } from "../../../../codeCharta.model"
|
|
8
|
+
import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector"
|
|
9
9
|
|
|
10
10
|
@Component({
|
|
11
11
|
selector: "cc-mark-folder-row",
|
|
@@ -13,11 +13,11 @@ import { rightClickedNodeSelector } from "./selectors/rightClickedNode.selector"
|
|
|
13
13
|
})
|
|
14
14
|
export class MarkFolderRowComponent {
|
|
15
15
|
markFolderItems$: Observable<MarkFolderItem[]>
|
|
16
|
-
|
|
16
|
+
codeMapNode$: Observable<CodeMapNode>
|
|
17
17
|
|
|
18
18
|
constructor(@Inject(Store) private store: Store) {
|
|
19
19
|
this.markFolderItems$ = store.select(markFolderItemsSelector)
|
|
20
|
-
this.
|
|
20
|
+
this.codeMapNode$ = store.select(rightClickedCodeMapNodeSelector)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
markFolder(path: string, color: string) {
|
package/app/codeCharta/{ui → state/effects}/nodeContextMenu/markFolderRow/markFolderRow.module.ts
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommonModule } from "@angular/common"
|
|
2
2
|
import { NgModule } from "@angular/core"
|
|
3
|
-
import { ColorPickerModule } from "
|
|
3
|
+
import { ColorPickerModule } from "../../../../ui/colorPicker/colorPicker.module"
|
|
4
4
|
import { MarkFolderRowComponent } from "./markFolderRow.component"
|
|
5
5
|
|
|
6
6
|
@NgModule({
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MarkedPackage } from "../../../../../codeCharta.model"
|
|
2
|
+
import { createSelector } from "../../../../angular-redux/createSelector"
|
|
3
|
+
import { mapColorsSelector } from "../../../../store/appSettings/mapColors/mapColors.selector"
|
|
4
|
+
import { markedPackagesSelector } from "../../../../store/fileSettings/markedPackages/markedPackages.selector"
|
|
5
|
+
import { findIndexOfMarkedPackageOrParent } from "../../../../store/fileSettings/markedPackages/util/findIndexOfMarkedPackageOrParent"
|
|
6
|
+
import { CcState } from "../../../../store/store"
|
|
7
|
+
import { rightClickedCodeMapNodeSelector } from "../../rightClickedCodeMapNode.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: { path?: string } | null, 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
|
+
[rightClickedCodeMapNodeSelector, markingColorsSelector, markedPackagesSelector],
|
|
28
|
+
_getMarkFolderItems
|
|
29
|
+
)
|
|
@@ -1,36 +1,24 @@
|
|
|
1
|
-
import { goto } from "
|
|
1
|
+
import { goto } from "../../../../puppeteer.helper"
|
|
2
2
|
import { NodeContextMenuPageObject } from "./nodeContextMenu.po"
|
|
3
|
-
import { SearchPanelModeSelectorPageObject } from "
|
|
4
|
-
import { MapTreeViewLevelPageObject } from "
|
|
5
|
-
import { CodeMapPageObject } from "
|
|
6
|
-
import { ERROR_MESSAGES } from "../../util/fileValidator"
|
|
7
|
-
import { DialogErrorPageObject } from "../dialog/dialog.error.po"
|
|
3
|
+
import { SearchPanelModeSelectorPageObject } from "../../../ui/searchPanelModeSelector/searchPanelModeSelector.po"
|
|
4
|
+
import { MapTreeViewLevelPageObject } from "../../../ui/mapTreeView/mapTreeView.level.po"
|
|
5
|
+
import { CodeMapPageObject } from "../../../ui/codeMap/codeMap.po"
|
|
8
6
|
|
|
9
7
|
describe("NodeContextMenu", () => {
|
|
10
8
|
let contextMenu: NodeContextMenuPageObject
|
|
11
9
|
let searchPanelModeSelector: SearchPanelModeSelectorPageObject
|
|
12
10
|
let mapTreeViewLevel: MapTreeViewLevelPageObject
|
|
13
11
|
let codeMap: CodeMapPageObject
|
|
14
|
-
let dialogError: DialogErrorPageObject
|
|
15
12
|
|
|
16
13
|
beforeEach(async () => {
|
|
17
14
|
contextMenu = new NodeContextMenuPageObject()
|
|
18
15
|
searchPanelModeSelector = new SearchPanelModeSelectorPageObject()
|
|
19
16
|
mapTreeViewLevel = new MapTreeViewLevelPageObject()
|
|
20
17
|
codeMap = new CodeMapPageObject()
|
|
21
|
-
dialogError = new DialogErrorPageObject()
|
|
22
18
|
|
|
23
19
|
await goto()
|
|
24
20
|
})
|
|
25
21
|
|
|
26
|
-
it("should show error message when user excludes all files", async () => {
|
|
27
|
-
await searchPanelModeSelector.toggleTreeView()
|
|
28
|
-
await mapTreeViewLevel.openContextMenu("/root")
|
|
29
|
-
await contextMenu.clickOnExclude()
|
|
30
|
-
|
|
31
|
-
expect(await dialogError.getMessage()).toEqual(`${ERROR_MESSAGES.blacklistError}`)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
22
|
it("right clicking a folder should open a context menu with color options", async () => {
|
|
35
23
|
await searchPanelModeSelector.toggleTreeView()
|
|
36
24
|
await mapTreeViewLevel.openContextMenu("/root")
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ApplicationInitStatus } from "@angular/core"
|
|
2
|
+
import { TestBed } from "@angular/core/testing"
|
|
3
|
+
import { fireEvent } from "@testing-library/angular"
|
|
4
|
+
import { MaterialModule } from "../../../../material/material.module"
|
|
5
|
+
import { EffectsModule } from "../../angular-redux/effects/effects.module"
|
|
6
|
+
import { NodeContextMenuService } from "./nodeContextMenu.service"
|
|
7
|
+
import { NodeContextMenuCardModule } from "./nodeContextMenuCard/nodeContextMenuCard.module"
|
|
8
|
+
import { OpenNodeContextMenuEffect } from "./openNodeContextMenu.effect"
|
|
9
|
+
|
|
10
|
+
describe("nodeContextMenuService", () => {
|
|
11
|
+
let mockedWheelTargetElement
|
|
12
|
+
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
mockedWheelTargetElement = { addEventListener: jest.fn(), removeEventListener: jest.fn() }
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
jest.spyOn(document, "getElementById").mockImplementation(() => mockedWheelTargetElement)
|
|
17
|
+
|
|
18
|
+
TestBed.configureTestingModule({
|
|
19
|
+
imports: [MaterialModule, EffectsModule.forRoot([OpenNodeContextMenuEffect]), NodeContextMenuCardModule],
|
|
20
|
+
providers: [NodeContextMenuService]
|
|
21
|
+
})
|
|
22
|
+
await TestBed.inject(ApplicationInitStatus).donePromise
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it("should close on document click", () => {
|
|
26
|
+
const nodeContextMenu = TestBed.inject(NodeContextMenuService)
|
|
27
|
+
const closeSpy = jest.spyOn(nodeContextMenu, "close")
|
|
28
|
+
nodeContextMenu.open(10, 10)
|
|
29
|
+
|
|
30
|
+
document.dispatchEvent(new MouseEvent("click"))
|
|
31
|
+
|
|
32
|
+
expect(closeSpy).toHaveBeenCalled()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("should not close when clicking within (its) color picker", () => {
|
|
36
|
+
const nodeContextMenu = TestBed.inject(NodeContextMenuService)
|
|
37
|
+
const closeSpy = jest.spyOn(nodeContextMenu, "close")
|
|
38
|
+
nodeContextMenu.open(10, 10)
|
|
39
|
+
|
|
40
|
+
const mockedMouseEvent = { composedPath: () => [{ nodeName: "COLOR-CHROME" }] } as unknown as MouseEvent
|
|
41
|
+
nodeContextMenu["onLeftClickHideNodeContextMenu"](mockedMouseEvent)
|
|
42
|
+
|
|
43
|
+
expect(closeSpy).not.toHaveBeenCalled()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it("should not close when opening its color picker", () => {
|
|
47
|
+
const nodeContextMenu = TestBed.inject(NodeContextMenuService)
|
|
48
|
+
const closeSpy = jest.spyOn(nodeContextMenu, "close")
|
|
49
|
+
nodeContextMenu.open(10, 10)
|
|
50
|
+
|
|
51
|
+
const mockedMouseEvent = { composedPath: () => [{ nodeName: "CC-COLOR-PICKER" }] } as unknown as MouseEvent
|
|
52
|
+
nodeContextMenu["onLeftClickHideNodeContextMenu"](mockedMouseEvent)
|
|
53
|
+
|
|
54
|
+
expect(closeSpy).not.toHaveBeenCalled()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("should remove all listeners when closing", () => {
|
|
58
|
+
const documentRemoveEventListenerSpy = jest.spyOn(document, "removeEventListener")
|
|
59
|
+
const nodeContextMenu = TestBed.inject(NodeContextMenuService)
|
|
60
|
+
|
|
61
|
+
nodeContextMenu.close()
|
|
62
|
+
|
|
63
|
+
expect(documentRemoveEventListenerSpy).toHaveBeenCalledWith("click", nodeContextMenu["onLeftClickHideNodeContextMenu"], true)
|
|
64
|
+
expect(documentRemoveEventListenerSpy).toHaveBeenCalledWith("mousedown", nodeContextMenu["onRightClickHideNodeContextMenu"], true)
|
|
65
|
+
expect(mockedWheelTargetElement.removeEventListener).toHaveBeenCalledWith("wheel", nodeContextMenu.close, true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it("should prevent default browser context menu to open", () => {
|
|
69
|
+
const nodeContextMenu = TestBed.inject(NodeContextMenuService)
|
|
70
|
+
nodeContextMenu.open(10, 10)
|
|
71
|
+
let wasDefaultContextMenuPrevented
|
|
72
|
+
document.addEventListener("contextmenu", event => {
|
|
73
|
+
wasDefaultContextMenuPrevented = event.defaultPrevented
|
|
74
|
+
})
|
|
75
|
+
fireEvent.contextMenu(nodeContextMenu["overlayReference"].overlayElement)
|
|
76
|
+
expect(wasDefaultContextMenuPrevented).toBe(true)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Overlay, OverlayRef } from "@angular/cdk/overlay"
|
|
2
|
+
import { ComponentPortal } from "@angular/cdk/portal"
|
|
3
|
+
import { Inject, Injectable } from "@angular/core"
|
|
4
|
+
import { Store } from "../../angular-redux/store"
|
|
5
|
+
import { setRightClickedNodeData } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions"
|
|
6
|
+
import { NodeContextMenuCardComponent } from "./nodeContextMenuCard/nodeContextMenuCard.component"
|
|
7
|
+
|
|
8
|
+
@Injectable({ providedIn: "root" })
|
|
9
|
+
export class NodeContextMenuService {
|
|
10
|
+
private overlayReference: OverlayRef | null = null
|
|
11
|
+
|
|
12
|
+
constructor(@Inject(Overlay) private overlay: Overlay, @Inject(Store) private store: Store) {}
|
|
13
|
+
|
|
14
|
+
open(x: number, y: number) {
|
|
15
|
+
const positionStrategy = this.overlay
|
|
16
|
+
.position()
|
|
17
|
+
.flexibleConnectedTo({ x, y })
|
|
18
|
+
.withPositions([
|
|
19
|
+
{
|
|
20
|
+
originX: "end",
|
|
21
|
+
originY: "bottom",
|
|
22
|
+
overlayX: "start",
|
|
23
|
+
overlayY: "top"
|
|
24
|
+
}
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
this.overlayReference = this.overlay.create({
|
|
28
|
+
positionStrategy,
|
|
29
|
+
scrollStrategy: this.overlay.scrollStrategies.close()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
this.overlayReference.attach(new ComponentPortal(NodeContextMenuCardComponent))
|
|
33
|
+
|
|
34
|
+
this.overlayReference.overlayElement.addEventListener("contextmenu", event => {
|
|
35
|
+
event.preventDefault()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
document.addEventListener("click", this.onLeftClickHideNodeContextMenu, false)
|
|
39
|
+
document.addEventListener("mousedown", this.onRightClickHideNodeContextMenu, true)
|
|
40
|
+
document.getElementById("codeMap").addEventListener("wheel", this.close, true)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
close = () => {
|
|
44
|
+
document.removeEventListener("click", this.onLeftClickHideNodeContextMenu, true)
|
|
45
|
+
document.removeEventListener("mousedown", this.onRightClickHideNodeContextMenu, true)
|
|
46
|
+
document.getElementById("codeMap").removeEventListener("wheel", this.close, true)
|
|
47
|
+
|
|
48
|
+
this.store.dispatch(setRightClickedNodeData(null))
|
|
49
|
+
|
|
50
|
+
if (this.overlayReference) {
|
|
51
|
+
this.overlayReference.dispose()
|
|
52
|
+
this.overlayReference = null
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private onLeftClickHideNodeContextMenu = (mouseEvent: MouseEvent) => {
|
|
57
|
+
if (this.isEventFromColorPicker(mouseEvent)) return
|
|
58
|
+
|
|
59
|
+
this.close()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private onRightClickHideNodeContextMenu = event => {
|
|
63
|
+
if (event.button !== 2) return
|
|
64
|
+
// Close on right click down, to close before the map gets potential moved by right clicked
|
|
65
|
+
this.close()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private isEventFromColorPicker(mouseEvent: MouseEvent) {
|
|
69
|
+
const elements = mouseEvent.composedPath() as Node[]
|
|
70
|
+
return elements.some(element => element?.nodeName === "CC-COLOR-PICKER" || element?.nodeName === "COLOR-CHROME")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LastPartOfNodePathPipe } from "./lastPartOfNodePath.pipe"
|
|
2
|
+
|
|
3
|
+
describe("lastPartOfNodePathPipe", () => {
|
|
4
|
+
it("should shorten children with '...'-prefix", () => {
|
|
5
|
+
expect(new LastPartOfNodePathPipe().transform("/root/child.ts")).toBe(".../child.ts")
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it("should not shorten a top level entry", () => {
|
|
9
|
+
expect(new LastPartOfNodePathPipe().transform("/root")).toBe("/root")
|
|
10
|
+
})
|
|
11
|
+
})
|
package/app/codeCharta/state/effects/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from "@angular/core"
|
|
2
|
+
|
|
3
|
+
@Pipe({ name: "lastPartOfNodePath" })
|
|
4
|
+
export class LastPartOfNodePathPipe implements PipeTransform {
|
|
5
|
+
transform(path: string) {
|
|
6
|
+
return `${path.lastIndexOf("/") === 0 ? "" : "..."}${path.slice(path.lastIndexOf("/"))}`
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<mat-card id="codemap-context-menu" *ngIf="codeMapNode$ | async; let codeMapNode">
|
|
2
|
+
<div *ngIf="codeMapNode?.children?.length > 0">
|
|
3
|
+
<cc-mark-folder-row></cc-mark-folder-row>
|
|
4
|
+
<mat-divider></mat-divider>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="button-group">
|
|
8
|
+
<button mat-button disabled="true" title="{{ codeMapNode.path }}">
|
|
9
|
+
{{ codeMapNode.path | lastPartOfNodePath }}
|
|
10
|
+
</button>
|
|
11
|
+
|
|
12
|
+
<cc-focus-buttons [codeMapNode]="codeMapNode"></cc-focus-buttons>
|
|
13
|
+
<cc-flatten-buttons [codeMapNode]="codeMapNode"></cc-flatten-buttons>
|
|
14
|
+
<cc-highlight-buttons [codeMapNode]="codeMapNode"></cc-highlight-buttons>
|
|
15
|
+
<cc-exclude-button [codeMapNode]="codeMapNode"></cc-exclude-button>
|
|
16
|
+
</div>
|
|
17
|
+
</mat-card>
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
z-index: 2000 !important;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
node-context-menu-component {
|
|
7
|
-
#codemap-context-menu {
|
|
8
|
-
position: absolute;
|
|
9
|
-
z-index: 2000;
|
|
10
|
-
}
|
|
1
|
+
#codemap-context-menu {
|
|
2
|
+
padding: 2px;
|
|
11
3
|
|
|
12
4
|
.button-group {
|
|
13
5
|
display: inline-grid;
|
|
6
|
+
width: 100%;
|
|
14
7
|
}
|
|
15
8
|
|
|
16
9
|
.png-icon {
|
|
10
|
+
width: 17px;
|
|
11
|
+
height: 17px;
|
|
17
12
|
margin: 5px auto auto;
|
|
18
13
|
padding: 0;
|
|
19
14
|
display: inline-block;
|
|
20
15
|
background-repeat: no-repeat no-repeat;
|
|
21
16
|
pointer-events: none;
|
|
22
17
|
}
|
|
23
|
-
|
|
18
|
+
|
|
24
19
|
[mat-button] {
|
|
25
20
|
width: 100%;
|
|
26
21
|
text-align: left;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TestBed } from "@angular/core/testing"
|
|
2
|
+
import { render, screen } from "@testing-library/angular"
|
|
3
|
+
import { mocked } from "ts-jest/utils"
|
|
4
|
+
import { ThreeSceneServiceToken } from "../../../../services/ajs-upgraded-providers"
|
|
5
|
+
import { VALID_FILE_NODE_WITH_ID, VALID_NODE_WITH_PATH } from "../../../../util/dataMocks"
|
|
6
|
+
import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector"
|
|
7
|
+
import { NodeContextMenuCardComponent } from "./nodeContextMenuCard.component"
|
|
8
|
+
import { NodeContextMenuCardModule } from "./nodeContextMenuCard.module"
|
|
9
|
+
|
|
10
|
+
jest.mock("../rightClickedCodeMapNode.selector", () => ({
|
|
11
|
+
rightClickedCodeMapNodeSelector: jest.fn()
|
|
12
|
+
}))
|
|
13
|
+
const mockedRightClickedCodeMapNodeSelector = mocked(rightClickedCodeMapNodeSelector)
|
|
14
|
+
|
|
15
|
+
describe("NodeContextMenuCardComponent", () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
TestBed.configureTestingModule({
|
|
18
|
+
imports: [NodeContextMenuCardModule],
|
|
19
|
+
providers: [
|
|
20
|
+
{
|
|
21
|
+
provide: ThreeSceneServiceToken,
|
|
22
|
+
useValue: {
|
|
23
|
+
addNodeAndChildrenToConstantHighlight: jest.fn(),
|
|
24
|
+
removeNodeAndChildrenFromConstantHighlight: jest.fn(),
|
|
25
|
+
getConstantHighlight: jest.fn()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("should not display mark folder option if node is a leaf", async () => {
|
|
33
|
+
mockedRightClickedCodeMapNodeSelector.mockImplementation(() => VALID_FILE_NODE_WITH_ID)
|
|
34
|
+
await render(NodeContextMenuCardComponent, { excludeComponentDeclaration: true })
|
|
35
|
+
expect(screen.queryByTitle("Colorize folder")).toBe(null)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("should display all information", async () => {
|
|
39
|
+
mockedRightClickedCodeMapNodeSelector.mockImplementation(() => VALID_NODE_WITH_PATH)
|
|
40
|
+
await render(NodeContextMenuCardComponent, { excludeComponentDeclaration: true })
|
|
41
|
+
|
|
42
|
+
expect(screen.queryByText("/root")).not.toBe(null)
|
|
43
|
+
expect(screen.queryByText("FOCUS")).not.toBe(null)
|
|
44
|
+
expect(screen.queryByText("FLATTEN")).not.toBe(null)
|
|
45
|
+
expect(screen.queryByText("KEEP HIGHLIGHT")).not.toBe(null)
|
|
46
|
+
expect(screen.queryByText("EXCLUDE")).not.toBe(null)
|
|
47
|
+
expect(screen.queryAllByTitle("Colorize folder").length).toBe(5)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "./nodeContextMenuCard.component.scss"
|
|
2
|
+
import { Component, Inject, OnInit } from "@angular/core"
|
|
3
|
+
import { Store } from "../../../angular-redux/store"
|
|
4
|
+
import { rightClickedCodeMapNodeSelector } from "../rightClickedCodeMapNode.selector"
|
|
5
|
+
import { Observable } from "rxjs"
|
|
6
|
+
import { CodeMapNode } from "../../../../codeCharta.model"
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
template: require("./nodeContextMenuCard.component.html")
|
|
10
|
+
})
|
|
11
|
+
export class NodeContextMenuCardComponent implements OnInit {
|
|
12
|
+
codeMapNode$: Observable<CodeMapNode>
|
|
13
|
+
|
|
14
|
+
constructor(@Inject(Store) private store: Store) {}
|
|
15
|
+
|
|
16
|
+
ngOnInit(): void {
|
|
17
|
+
this.codeMapNode$ = this.store.select(rightClickedCodeMapNodeSelector)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CommonModule } from "@angular/common"
|
|
2
|
+
import { NgModule } from "@angular/core"
|
|
3
|
+
import { MaterialModule } from "../../../../../material/material.module"
|
|
4
|
+
import { ExcludeButtonComponent } from "../excludeButton/excludeButton.component"
|
|
5
|
+
import { FlattenButtonsModule } from "../flattenButtons/flattenButtons.module"
|
|
6
|
+
import { FocusButtonsModule } from "../focusButtons/focusButtons.module"
|
|
7
|
+
import { HighlightButtonsModule } from "../highlightButtons/highlightButtons.module"
|
|
8
|
+
import { MarkFolderRowModule } from "../markFolderRow/markFolderRow.module"
|
|
9
|
+
import { LastPartOfNodePathPipe } from "./lastPartOfNodePath.pipe"
|
|
10
|
+
import { NodeContextMenuCardComponent } from "./nodeContextMenuCard.component"
|
|
11
|
+
|
|
12
|
+
@NgModule({
|
|
13
|
+
imports: [CommonModule, MaterialModule, FlattenButtonsModule, FocusButtonsModule, HighlightButtonsModule, MarkFolderRowModule],
|
|
14
|
+
declarations: [NodeContextMenuCardComponent, LastPartOfNodePathPipe, ExcludeButtonComponent],
|
|
15
|
+
exports: [NodeContextMenuCardComponent],
|
|
16
|
+
entryComponents: [NodeContextMenuCardComponent]
|
|
17
|
+
})
|
|
18
|
+
export class NodeContextMenuCardModule {}
|
|
@@ -0,0 +1,32 @@
|
|
|
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 { EffectsModule } from "../../angular-redux/effects/effects.module"
|
|
6
|
+
import { setRightClickedNodeData } from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions"
|
|
7
|
+
import { NodeContextMenuService } from "./nodeContextMenu.service"
|
|
8
|
+
import { OpenNodeContextMenuEffect } from "./openNodeContextMenu.effect"
|
|
9
|
+
|
|
10
|
+
describe("OpenNodeContextMenuEffect", () => {
|
|
11
|
+
let openSpy
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
openSpy = jest.fn()
|
|
14
|
+
EffectsModule.actions$ = new Subject<Action>()
|
|
15
|
+
TestBed.configureTestingModule({
|
|
16
|
+
imports: [EffectsModule.forRoot([OpenNodeContextMenuEffect])],
|
|
17
|
+
providers: [{ provide: NodeContextMenuService, useValue: { open: openSpy } }]
|
|
18
|
+
})
|
|
19
|
+
await TestBed.inject(ApplicationInitStatus).donePromise
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it("should ignore empty rightClickedNodeData", () => {
|
|
23
|
+
EffectsModule.actions$.next(setRightClickedNodeData(null))
|
|
24
|
+
expect(openSpy).not.toHaveBeenCalled()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it("should open node context menu", () => {
|
|
28
|
+
EffectsModule.actions$.next(setRightClickedNodeData({ nodeId: 1, xPositionOfRightClickEvent: 2, yPositionOfRightClickEvent: 3 }))
|
|
29
|
+
expect(openSpy).toHaveBeenCalledTimes(1)
|
|
30
|
+
expect(openSpy).toHaveBeenCalledWith(2, 3)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Inject, Injectable } from "@angular/core"
|
|
2
|
+
import { createEffect } from "../../angular-redux/effects/createEffect"
|
|
3
|
+
import { Actions, ActionsToken } from "../../angular-redux/effects/effects.module"
|
|
4
|
+
import { ofType } from "../../angular-redux/ofType"
|
|
5
|
+
import { NodeContextMenuService } from "./nodeContextMenu.service"
|
|
6
|
+
import {
|
|
7
|
+
RightClickedNodeDataActions,
|
|
8
|
+
SetRightClickedNodeDataAction
|
|
9
|
+
} from "../../store/appStatus/rightClickedNodeData/rightClickedNodeData.actions"
|
|
10
|
+
import { tap } from "rxjs"
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class OpenNodeContextMenuEffect {
|
|
14
|
+
constructor(
|
|
15
|
+
@Inject(ActionsToken) private actions$: Actions,
|
|
16
|
+
@Inject(NodeContextMenuService) private nodeContextMenu: NodeContextMenuService
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
openNodeContextMenu$ = createEffect(
|
|
20
|
+
() =>
|
|
21
|
+
this.actions$.pipe(
|
|
22
|
+
ofType<SetRightClickedNodeDataAction>(RightClickedNodeDataActions.SET_RIGHT_CLICKED_NODE_DATA),
|
|
23
|
+
tap(rightClickedNodeData => {
|
|
24
|
+
if (rightClickedNodeData.payload)
|
|
25
|
+
this.nodeContextMenu.open(
|
|
26
|
+
rightClickedNodeData.payload.xPositionOfRightClickEvent,
|
|
27
|
+
rightClickedNodeData.payload.yPositionOfRightClickEvent
|
|
28
|
+
)
|
|
29
|
+
})
|
|
30
|
+
),
|
|
31
|
+
{ dispatch: false }
|
|
32
|
+
)
|
|
33
|
+
}
|