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
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CodeCharta Visualization
2
2
 
3
- [![Build Status](https://travis-ci.org/MaibornWolff/codecharta.svg?branch=main)](https://travis-ci.org/MaibornWolff/codecharta)
3
+ [![Quality Gate Status For Visualization](https://sonarcloud.io/api/project_badges/measure?project=maibornwolff-gmbh_codecharta_visualization&metric=alert_status)](https://sonarcloud.io/project/overview?id=maibornwolff-gmbh_codecharta_visualization)
4
4
 
5
5
  > CodeCharta by [MaibornWolff](https://www.maibornwolff.de)
6
6
 
@@ -19,6 +19,8 @@ You can start with **Codecharta Visualization** on multiple ways:
19
19
  - Installation as a [npm package](#npm-package) (Recommended)
20
20
  - Run an operating system specific [standalone](#run-a-standalone)
21
21
  - Build it yourself from the github [repository](#build-it-yourself)
22
+ - Use [docker-compose](https://maibornwolff.github.io/codecharta/docs/docker-containers/) to run this with other needed tools like a Sonar instance or analyzing tools of codecharta-analysis.
23
+ - Use our [Dockerfile](#run-in-docker-container) to run the visualization in a container
22
24
  - Try out the [online version](https://maibornwolff.github.io/codecharta/visualization/app/index.html?file=codecharta.cc.json&file=codecharta_analysis.cc.json)
23
25
 
24
26
  > Be aware, that if you are on Apple Silicon, you need to do additional config for npm installation
@@ -140,6 +142,16 @@ $ npm run e2e:auto
140
142
 
141
143
  > To follow/watch the steps the e2e test is performing, deactivate headless mode in `jest-puppeteer.config.js` (and maybe set the `slowMo` parameter)
142
144
 
145
+ ## Run in Docker container
146
+
147
+ You can use this via docker compose or as a standalone container. This section will deal with how to use the visualization as a standalone container. For information on how to use this with docker compose, please check out [Docker Getting Started](https://maibornwolff.github.io/codecharta/docs/docker-containers/)
148
+ We assume that you already installed docker, if not, you have to do that before!
149
+
150
+ To containerize the visualization, please follow the below listed steps.
151
+
152
+ - Start the docker container: `docker run -d -p 9000:80 codecharta/codecharta-visualization`. This detaches the container and exposes port 80 on the container and port 9000 on the host.
153
+ - Open `localhost:9000` in your browser and you can already use the visualization, upload `cc.json` files and play around!
154
+
143
155
  # JSON structure
144
156
 
145
157
  [Example Data](/visualization/app/codeCharta/assets/sample1.cc.json)
@@ -9,7 +9,7 @@ export class UrlExtractor {
9
9
  constructor(private httpClient: HttpClient) {}
10
10
 
11
11
  getParameterByName(name: string) {
12
- const sanitizedName = name.replace(/[[\]]/g, "\\$&")
12
+ const sanitizedName = name.replaceAll(/[[\]]/g, "\\$&")
13
13
  const regex = new RegExp(`[?&]${sanitizedName}(=([^&#]*)|&|#|$)`),
14
14
  results = regex.exec(window.location.href)
15
15
 
@@ -19,7 +19,7 @@ export class UrlExtractor {
19
19
  if (!results[2]) {
20
20
  return ""
21
21
  }
22
- return decodeURIComponent(results[2].replace(/\+/g, " "))
22
+ return decodeURIComponent(results[2].replaceAll("+", " "))
23
23
  }
24
24
 
25
25
  async getFileDataFromQueryParam() {
@@ -84,7 +84,11 @@ function getMetricDataFromMap(nodeEdgeMetricsMap: NodeEdgeMetricsMap) {
84
84
  minimumMetricValue = combinedValue
85
85
  }
86
86
  }
87
- metricData.push({ name: edgeMetric, maxValue: maximumMetricValue, minValue: minimumMetricValue })
87
+ metricData.push({
88
+ name: edgeMetric,
89
+ maxValue: maximumMetricValue,
90
+ minValue: minimumMetricValue
91
+ })
88
92
  }
89
93
 
90
94
  return metricData
@@ -1,11 +1,8 @@
1
1
  import { selectedNodeSelector } from "../selectedNode.selector"
2
2
  import { Metric } from "../../../ui/attributeSideBar/util/metric"
3
3
  import { primaryMetricNamesSelector } from "./primaryMetricNames.selector"
4
- import { getMetricDescriptors } from "../../../ui/attributeSideBar/util/metricDescriptors"
5
- import { attributeDescriptorsSelector } from "../../store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
6
4
  import { Edge } from "app/codeCharta/ui/attributeSideBar/util/edge"
7
5
  import { CodeMapNode } from "app/codeCharta/codeCharta.model"
8
- import { AttributeDescriptors } from "../../../codeCharta.model"
9
6
  import { createSelector } from "@ngrx/store"
10
7
 
11
8
  export type PrimaryMetrics = {
@@ -18,8 +15,7 @@ export type PrimaryMetrics = {
18
15
  export const primaryMetricsSelector = createSelector(
19
16
  selectedNodeSelector,
20
17
  primaryMetricNamesSelector,
21
- attributeDescriptorsSelector,
22
- (selectedNode, primaryMetricNames, attributeDescriptors) => {
18
+ (selectedNode, primaryMetricNames) => {
23
19
  if (!selectedNode) {
24
20
  return
25
21
  }
@@ -27,32 +23,28 @@ export const primaryMetricsSelector = createSelector(
27
23
  return {
28
24
  area: {
29
25
  name: primaryMetricNames.areaMetric,
30
- value: selectedNode.attributes[primaryMetricNames.areaMetric],
31
- descriptors: getMetricDescriptors(primaryMetricNames.areaMetric, attributeDescriptors)
26
+ value: selectedNode.attributes[primaryMetricNames.areaMetric]
32
27
  },
33
28
  height: {
34
29
  name: primaryMetricNames.heightMetric,
35
- value: selectedNode.attributes[primaryMetricNames.heightMetric],
36
- descriptors: getMetricDescriptors(primaryMetricNames.heightMetric, attributeDescriptors)
30
+ value: selectedNode.attributes[primaryMetricNames.heightMetric]
37
31
  },
38
32
  color: {
39
33
  name: primaryMetricNames.colorMetric,
40
- value: selectedNode.attributes[primaryMetricNames.colorMetric],
41
- descriptors: getMetricDescriptors(primaryMetricNames.colorMetric, attributeDescriptors)
34
+ value: selectedNode.attributes[primaryMetricNames.colorMetric]
42
35
  },
43
- edge: getEdge(primaryMetricNames.edgeMetric, selectedNode, attributeDescriptors)
36
+ edge: getEdge(primaryMetricNames.edgeMetric, selectedNode)
44
37
  }
45
38
  }
46
39
  )
47
40
 
48
- function getEdge(key: string, selectedNode: CodeMapNode, attributeDescriptors: AttributeDescriptors): Edge {
41
+ function getEdge(key: string, selectedNode: CodeMapNode): Edge {
49
42
  if (key === undefined || key === null) {
50
43
  return null
51
44
  }
52
45
  return {
53
46
  name: key,
54
47
  incoming: selectedNode.edgeAttributes[key]?.incoming,
55
- outgoing: selectedNode.edgeAttributes[key]?.outgoing,
56
- descriptors: getMetricDescriptors(key, attributeDescriptors)
48
+ outgoing: selectedNode.edgeAttributes[key]?.outgoing
57
49
  }
58
50
  }
@@ -8,6 +8,7 @@ import { BehaviorSubject } from "rxjs"
8
8
  import { Action } from "@ngrx/store"
9
9
  import { setStandard } from "../../files/files.actions"
10
10
  import { getLastAction } from "../../../../util/testUtils/store.utils"
11
+ import { setColorMetric } from "../colorMetric/colorMetric.actions"
11
12
 
12
13
  describe("ResetColorRangeEffect", () => {
13
14
  let actions$: BehaviorSubject<Action>
@@ -48,4 +49,12 @@ describe("ResetColorRangeEffect", () => {
48
49
  store.refreshState()
49
50
  expect(await getLastAction(store)).not.toEqual({ value: { from: 53, to: 86 }, type: "SET_COLOR_RANGE" })
50
51
  })
52
+
53
+ it("should fire when colorMetric selection changed", async () => {
54
+ const store = TestBed.inject(MockStore)
55
+ store.overrideSelector(selectedColorMetricDataSelector, { minValue: 20, maxValue: 120 })
56
+ store.refreshState()
57
+ actions$.next(setColorMetric({ value: "anotherMetric" }))
58
+ expect(await getLastAction(store)).toEqual({ value: { from: 53, to: 86 }, type: "SET_COLOR_RANGE" })
59
+ })
51
60
  })
@@ -7,6 +7,7 @@ import { calculateInitialColorRange } from "./calculateInitialColorRange"
7
7
  import { setColorRange } from "./colorRange.actions"
8
8
  import { fileActions } from "../../files/files.actions"
9
9
  import { CcState } from "../../../../codeCharta.model"
10
+ import { setColorMetric } from "../colorMetric/colorMetric.actions"
10
11
 
11
12
  @Injectable()
12
13
  export class ResetColorRangeEffect {
@@ -19,4 +20,12 @@ export class ResetColorRangeEffect {
19
20
  map(selectedColorMetricData => setColorRange({ value: calculateInitialColorRange(selectedColorMetricData) }))
20
21
  )
21
22
  )
23
+
24
+ resetColorRangeOnColorMetricChange$ = createEffect(() =>
25
+ this.actions$.pipe(
26
+ ofType(setColorMetric),
27
+ switchMap(() => this.store.select(selectedColorMetricDataSelector).pipe(take(1))),
28
+ map(selectedColorMetricData => setColorRange({ value: calculateInitialColorRange(selectedColorMetricData) }))
29
+ )
30
+ )
22
31
  }
@@ -133,5 +133,32 @@ cc-attribute-side-bar {
133
133
  margin-top: 5px;
134
134
  }
135
135
  }
136
+
137
+ cc-attribute-side-bar-primary-metrics,
138
+ cc-attribute-side-bar-secondary-metrics {
139
+ .metric-box,
140
+ .metrics-wrapper {
141
+ i.fa.fa-external-link {
142
+ font-size: 10px;
143
+ min-width: 10px;
144
+ text-align: center;
145
+ }
146
+
147
+ a:link,
148
+ a:visited {
149
+ text-decoration: none;
150
+ }
151
+
152
+ a:hover {
153
+ color: blue;
154
+ text-decoration: solid;
155
+ text-decoration-line: underline;
156
+ }
157
+
158
+ a:active {
159
+ color: red;
160
+ }
161
+ }
162
+ }
136
163
  }
137
164
  }
@@ -18,6 +18,7 @@ import { primaryMetricsSelector } from "../../state/selectors/primaryMetrics/pri
18
18
  import { attributeTypesSelector } from "../../state/store/fileSettings/attributeTypes/attributeTypes.selector"
19
19
  import { defaultAttributeTypes } from "../../state/store/fileSettings/attributeTypes/attributeTypes.reducer"
20
20
  import { showAttributeTypeSelectorSelector } from "./util/showAttributeTypeSelector.selector"
21
+ import { metricTitles } from "../../util/metric/metricTitles"
21
22
 
22
23
  let selectedMetricNames
23
24
 
@@ -110,31 +111,29 @@ describe("AttributeSideBarComponent", () => {
110
111
  it("should contain primary/secondary metrics with title/tooltip attribute/metric descriptor information", async () => {
111
112
  selectedMetricNames.areaMetric = "a"
112
113
  selectedMetricNames.heightMetric = "b"
113
- selectedMetricNames.colorMetric = "someColor"
114
+ selectedMetricNames.colorMetric = "mcc"
114
115
  selectedMetricNames.edgeMetric = "someEdge"
115
116
 
116
117
  const { container, detectChanges } = await render(AttributeSideBarComponent, { excludeComponentDeclaration: true })
117
118
 
118
119
  const store = TestBed.inject(MockStore)
119
120
  store.overrideSelector(primaryMetricsSelector, {
120
- area: { name: "a", value: 3, descriptors: { ...TEST_ATTRIBUTE_DESCRIPTORS.a, key: "a" } },
121
- height: { name: "b", value: 1, descriptors: { ...TEST_ATTRIBUTE_DESCRIPTORS.b, key: "b" } },
121
+ area: { name: "a", value: 3 },
122
+ height: { name: "b", value: 1 },
122
123
  color: {
123
- name: "someColor",
124
- value: 10,
125
- descriptors: { key: "someColor", description: "", hintHighValue: "", hintLowValue: "", link: "", title: "" }
124
+ name: "mcc",
125
+ value: 10
126
126
  },
127
127
  edge: {
128
- name: "a",
128
+ name: "someEdge",
129
129
  incoming: 20,
130
- outgoing: 60,
131
- descriptors: { key: "someEdge", description: "", hintHighValue: "", hintLowValue: "", link: "", title: "" }
130
+ outgoing: 60
132
131
  }
133
132
  })
134
133
 
135
134
  const selectedNode = klona(TEST_NODE_FOLDER)
136
135
  selectedNode["children"] = [{}]
137
- selectedNode["attributes"] = { a: 3, b: 1, c: 4, someColor: 10 }
136
+ selectedNode["attributes"] = { a: 3, b: 1, mcc: 4, rloc: 222, someColor: 10, d: 100 }
138
137
  selectedNode["edgeAttributes"] = { someEdge: { incoming: 20, outgoing: 60 } }
139
138
  mockSelectedNode(selectedNode as unknown as CodeMapNode, detectChanges)
140
139
 
@@ -142,11 +141,15 @@ describe("AttributeSideBarComponent", () => {
142
141
  const attributeTypeSelectorWithinSecondaryMetrics = container.querySelectorAll("cc-attribute-side-bar-secondary-metrics tr")
143
142
  expect(attributeTypeSelectorWithinPrimaryMetrics[0].getAttribute("title")).toBe("a_testTitle (a):\na_testDescription")
144
143
  expect(attributeTypeSelectorWithinPrimaryMetrics[1].getAttribute("title")).toBe("b_testTitle (b)")
145
- expect(attributeTypeSelectorWithinPrimaryMetrics[2].getAttribute("title")).toBe("someColor")
146
- expect(attributeTypeSelectorWithinPrimaryMetrics[3].getAttribute("title")).toBe("someEdge")
147
-
148
- expect(attributeTypeSelectorWithinSecondaryMetrics[1].getAttribute("title")).toBe("c:\nc_testDescription")
149
- expect(attributeTypeSelectorWithinSecondaryMetrics.length).toBe(2)
144
+ expect(attributeTypeSelectorWithinPrimaryMetrics[1].querySelector("a").getAttribute("href")).toBe("https://test.link")
145
+ expect(attributeTypeSelectorWithinPrimaryMetrics[2].getAttribute("title")).toBe(metricTitles.get("mcc"))
146
+ expect(attributeTypeSelectorWithinPrimaryMetrics[3].getAttribute("title")).toBe("")
147
+
148
+ expect(attributeTypeSelectorWithinSecondaryMetrics[1].querySelector("a").getAttribute("href")).toBe("https://test2.link")
149
+ expect(attributeTypeSelectorWithinSecondaryMetrics[1].getAttribute("title")).toBe("d")
150
+ expect(attributeTypeSelectorWithinSecondaryMetrics[2].getAttribute("title")).toBe(metricTitles.get("rloc"))
151
+ expect(attributeTypeSelectorWithinSecondaryMetrics[3].getAttribute("title")).toBe("") // someColor
152
+ expect(attributeTypeSelectorWithinSecondaryMetrics.length).toBe(4) // header + three entries
150
153
  })
151
154
  })
152
155
 
@@ -10,10 +10,18 @@ import { AttributeSideBarPrimaryMetricComponent } from "./attributeSideBarPrimar
10
10
  import { AttributeSideBarHeaderSectionComponent } from "./attributeSideBarHeaderSection/attributeSideBarHeaderSection.component"
11
11
  import { NodePathComponent } from "./attributeSideBarHeaderSection/nodePath/nodePath.component"
12
12
  import { MaterialModule } from "../../../material/material.module"
13
- import { SimplePipesModule } from "../../util/simplePipes/SimplePipesModule"
13
+ import { RemoveExtensionPipeModule } from "../../util/pipes/RemoveExtensionPipeModule"
14
+ import { AttributeDescriptorTooltipPipeModule } from "../../util/pipes/AttributeDescriptorTooltipPipeModule"
14
15
 
15
16
  @NgModule({
16
- imports: [CommonModule, MaterialModule, AttributeTypeSelectorModule, MetricDeltaSelectedModule, SimplePipesModule],
17
+ imports: [
18
+ CommonModule,
19
+ MaterialModule,
20
+ AttributeTypeSelectorModule,
21
+ MetricDeltaSelectedModule,
22
+ RemoveExtensionPipeModule,
23
+ AttributeDescriptorTooltipPipeModule
24
+ ],
17
25
  declarations: [
18
26
  AttributeSideBarComponent,
19
27
  AttributeSideBarHeaderSectionComponent,
@@ -54,7 +54,7 @@ describe("nodePathComponent", () => {
54
54
  store.refreshState()
55
55
  detectChanges()
56
56
 
57
- expect(container.textContent.replace(/\s+/g, " ")).toContain("some/folder ( 2 files )")
57
+ expect(container.textContent.replaceAll(/\s+/g, " ")).toContain("some/folder ( 2 files )")
58
58
  })
59
59
 
60
60
  it("should display node path,amount of files, added and removed files, when a folder is selected and delta mode is enabled", async () => {
@@ -75,7 +75,7 @@ describe("nodePathComponent", () => {
75
75
  store.refreshState()
76
76
  detectChanges()
77
77
 
78
- expect(container.textContent.replace(/\s+/g, " ")).toContain("some/folder ( 2 files | Δ1 | Δ-2 | Δ3)")
78
+ expect(container.textContent.replaceAll(/\s+/g, " ")).toContain("some/folder ( 2 files | Δ1 | Δ-2 | Δ3)")
79
79
  })
80
80
 
81
81
  it("should display amount of files with correct english grammar, when an empty folder is selected and delta mode is enabled", async () => {
@@ -10,5 +10,11 @@
10
10
  <span class="primary-metric-value">{{ metric.value | number: "1.0-0" }}</span>
11
11
  </div>
12
12
  <cc-metric-delta-selected [metricName]="metric.name"></cc-metric-delta-selected>
13
- <span class="metric-name">{{ metric.name }}</span>
13
+ <a class="metric-name" [href]="link" target="_blank" *ngIf="metricLink as link; else primaryMetricNoLink">
14
+ {{ metric.name }}
15
+ <i class="fa fa-external-link"></i>
16
+ </a>
17
+ <ng-template #primaryMetricNoLink
18
+ ><span class="metric-name">{{ metric.name }}</span></ng-template
19
+ >
14
20
  </div>
@@ -14,6 +14,7 @@ import { showAttributeTypeSelectorSelector } from "../../util/showAttributeTypeS
14
14
  export class AttributeSideBarPrimaryMetricComponent {
15
15
  @Input() iconName: string
16
16
  @Input() metric: Metric
17
+ @Input() metricLink: string
17
18
  showAttributeTypeSelector$: Observable<boolean>
18
19
 
19
20
  constructor(store: Store<CcState>) {
@@ -1,30 +1,33 @@
1
- <div class="metric-box">
1
+ <div class="metric-box" *ngIf="attributeDescriptors$ | async as attributeDescriptors">
2
2
  <table *ngIf="primaryMetrics$ | async; let primaryMetrics" class="primary-metrics" aria-hidden="true">
3
3
  <th scope="col">Primary Metrics</th>
4
4
 
5
5
  <tr>
6
- <td [title]="primaryMetrics.area.descriptors | metricDescriptorTitle">
6
+ <td [title]="attributeDescriptors[primaryMetrics.area.name] | attributeDescriptorTooltip: primaryMetrics.area.name">
7
7
  <cc-attribute-side-bar-primary-metric
8
8
  [iconName]="'fa fa-arrows-alt'"
9
9
  [metric]="primaryMetrics.area"
10
+ [metricLink]="attributeDescriptors[primaryMetrics.area.name]?.link"
10
11
  ></cc-attribute-side-bar-primary-metric>
11
12
  </td>
12
- <td [title]="primaryMetrics.height.descriptors | metricDescriptorTitle">
13
+ <td [title]="attributeDescriptors[primaryMetrics.height.name] | attributeDescriptorTooltip: primaryMetrics.height.name">
13
14
  <cc-attribute-side-bar-primary-metric
14
15
  [iconName]="'fa fa-arrows-v'"
15
16
  [metric]="primaryMetrics.height"
17
+ [metricLink]="attributeDescriptors[primaryMetrics.height.name]?.link"
16
18
  ></cc-attribute-side-bar-primary-metric>
17
19
  </td>
18
20
  </tr>
19
21
  <tr>
20
- <td [title]="primaryMetrics.color.descriptors | metricDescriptorTitle">
22
+ <td [title]="attributeDescriptors[primaryMetrics.color.name] | attributeDescriptorTooltip: primaryMetrics.color.name">
21
23
  <cc-attribute-side-bar-primary-metric
22
24
  [iconName]="'fa fa-paint-brush'"
23
25
  [metric]="primaryMetrics.color"
26
+ [metricLink]="attributeDescriptors[primaryMetrics.color.name]?.link"
24
27
  ></cc-attribute-side-bar-primary-metric>
25
28
  </td>
26
29
  <ng-container *ngIf="primaryMetrics.edge as edge; else sidebarPrimaryMetricsEdgeElse">
27
- <td [title]="edge.descriptors | metricDescriptorTitle">
30
+ <td [title]="attributeDescriptors[edge.name] | attributeDescriptorTooltip: edge.name">
28
31
  <div class="primary-metric-box">
29
32
  <div class="primary-metric-row">
30
33
  <i class="fa fa-exchange"></i>
@@ -40,7 +43,18 @@
40
43
  {{ edge.outgoing | number: "1.0-0" }}
41
44
  </span>
42
45
  </div>
43
- <span class="metric-name">{{ edge.name }} (in/out)</span>
46
+ <a
47
+ class="metric-name"
48
+ [href]="link"
49
+ target="_blank"
50
+ *ngIf="attributeDescriptors[edge.name]?.link as link; else primaryMetricNoLink"
51
+ >
52
+ {{ edge.name }} (in/out)
53
+ <i class="fa fa-external-link"></i>
54
+ </a>
55
+ <ng-template #primaryMetricNoLink
56
+ ><span class="metric-name">{{ edge.name }} (in/out)</span></ng-template
57
+ >
44
58
  </div>
45
59
  </td>
46
60
  </ng-container>
@@ -4,7 +4,8 @@ import { Observable } from "rxjs"
4
4
  import { showAttributeTypeSelectorSelector } from "../util/showAttributeTypeSelector.selector"
5
5
  import { PrimaryMetrics, primaryMetricsSelector } from "../../../state/selectors/primaryMetrics/primaryMetrics.selector"
6
6
  import { Store } from "@ngrx/store"
7
- import { CcState } from "../../../codeCharta.model"
7
+ import { AttributeDescriptors, CcState } from "../../../codeCharta.model"
8
+ import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
8
9
 
9
10
  @Component({
10
11
  selector: "cc-attribute-side-bar-primary-metrics",
@@ -14,9 +15,11 @@ import { CcState } from "../../../codeCharta.model"
14
15
  export class AttributeSideBarPrimaryMetricsComponent {
15
16
  primaryMetrics$: Observable<PrimaryMetrics>
16
17
  showAttributeTypeSelector$: Observable<boolean>
18
+ attributeDescriptors$: Observable<AttributeDescriptors>
17
19
 
18
- constructor(store: Store<CcState>) {
19
- this.primaryMetrics$ = store.select(primaryMetricsSelector)
20
- this.showAttributeTypeSelector$ = store.select(showAttributeTypeSelectorSelector)
20
+ constructor(private store: Store<CcState>) {
21
+ this.primaryMetrics$ = this.store.select(primaryMetricsSelector)
22
+ this.showAttributeTypeSelector$ = this.store.select(showAttributeTypeSelectorSelector)
23
+ this.attributeDescriptors$ = this.store.select(attributeDescriptorsSelector)
21
24
  }
22
25
  }
@@ -1,11 +1,14 @@
1
1
  <div class="secondary-metrics-wrapper">
2
2
  <div class="metrics-wrapper">
3
- <div class="metric-box scrollable-content">
3
+ <div class="metric-box scrollable-content" *ngIf="attributeDescriptors$ | async as attributeDescriptors">
4
4
  <table class="secondary-metrics" aria-hidden="true">
5
5
  <tr>
6
6
  <th scope="col" colspan="2">Secondary Metrics</th>
7
7
  </tr>
8
- <tr *ngFor="let secondaryMetric of secondaryMetrics$ | async" [title]="secondaryMetric.descriptors | metricDescriptorTitle">
8
+ <tr
9
+ *ngFor="let secondaryMetric of secondaryMetrics$ | async"
10
+ [title]="attributeDescriptors[secondaryMetric.name] | attributeDescriptorTooltip: secondaryMetric.name"
11
+ >
9
12
  <td class="secondary-metric-box">
10
13
  <div class="secondary-metric-row">
11
14
  <cc-attribute-type-selector
@@ -22,7 +25,18 @@
22
25
  <cc-metric-delta-selected [metricName]="secondaryMetric.name"></cc-metric-delta-selected>
23
26
  </td>
24
27
  <td>
25
- <span class="metric-name">{{ secondaryMetric.name }}</span>
28
+ <a
29
+ class="metric-name"
30
+ [href]="link"
31
+ target="_blank"
32
+ *ngIf="attributeDescriptors[secondaryMetric.name]?.link as link; else secondaryMetricNoLink"
33
+ >
34
+ {{ secondaryMetric.name }}
35
+ <i class="fa fa-external-link"></i>
36
+ </a>
37
+ <ng-template #secondaryMetricNoLink
38
+ ><span class="metric-name">{{ secondaryMetric.name }}</span>
39
+ </ng-template>
26
40
  </td>
27
41
  </tr>
28
42
  </table>
@@ -1,12 +1,13 @@
1
1
  import { Component, ViewEncapsulation } from "@angular/core"
2
2
  import { Store } from "@ngrx/store"
3
3
  import { Observable } from "rxjs"
4
- import { CcState } from "../../../codeCharta.model"
4
+ import { AttributeDescriptors, CcState } from "../../../codeCharta.model"
5
5
 
6
6
  import { Metric } from "../util/metric"
7
7
  import { showAttributeTypeSelectorSelector } from "../util/showAttributeTypeSelector.selector"
8
8
  import { showDeltaValueSelector } from "../util/showDeltaValueSelector"
9
9
  import { secondaryMetricsSelector } from "./secondaryMetrics.selector"
10
+ import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
10
11
 
11
12
  @Component({
12
13
  selector: "cc-attribute-side-bar-secondary-metrics",
@@ -17,10 +18,12 @@ export class AttributeSideBarSecondaryMetricsComponent {
17
18
  secondaryMetrics$: Observable<Metric[]>
18
19
  showAttributeTypeSelector$: Observable<boolean>
19
20
  showDeltaValue$: Observable<boolean>
21
+ attributeDescriptors$: Observable<AttributeDescriptors>
20
22
 
21
- constructor(store: Store<CcState>) {
22
- this.secondaryMetrics$ = store.select(secondaryMetricsSelector)
23
- this.showAttributeTypeSelector$ = store.select(showAttributeTypeSelectorSelector)
24
- this.showDeltaValue$ = store.select(showDeltaValueSelector)
23
+ constructor(private store: Store<CcState>) {
24
+ this.secondaryMetrics$ = this.store.select(secondaryMetricsSelector)
25
+ this.showAttributeTypeSelector$ = this.store.select(showAttributeTypeSelectorSelector)
26
+ this.showDeltaValue$ = this.store.select(showDeltaValueSelector)
27
+ this.attributeDescriptors$ = this.store.select(attributeDescriptorsSelector)
25
28
  }
26
29
  }
@@ -1,6 +1,5 @@
1
1
  import { DIFFERENT_NODE } from "../../../util/dataMocks"
2
2
  import { _calculateSecondaryMetrics } from "./secondaryMetrics.selector"
3
- import { AttributeDescriptors } from "../../../codeCharta.model"
4
3
 
5
4
  const primaryMetricNames = {
6
5
  areaMetric: "a",
@@ -9,38 +8,20 @@ const primaryMetricNames = {
9
8
  edgeMetric: "None"
10
9
  }
11
10
 
12
- const attributeDescriptors: AttributeDescriptors = {}
13
-
14
11
  describe("secondaryMetricsSelector", () => {
15
12
  it("should return an empty list if there is no selectedNode", () => {
16
- expect(_calculateSecondaryMetrics(primaryMetricNames, attributeDescriptors)).toEqual([])
13
+ expect(_calculateSecondaryMetrics(primaryMetricNames)).toEqual([])
17
14
  })
18
15
 
19
16
  it("should return a by name sorted list of metrics without primary metrics", () => {
20
- expect(_calculateSecondaryMetrics(primaryMetricNames, attributeDescriptors, DIFFERENT_NODE)).toEqual([
17
+ expect(_calculateSecondaryMetrics(primaryMetricNames, DIFFERENT_NODE)).toEqual([
21
18
  {
22
19
  name: "b",
23
- value: 15,
24
- descriptors: {
25
- description: undefined,
26
- hintHighValue: undefined,
27
- hintLowValue: undefined,
28
- key: "b",
29
- link: undefined,
30
- title: undefined
31
- }
20
+ value: 15
32
21
  },
33
22
  {
34
23
  name: "mcc",
35
- value: 14,
36
- descriptors: {
37
- description: undefined,
38
- hintHighValue: undefined,
39
- hintLowValue: undefined,
40
- key: "mcc",
41
- link: undefined,
42
- title: "Cyclomatic Complexity"
43
- }
24
+ value: 14
44
25
  }
45
26
  ])
46
27
  })
@@ -1,16 +1,10 @@
1
- import { CodeMapNode, PrimaryMetrics, AttributeDescriptors } from "../../../codeCharta.model"
1
+ import { CodeMapNode, PrimaryMetrics } from "../../../codeCharta.model"
2
2
  import { primaryMetricNamesSelector } from "../../../state/selectors/primaryMetrics/primaryMetricNames.selector"
3
3
  import { selectedNodeSelector } from "../../../state/selectors/selectedNode.selector"
4
4
  import { Metric } from "../util/metric"
5
- import { attributeDescriptorsSelector } from "../../../state/store/fileSettings/attributeDescriptors/attributeDescriptors.selector"
6
- import { getMetricDescriptors } from "../util/metricDescriptors"
7
5
  import { createSelector } from "@ngrx/store"
8
6
 
9
- export const _calculateSecondaryMetrics = (
10
- primaryMetrics: PrimaryMetrics,
11
- attributeDescriptors: AttributeDescriptors,
12
- node?: Pick<CodeMapNode, "attributes">
13
- ) => {
7
+ export const _calculateSecondaryMetrics = (primaryMetrics: PrimaryMetrics, node?: Pick<CodeMapNode, "attributes">) => {
14
8
  if (!node) {
15
9
  return [] as Metric[]
16
10
  }
@@ -22,14 +16,8 @@ export const _calculateSecondaryMetrics = (
22
16
 
23
17
  return secondaryMetricNames.map(secondaryMetricName => ({
24
18
  name: secondaryMetricName,
25
- value: node.attributes[secondaryMetricName],
26
- descriptors: getMetricDescriptors(secondaryMetricName, attributeDescriptors)
19
+ value: node.attributes[secondaryMetricName]
27
20
  }))
28
21
  }
29
22
 
30
- export const secondaryMetricsSelector = createSelector(
31
- primaryMetricNamesSelector,
32
- attributeDescriptorsSelector,
33
- selectedNodeSelector,
34
- _calculateSecondaryMetrics
35
- )
23
+ export const secondaryMetricsSelector = createSelector(primaryMetricNamesSelector, selectedNodeSelector, _calculateSecondaryMetrics)
@@ -12,7 +12,7 @@ import { mapColorsSelector } from "../../../state/store/appSettings/mapColors/ma
12
12
  describe("MetricDeltaSelectedComponent", () => {
13
13
  const areColorsEqual = (hex: string, styleColor: string) => {
14
14
  const formattedHex = ColorConverter.convertHexToRgba(hex).replace(/,1\)$/, ")").replace("a", "")
15
- const formattedStyleColor = styleColor.replace(/ /g, "")
15
+ const formattedStyleColor = styleColor.replaceAll(" ", "")
16
16
  return formattedHex === formattedStyleColor
17
17
  }
18
18
 
@@ -1,7 +1,5 @@
1
- import { MetricDescriptors } from "./metricDescriptors"
2
1
  export type Edge = {
3
2
  name: string
4
3
  incoming: number | undefined
5
4
  outgoing: number | undefined
6
- descriptors: MetricDescriptors
7
5
  }
@@ -1,6 +1,4 @@
1
- import { MetricDescriptors } from "./metricDescriptors"
2
1
  export type Metric = {
3
2
  name: string
4
3
  value: number
5
- descriptors: MetricDescriptors
6
4
  }
@@ -256,12 +256,9 @@ export class CodeMapArrowService implements OnDestroy {
256
256
  }
257
257
 
258
258
  private buildArrow(points: Vector3[], ARROW_COLOR = 0, headLength = 10, headWidth = 10) {
259
- const direction = points[points.length - 1]
260
- .clone()
261
- .sub(points[points.length - 2].clone())
262
- .normalize()
259
+ const direction = points.at(-1).clone().sub(points.at(-2).clone()).normalize()
263
260
 
264
- const origin = points[points.length - 1].clone()
261
+ const origin = points.at(-1).clone()
265
262
  if (direction.y < 0) {
266
263
  origin.y += headLength + 1
267
264
  }