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.
Files changed (67) hide show
  1. package/app/app.module.ts +18 -8
  2. package/app/codeCharta/codeCharta.component.ts +2 -0
  3. package/app/codeCharta/codeCharta.model.ts +2 -0
  4. package/app/codeCharta/codeCharta.service.spec.ts +41 -50
  5. package/app/codeCharta/codeCharta.service.ts +33 -32
  6. package/app/codeCharta/e2e/url.e2e.ts +1 -1
  7. package/app/codeCharta/state/store/appStatus/appStatus.reducer.ts +3 -1
  8. package/app/codeCharta/state/store/appStatus/appStatus.selector.ts +3 -0
  9. package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions.ts +23 -0
  10. package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.reducer.ts +15 -0
  11. package/app/codeCharta/state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector.ts +4 -0
  12. package/app/codeCharta/state/store/state.actions.ts +3 -1
  13. package/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts +6 -8
  14. package/app/codeCharta/ui/customConfigs/customConfigs.component.html +9 -9
  15. package/app/codeCharta/ui/dialog/dialog.addCustomConfigSettings.component.html +2 -2
  16. package/app/codeCharta/ui/dialog/dialog.changelog.component.scss +15 -0
  17. package/app/codeCharta/ui/dialog/dialog.changelog.component.spec.ts +15 -15
  18. package/app/codeCharta/ui/dialog/dialog.changelog.component.ts +2 -1
  19. package/app/codeCharta/ui/dialog/dialog.service.spec.ts +68 -0
  20. package/app/codeCharta/ui/dialog/dialog.service.ts +38 -17
  21. package/app/codeCharta/ui/edgeChooser/edgeChooser.e2e.ts +3 -2
  22. package/app/codeCharta/ui/fileChooser/fileChooser.e2e.ts +5 -6
  23. package/app/codeCharta/ui/filePanel/filePanel.component.html +24 -106
  24. package/app/codeCharta/ui/filePanel/filePanel.component.scss +12 -57
  25. package/app/codeCharta/ui/filePanel/filePanel.component.spec.ts +40 -72
  26. package/app/codeCharta/ui/filePanel/filePanel.component.ts +29 -81
  27. package/app/codeCharta/ui/filePanel/filePanel.module.ts +13 -1
  28. package/app/codeCharta/ui/filePanel/filePanel.po.ts +6 -24
  29. package/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.html +23 -0
  30. package/app/codeCharta/ui/filePanel/filePanelDeltaSelector/filePanelDeltaSelector.component.ts +18 -0
  31. package/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.html +18 -0
  32. package/app/codeCharta/ui/filePanel/filePanelFileSelector/filePanelFileSelector.component.ts +16 -0
  33. package/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.html +18 -0
  34. package/app/codeCharta/ui/filePanel/filePanelStateButtons/filePanelStateButtons.component.ts +11 -0
  35. package/app/codeCharta/ui/mapTreeView/mapTreeView.level.e2e.ts +7 -5
  36. package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.html +1 -1
  37. package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.spec.ts +6 -16
  38. package/app/codeCharta/ui/mapTreeView/mapTreeViewLevel/mapTreeViewLevel.component.ts +15 -11
  39. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.html +22 -0
  40. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.scss +31 -0
  41. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts +35 -0
  42. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.ts +30 -0
  43. package/app/codeCharta/ui/nodeContextMenu/{markFolderColorPicker/markFolderColorPicker.module.ts → markFolderRow/markFolderRow.module.ts} +4 -5
  44. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts +17 -0
  45. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.ts +29 -0
  46. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.spec.ts +15 -0
  47. package/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/rightClickedNode.selector.ts +9 -0
  48. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.html +2 -15
  49. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.scss +0 -15
  50. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.spec.ts +10 -119
  51. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.component.ts +40 -134
  52. package/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.module.ts +2 -2
  53. package/app/codeCharta/ui/ribbonBar/ribbonBar.component.html +1 -1
  54. package/app/codeCharta/ui/toolBar/toolBar.component.html +1 -1
  55. package/app/codeCharta/ui/toolBar/toolBar.component.scss +1 -1
  56. package/app/codeCharta/ui/ui.ts +2 -2
  57. package/app/codeCharta/util/customConfigHelper.spec.ts +155 -60
  58. package/app/codeCharta/util/customConfigHelper.ts +33 -3
  59. package/app/codeCharta/util/dataMocks.ts +4 -2
  60. package/app/codeCharta/util/fileValidator.spec.ts +69 -182
  61. package/app/codeCharta/util/fileValidator.ts +61 -37
  62. package/dist/webpack/bundle.js +852 -485
  63. package/dist/webpack/bundle.js.map +1 -1
  64. package/package.json +1 -1
  65. package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.html +0 -9
  66. package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.scss +0 -13
  67. package/app/codeCharta/ui/nodeContextMenu/markFolderColorPicker/markFolderColorPicker.component.ts +0 -10
@@ -1,22 +1,16 @@
1
1
  import "./filePanel.component.scss"
2
2
  import { IRootScopeService } from "angular"
3
3
  import { StoreService } from "../../state/store.service"
4
- import { removeFile, setDeltaByNames, setMultipleByNames, setSingleByName } from "../../state/store/files/files.actions"
4
+ import { removeFile, setDeltaByNames, setMultipleByNames } from "../../state/store/files/files.actions"
5
5
  import { FilesSelectionSubscriber, FilesService } from "../../state/store/files/files.service"
6
- import {
7
- fileStatesAvailable,
8
- getFileNameOf,
9
- getVisibleFileStates,
10
- isDeltaState,
11
- isPartialState,
12
- isSingleState
13
- } from "../../model/files/files.helper"
6
+ import { fileStatesAvailable, getFileNameOf, getVisibleFileStates, isDeltaState, isPartialState } from "../../model/files/files.helper"
14
7
  import { FileSelectionState, FileState } from "../../model/files/files"
15
8
  import { CodeChartaService } from "../../codeCharta.service"
16
9
  import { removeRecentFile } from "../../state/store/dynamicSettings/recentFiles/recentFiles.actions"
10
+ import { MapColorsService, MapColorsSubscriber } from "../../state/store/appSettings/mapColors/mapColors.service"
11
+ import { MapColors } from "../../codeCharta.model"
17
12
 
18
13
  interface SelectedFileNames {
19
- single: string
20
14
  delta: {
21
15
  reference: string
22
16
  comparison: string
@@ -24,34 +18,29 @@ interface SelectedFileNames {
24
18
  partial: string[]
25
19
  }
26
20
 
27
- export class FilePanelController implements FilesSelectionSubscriber {
21
+ export class FilePanelController implements FilesSelectionSubscriber, MapColorsSubscriber {
28
22
  private lastRenderState: FileSelectionState
29
23
 
30
24
  private _viewModel: {
31
- isSingleState: boolean
32
25
  isPartialState: boolean
33
26
  isDeltaState: boolean
34
27
  files: FileState[]
35
28
  renderState: FileSelectionState
36
29
  selectedFileNames: SelectedFileNames
37
- pictogramFirstFileColor: string
38
30
  pictogramUpperColor: string
39
31
  pictogramLowerColor: string
40
32
  } = {
41
- isSingleState: null,
42
33
  isPartialState: null,
43
34
  isDeltaState: null,
44
35
  files: null,
45
36
  renderState: null,
46
37
  selectedFileNames: {
47
- single: null,
48
38
  delta: {
49
39
  reference: null,
50
40
  comparison: null
51
41
  },
52
42
  partial: []
53
43
  },
54
- pictogramFirstFileColor: null,
55
44
  pictogramUpperColor: null,
56
45
  pictogramLowerColor: null
57
46
  }
@@ -59,41 +48,25 @@ export class FilePanelController implements FilesSelectionSubscriber {
59
48
  constructor(private $rootScope: IRootScopeService, private storeService: StoreService) {
60
49
  "ngInject"
61
50
  FilesService.subscribe(this.$rootScope, this)
51
+ MapColorsService.subscribe(this.$rootScope, this)
62
52
  }
63
53
 
64
- onRemoveFile(filename, state, $event): void {
54
+ onMapColorsChanged(mapColors: MapColors) {
55
+ this._viewModel.pictogramUpperColor = mapColors.positiveDelta
56
+ this._viewModel.pictogramLowerColor = mapColors.negativeDelta
57
+ }
58
+
59
+ onRemoveFile(filename, $event): void {
65
60
  this.storeService.dispatch(removeFile(filename))
66
61
  this.storeService.dispatch(removeRecentFile(filename))
67
62
 
68
63
  const files = this.storeService.getState().files
69
- if (state === FileSelectionState.Single) {
70
- this.singleStateFileRemove(files)
71
- } else {
72
- this.partialStateFileRemove(files)
73
- }
64
+ this.partialStateFileRemove(files)
74
65
 
75
66
  $event.stopPropagation()
76
67
  $event.preventDefault()
77
68
  }
78
69
 
79
- singleStateFileRemove(files: FileState[]) {
80
- if (!isSingleState(files)) {
81
- this.selectRemainingFile(files)
82
- } else {
83
- this.keepSelection()
84
- }
85
- }
86
-
87
- private keepSelection() {
88
- const selectedFile = this.storeService.getState().files.find(fileState => fileState.selectedAs === FileSelectionState.Single)
89
- this.onSingleFileChange(getFileNameOf(selectedFile))
90
- }
91
-
92
- private selectRemainingFile(files: FileState[]) {
93
- const remainingFile = files[files.length - 1]
94
- this.onSingleFileChange(getFileNameOf(remainingFile))
95
- }
96
-
97
70
  private partialStateFileRemove(files: FileState[]) {
98
71
  const selectedFiles = files.filter(x => x.selectedAs === FileSelectionState.Partial).map(fileState => getFileNameOf(fileState))
99
72
 
@@ -106,31 +79,20 @@ export class FilePanelController implements FilesSelectionSubscriber {
106
79
 
107
80
  onFilesSelectionChanged(files: FileState[]) {
108
81
  this._viewModel.files = files
109
- this._viewModel.isSingleState = isSingleState(files)
110
82
  this._viewModel.isPartialState = isPartialState(files)
111
83
  this._viewModel.isDeltaState = isDeltaState(files)
112
- this.setPictogramColor()
113
84
  this.updateSelectedFileNamesInViewModel()
114
85
  this.lastRenderState = this._viewModel.renderState
115
86
  }
116
87
 
117
- onPartialSelectionClosed() {
88
+ onPartialSelectionClosed = () => {
118
89
  this.updateSelectedFileNamesInViewModel()
119
90
  }
120
91
 
121
- private setPictogramColor() {
122
- this._viewModel.pictogramFirstFileColor = "#808080"
123
- this._viewModel.pictogramUpperColor = this.storeService.getState().appSettings.mapColors.positiveDelta
124
- this._viewModel.pictogramLowerColor = this.storeService.getState().appSettings.mapColors.negativeDelta
125
- }
126
-
127
92
  private updateSelectedFileNamesInViewModel() {
128
93
  const visibleFileStates = getVisibleFileStates(this._viewModel.files)
129
94
 
130
- if (this._viewModel.isSingleState) {
131
- this._viewModel.renderState = FileSelectionState.Single
132
- this._viewModel.selectedFileNames.single = visibleFileStates[0].file.fileMeta.fileName
133
- } else if (this._viewModel.isDeltaState) {
95
+ if (this._viewModel.isDeltaState) {
134
96
  this._viewModel.renderState = FileSelectionState.Comparison
135
97
 
136
98
  let reference = visibleFileStates[0].file.fileMeta.fileName
@@ -148,26 +110,24 @@ export class FilePanelController implements FilesSelectionSubscriber {
148
110
  }
149
111
  }
150
112
 
151
- onSingleFileChange(singleFileName: string) {
152
- this.storeService.dispatch(setSingleByName(singleFileName))
153
- const rootName = this._viewModel.files.find(x => x.selectedAs === FileSelectionState.Single).file.map.name
154
- CodeChartaService.updateRootData(rootName)
155
- }
156
-
157
- onDeltaReferenceFileChange(referenceFileName: string) {
158
- const rootName = this._viewModel.files.find(x => x.file.fileMeta.fileName === referenceFileName).file.map.name
113
+ onDeltaReferenceFileChange = (referenceFileName: string) => {
114
+ const rootFile = this._viewModel.files.find(x => x.file.fileMeta.fileName === referenceFileName)
115
+ if (!rootFile) {
116
+ return
117
+ }
118
+ const rootName = rootFile.file.map.name
159
119
  CodeChartaService.updateRootData(rootName)
160
120
  this.storeService.dispatch(setDeltaByNames(referenceFileName, this._viewModel.selectedFileNames.delta.comparison))
161
121
  }
162
122
 
163
- onDeltaComparisonFileChange(comparisonFileName: string) {
123
+ onDeltaComparisonFileChange = (comparisonFileName: string) => {
164
124
  const referenceFileName = this._viewModel.selectedFileNames.delta.reference
165
125
  const rootName = this._viewModel.files.find(x => x.file.fileMeta.fileName === referenceFileName).file.map.name
166
126
  CodeChartaService.updateRootData(rootName)
167
127
  this.storeService.dispatch(setDeltaByNames(referenceFileName, comparisonFileName))
168
128
  }
169
129
 
170
- onPartialFilesChange(partialFileNames: string[]) {
130
+ onPartialFilesChange = (partialFileNames: string[]) => {
171
131
  if (partialFileNames.length > 0) {
172
132
  this.storeService.dispatch(setMultipleByNames(partialFileNames))
173
133
  } else {
@@ -175,26 +135,17 @@ export class FilePanelController implements FilesSelectionSubscriber {
175
135
  }
176
136
  }
177
137
 
178
- onSingleStateSelected() {
179
- this._viewModel.selectedFileNames.single = this.getLastVisibleFileName()
180
- this.onSingleFileChange(this._viewModel.selectedFileNames.single)
181
- }
182
-
183
- onPartialStateSelected() {
184
- this.selectRecentPartialFiles()
185
- }
186
-
187
- onDeltaStateSelected() {
138
+ onDeltaStateSelected = () => {
188
139
  this._viewModel.selectedFileNames.delta.reference = this.getLastVisibleFileName()
189
140
  this.onDeltaComparisonFileChange(null)
190
141
  }
191
142
 
192
- selectAllPartialFiles() {
143
+ selectAllPartialFiles = () => {
193
144
  const allFileNames = this._viewModel.files.map(x => x.file.fileMeta.fileName)
194
145
  this.onPartialFilesChange(allFileNames)
195
146
  }
196
147
 
197
- selectRecentPartialFiles() {
148
+ selectRecentPartialFiles = () => {
198
149
  const recentFileNames = this.storeService.getState().dynamicSettings.recentFiles
199
150
  if (recentFileNames.length > 0) {
200
151
  this.onPartialFilesChange(recentFileNames)
@@ -203,11 +154,11 @@ export class FilePanelController implements FilesSelectionSubscriber {
203
154
  }
204
155
  }
205
156
 
206
- selectZeroPartialFiles() {
157
+ selectZeroPartialFiles = () => {
207
158
  this.onPartialFilesChange([])
208
159
  }
209
160
 
210
- invertPartialFileSelection() {
161
+ invertPartialFileSelection = () => {
211
162
  const invertedFileNames: string[] = []
212
163
  const partialFileNames = new Set(this._viewModel.selectedFileNames.partial)
213
164
 
@@ -225,9 +176,6 @@ export class FilePanelController implements FilesSelectionSubscriber {
225
176
  }
226
177
 
227
178
  private getLastVisibleFileName() {
228
- if (this.lastRenderState === FileSelectionState.Single) {
229
- return this._viewModel.selectedFileNames.single
230
- }
231
179
  if (this.lastRenderState === FileSelectionState.Partial) {
232
180
  const visibleFileStates = getVisibleFileStates(this._viewModel.files)
233
181
  if (fileStatesAvailable(this._viewModel.files)) {
@@ -242,7 +190,7 @@ export class FilePanelController implements FilesSelectionSubscriber {
242
190
  }
243
191
 
244
192
  export const filePanelComponent = {
245
- selector: "filePanelComponent",
193
+ selector: "ccFilePanel",
246
194
  template: require("./filePanel.component.html"),
247
195
  controller: FilePanelController
248
196
  }
@@ -1,6 +1,18 @@
1
1
  import angular from "angular"
2
+
2
3
  import "../../state/state.module"
4
+
3
5
  import "../dialog/dialog.module"
6
+
4
7
  import { filePanelComponent } from "./filePanel.component"
8
+ import { downgradeComponent } from "@angular/upgrade/static"
9
+ import { FilePanelFileSelectorComponent } from "./filePanelFileSelector/filePanelFileSelector.component"
10
+ import { FilePanelStateButtonsComponent } from "./filePanelStateButtons/filePanelStateButtons.component"
11
+ import { FilePanelDeltaSelectorComponent } from "./filePanelDeltaSelector/filePanelDeltaSelector.component"
5
12
 
6
- angular.module("app.codeCharta.ui.filePanel", ["app.codeCharta.state"]).component(filePanelComponent.selector, filePanelComponent)
13
+ angular
14
+ .module("app.codeCharta.ui.filePanel", ["app.codeCharta.state"])
15
+ .component(filePanelComponent.selector, filePanelComponent)
16
+ .directive("ccFilePanelFileSelector", downgradeComponent({ component: FilePanelFileSelectorComponent }))
17
+ .directive("ccFilePanelStateButtons", downgradeComponent({ component: FilePanelStateButtonsComponent }))
18
+ .directive("ccFilePanelDeltaSelector", downgradeComponent({ component: FilePanelDeltaSelectorComponent }))
@@ -2,32 +2,14 @@ import { clickButtonOnPageElement } from "../../../puppeteer.helper"
2
2
 
3
3
  export class FilePanelPageObject {
4
4
  async getSelectedName() {
5
- await page.waitForSelector("file-panel-component md-select .md-text")
6
- return page.$eval("file-panel-component md-select .md-text", element => element["innerText"])
7
- }
8
-
9
- async getSelectedChangedName(oldName: string) {
10
- await page.waitForSelector("file-panel-component md-select .md-text")
11
- await this.waitUntilNameChange(oldName)
12
- return page.$eval("file-panel-component md-select .md-text", element => element["innerText"])
13
- }
14
-
15
- private async waitUntilNameChange(oldName: string) {
16
- await page.waitForFunction(
17
- names => {
18
- return document.querySelector(`file-panel-component md-select .md-text md-truncate`).textContent !== names
19
- },
20
- {},
21
- oldName
22
- )
5
+ await page.waitForSelector("cc-file-panel cc-file-panel-file-selector .mat-select-value-text span")
6
+ return page.$eval("cc-file-panel cc-file-panel-file-selector .mat-select-value-text span", element => element["innerText"])
23
7
  }
24
8
 
25
9
  async getAllNames() {
26
- await clickButtonOnPageElement("file-panel-component md-select")
27
- await page.waitForSelector(".md-select-menu-container.md-active > md-select-menu")
28
-
29
- const content = await page.$eval(".md-select-menu-container.md-active > md-select-menu", element => element["innerText"])
30
-
31
- return content.split("\n")
10
+ await clickButtonOnPageElement("cc-file-panel cc-file-panel-file-selector mat-select")
11
+ await page.waitForSelector(".mat-select-panel")
12
+ const content = await page.$$eval(".mat-select-panel .mat-option-text", element => element.map(item => item["innerText"]))
13
+ return content
32
14
  }
33
15
  }
@@ -0,0 +1,23 @@
1
+ <mat-select
2
+ class="delta-select"
3
+ placeholder="select reference file"
4
+ [(ngModel)]="selectedDeltaReferenceFile"
5
+ (selectionChange)="handleDeltaReferenceFileChange(selectedDeltaReferenceFile)"
6
+ >
7
+ <mat-option *ngFor="let file of files" [value]="file.file.fileMeta.fileName">
8
+ {{ file.file.fileMeta.fileName }}
9
+ </mat-option>
10
+ </mat-select>
11
+
12
+ <div class="pictogram" [style.background]="'linear-gradient(' + pictogramUpperColor + ' 50%, ' + pictogramLowerColor + ' 50%)'"></div>
13
+
14
+ <mat-select
15
+ class="delta-select"
16
+ placeholder="select comparison file"
17
+ [(ngModel)]="selectedDeltaComparisonFile"
18
+ (selectionChange)="handleDeltaComparisonFileChange(selectedDeltaComparisonFile)"
19
+ >
20
+ <mat-option *ngFor="let file of files" [value]="file.file.fileMeta.fileName">
21
+ {{ file.file.fileMeta.fileName }}
22
+ </mat-option>
23
+ </mat-select>
@@ -0,0 +1,18 @@
1
+ import { Component, Input } from "@angular/core"
2
+ import { FileState } from "../../../model/files/files"
3
+
4
+ @Component({
5
+ selector: "cc-file-panel-delta-selector",
6
+ template: require("./filePanelDeltaSelector.component.html")
7
+ })
8
+ export class FilePanelDeltaSelectorComponent {
9
+ @Input() files: FileState[]
10
+ @Input() pictogramFirstColor: string
11
+ @Input() pictogramUpperColor: string
12
+ @Input() pictogramLowerColor: string
13
+ @Input() handleDeltaReferenceFileChange: (referenceFileName: string) => void
14
+ @Input() handleDeltaComparisonFileChange: (comparisonFileName: string) => void
15
+
16
+ selectedDeltaReferenceFile: string
17
+ selectedDeltaComparisonFile: string
18
+ }
@@ -0,0 +1,18 @@
1
+ <mat-select
2
+ class="standard-select"
3
+ [(ngModel)]="selectedFileNames"
4
+ (selectionChange)="handleSelectedFilesChanged(selectedFileNames)"
5
+ name="recentFiles"
6
+ [placeholder]="selectedFileNames"
7
+ multiple
8
+ (closed)="handleOnSelectionClosed()"
9
+ >
10
+ <div class="actions">
11
+ <button mat-button (click)="handleSelectAllPartialFiles()">All</button>
12
+ <button mat-button (click)="handleSelectZeroPartialFiles()">None</button>
13
+ <button mat-button (click)="handleInvertSelectedPartialFiles()">Invert</button>
14
+ </div>
15
+ <mat-option *ngFor="let file of files" [value]="file.file.fileMeta.fileName">
16
+ {{ file.file.fileMeta.fileName }}
17
+ </mat-option>
18
+ </mat-select>
@@ -0,0 +1,16 @@
1
+ import { Component, Input } from "@angular/core"
2
+ import { FileState } from "../../../model/files/files"
3
+
4
+ @Component({
5
+ selector: "cc-file-panel-file-selector",
6
+ template: require("./filePanelFileSelector.component.html")
7
+ })
8
+ export class FilePanelFileSelectorComponent {
9
+ @Input() files: FileState[]
10
+ @Input() selectedFileNames: string[]
11
+ @Input() handleSelectedFilesChanged: (selectedFileNames: string[]) => void
12
+ @Input() handleSelectAllPartialFiles: () => void
13
+ @Input() handleSelectZeroPartialFiles: () => void
14
+ @Input() handleInvertSelectedPartialFiles: () => void
15
+ @Input() handleOnSelectionClosed: () => void
16
+ }
@@ -0,0 +1,18 @@
1
+ <div class="mode-chooser">
2
+ <button
3
+ mat-button
4
+ class="state-selector-button mode-selector left"
5
+ (click)="handleStandardButtonClicked()"
6
+ [class.current]="!isDeltaState"
7
+ >
8
+ <span class="text">Standard</span>
9
+ </button>
10
+ <button
11
+ mat-button
12
+ class="state-selector-button mode-selector right"
13
+ (click)="handleDeltaButtonClicked()"
14
+ [class.current]="isDeltaState"
15
+ >
16
+ <span class="text">Delta</span>
17
+ </button>
18
+ </div>
@@ -0,0 +1,11 @@
1
+ import { Component, Input } from "@angular/core"
2
+
3
+ @Component({
4
+ selector: "cc-file-panel-state-buttons",
5
+ template: require("./filePanelStateButtons.component.html")
6
+ })
7
+ export class FilePanelStateButtonsComponent {
8
+ @Input() isDeltaState: boolean
9
+ @Input() handleStandardButtonClicked: () => void
10
+ @Input() handleDeltaButtonClicked: () => void
11
+ }
@@ -18,10 +18,11 @@ describe("MapTreeViewLevel", () => {
18
18
 
19
19
  describe("Blacklist", () => {
20
20
  it("excluding a building should exclude it from the tree-view as well", async () => {
21
- const filePath = "/root/ParentLeaf/smallLeaf.html"
21
+ const filePath = "/root/sample1.cc.json/ParentLeaf/smallLeaf.html"
22
22
 
23
23
  await searchPanelModeSelector.toggleTreeView()
24
- await mapTreeViewLevel.openFolder("/root/ParentLeaf")
24
+ await mapTreeViewLevel.openFolder("/root/sample1.cc.json")
25
+ await mapTreeViewLevel.openFolder("/root/sample1.cc.json/ParentLeaf")
25
26
  await mapTreeViewLevel.openContextMenu(filePath)
26
27
  await nodeContextMenu.exclude()
27
28
 
@@ -31,12 +32,13 @@ describe("MapTreeViewLevel", () => {
31
32
 
32
33
  describe("NodeContextMenu", () => {
33
34
  it("NodeContextMenu path should remain marked when hovering over another mapTreeView Element", async () => {
34
- const filePath = "/root/ParentLeaf/smallLeaf.html"
35
+ const filePath = "/root/sample1.cc.json/ParentLeaf/smallLeaf.html"
35
36
 
36
37
  await searchPanelModeSelector.toggleTreeView()
37
- await mapTreeViewLevel.openFolder("/root/ParentLeaf")
38
+ await mapTreeViewLevel.openFolder("/root/sample1.cc.json")
39
+ await mapTreeViewLevel.openFolder("/root/sample1.cc.json/ParentLeaf")
38
40
  await mapTreeViewLevel.openContextMenu(filePath)
39
- await mapTreeViewLevel.hoverNode("/root/sample1OnlyLeaf.scss")
41
+ await mapTreeViewLevel.hoverNode("/root/sample1.cc.json/sample1OnlyLeaf.scss")
40
42
 
41
43
  expect(await mapTreeViewLevel.isNodeMarked(filePath)).toBeTruthy()
42
44
  })
@@ -3,7 +3,7 @@
3
3
  id="{{ node.path }}"
4
4
  class="tree-element-label-{{ depth }} tree-element-label"
5
5
  [class.hovered]="(hoveredBuildingPath$ | async) === node.path"
6
- [class.marked]="isContextMenuOpenForNode"
6
+ [class.marked]="(rightClickedNodeData$ | async)?.nodeId === node.id"
7
7
  (mouseenter)="onMouseEnter()"
8
8
  (mouseleave)="onMouseLeave()"
9
9
  (click)="toggleOpen()"
@@ -4,17 +4,10 @@ import userEvent from "@testing-library/user-event"
4
4
 
5
5
  import { searchedNodePathsSelector } from "../../../state/selectors/searchedNodes/searchedNodePaths.selector"
6
6
  import { Store } from "../../../state/store/store"
7
- import { NodeContextMenuController } from "../../nodeContextMenu/nodeContextMenu.component"
8
7
  import { MapTreeViewModule } from "../mapTreeView.module"
9
8
  import { MapTreeViewLevelComponent } from "./mapTreeViewLevel.component"
10
9
  import { rootNode } from "./mocks"
11
10
 
12
- jest.mock("../../nodeContextMenu/nodeContextMenu.component", () => ({
13
- NodeContextMenuController: {
14
- subscribeToHideNodeContextMenu: () => {},
15
- broadcastShowEvent: jest.fn()
16
- }
17
- }))
18
11
  jest.mock("../../../state/selectors/searchedNodes/searchedNodePaths.selector", () => ({
19
12
  searchedNodePathsSelector: jest.fn(
20
13
  jest.requireActual("../../../state/selectors/searchedNodes/searchedNodePaths.selector").searchedNodePathsSelector
@@ -76,21 +69,18 @@ describe("mapTreeViewLevel", () => {
76
69
  expect(firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")).toBeTruthy()
77
70
  })
78
71
 
79
- it("should open nodeContextMenu when options button clicked and be marked afterwards", async () => {
80
- const nodeContextMenuSpy = jest.spyOn(NodeContextMenuController, "broadcastShowEvent")
81
-
72
+ it("should show option button on hover and be marked after context menu was opened", async () => {
82
73
  const { container } = await render(MapTreeViewLevelComponent, { componentProperties, excludeComponentDeclaration: true })
74
+
83
75
  const firstLevelFolder = container.querySelector("#\\/root\\/ParentLeaf")
76
+ let optionsButton = firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")
77
+ expect(optionsButton).toBe(null)
84
78
 
85
79
  userEvent.hover(firstLevelFolder)
86
- const optionsButton = firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")
80
+ optionsButton = firstLevelFolder.querySelector("cc-map-tree-view-item-option-buttons")
81
+ expect(optionsButton).not.toBe(null)
87
82
  fireEvent.click(optionsButton.querySelector("[title='Open Node-Context-Menu']"))
88
83
 
89
- expect(nodeContextMenuSpy).toHaveBeenCalled()
90
- const argumentsToNodeContextMenu = nodeContextMenuSpy.mock.calls[0]
91
- expect(argumentsToNodeContextMenu[1]).toBe("/root/ParentLeaf")
92
- expect(argumentsToNodeContextMenu[2]).toBe("Folder")
93
-
94
84
  const isMarked = container.querySelector("#\\/root\\/ParentLeaf.marked")
95
85
  expect(isMarked).toBeTruthy()
96
86
  })
@@ -5,7 +5,11 @@ import { Store } from "../../../state/angular-redux/store"
5
5
  import { CodeMapNode } from "../../../codeCharta.model"
6
6
  import { hoveredBuildingPathSelector } from "../../../state/store/appStatus/hoveredBuildingPath/hoveredBuildingPath.selector"
7
7
  import { setHoveredBuildingPath } from "../../../state/store/appStatus/hoveredBuildingPath/hoveredBuildingPath.actions"
8
- import { NodeContextMenuController } from "../../nodeContextMenu/nodeContextMenu.component"
8
+ import {
9
+ RightClickedNodeData,
10
+ setRightClickedNodeData
11
+ } from "../../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.actions"
12
+ import { rightClickedNodeDataSelector } from "../../../state/store/appStatus/rightClickedNodeData/rightClickedNodeData.selector"
9
13
 
10
14
  @Component({
11
15
  selector: "cc-map-tree-view-level",
@@ -16,14 +20,13 @@ export class MapTreeViewLevelComponent implements OnInit {
16
20
  @Input() depth: number
17
21
 
18
22
  hoveredBuildingPath$: Observable<string | null>
23
+ rightClickedNodeData$: Observable<RightClickedNodeData>
19
24
 
20
25
  isOpen = false
21
- isContextMenuOpenForNode = false
22
26
 
23
27
  constructor(@Inject(Store) private store: Store) {
24
28
  this.hoveredBuildingPath$ = this.store.select(hoveredBuildingPathSelector)
25
-
26
- NodeContextMenuController.subscribeToHideNodeContextMenu(undefined, this)
29
+ this.rightClickedNodeData$ = this.store.select(rightClickedNodeDataSelector)
27
30
  }
28
31
 
29
32
  ngOnInit(): void {
@@ -33,10 +36,6 @@ export class MapTreeViewLevelComponent implements OnInit {
33
36
  }
34
37
  }
35
38
 
36
- onHideNodeContextMenu() {
37
- this.isContextMenuOpenForNode = false
38
- }
39
-
40
39
  onMouseEnter() {
41
40
  this.store.dispatch(setHoveredBuildingPath(this.node.path))
42
41
  }
@@ -49,8 +48,13 @@ export class MapTreeViewLevelComponent implements OnInit {
49
48
  $event.stopPropagation()
50
49
  $event.preventDefault()
51
50
 
52
- this.isContextMenuOpenForNode = true
53
- NodeContextMenuController.broadcastShowEvent(undefined, this.node.path, this.node.type, $event.clientX, $event.clientY)
51
+ this.store.dispatch(
52
+ setRightClickedNodeData({
53
+ nodeId: this.node.id,
54
+ xPositionOfRightClickEvent: $event.clientX,
55
+ yPositionOfRightClickEvent: $event.clientY
56
+ })
57
+ )
54
58
 
55
59
  document.querySelector(".tree-element-0").addEventListener("scroll", this.scrollFunction)
56
60
  }
@@ -60,7 +64,7 @@ export class MapTreeViewLevelComponent implements OnInit {
60
64
  }
61
65
 
62
66
  private scrollFunction = () => {
63
- NodeContextMenuController.broadcastHideEvent()
67
+ this.store.dispatch(setRightClickedNodeData(null))
64
68
  document.querySelector(".tree-element-0").removeEventListener("scroll", this.scrollFunction)
65
69
  }
66
70
  }
@@ -0,0 +1,22 @@
1
+ <div class="row" *ngIf="node$ | async as node">
2
+ <ng-container *ngFor="let markFolderItem of markFolderItems$ | async">
3
+ <button
4
+ [style.background-color]="markFolderItem.color"
5
+ (click)="markFolderItem.isMarked ? unmarkFolder(node.path) : markFolder(node.path, markFolderItem.color)"
6
+ class="colorButton"
7
+ title="Colorize folder"
8
+ >
9
+ <i class="fa fa-times" *ngIf="markFolderItem.isMarked"></i>
10
+ </button>
11
+ </ng-container>
12
+
13
+ <cc-color-picker
14
+ [hexColor]="'#ff0000'"
15
+ (onColorChange)="markFolder(node.path, $event)"
16
+ [triggerTemplate]="colorPickerTriggerTemplate"
17
+ ></cc-color-picker>
18
+ </div>
19
+
20
+ <ng-template #colorPickerTriggerTemplate>
21
+ <div class="cc-color-picker-trigger fa fa-paint-brush"></div>
22
+ </ng-template>
@@ -0,0 +1,31 @@
1
+ cc-mark-folder-row {
2
+ .row {
3
+ display: flex;
4
+ }
5
+
6
+ :hover {
7
+ cursor: pointer;
8
+ }
9
+
10
+ .colorButton {
11
+ width: 32px;
12
+ height: 32px;
13
+
14
+ i {
15
+ font-size: 25px;
16
+ display: block;
17
+ color: red;
18
+ text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
19
+ }
20
+ }
21
+
22
+ cc-color-picker {
23
+ width: 32px;
24
+ height: 32px;
25
+
26
+ .cc-color-picker-trigger {
27
+ font-size: 25px;
28
+ margin-top: 8px;
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,35 @@
1
+ import { TestBed } from "@angular/core/testing"
2
+ import { fireEvent, render } from "@testing-library/angular"
3
+ import { MarkFolderRowComponent } from "./markFolderRow.component"
4
+ import { MarkFolderRowModule } from "./markFolderRow.module"
5
+
6
+ jest.mock("./selectors/rightClickedNode.selector", () => ({
7
+ rightClickedNodeSelector: () => ({ path: "/root" })
8
+ }))
9
+
10
+ describe("markFolderRow component", () => {
11
+ beforeEach(() => {
12
+ TestBed.configureTestingModule({
13
+ imports: [MarkFolderRowModule]
14
+ })
15
+ })
16
+
17
+ it("should let a user mark and unmark a node", async () => {
18
+ const { container } = await render(MarkFolderRowComponent, { excludeComponentDeclaration: true })
19
+
20
+ expect(container.querySelectorAll("button").length).toBe(5)
21
+ expect(container.querySelectorAll("cc-color-picker").length).toBe(1)
22
+ expect(container.querySelectorAll(".fa-times").length).toBe(0)
23
+
24
+ fireEvent.click(getFirstColorButton(container))
25
+ expect(container.querySelectorAll(".fa-times").length).toBe(1)
26
+ expect(getFirstColorButton(container).querySelector(".fa-times")).not.toBe(null)
27
+
28
+ fireEvent.click(getFirstColorButton(container))
29
+ expect(container.querySelectorAll(".fa-times").length).toBe(0)
30
+
31
+ function getFirstColorButton(container: Element) {
32
+ return container.querySelectorAll("button[title='Colorize folder']")[0]
33
+ }
34
+ })
35
+ })