codecharta-visualization 1.117.0 → 1.118.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 (76) hide show
  1. package/README.md +13 -1
  2. package/app/codeCharta/services/loadInitialFile/urlExtractor.ts +2 -2
  3. package/app/codeCharta/state/selectors/accumulatedData/metricData/edgeMetricData.calculator.ts +5 -1
  4. package/app/codeCharta/state/selectors/primaryMetrics/primaryMetrics.selector.ts +7 -15
  5. package/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.spec.ts +9 -0
  6. package/app/codeCharta/state/store/dynamicSettings/colorRange/resetColorRange.effect.ts +9 -0
  7. package/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.scss +27 -0
  8. package/app/codeCharta/ui/attributeSideBar/attributeSideBar.component.spec.ts +18 -15
  9. package/app/codeCharta/ui/attributeSideBar/attributeSideBar.module.ts +10 -2
  10. package/app/codeCharta/ui/attributeSideBar/attributeSideBarHeaderSection/nodePath/nodePath.component.spec.ts +2 -2
  11. package/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.html +7 -1
  12. package/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetric/attributeSideBarPrimaryMetric.component.ts +1 -0
  13. package/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.html +20 -6
  14. package/app/codeCharta/ui/attributeSideBar/attributeSideBarPrimaryMetrics/attributeSideBarPrimaryMetrics.component.ts +7 -4
  15. package/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.html +17 -3
  16. package/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/attributeSideBarSecondaryMetrics.component.ts +8 -5
  17. package/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.spec.ts +4 -23
  18. package/app/codeCharta/ui/attributeSideBar/attributeSideBarSecondaryMetrics/secondaryMetrics.selector.ts +4 -16
  19. package/app/codeCharta/ui/attributeSideBar/metricDeltaSelected/metricDeltaSelected.component.spec.ts +1 -1
  20. package/app/codeCharta/ui/attributeSideBar/util/edge.ts +0 -2
  21. package/app/codeCharta/ui/attributeSideBar/util/metric.ts +0 -2
  22. package/app/codeCharta/ui/codeMap/arrow/codeMap.arrow.service.ts +2 -5
  23. package/app/codeCharta/ui/customConfigs/customConfigs.module.ts +4 -3
  24. package/app/codeCharta/ui/customConfigs/uploadCustomConfigButton/uploadCustomConfigButton.component.ts +1 -1
  25. package/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.spec.ts +3 -1
  26. package/app/codeCharta/ui/filePanel/filePanel.module.ts +2 -2
  27. package/app/codeCharta/ui/legendPanel/legendBlock/legendBlock.component.html +24 -20
  28. package/app/codeCharta/ui/legendPanel/legendBlock/legendBlock.component.ts +10 -3
  29. package/app/codeCharta/ui/legendPanel/legendPanel.component.html +7 -13
  30. package/app/codeCharta/ui/legendPanel/legendPanel.component.scss +16 -18
  31. package/app/codeCharta/ui/legendPanel/legendPanel.component.spec.ts +34 -12
  32. package/app/codeCharta/ui/legendPanel/legendPanel.component.ts +8 -8
  33. package/app/codeCharta/ui/legendPanel/legendPanel.module.ts +3 -2
  34. package/app/codeCharta/ui/metricChooser/metricChooser.component.html +7 -2
  35. package/app/codeCharta/ui/metricChooser/metricChooser.component.scss +8 -0
  36. package/app/codeCharta/ui/metricChooser/metricChooser.component.spec.ts +39 -11
  37. package/app/codeCharta/ui/metricChooser/metricChooser.component.ts +2 -2
  38. package/app/codeCharta/ui/metricChooser/metricChooser.module.ts +3 -2
  39. package/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.html +1 -0
  40. package/app/codeCharta/ui/ribbonBar/areaMetricChooser/areaMetricChooser.component.spec.ts +17 -6
  41. package/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.html +1 -0
  42. package/app/codeCharta/ui/ribbonBar/colorMetricChooser/colorMetricChooser.component.spec.ts +19 -6
  43. package/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.html +1 -0
  44. package/app/codeCharta/ui/ribbonBar/edgeMetricChooser/edgeMetricChooser.component.spec.ts +15 -5
  45. package/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.html +1 -0
  46. package/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.component.spec.ts +21 -8
  47. package/app/codeCharta/ui/ribbonBar/heightMetricChooser/heightMetricChooser.module.ts +1 -1
  48. package/app/codeCharta/ui/ribbonBar/ribbonBar.module.ts +1 -1
  49. package/app/codeCharta/util/algorithm/streetLayout/horizontalStreet.ts +2 -2
  50. package/app/codeCharta/util/algorithm/streetLayout/verticalStreet.ts +2 -2
  51. package/app/codeCharta/util/dataMocks.ts +18 -1
  52. package/app/codeCharta/util/gameObjectsParser/gameObjectsImporter.ts +1 -1
  53. package/app/codeCharta/util/pipes/AttributeDescriptorTooltipPipeModule.ts +8 -0
  54. package/app/codeCharta/util/pipes/RemoveExtensionPipeModule.ts +8 -0
  55. package/app/codeCharta/util/pipes/TruncateTextPipeModule.ts +8 -0
  56. package/app/codeCharta/util/pipes/attributeDescriptorTooltip.pipe.spec.ts +61 -0
  57. package/app/codeCharta/util/pipes/attributeDescriptorTooltip.pipe.ts +19 -0
  58. package/dist/webpack/index.html +1 -1
  59. package/dist/webpack/main.d6c4fa1a534cc4e7.js +1 -0
  60. package/package.json +3 -3
  61. package/app/codeCharta/ui/attributeSideBar/util/metricDescriptors.ts +0 -30
  62. package/app/codeCharta/ui/legendPanel/selectors/legendAreaMetric.selector.ts +0 -10
  63. package/app/codeCharta/ui/legendPanel/selectors/legendColorMetric.selector.ts +0 -10
  64. package/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.spec.ts +0 -76
  65. package/app/codeCharta/ui/legendPanel/selectors/legendEdgeMetric.selector.ts +0 -25
  66. package/app/codeCharta/ui/legendPanel/selectors/legendHeightMetric.selector.ts +0 -10
  67. package/app/codeCharta/util/simplePipes/SimplePipesModule.ts +0 -9
  68. package/app/codeCharta/util/simplePipes/metricDescriptorTitle.pipe.spec.ts +0 -62
  69. package/app/codeCharta/util/simplePipes/metricDescriptorTitle.pipe.ts +0 -18
  70. package/dist/webpack/main.276ed7d686dd2d87.js +0 -1
  71. /package/app/codeCharta/ui/ribbonBar/colorMetricChooser/{heightMetricChooser.module.ts → colorMetricChooser.module.ts} +0 -0
  72. /package/app/codeCharta/ui/ribbonBar/heightMetricChooser/{areaMetricChooser.component.ts → heightMetricChooser.component.ts} +0 -0
  73. /package/app/codeCharta/util/{simplePipes → pipes}/removeExtension.pipe.spec.ts +0 -0
  74. /package/app/codeCharta/util/{simplePipes → pipes}/removeExtension.pipe.ts +0 -0
  75. /package/app/codeCharta/util/{truncateText.pipe.ts → pipes/truncateText.pipe.ts} +0 -0
  76. /package/app/codeCharta/util/{truncateText.spec.ts → pipes/truncateText.spec.ts} +0 -0
@@ -13,7 +13,7 @@ import { ApplyCustomConfigButtonComponent } from "./customConfigList/customConfi
13
13
  import { CustomConfigColorSchemaBySelectionMode } from "./customConfigList/customConfigItemGroup/customConfigDescription/customConfigColorSchemaBySelectionMode.pipe"
14
14
  import { FormsModule } from "@angular/forms"
15
15
  import { CustomConfigNoteDialogButtonModule } from "./customConfigNoteDialogButton/customConfigNoteDialogButton.module"
16
- import { TruncateTextPipe } from "../../util/truncateText.pipe"
16
+ import { TruncateTextPipeModule } from "../../util/pipes/TruncateTextPipeModule"
17
17
 
18
18
  @NgModule({
19
19
  imports: [
@@ -23,7 +23,8 @@ import { TruncateTextPipe } from "../../util/truncateText.pipe"
23
23
  UploadCustomConfigButtonModule,
24
24
  AddCustomConfigButtonModule,
25
25
  DownloadCustomConfigButtonModule,
26
- FormsModule
26
+ FormsModule,
27
+ TruncateTextPipeModule
27
28
  ],
28
29
  declarations: [
29
30
  CustomConfigsComponent,
@@ -32,7 +33,7 @@ import { TruncateTextPipe } from "../../util/truncateText.pipe"
32
33
  ApplyCustomConfigButtonComponent,
33
34
  CustomConfig2ApplicableMessage,
34
35
  CustomConfig2ApplicableColor,
35
- TruncateTextPipe,
36
+
36
37
  CustomConfigColorSchemaBySelectionMode
37
38
  ],
38
39
  exports: [CustomConfigsComponent]
@@ -11,7 +11,7 @@ import { readFiles } from "../../../util/uploadFiles/readFiles"
11
11
  export class UploadCustomConfigButtonComponent {
12
12
  upload() {
13
13
  const fileInput = createCCFileInput()
14
- fileInput.addEventListener("change", async () => {
14
+ fileInput.addEventListener("change", () => {
15
15
  void this.uploadOnEvent(fileInput)
16
16
  })
17
17
  fileInput.click()
@@ -10,6 +10,7 @@ import { metricDistributionSelector } from "./selectors/metricDistribution.selec
10
10
  import { distributionMetricSelector } from "../../state/store/dynamicSettings/distributionMetric/distributionMetric.selector"
11
11
  import { defaultDistributionMetric } from "../../state/store/dynamicSettings/distributionMetric/distributionMetric.reducer"
12
12
  import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector"
13
+ import { attributeDescriptorsSelector } from "../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
13
14
 
14
15
  describe("fileExtensionBarComponent", () => {
15
16
  beforeEach(() => {
@@ -42,7 +43,8 @@ describe("fileExtensionBarComponent", () => {
42
43
  ]
43
44
  },
44
45
  { selector: distributionMetricSelector, value: defaultDistributionMetric },
45
- { selector: metricDataSelector, value: { nodeMetricData: [] } }
46
+ { selector: metricDataSelector, value: { nodeMetricData: [] } },
47
+ { selector: attributeDescriptorsSelector, value: {} }
46
48
  ]
47
49
  })
48
50
  ]
@@ -6,12 +6,12 @@ import { NgModule } from "@angular/core"
6
6
  import { CommonModule } from "@angular/common"
7
7
  import { MaterialModule } from "../../../material/material.module"
8
8
  import { FormsModule } from "@angular/forms"
9
- import { SimplePipesModule } from "../../util/simplePipes/SimplePipesModule"
10
9
  import { FileSelectionModeService } from "./fileSelectionMode.service"
11
10
  import { FilePanelComponent } from "./filePanel.component"
11
+ import { RemoveExtensionPipeModule } from "../../util/pipes/RemoveExtensionPipeModule"
12
12
 
13
13
  @NgModule({
14
- imports: [CommonModule, MaterialModule, FormsModule, SimplePipesModule],
14
+ imports: [CommonModule, MaterialModule, FormsModule, RemoveExtensionPipeModule],
15
15
  declarations: [
16
16
  FilePanelDeltaSelectorComponent,
17
17
  FilePanelFileSelectorComponent,
@@ -1,20 +1,24 @@
1
- <ng-container *ngIf="metricDecorations.title; then titleExists; else onlyShowName" class="legend-block"></ng-container>
2
- <ng-template #titleExists>
3
- <ng-container *ngIf="metricDecorations.description; then showTitleAndDescription; else showTitle"></ng-container>
4
- </ng-template>
5
-
6
- <ng-template #showTitleAndDescription>
7
- <div title="{{ metricDecorations.description }}">
8
- {{ metricFor }} metric: <span class="bold">{{ metricDecorations.title }}</span> ({{ metricDecorations.key }})
9
- </div>
10
- </ng-template>
11
- <ng-template #showTitle>
12
- <div>
13
- {{ metricFor }} metric: <span class="bold">{{ metricDecorations.title }}</span> ({{ metricDecorations.key }})
14
- </div>
15
- </ng-template>
16
- <ng-template #onlyShowName>
17
- <div>
18
- {{ metricFor }} metric: <span class="bold">{{ metricDecorations.key }}</span>
19
- </div>
20
- </ng-template>
1
+ <ng-container *ngIf="attributeDescriptors$ | async as attributeDescriptors">
2
+ <ng-container *ngIf="attributeDescriptors[metricName]?.title as descriptorTitle; else metricTitleFallback" class="legend-block">
3
+ <div [title]="attributeDescriptors[metricName] | attributeDescriptorTooltip: metricName">
4
+ {{ metricSpecification }} metric:
5
+ <a [href]="link" target="_blank" *ngIf="attributeDescriptors[metricName].link as link; else metricNoLink">
6
+ <span class="bold">{{ descriptorTitle }}</span> ({{ metricName }}) <i class="fa fa-external-link"></i>
7
+ </a>
8
+ <ng-template #metricNoLink>
9
+ <span class="bold">{{ descriptorTitle }}</span> ({{ metricName }})
10
+ </ng-template>
11
+ </div>
12
+ </ng-container>
13
+ <ng-template #metricTitleFallback>
14
+ <div>
15
+ {{ metricSpecification }} metric:
16
+ <ng-container *ngIf="fallbackTitles.get(metricName) as metricTitle; else noFallback">
17
+ <span class="bold">{{ metricTitle }}</span> ({{ metricName }})
18
+ </ng-container>
19
+ <ng-template #noFallback>
20
+ <span class="bold"> {{ metricName }} </span>
21
+ </ng-template>
22
+ </div>
23
+ </ng-template>
24
+ </ng-container>
@@ -1,5 +1,8 @@
1
1
  import { Component, Input, ViewEncapsulation } from "@angular/core"
2
- import { MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors"
2
+ import { CcState } from "../../../codeCharta.model"
3
+ import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
4
+ import { Store } from "@ngrx/store"
5
+ import { metricTitles } from "../../../util/metric/metricTitles"
3
6
 
4
7
  @Component({
5
8
  selector: "cc-legend-block",
@@ -7,6 +10,10 @@ import { MetricDescriptors } from "../../attributeSideBar/util/metricDescriptors
7
10
  encapsulation: ViewEncapsulation.None
8
11
  })
9
12
  export class LegendBlockComponent {
10
- @Input() metricFor: string
11
- @Input() metricDecorations: MetricDescriptors
13
+ @Input() metricName: string
14
+ @Input() metricSpecification: string
15
+ attributeDescriptors$ = this.store.select(attributeDescriptorsSelector)
16
+ fallbackTitles: Map<string, string> = metricTitles
17
+
18
+ constructor(private store: Store<CcState>) {}
12
19
  }
@@ -1,14 +1,10 @@
1
1
  <div class="block-wrapper" [class.visible]="isLegendVisible" [class.isAttributeSideBarVisible]="isAttributeSideBarVisibleService.isOpen">
2
2
  <div *ngIf="!(isDeltaState$ | async)">
3
- <cc-legend-block [metricDecorations]="areaMetric$ | async" [metricFor]="'Area'"></cc-legend-block>
4
- <cc-legend-block [metricDecorations]="heightMetric$ | async" [metricFor]="'Height'"></cc-legend-block>
5
- <cc-legend-block
6
- *ngIf="edgeMetric$ | async; let edgeMetric"
7
- [metricDecorations]="edgeMetric"
8
- [metricFor]="'Edge'"
9
- ></cc-legend-block>
3
+ <cc-legend-block [metricName]="areaMetric$ | async" metricSpecification="Area"></cc-legend-block>
4
+ <cc-legend-block [metricName]="heightMetric$ | async" metricSpecification="Height"></cc-legend-block>
5
+ <cc-legend-block *ngIf="edgeMetric$ | async; let edgeMetric" [metricName]="edgeMetric" metricSpecification="Edge"></cc-legend-block>
10
6
  <hr />
11
- <cc-legend-block [metricDecorations]="colorMetric$ | async" [metricFor]="'Color'"></cc-legend-block>
7
+ <cc-legend-block [metricName]="colorMetric$ | async" metricSpecification="Color"></cc-legend-block>
12
8
  <cc-color-picker-for-map-color [mapColorFor]="'positive'"></cc-color-picker-for-map-color>
13
9
  <cc-color-picker-for-map-color [mapColorFor]="'neutral'"></cc-color-picker-for-map-color>
14
10
  <cc-color-picker-for-map-color [mapColorFor]="'negative'"></cc-color-picker-for-map-color>
@@ -22,12 +18,10 @@
22
18
  <hr />
23
19
  <cc-color-picker-for-map-color [mapColorFor]="'selected'"></cc-color-picker-for-map-color>
24
20
 
25
- <ng-container *ngIf="edgeMetric$ | async; let edgeMetric">
21
+ <ng-container *ngIf="edgeMetric$ | async">
26
22
  <hr />
27
- <div ng-if="$ctrl._viewModel.edgeMetricHasEdge">
28
- <cc-color-picker-for-map-color [mapColorFor]="'outgoingEdge'"></cc-color-picker-for-map-color>
29
- <cc-color-picker-for-map-color [mapColorFor]="'incomingEdge'"></cc-color-picker-for-map-color>
30
- </div>
23
+ <cc-color-picker-for-map-color [mapColorFor]="'outgoingEdge'"></cc-color-picker-for-map-color>
24
+ <cc-color-picker-for-map-color [mapColorFor]="'incomingEdge'"></cc-color-picker-for-map-color>
31
25
  </ng-container>
32
26
 
33
27
  <cc-legend-marked-packages></cc-legend-marked-packages>
@@ -51,34 +51,32 @@ cc-legend-panel {
51
51
  color: #000;
52
52
  }
53
53
 
54
- .legend-block {
55
- display: block;
56
- min-height: 25px;
57
- max-width: 350px;
58
- overflow: hidden;
54
+ cc-legend-block {
55
+ a:link,
56
+ a:visited {
57
+ text-decoration: none;
58
+ color: #000;
59
+ }
59
60
 
60
- i,
61
- img {
62
- display: inline-block;
63
- width: 14px;
61
+ a:hover {
62
+ color: blue;
63
+ text-decoration: solid;
64
+ text-decoration-line: underline;
64
65
  }
65
66
 
66
- i {
67
- margin-right: 4px;
67
+ a:active {
68
+ color: red;
68
69
  }
69
70
 
70
- img {
71
- padding-top: 3px;
72
- height: 17px;
71
+ i.fa.fa-external-link {
72
+ font-size: 10px;
73
+ min-width: 10px;
74
+ text-align: center;
73
75
  }
74
76
 
75
77
  span {
76
78
  display: inline-block;
77
79
  }
78
-
79
- .set-left-margin {
80
- margin-left: 18px;
81
- }
82
80
  }
83
81
 
84
82
  .bold {
@@ -13,11 +13,8 @@ import { colorRangeSelector } from "../../state/store/dynamicSettings/colorRange
13
13
  import { State } from "@ngrx/store"
14
14
  import { mapColorsSelector } from "../../state/store/appSettings/mapColors/mapColors.selector"
15
15
  import { defaultMapColors } from "../../state/store/appSettings/mapColors/mapColors.reducer"
16
- import { legendHeightMetricSelector } from "./selectors/legendHeightMetric.selector"
17
- import { legendAreaMetricSelector } from "./selectors/legendAreaMetric.selector"
18
- import { legendColorMetricSelector } from "./selectors/legendColorMetric.selector"
19
16
  import { selectedColorMetricDataSelector } from "../../state/selectors/accumulatedData/metricData/selectedColorMetricData.selector"
20
- import { getMetricDescriptors } from "../attributeSideBar/util/metricDescriptors"
17
+ import { attributeDescriptorsSelector } from "../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
21
18
 
22
19
  describe("LegendPanelController", () => {
23
20
  beforeEach(() => {
@@ -27,15 +24,13 @@ describe("LegendPanelController", () => {
27
24
  provideMockStore({
28
25
  selectors: [
29
26
  { selector: heightMetricSelector, value: "mcc" },
30
- { selector: legendHeightMetricSelector, value: getMetricDescriptors("mcc") },
31
27
  { selector: areaMetricSelector, value: "loc" },
32
- { selector: legendAreaMetricSelector, value: getMetricDescriptors("loc") },
33
28
  { selector: colorMetricSelector, value: "rloc" },
34
- { selector: legendColorMetricSelector, value: getMetricDescriptors("rloc") },
35
29
  { selector: colorRangeSelector, value: { from: 21, to: 42, max: 9001 } },
36
30
  { selector: isDeltaStateSelector, value: true },
37
31
  { selector: mapColorsSelector, value: defaultMapColors },
38
- { selector: selectedColorMetricDataSelector, value: {} }
32
+ { selector: selectedColorMetricDataSelector, value: {} },
33
+ { selector: attributeDescriptorsSelector, value: {} }
39
34
  ]
40
35
  }),
41
36
  { provide: State, useValue: {} }
@@ -65,8 +60,7 @@ describe("LegendPanelController", () => {
65
60
  detectChanges()
66
61
  fireEvent.click(screen.getByTitle("Show panel"))
67
62
 
68
- const areDeltaEntriesShown = screen.queryAllByText("delta", { exact: false }).length > 0
69
- expect(areDeltaEntriesShown).toBe(false)
63
+ expect(screen.queryAllByText("delta", { exact: false }).length).not.toBeGreaterThan(0)
70
64
 
71
65
  const metricDescriptions = container.querySelectorAll("cc-legend-block")
72
66
  expect(metricDescriptions[0].textContent).toMatch("Area metric: Lines of Code (loc)")
@@ -74,12 +68,40 @@ describe("LegendPanelController", () => {
74
68
  expect(metricDescriptions[2].textContent).toMatch("Color metric: Real Lines of Code (rloc)")
75
69
  })
76
70
 
71
+ it("should contain elements with titles and links if attributeDescriptors are present", async () => {
72
+ const { container, detectChanges } = await render(LegendPanelComponent, { excludeComponentDeclaration: true })
73
+ const store = TestBed.inject(MockStore)
74
+ const metricLink = "https://rl.oc"
75
+ store.overrideSelector(isDeltaStateSelector, false)
76
+ const mccAttributeDescriptor = {
77
+ mcc: { title: "MCC_Title", description: "MCC_description", hintLowValue: "MCC_lowValue", hintHighValue: "", link: "" }
78
+ }
79
+ store.overrideSelector(attributeDescriptorsSelector, {
80
+ ...mccAttributeDescriptor,
81
+ rloc: { title: "RLOC_Title", description: "RLOC_Description", hintLowValue: "", hintHighValue: "", link: metricLink }
82
+ })
83
+ store.refreshState()
84
+ detectChanges()
85
+ fireEvent.click(screen.getByTitle("Show panel"))
86
+ expect(screen.queryAllByText("delta", { exact: false }).length).not.toBeGreaterThan(0)
87
+
88
+ const metricDescriptions = container.querySelectorAll("cc-legend-block")
89
+ expect(metricDescriptions[0].textContent).toMatch("Area metric: Lines of Code (loc)")
90
+ expect(metricDescriptions[1].textContent).toMatch("Height metric: MCC_Title (mcc)")
91
+ expect(metricDescriptions[1].firstElementChild.getAttribute("title")).toMatch(
92
+ "MCC_Title (mcc):\nMCC_description\nLow Values: MCC_lowValue"
93
+ )
94
+ expect(metricDescriptions[1].querySelector("a")).toBeNull()
95
+ expect(metricDescriptions[2].textContent).toMatch("Color metric: RLOC_Title (rloc)")
96
+ expect(metricDescriptions[2].firstElementChild.getAttribute("title")).toMatch("RLOC_Title (rloc)")
97
+ expect(metricDescriptions[2].querySelector("a").getAttribute("href")).toMatch(metricLink)
98
+ })
99
+
77
100
  it("should display legend for delta mode", async () => {
78
101
  const { container } = await render(LegendPanelComponent, { excludeComponentDeclaration: true })
79
102
  fireEvent.click(screen.getByTitle("Show panel"))
80
103
 
81
- const areDeltaEntriesShown = screen.queryAllByText("delta", { exact: false }).length > 0
82
- expect(areDeltaEntriesShown).toBe(true)
104
+ expect(screen.queryAllByText("delta", { exact: false }).length).toBeGreaterThan(0)
83
105
 
84
106
  const metricDescriptions = container.querySelectorAll("cc-legend-block")
85
107
  expect(metricDescriptions.length).toBe(0)
@@ -1,12 +1,12 @@
1
1
  import { Component, ViewEncapsulation } from "@angular/core"
2
2
  import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector"
3
- import { legendColorMetricSelector } from "./selectors/legendColorMetric.selector"
4
- import { legendHeightMetricSelector } from "./selectors/legendHeightMetric.selector"
5
- import { legendAreaMetricSelector } from "./selectors/legendAreaMetric.selector"
6
- import { legendEdgeMetricSelector } from "./selectors/legendEdgeMetric.selector"
7
3
  import { IsAttributeSideBarVisibleService } from "../../services/isAttributeSideBarVisible.service"
8
4
  import { Store } from "@ngrx/store"
9
5
  import { CcState } from "../../codeCharta.model"
6
+ import { heightMetricSelector } from "../../state/store/dynamicSettings/heightMetric/heightMetric.selector"
7
+ import { areaMetricSelector } from "../../state/store/dynamicSettings/areaMetric/areaMetric.selector"
8
+ import { colorMetricSelector } from "../../state/store/dynamicSettings/colorMetric/colorMetric.selector"
9
+ import { edgeMetricSelector } from "../../state/store/dynamicSettings/edgeMetric/edgeMetric.selector"
10
10
 
11
11
  @Component({
12
12
  selector: "cc-legend-panel",
@@ -17,10 +17,10 @@ import { CcState } from "../../codeCharta.model"
17
17
  export class LegendPanelComponent {
18
18
  isLegendVisible = false
19
19
  isDeltaState$ = this.store.select(isDeltaStateSelector)
20
- heightMetric$ = this.store.select(legendHeightMetricSelector)
21
- areaMetric$ = this.store.select(legendAreaMetricSelector)
22
- colorMetric$ = this.store.select(legendColorMetricSelector)
23
- edgeMetric$ = this.store.select(legendEdgeMetricSelector)
20
+ heightMetric$ = this.store.select(heightMetricSelector)
21
+ areaMetric$ = this.store.select(areaMetricSelector)
22
+ colorMetric$ = this.store.select(colorMetricSelector)
23
+ edgeMetric$ = this.store.select(edgeMetricSelector)
24
24
 
25
25
  constructor(public isAttributeSideBarVisibleService: IsAttributeSideBarVisibleService, private store: Store<CcState>) {}
26
26
 
@@ -6,10 +6,11 @@ import { LegendPanelComponent } from "./legendPanel.component"
6
6
  import { MaterialModule } from "../../../material/material.module"
7
7
  import { LegendBlockComponent } from "./legendBlock/legendBlock.component"
8
8
  import { ColorPickerForMapColorModule } from "../colorPickerForMapColor/colorPickerForMapColor.module"
9
+ import { AttributeDescriptorTooltipPipeModule } from "../../util/pipes/AttributeDescriptorTooltipPipeModule"
9
10
 
10
11
  @NgModule({
11
- imports: [CommonModule, MaterialModule, LegendMarkedPackagesModule, ColorPickerForMapColorModule],
12
12
  declarations: [LegendPanelComponent, LegendBlockComponent],
13
- exports: [LegendPanelComponent]
13
+ exports: [LegendPanelComponent],
14
+ imports: [CommonModule, MaterialModule, LegendMarkedPackagesModule, ColorPickerForMapColorModule, AttributeDescriptorTooltipPipeModule]
14
15
  })
15
16
  export class LegendPanelModule {}
@@ -4,7 +4,9 @@
4
4
  (selectionChange)="handleMetricChanged($event.value)"
5
5
  (openedChange)="handleOpenedChanged($event)"
6
6
  [disabled]="isDisabled"
7
+ *ngIf="attributeDescriptors$ | async as attributeDescriptors"
7
8
  >
9
+ <mat-select-trigger>{{ selectedMetricName }}</mat-select-trigger>
8
10
  <mat-form-field class="cc-metric-chooser-search-field">
9
11
  <i matPrefix class="fa fa-search search-icon"></i>
10
12
  <input #searchTermInput matInput type="text" [placeholder]="searchPlaceholder" [(ngModel)]="searchTerm" />
@@ -13,10 +15,13 @@
13
15
  <mat-option
14
16
  *ngFor="let option of metricData$ | async | filterMetricDataBySearchTerm: searchTerm"
15
17
  [value]="option.name"
16
- matTooltip="{{ metricDataDescription.get(option.name) }}"
18
+ [title]="attributeDescriptors[option.name] | attributeDescriptorTooltip: option.name"
17
19
  >
18
20
  {{ option.name }}
19
- <span class="metric-max-value">({{ option.maxValue }})</span>
21
+ <span class="metric-max-value">({{ option.maxValue }})</span><br />
22
+ <span class="metric-subtitle" *ngIf="attributeDescriptors[option.name]?.description as descriptorSubtitle">
23
+ {{ descriptorSubtitle }}
24
+ </span>
20
25
  </mat-option>
21
26
  </div>
22
27
  </mat-select>
@@ -60,6 +60,14 @@ cc-metric-chooser {
60
60
  mat-option .metric-max-value {
61
61
  color: #ccc;
62
62
  }
63
+
64
+ mat-option .metric-subtitle {
65
+ color: #999;
66
+ font-size: 11px;
67
+ overflow: hidden;
68
+ white-space: nowrap;
69
+ text-overflow: ellipsis;
70
+ }
63
71
  }
64
72
  }
65
73
 
@@ -7,6 +7,8 @@ import { MetricChooserComponent } from "./metricChooser.component"
7
7
  import { MetricChooserModule } from "./metricChooser.module"
8
8
  import { provideMockStore } from "@ngrx/store/testing"
9
9
  import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector"
10
+ import { attributeDescriptorsSelector } from "../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
11
+ import { TEST_ATTRIBUTE_DESCRIPTORS_FULL } from "../../util/dataMocks"
10
12
 
11
13
  describe("metricChooserComponent", () => {
12
14
  beforeEach(() => {
@@ -21,10 +23,13 @@ describe("metricChooserComponent", () => {
21
23
  nodeMetricData: [
22
24
  { name: "aMetric", maxValue: 1 },
23
25
  { name: "bMetric", maxValue: 2 },
24
- { name: "cMetric", maxValue: 3 }
26
+ { name: "cMetric", maxValue: 3 },
27
+ { name: "fullMetric", maxValue: 42 },
28
+ { name: "mcc", maxValue: 55 }
25
29
  ]
26
30
  }
27
- }
31
+ },
32
+ { selector: attributeDescriptorsSelector, value: TEST_ATTRIBUTE_DESCRIPTORS_FULL }
28
33
  ]
29
34
  })
30
35
  ]
@@ -33,7 +38,7 @@ describe("metricChooserComponent", () => {
33
38
 
34
39
  it("should be a select for metrics", async () => {
35
40
  let selectedMetricName = "aMetric"
36
- await render(MetricChooserComponent, {
41
+ const { rerender, detectChanges } = await render(MetricChooserComponent, {
37
42
  excludeComponentDeclaration: true,
38
43
  componentProperties: {
39
44
  searchPlaceholder: "search metric (max value)",
@@ -42,28 +47,44 @@ describe("metricChooserComponent", () => {
42
47
  }
43
48
  })
44
49
 
45
- await userEvent.click(await screen.findByText("aMetric (1)"))
50
+ await userEvent.click(await screen.findByText("aMetric"))
46
51
  const options = screen.queryAllByRole("option")
47
52
  expect(options[0].textContent).toMatch("aMetric (1)")
48
53
  expect(options[1].textContent).toMatch("bMetric (2)")
49
54
  expect(options[2].textContent).toMatch("cMetric (3)")
55
+ expect(options[3].textContent).toMatch("fullMetric (42) FullTestDescription")
56
+ expect(options[3].getAttribute("title")).toMatch(
57
+ "FullTestTitle (fullMetric):\nFullTestDescription\nHigh Values: FullTestHigh\nLow Values: FullLowValue"
58
+ )
59
+ expect(options[4].textContent).toMatch("mcc (55)")
60
+ expect(options[4].getAttribute("title")).toMatch("Cyclomatic Complexity")
50
61
 
51
62
  await userEvent.click(options[1])
52
- expect(screen.queryByText("aMetric (1)")).toBe(null)
53
- expect(screen.queryByText("bMetric (2)")).not.toBe(null)
63
+
64
+ await rerender({
65
+ componentProperties: {
66
+ searchPlaceholder: "search metric (max value)",
67
+ selectedMetricName,
68
+ handleMetricChanged: (value: string) => (selectedMetricName = value)
69
+ }
70
+ })
71
+ detectChanges()
72
+ expect(screen.queryByText("aMetric")).toBe(null)
73
+ expect(screen.queryByText("bMetric")).not.toBe(null)
54
74
  })
55
75
 
56
76
  it("should focus search field initially, filter options by search term, and reset search term on close", async () => {
57
- await render(MetricChooserComponent, {
77
+ let selectedMetricName = "aMetric"
78
+ const { rerender } = await render(MetricChooserComponent, {
58
79
  excludeComponentDeclaration: true,
59
80
  componentProperties: {
60
81
  searchPlaceholder: "search metric (max value)",
61
- selectedMetricName: "aMetric",
62
- handleMetricChanged: jest.fn()
82
+ selectedMetricName,
83
+ handleMetricChanged: (value: string) => (selectedMetricName = value)
63
84
  }
64
85
  })
65
86
 
66
- await userEvent.click(await screen.findByText("aMetric (1)"))
87
+ await userEvent.click(await screen.findByText("aMetric"))
67
88
  screen.getByPlaceholderText("search metric (max value)")
68
89
  const searchBox = getSearchBox()
69
90
  expect(document.activeElement).toBe(searchBox)
@@ -76,7 +97,14 @@ describe("metricChooserComponent", () => {
76
97
  await userEvent.click(options[0])
77
98
  expect(screen.queryByRole("listbox")).toBeNull()
78
99
 
79
- await userEvent.click(await screen.findByText("bMetric (2)"))
100
+ await rerender({
101
+ componentProperties: {
102
+ searchPlaceholder: "search metric (max value)",
103
+ selectedMetricName,
104
+ handleMetricChanged: (value: string) => (selectedMetricName = value)
105
+ }
106
+ })
107
+ await userEvent.click(await screen.findByText("bMetric"))
80
108
  expect(getSearchBox().value).toBe("")
81
109
 
82
110
  function getSearchBox() {
@@ -1,8 +1,8 @@
1
1
  import { Component, ElementRef, Input, OnInit, ViewChild, ViewEncapsulation } from "@angular/core"
2
2
  import { map, Observable } from "rxjs"
3
3
  import { EdgeMetricData, NodeMetricData, CcState } from "../../codeCharta.model"
4
- import { metricTitles } from "../../util/metric/metricTitles"
5
4
  import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector"
5
+ import { attributeDescriptorsSelector } from "../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
6
6
  import { Store } from "@ngrx/store"
7
7
 
8
8
  type MetricChooserType = "node" | "edge"
@@ -22,7 +22,7 @@ export class MetricChooserComponent implements OnInit {
22
22
  @ViewChild("searchTermInput") searchTermInput: ElementRef<HTMLInputElement>
23
23
  searchTerm = ""
24
24
  metricData$: Observable<NodeMetricData[] | EdgeMetricData[]>
25
- metricDataDescription: Map<string, string> = metricTitles
25
+ attributeDescriptors$ = this.store.select(attributeDescriptorsSelector)
26
26
 
27
27
  constructor(private store: Store<CcState>) {}
28
28
 
@@ -4,10 +4,11 @@ import { FormsModule } from "@angular/forms"
4
4
  import { MaterialModule } from "../../../material/material.module"
5
5
  import { FilterMetricDataBySearchTermPipe } from "./filterMetricDataBySearchTerm.pipe"
6
6
  import { MetricChooserComponent } from "./metricChooser.component"
7
+ import { AttributeDescriptorTooltipPipeModule } from "../../util/pipes/AttributeDescriptorTooltipPipeModule"
7
8
 
8
9
  @NgModule({
9
- imports: [CommonModule, MaterialModule, FormsModule],
10
10
  declarations: [MetricChooserComponent, FilterMetricDataBySearchTermPipe],
11
- exports: [MetricChooserComponent]
11
+ exports: [MetricChooserComponent],
12
+ imports: [CommonModule, MaterialModule, FormsModule, AttributeDescriptorTooltipPipeModule]
12
13
  })
13
14
  export class MetricChooserModule {}
@@ -4,6 +4,7 @@
4
4
  [selectedMetricName]="areaMetric$ | async"
5
5
  [searchPlaceholder]="'Area Metric (highest value)'"
6
6
  [handleMetricChanged]="handleAreaMetricChanged"
7
+ title="Change area metric"
7
8
  >
8
9
  <cc-metric-chooser-value-hovered hoveredInformation [metricFor]="'areaMetric'"></cc-metric-chooser-value-hovered>
9
10
  </cc-metric-chooser>
@@ -4,10 +4,13 @@ import { expect } from "@jest/globals"
4
4
  import userEvent from "@testing-library/user-event"
5
5
  import { AreaMetricChooserComponent } from "./areaMetricChooser.component"
6
6
  import { AreaMetricChooserModule } from "./areaMetricChooser.module"
7
- import { provideMockStore } from "@ngrx/store/testing"
7
+ import { MockStore, provideMockStore } from "@ngrx/store/testing"
8
8
  import { metricDataSelector } from "../../../state/selectors/accumulatedData/metricData/metricData.selector"
9
9
  import { areaMetricSelector } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.selector"
10
10
  import { hoveredNodeSelector } from "../../../state/selectors/hoveredNode.selector"
11
+ import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
12
+ import { getLastAction } from "../../../util/testUtils/store.utils"
13
+ import { setAreaMetric } from "../../../state/store/dynamicSettings/areaMetric/areaMetric.actions"
11
14
 
12
15
  describe("areaMetricChooserComponent", () => {
13
16
  beforeEach(() => {
@@ -26,7 +29,8 @@ describe("areaMetricChooserComponent", () => {
26
29
  }
27
30
  },
28
31
  { selector: areaMetricSelector, value: "aMetric" },
29
- { selector: hoveredNodeSelector, value: null }
32
+ { selector: hoveredNodeSelector, value: null },
33
+ { selector: attributeDescriptorsSelector, value: {} }
30
34
  ]
31
35
  })
32
36
  ]
@@ -34,16 +38,23 @@ describe("areaMetricChooserComponent", () => {
34
38
  })
35
39
 
36
40
  it("should be a select for area metric", async () => {
37
- await render(AreaMetricChooserComponent, { excludeComponentDeclaration: true })
41
+ const { detectChanges } = await render(AreaMetricChooserComponent, { excludeComponentDeclaration: true })
38
42
 
39
- await userEvent.click(await screen.findByText("aMetric (1)"))
43
+ await userEvent.click(await screen.findByText("aMetric"))
40
44
  expect(screen.getByPlaceholderText("Area Metric (highest value)")).not.toBe(null)
41
45
  const options = screen.queryAllByRole("option")
42
46
  expect(options[0].textContent).toMatch("aMetric (1)")
43
47
  expect(options[1].textContent).toMatch("bMetric (2)")
44
48
 
45
49
  await userEvent.click(options[1])
46
- expect(screen.queryByText("aMetric (1)")).toBe(null)
47
- expect(screen.queryByText("bMetric (2)")).not.toBe(null)
50
+
51
+ const store = TestBed.inject(MockStore)
52
+ expect(await getLastAction(store)).toEqual(setAreaMetric({ value: "bMetric" }))
53
+ store.overrideSelector(areaMetricSelector, "bMetric")
54
+ store.refreshState()
55
+ detectChanges()
56
+
57
+ expect(screen.queryByText("aMetric")).toBe(null)
58
+ expect(screen.queryByText("bMetric")).not.toBe(null)
48
59
  })
49
60
  })
@@ -5,6 +5,7 @@
5
5
  [searchPlaceholder]="'Color Metric (highest value)'"
6
6
  [handleMetricChanged]="handleColorMetricChanged"
7
7
  [isDisabled]="isColorMetricLinkedToHeightMetric$ | async"
8
+ [attr.title]="(isColorMetricLinkedToHeightMetric$ | async) ? 'Currently linked to height metric' : 'Change color metric'"
8
9
  >
9
10
  <cc-metric-chooser-value-hovered hoveredInformation [metricFor]="'colorMetric'"></cc-metric-chooser-value-hovered>
10
11
  </cc-metric-chooser>