@backstage/plugin-app-visualizer 0.1.25-next.1 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/components/AppVisualizerPage/AppVisualizerPage.esm.js +2 -2
- package/dist/components/AppVisualizerPage/AppVisualizerPage.esm.js.map +1 -1
- package/dist/components/AppVisualizerPage/DetailedVisualizer.esm.js +173 -181
- package/dist/components/AppVisualizerPage/DetailedVisualizer.esm.js.map +1 -1
- package/dist/components/AppVisualizerPage/TextVisualizer.esm.js +18 -34
- package/dist/components/AppVisualizerPage/TextVisualizer.esm.js.map +1 -1
- package/dist/components/AppVisualizerPage/TreeVisualizer.esm.js +14 -20
- package/dist/components/AppVisualizerPage/TreeVisualizer.esm.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/package.json.esm.js +4 -3
- package/dist/package.json.esm.js.map +1 -1
- package/dist/plugin.esm.js +2 -2
- package/dist/plugin.esm.js.map +1 -1
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @backstage/plugin-app-visualizer
|
|
2
2
|
|
|
3
|
+
## 0.1.25
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e81b3f0: Improve tree visualizer to use a horizontal layout and fill the content space.
|
|
8
|
+
- 722e2df: Migrated to use `@backstage/ui`.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/ui@0.9.0
|
|
11
|
+
- @backstage/frontend-plugin-api@0.13.0
|
|
12
|
+
- @backstage/core-components@0.18.3
|
|
13
|
+
- @backstage/core-plugin-api@1.12.0
|
|
14
|
+
|
|
15
|
+
## 0.1.25-next.2
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 722e2df: Migrated to use `@backstage/ui`.
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/ui@0.9.0-next.3
|
|
22
|
+
- @backstage/frontend-plugin-api@0.12.2-next.2
|
|
23
|
+
- @backstage/core-components@0.18.3-next.2
|
|
24
|
+
|
|
3
25
|
## 0.1.25-next.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import { Page, Header, Content, HeaderTabs } from '@backstage/core-components';
|
|
3
3
|
import { useApi } from '@backstage/core-plugin-api';
|
|
4
4
|
import { appTreeApiRef } from '@backstage/frontend-plugin-api';
|
|
5
|
-
import
|
|
5
|
+
import { Flex } from '@backstage/ui';
|
|
6
6
|
import { useMemo, useCallback, useEffect } from 'react';
|
|
7
7
|
import { DetailedVisualizer } from './DetailedVisualizer.esm.js';
|
|
8
8
|
import { TextVisualizer } from './TextVisualizer.esm.js';
|
|
@@ -54,7 +54,7 @@ function AppVisualizerPage() {
|
|
|
54
54
|
}, [element, navigate, tabs]);
|
|
55
55
|
return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
|
|
56
56
|
/* @__PURE__ */ jsx(Header, { title: "App Visualizer" }),
|
|
57
|
-
/* @__PURE__ */ jsx(Content, { noPadding: true, stretch: true, children: /* @__PURE__ */ jsxs(
|
|
57
|
+
/* @__PURE__ */ jsx(Content, { noPadding: true, stretch: true, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { height: "100%" }, children: [
|
|
58
58
|
/* @__PURE__ */ jsx(
|
|
59
59
|
HeaderTabs,
|
|
60
60
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppVisualizerPage.esm.js","sources":["../../../src/components/AppVisualizerPage/AppVisualizerPage.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Content, Header, HeaderTabs, Page } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { appTreeApiRef } from '@backstage/frontend-plugin-api';\nimport
|
|
1
|
+
{"version":3,"file":"AppVisualizerPage.esm.js","sources":["../../../src/components/AppVisualizerPage/AppVisualizerPage.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Content, Header, HeaderTabs, Page } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { appTreeApiRef } from '@backstage/frontend-plugin-api';\nimport { Flex } from '@backstage/ui';\nimport { useCallback, useEffect, useMemo } from 'react';\nimport { DetailedVisualizer } from './DetailedVisualizer';\nimport { TextVisualizer } from './TextVisualizer';\nimport { TreeVisualizer } from './TreeVisualizer';\nimport {\n matchRoutes,\n useLocation,\n useNavigate,\n useParams,\n useRoutes,\n} from 'react-router-dom';\n\nexport function AppVisualizerPage() {\n const appTreeApi = useApi(appTreeApiRef);\n const { tree } = appTreeApi.getTree();\n\n const tabs = useMemo(\n () => [\n {\n id: 'tree',\n path: 'tree',\n label: 'Tree',\n element: <TreeVisualizer tree={tree} />,\n },\n {\n id: 'detailed',\n path: 'detailed',\n label: 'Detailed',\n element: <DetailedVisualizer tree={tree} />,\n },\n {\n id: 'text',\n path: 'text',\n label: 'Text',\n element: <TextVisualizer tree={tree} />,\n },\n ],\n [tree],\n );\n\n const location = useLocation();\n const element = useRoutes(tabs, location);\n\n const currentPath = `/${useParams()['*']}`;\n const [matchedRoute] = matchRoutes(tabs, currentPath) ?? [];\n\n const currentTabIndex = matchedRoute\n ? tabs.findIndex(t => t.path === matchedRoute.route.path)\n : 0;\n\n const navigate = useNavigate();\n const handleTabChange = useCallback(\n (index: number) => {\n navigate(tabs[index].id);\n },\n [navigate, tabs],\n );\n\n useEffect(() => {\n if (!element) {\n navigate(tabs[0].path);\n }\n }, [element, navigate, tabs]);\n\n return (\n <Page themeId=\"tool\">\n <Header title=\"App Visualizer\" />\n <Content noPadding stretch>\n <Flex direction=\"column\" style={{ height: '100%' }}>\n <HeaderTabs\n tabs={tabs}\n selectedIndex={currentTabIndex}\n onChange={handleTabChange}\n />\n {element}\n </Flex>\n </Content>\n </Page>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAgCO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,UAAA,CAAW,OAAA,EAAQ;AAEpC,EAAA,MAAM,IAAA,GAAO,OAAA;AAAA,IACX,MAAM;AAAA,MACJ;AAAA,QACE,EAAA,EAAI,MAAA;AAAA,QACJ,IAAA,EAAM,MAAA;AAAA,QACN,KAAA,EAAO,MAAA;AAAA,QACP,OAAA,kBAAS,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY;AAAA,OACvC;AAAA,MACA;AAAA,QACE,EAAA,EAAI,UAAA;AAAA,QACJ,IAAA,EAAM,UAAA;AAAA,QACN,KAAA,EAAO,UAAA;AAAA,QACP,OAAA,kBAAS,GAAA,CAAC,kBAAA,EAAA,EAAmB,IAAA,EAAY;AAAA,OAC3C;AAAA,MACA;AAAA,QACE,EAAA,EAAI,MAAA;AAAA,QACJ,IAAA,EAAM,MAAA;AAAA,QACN,KAAA,EAAO,MAAA;AAAA,QACP,OAAA,kBAAS,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY;AAAA;AACvC,KACF;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,EAAM,QAAQ,CAAA;AAExC,EAAA,MAAM,WAAA,GAAc,CAAA,CAAA,EAAI,SAAA,EAAU,CAAE,GAAG,CAAC,CAAA,CAAA;AACxC,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,YAAY,IAAA,EAAM,WAAW,KAAK,EAAC;AAE1D,EAAA,MAAM,eAAA,GAAkB,YAAA,GACpB,IAAA,CAAK,SAAA,CAAU,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,YAAA,CAAa,KAAA,CAAM,IAAI,CAAA,GACtD,CAAA;AAEJ,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,eAAA,GAAkB,WAAA;AAAA,IACtB,CAAC,KAAA,KAAkB;AACjB,MAAA,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA,CAAE,EAAE,CAAA;AAAA,IACzB,CAAA;AAAA,IACA,CAAC,UAAU,IAAI;AAAA,GACjB;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,CAAE,IAAI,CAAA;AAAA,IACvB;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,QAAA,EAAU,IAAI,CAAC,CAAA;AAE5B,EAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,MAAA,EACZ,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,OAAM,gBAAA,EAAiB,CAAA;AAAA,oBAC/B,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAS,IAAA,EAAC,SAAO,IAAA,EACxB,QAAA,kBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAO,EAC/C,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,IAAA;AAAA,UACA,aAAA,EAAe,eAAA;AAAA,UACf,QAAA,EAAU;AAAA;AAAA,OACZ;AAAA,MACC;AAAA,KAAA,EACH,CAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1,126 +1,60 @@
|
|
|
1
|
-
import { jsxs, jsx
|
|
2
|
-
import { ThemeBlueprint, NavItemBlueprint, coreExtensionData, ApiBlueprint,
|
|
3
|
-
import Box from '@
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import Typography from '@material-ui/core/Typography';
|
|
7
|
-
import * as colors from '@material-ui/core/colors';
|
|
8
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
9
|
-
import InputIcon from '@material-ui/icons/InputSharp';
|
|
10
|
-
import DisabledIcon from '@material-ui/icons/NotInterestedSharp';
|
|
11
|
-
import { Link } from 'react-router-dom';
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { ThemeBlueprint, NavItemBlueprint, coreExtensionData, ApiBlueprint, useApi, routeResolutionApiRef } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { Flex, Box, TooltipTrigger, Text, Tooltip, Link } from '@backstage/ui';
|
|
4
|
+
import { RiCloseCircleLine, RiInputField } from '@remixicon/react';
|
|
5
|
+
import { Focusable } from 'react-aria-components';
|
|
12
6
|
|
|
7
|
+
function getContrastColor(bgColor) {
|
|
8
|
+
const hex = bgColor.replace("#", "");
|
|
9
|
+
const r = parseInt(hex.substr(0, 2), 16);
|
|
10
|
+
const g = parseInt(hex.substr(2, 2), 16);
|
|
11
|
+
const b = parseInt(hex.substr(4, 2), 16);
|
|
12
|
+
const brightness = (r * 299 + g * 587 + b * 114) / 1e3;
|
|
13
|
+
return brightness > 128 ? "#000000" : "#ffffff";
|
|
14
|
+
}
|
|
13
15
|
function createOutputColorGenerator(colorMap, availableColors) {
|
|
14
16
|
const map = /* @__PURE__ */ new Map();
|
|
15
17
|
let i = 0;
|
|
16
18
|
return function getOutputColor2(id) {
|
|
19
|
+
let backgroundColor;
|
|
17
20
|
if (id in colorMap) {
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
backgroundColor = colorMap[id];
|
|
22
|
+
} else {
|
|
23
|
+
const cached = map.get(id);
|
|
24
|
+
if (cached) {
|
|
25
|
+
return cached;
|
|
26
|
+
}
|
|
27
|
+
backgroundColor = availableColors[i];
|
|
28
|
+
i += 1;
|
|
29
|
+
if (i >= availableColors.length) {
|
|
30
|
+
i = 0;
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return color;
|
|
33
|
+
const result = {
|
|
34
|
+
backgroundColor,
|
|
35
|
+
color: getContrastColor(backgroundColor)
|
|
36
|
+
};
|
|
37
|
+
map.set(id, result);
|
|
38
|
+
return result;
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
41
|
const getOutputColor = createOutputColorGenerator(
|
|
34
42
|
{
|
|
35
|
-
[coreExtensionData.reactElement.id]:
|
|
36
|
-
[coreExtensionData.routePath.id]:
|
|
37
|
-
[coreExtensionData.routeRef.id]:
|
|
38
|
-
[ApiBlueprint.dataRefs.factory.id]:
|
|
39
|
-
[ThemeBlueprint.dataRefs.theme.id]:
|
|
40
|
-
[NavItemBlueprint.dataRefs.target.id]:
|
|
43
|
+
[coreExtensionData.reactElement.id]: "#4caf50",
|
|
44
|
+
[coreExtensionData.routePath.id]: "#ffeb3b",
|
|
45
|
+
[coreExtensionData.routeRef.id]: "#9c27b0",
|
|
46
|
+
[ApiBlueprint.dataRefs.factory.id]: "#2196f3",
|
|
47
|
+
[ThemeBlueprint.dataRefs.theme.id]: "#cddc39",
|
|
48
|
+
[NavItemBlueprint.dataRefs.target.id]: "#ff9800"
|
|
41
49
|
},
|
|
42
|
-
[
|
|
43
|
-
colors.blue[200],
|
|
44
|
-
colors.orange[200],
|
|
45
|
-
colors.green[200],
|
|
46
|
-
colors.red[200],
|
|
47
|
-
colors.yellow[200],
|
|
48
|
-
colors.purple[200],
|
|
49
|
-
colors.lime[200]
|
|
50
|
-
]
|
|
50
|
+
["#90caf9", "#ffcc80", "#a5d6a7", "#ef9a9a", "#fff59d", "#ce93d8", "#e6ee9c"]
|
|
51
51
|
);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
borderLeftStyle: "solid",
|
|
59
|
-
borderLeftColor: ({ depth }) => colors.grey[700 - depth % 6 * 100],
|
|
60
|
-
cursor: "pointer",
|
|
61
|
-
"&:hover $extensionHeader": {
|
|
62
|
-
color: ({ enabled }) => enabled ? theme.palette.primary.main : theme.palette.text.secondary
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
extensionHeader: {
|
|
66
|
-
display: "flex",
|
|
67
|
-
alignItems: "center",
|
|
68
|
-
width: "fit-content",
|
|
69
|
-
padding: theme.spacing(0.5, 1),
|
|
70
|
-
color: ({ enabled }) => enabled ? theme.palette.text.primary : theme.palette.text.disabled,
|
|
71
|
-
background: theme.palette.background.paper,
|
|
72
|
-
borderTopRightRadius: theme.shape.borderRadius,
|
|
73
|
-
borderBottomRightRadius: theme.shape.borderRadius
|
|
74
|
-
},
|
|
75
|
-
extensionHeaderId: {
|
|
76
|
-
userSelect: "all"
|
|
77
|
-
},
|
|
78
|
-
extensionHeaderOutputs: {
|
|
79
|
-
display: "flex",
|
|
80
|
-
alignItems: "center",
|
|
81
|
-
marginLeft: theme.spacing(1),
|
|
82
|
-
gap: theme.spacing(1)
|
|
83
|
-
},
|
|
84
|
-
attachments: {
|
|
85
|
-
gap: theme.spacing(2),
|
|
86
|
-
display: "flex",
|
|
87
|
-
flexDirection: "column"
|
|
88
|
-
},
|
|
89
|
-
attachmentsInput: {
|
|
90
|
-
"&:first-child $attachmentsInputTitle": {
|
|
91
|
-
borderTop: 0
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
attachmentsInputTitle: {
|
|
95
|
-
display: "flex",
|
|
96
|
-
alignItems: "center",
|
|
97
|
-
width: "fit-content",
|
|
98
|
-
padding: theme.spacing(1),
|
|
99
|
-
borderTopWidth: theme.spacing(config.borderWidth),
|
|
100
|
-
borderTopStyle: "solid",
|
|
101
|
-
borderTopColor: ({ depth }) => colors.grey[700 - depth % 6 * 100]
|
|
102
|
-
},
|
|
103
|
-
attachmentsInputName: {
|
|
104
|
-
marginLeft: theme.spacing(1)
|
|
105
|
-
},
|
|
106
|
-
attachmentsInputChildren: {
|
|
107
|
-
display: "flex",
|
|
108
|
-
flexDirection: "column",
|
|
109
|
-
alignItems: "flex-start",
|
|
110
|
-
gap: theme.spacing(0.5),
|
|
111
|
-
marginLeft: theme.spacing(1),
|
|
112
|
-
marginBottom: theme.spacing(1)
|
|
113
|
-
}
|
|
114
|
-
}));
|
|
115
|
-
const useOutputStyles = makeStyles((theme) => ({
|
|
116
|
-
output: ({ color }) => ({
|
|
117
|
-
padding: `0 10px`,
|
|
118
|
-
height: 20,
|
|
119
|
-
borderRadius: 10,
|
|
120
|
-
color: theme.palette.getContrastText(color),
|
|
121
|
-
backgroundColor: color
|
|
122
|
-
})
|
|
123
|
-
}));
|
|
52
|
+
function getBorderColor(depth) {
|
|
53
|
+
const greyLevels = [8, 7, 6, 5];
|
|
54
|
+
const index = depth % greyLevels.length;
|
|
55
|
+
const level = greyLevels[index];
|
|
56
|
+
return `var(--bui-gray-${level})`;
|
|
57
|
+
}
|
|
124
58
|
function getFullPath(node) {
|
|
125
59
|
if (!node) {
|
|
126
60
|
return "";
|
|
@@ -132,46 +66,75 @@ function getFullPath(node) {
|
|
|
132
66
|
}
|
|
133
67
|
return getFullPath(parent) + part;
|
|
134
68
|
}
|
|
135
|
-
function OutputLink(props) {
|
|
136
|
-
const routeRef = props.node?.instance?.getData(coreExtensionData.routeRef);
|
|
137
|
-
try {
|
|
138
|
-
const link = useRouteRef(routeRef);
|
|
139
|
-
return /* @__PURE__ */ jsx(Tooltip, { title: /* @__PURE__ */ jsx(Typography, { children: props.dataRef.id }), children: /* @__PURE__ */ jsx(Box, { className: props.className, children: link ? /* @__PURE__ */ jsx(Link, { to: link(), children: "link" }) : null }) });
|
|
140
|
-
} catch (ex) {
|
|
141
|
-
console.warn(
|
|
142
|
-
props.node?.spec.id ? `Unable to generate output link for ${props.node.spec.id}` : "Unable to generate output link",
|
|
143
|
-
ex
|
|
144
|
-
);
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
69
|
function Output(props) {
|
|
149
70
|
const { dataRef, node } = props;
|
|
150
71
|
const { id } = dataRef;
|
|
151
72
|
const instance = node?.instance;
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
73
|
+
const routeResolutionApi = useApi(routeResolutionApiRef);
|
|
74
|
+
const { backgroundColor, color } = getOutputColor(id);
|
|
75
|
+
const chipStyle = {
|
|
76
|
+
height: 20,
|
|
77
|
+
padding: "0 10px",
|
|
78
|
+
borderRadius: "10px",
|
|
79
|
+
color,
|
|
80
|
+
backgroundColor,
|
|
81
|
+
display: "flex",
|
|
82
|
+
alignItems: "center",
|
|
83
|
+
fontWeight: "var(--bui-font-weight-regular)"
|
|
84
|
+
};
|
|
85
|
+
if (id === coreExtensionData.routeRef.id && node) {
|
|
86
|
+
try {
|
|
87
|
+
const routeRef = props.node?.instance?.getData(
|
|
88
|
+
coreExtensionData.routeRef
|
|
89
|
+
);
|
|
90
|
+
const link = routeRef && routeResolutionApi.resolve(routeRef)?.();
|
|
91
|
+
if (link) {
|
|
92
|
+
return /* @__PURE__ */ jsxs(TooltipTrigger, { children: [
|
|
93
|
+
/* @__PURE__ */ jsx(Link, { href: link, style: chipStyle, children: "link" }),
|
|
94
|
+
/* @__PURE__ */ jsx(Tooltip, { children: id })
|
|
95
|
+
] });
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
155
99
|
}
|
|
156
|
-
|
|
157
|
-
|
|
100
|
+
let tooltip = id;
|
|
101
|
+
let text = void 0;
|
|
102
|
+
if (id === coreExtensionData.routePath.id) {
|
|
103
|
+
text = String(instance?.getData(dataRef) ?? "");
|
|
104
|
+
tooltip = getFullPath(node);
|
|
158
105
|
}
|
|
159
|
-
return /* @__PURE__ */
|
|
106
|
+
return /* @__PURE__ */ jsxs(TooltipTrigger, { children: [
|
|
107
|
+
/* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx(Text, { style: { ...chipStyle, cursor: "help" }, children: text }) }),
|
|
108
|
+
/* @__PURE__ */ jsx(Tooltip, { style: { maxWidth: "unset" }, children: tooltip })
|
|
109
|
+
] });
|
|
160
110
|
}
|
|
161
111
|
function Attachments(props) {
|
|
162
|
-
const { node,
|
|
112
|
+
const { node, depth } = props;
|
|
163
113
|
const { attachments } = node.edges;
|
|
164
|
-
const classes = useStyles({ enabled, depth });
|
|
165
114
|
if (attachments.size === 0) {
|
|
166
115
|
return null;
|
|
167
116
|
}
|
|
168
|
-
return /* @__PURE__ */ jsx(
|
|
169
|
-
return /* @__PURE__ */ jsxs(Box, {
|
|
170
|
-
/* @__PURE__ */ jsxs(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
117
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "4", children: [...attachments.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, children], idx) => {
|
|
118
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
119
|
+
/* @__PURE__ */ jsxs(
|
|
120
|
+
Flex,
|
|
121
|
+
{
|
|
122
|
+
p: "2",
|
|
123
|
+
align: "center",
|
|
124
|
+
style: {
|
|
125
|
+
borderTopWidth: "var(--bui-space-1_5)",
|
|
126
|
+
borderTopStyle: "solid",
|
|
127
|
+
borderTopColor: getBorderColor(depth),
|
|
128
|
+
borderTop: idx === 0 ? "none" : void 0,
|
|
129
|
+
width: "fit-content"
|
|
130
|
+
},
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ jsx(RiInputField, { size: 16 }),
|
|
133
|
+
/* @__PURE__ */ jsx("div", { style: { marginLeft: "var(--bui-space-2)" }, children: key })
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
/* @__PURE__ */ jsx(Flex, { ml: "2", mb: "2", direction: "column", align: "start", gap: "1", children: children.map((childNode) => /* @__PURE__ */ jsx(
|
|
175
138
|
Extension,
|
|
176
139
|
{
|
|
177
140
|
node: childNode,
|
|
@@ -182,33 +145,59 @@ function Attachments(props) {
|
|
|
182
145
|
] }, key);
|
|
183
146
|
}) });
|
|
184
147
|
}
|
|
185
|
-
function ExtensionTooltip(props) {
|
|
186
|
-
const parts = [];
|
|
187
|
-
let node = props.node;
|
|
188
|
-
parts.push(node.spec.id);
|
|
189
|
-
while (node.edges.attachedTo) {
|
|
190
|
-
const input = node.edges.attachedTo.input;
|
|
191
|
-
node = node.edges.attachedTo.node;
|
|
192
|
-
parts.push(`${node.spec.id} [${input}]`);
|
|
193
|
-
}
|
|
194
|
-
parts.reverse();
|
|
195
|
-
return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part) => /* @__PURE__ */ jsx(Typography, { children: part }, part)) });
|
|
196
|
-
}
|
|
197
148
|
function Extension(props) {
|
|
198
149
|
const { node, depth } = props;
|
|
199
150
|
const enabled = Boolean(node.instance);
|
|
200
|
-
const classes = useStyles({ enabled, depth });
|
|
201
151
|
const dataRefs = node.instance && [...node.instance.getDataRefs()];
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
152
|
+
const tooltipParts = [];
|
|
153
|
+
let currentNode = node;
|
|
154
|
+
tooltipParts.push(currentNode.spec.id);
|
|
155
|
+
while (currentNode.edges.attachedTo) {
|
|
156
|
+
const input = currentNode.edges.attachedTo.input;
|
|
157
|
+
currentNode = currentNode.edges.attachedTo.node;
|
|
158
|
+
tooltipParts.push(`${currentNode.spec.id} [${input}]`);
|
|
159
|
+
}
|
|
160
|
+
tooltipParts.reverse();
|
|
161
|
+
const tooltipText = tooltipParts.join("\n");
|
|
162
|
+
return /* @__PURE__ */ jsxs(
|
|
163
|
+
Box,
|
|
164
|
+
{
|
|
165
|
+
style: {
|
|
166
|
+
borderLeftWidth: "var(--bui-space-1_5)",
|
|
167
|
+
borderLeftStyle: "solid",
|
|
168
|
+
borderLeftColor: getBorderColor(depth)
|
|
169
|
+
},
|
|
170
|
+
children: [
|
|
171
|
+
/* @__PURE__ */ jsxs(
|
|
172
|
+
Flex,
|
|
173
|
+
{
|
|
174
|
+
py: "1",
|
|
175
|
+
px: "2",
|
|
176
|
+
align: "center",
|
|
177
|
+
style: {
|
|
178
|
+
width: "fit-content",
|
|
179
|
+
color: enabled ? "var(--bui-fg-primary)" : "var(--bui-fg-disabled)",
|
|
180
|
+
background: "var(--bui-bg-surface-1)",
|
|
181
|
+
borderTopRightRadius: "var(--bui-radius-2)",
|
|
182
|
+
borderBottomRightRadius: "var(--bui-radius-2)"
|
|
183
|
+
},
|
|
184
|
+
children: [
|
|
185
|
+
/* @__PURE__ */ jsxs(TooltipTrigger, { children: [
|
|
186
|
+
/* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx(Text, { style: { userSelect: "all" }, children: node.spec.id }) }),
|
|
187
|
+
/* @__PURE__ */ jsx(Tooltip, { style: { maxWidth: "unset" }, children: /* @__PURE__ */ jsx(Text, { style: { whiteSpace: "pre-wrap" }, children: tooltipText }) })
|
|
188
|
+
] }),
|
|
189
|
+
/* @__PURE__ */ jsxs(Flex, { ml: "2", align: "center", gap: "2", children: [
|
|
190
|
+
dataRefs && dataRefs.length > 0 && dataRefs.sort((a, b) => a.id.localeCompare(b.id)).map((ref) => /* @__PURE__ */ jsx(Output, { dataRef: ref, node }, ref.id)),
|
|
191
|
+
!enabled && /* @__PURE__ */ jsx(RiCloseCircleLine, { size: 16 })
|
|
192
|
+
] })
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
),
|
|
196
|
+
/* @__PURE__ */ jsx(Attachments, { node, enabled, depth })
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
node.spec.id
|
|
200
|
+
);
|
|
212
201
|
}
|
|
213
202
|
const legendMap = {
|
|
214
203
|
"React Element": coreExtensionData.reactElement,
|
|
@@ -222,33 +211,36 @@ function Legend() {
|
|
|
222
211
|
return /* @__PURE__ */ jsx(
|
|
223
212
|
Box,
|
|
224
213
|
{
|
|
225
|
-
|
|
226
|
-
maxWidth: 600,
|
|
227
|
-
p: 1,
|
|
214
|
+
p: "2",
|
|
228
215
|
style: {
|
|
216
|
+
display: "grid",
|
|
217
|
+
maxWidth: 600,
|
|
229
218
|
grid: "auto-flow / repeat(3, 1fr)",
|
|
230
|
-
gap:
|
|
219
|
+
gap: "var(--bui-space-4)"
|
|
231
220
|
},
|
|
232
|
-
children: Object.entries(legendMap).map(([label, dataRef]) => /* @__PURE__ */ jsxs(
|
|
233
|
-
|
|
234
|
-
{
|
|
235
|
-
|
|
236
|
-
style: { gap: 8 },
|
|
237
|
-
alignItems: "center",
|
|
238
|
-
children: [
|
|
239
|
-
/* @__PURE__ */ jsx(Output, { dataRef }),
|
|
240
|
-
/* @__PURE__ */ jsx(Typography, { children: label })
|
|
241
|
-
]
|
|
242
|
-
},
|
|
243
|
-
dataRef.id
|
|
244
|
-
))
|
|
221
|
+
children: Object.entries(legendMap).map(([label, dataRef]) => /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
|
|
222
|
+
/* @__PURE__ */ jsx(Output, { dataRef }),
|
|
223
|
+
/* @__PURE__ */ jsx("div", { children: label })
|
|
224
|
+
] }, dataRef.id))
|
|
245
225
|
}
|
|
246
226
|
);
|
|
247
227
|
}
|
|
248
228
|
function DetailedVisualizer({ tree }) {
|
|
249
|
-
return /* @__PURE__ */ jsxs(
|
|
250
|
-
/* @__PURE__ */ jsx(Box, { flex: "1 1 0", overflow: "auto"
|
|
251
|
-
/* @__PURE__ */ jsx(
|
|
229
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { height: "100%", flex: "1 1 100%" }, children: [
|
|
230
|
+
/* @__PURE__ */ jsx(Box, { ml: "4", mt: "4", style: { flex: "1 1 0", overflow: "auto" }, children: /* @__PURE__ */ jsx(Extension, { node: tree.root, depth: 0 }) }),
|
|
231
|
+
/* @__PURE__ */ jsx(
|
|
232
|
+
Box,
|
|
233
|
+
{
|
|
234
|
+
m: "2",
|
|
235
|
+
style: {
|
|
236
|
+
flex: "0 0 auto",
|
|
237
|
+
background: "var(--bui-bg-surface-1)",
|
|
238
|
+
border: "1px solid var(--bui-border)",
|
|
239
|
+
borderRadius: "var(--bui-radius-2)"
|
|
240
|
+
},
|
|
241
|
+
children: /* @__PURE__ */ jsx(Legend, {})
|
|
242
|
+
}
|
|
243
|
+
)
|
|
252
244
|
] });
|
|
253
245
|
}
|
|
254
246
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DetailedVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/DetailedVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppNode,\n AppTree,\n ExtensionDataRef,\n RouteRef,\n coreExtensionData,\n ApiBlueprint,\n NavItemBlueprint,\n ThemeBlueprint,\n useRouteRef,\n} from '@backstage/frontend-plugin-api';\nimport Box from '@material-ui/core/Box';\nimport Paper from '@material-ui/core/Paper';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport * as colors from '@material-ui/core/colors';\nimport { makeStyles } from '@material-ui/core/styles';\nimport InputIcon from '@material-ui/icons/InputSharp';\nimport DisabledIcon from '@material-ui/icons/NotInterestedSharp';\nimport { Link } from 'react-router-dom';\n\nfunction createOutputColorGenerator(\n colorMap: { [extDataId: string]: string },\n availableColors: string[],\n) {\n const map = new Map<string, string>();\n let i = 0;\n\n return function getOutputColor(id: string) {\n if (id in colorMap) {\n return colorMap[id];\n }\n let color = map.get(id);\n if (color) {\n return color;\n }\n color = availableColors[i];\n i += 1;\n if (i >= availableColors.length) {\n i = 0;\n }\n map.set(id, color);\n return color;\n };\n}\n\nconst getOutputColor = createOutputColorGenerator(\n {\n [coreExtensionData.reactElement.id]: colors.green[500],\n [coreExtensionData.routePath.id]: colors.yellow[500],\n [coreExtensionData.routeRef.id]: colors.purple[500],\n [ApiBlueprint.dataRefs.factory.id]: colors.blue[500],\n [ThemeBlueprint.dataRefs.theme.id]: colors.lime[500],\n [NavItemBlueprint.dataRefs.target.id]: colors.orange[500],\n },\n\n [\n colors.blue[200],\n colors.orange[200],\n colors.green[200],\n colors.red[200],\n colors.yellow[200],\n colors.purple[200],\n colors.lime[200],\n ],\n);\n\ninterface StyleProps {\n enabled: boolean;\n depth: number;\n}\n\nconst config = {\n borderWidth: 0.75,\n};\n\nconst useStyles = makeStyles(theme => ({\n extension: {\n borderLeftWidth: theme.spacing(config.borderWidth),\n borderLeftStyle: 'solid',\n borderLeftColor: ({ depth }: StyleProps) =>\n colors.grey[(700 - (depth % 6) * 100) as keyof typeof colors.grey],\n cursor: 'pointer',\n\n '&:hover $extensionHeader': {\n color: ({ enabled }: StyleProps) =>\n enabled ? theme.palette.primary.main : theme.palette.text.secondary,\n },\n },\n extensionHeader: {\n display: 'flex',\n alignItems: 'center',\n width: 'fit-content',\n\n padding: theme.spacing(0.5, 1),\n color: ({ enabled }: StyleProps) =>\n enabled ? theme.palette.text.primary : theme.palette.text.disabled,\n background: theme.palette.background.paper,\n\n borderTopRightRadius: theme.shape.borderRadius,\n borderBottomRightRadius: theme.shape.borderRadius,\n },\n extensionHeaderId: {\n userSelect: 'all',\n },\n extensionHeaderOutputs: {\n display: 'flex',\n alignItems: 'center',\n marginLeft: theme.spacing(1),\n gap: theme.spacing(1),\n },\n attachments: {\n gap: theme.spacing(2),\n display: 'flex',\n flexDirection: 'column',\n },\n attachmentsInput: {\n '&:first-child $attachmentsInputTitle': {\n borderTop: 0,\n },\n },\n attachmentsInputTitle: {\n display: 'flex',\n alignItems: 'center',\n width: 'fit-content',\n padding: theme.spacing(1),\n\n borderTopWidth: theme.spacing(config.borderWidth),\n borderTopStyle: 'solid',\n borderTopColor: ({ depth }: StyleProps) =>\n colors.grey[(700 - (depth % 6) * 100) as keyof typeof colors.grey],\n },\n attachmentsInputName: {\n marginLeft: theme.spacing(1),\n },\n attachmentsInputChildren: {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: theme.spacing(0.5),\n marginLeft: theme.spacing(1),\n marginBottom: theme.spacing(1),\n },\n}));\n\nconst useOutputStyles = makeStyles(theme => ({\n output: ({ color }: { color: string }) => ({\n padding: `0 10px`,\n height: 20,\n borderRadius: 10,\n color: theme.palette.getContrastText(color),\n backgroundColor: color,\n }),\n}));\n\nfunction getFullPath(node?: AppNode): string {\n if (!node) {\n return '';\n }\n const parent = node.edges.attachedTo?.node;\n const part = node.instance?.getData(coreExtensionData.routePath);\n if (!part) {\n return getFullPath(parent);\n }\n return getFullPath(parent) + part;\n}\n\nfunction OutputLink(props: {\n dataRef: ExtensionDataRef<unknown>;\n node?: AppNode;\n className: string;\n}) {\n const routeRef = props.node?.instance?.getData(coreExtensionData.routeRef);\n\n try {\n const link = useRouteRef(routeRef as RouteRef<undefined>);\n\n return (\n <Tooltip title={<Typography>{props.dataRef.id}</Typography>}>\n <Box className={props.className}>\n {link ? <Link to={link()}>link</Link> : null}\n </Box>\n </Tooltip>\n );\n } catch (ex) {\n // eslint-disable-next-line no-console\n console.warn(\n props.node?.spec.id\n ? `Unable to generate output link for ${props.node.spec.id}`\n : 'Unable to generate output link',\n ex,\n );\n return null;\n }\n}\n\nfunction Output(props: { dataRef: ExtensionDataRef<unknown>; node?: AppNode }) {\n const { dataRef, node } = props;\n const { id } = dataRef;\n const instance = node?.instance;\n\n const classes = useOutputStyles({ color: getOutputColor(id) });\n\n if (id === coreExtensionData.routePath.id) {\n return (\n <Tooltip title={<Typography>{getFullPath(node)}</Typography>}>\n <Box className={classes.output}>\n {String(instance?.getData(dataRef) ?? '')}\n </Box>\n </Tooltip>\n );\n }\n\n if (id === coreExtensionData.routeRef.id) {\n return <OutputLink {...props} className={classes.output} />;\n }\n\n return (\n <Tooltip title={<Typography>{id}</Typography>}>\n <Box className={classes.output} />\n </Tooltip>\n );\n}\n\nfunction Attachments(props: {\n node: AppNode;\n enabled: boolean;\n depth: number;\n}) {\n const { node, enabled, depth } = props;\n const { attachments } = node.edges;\n\n const classes = useStyles({ enabled, depth });\n\n if (attachments.size === 0) {\n return null;\n }\n\n return (\n <Box className={classes.attachments}>\n {[...attachments.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, children]) => {\n return (\n <Box key={key} className={classes.attachmentsInput}>\n <Box className={classes.attachmentsInputTitle}>\n <InputIcon />\n <Typography className={classes.attachmentsInputName}>\n {key}\n </Typography>\n </Box>\n <Box className={classes.attachmentsInputChildren}>\n {children.map(childNode => (\n <Extension\n key={childNode.spec.id}\n node={childNode}\n depth={depth + 1}\n />\n ))}\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n}\n\nfunction ExtensionTooltip(props: { node: AppNode }) {\n const parts = [];\n let node = props.node;\n parts.push(node.spec.id);\n while (node.edges.attachedTo) {\n const input = node.edges.attachedTo.input;\n node = node.edges.attachedTo.node;\n parts.push(`${node.spec.id} [${input}]`);\n }\n parts.reverse();\n\n return (\n <>\n {parts.map(part => (\n <Typography key={part}>{part}</Typography>\n ))}\n </>\n );\n}\n\nfunction Extension(props: { node: AppNode; depth: number }) {\n const { node, depth } = props;\n\n const enabled = Boolean(node.instance);\n const classes = useStyles({ enabled, depth });\n\n const dataRefs = node.instance && [...node.instance.getDataRefs()];\n\n return (\n <Box key={node.spec.id} className={classes.extension}>\n <Box className={classes.extensionHeader}>\n <Tooltip title={<ExtensionTooltip node={node} />}>\n <Typography className={classes.extensionHeaderId}>\n {node.spec.id}\n </Typography>\n </Tooltip>\n <Box className={classes.extensionHeaderOutputs}>\n {dataRefs &&\n dataRefs.length > 0 &&\n dataRefs\n .sort((a, b) => a.id.localeCompare(b.id))\n .map(ref => <Output key={ref.id} dataRef={ref} node={node} />)}\n {!enabled && <DisabledIcon fontSize=\"small\" />}\n </Box>\n </Box>\n <Attachments node={node} enabled={enabled} depth={depth} />\n </Box>\n );\n}\n\nconst legendMap = {\n 'React Element': coreExtensionData.reactElement,\n 'Utility API': ApiBlueprint.dataRefs.factory,\n 'Route Path': coreExtensionData.routePath,\n 'Route Ref': coreExtensionData.routeRef,\n 'Nav Target': NavItemBlueprint.dataRefs.target,\n Theme: ThemeBlueprint.dataRefs.theme,\n};\n\nfunction Legend() {\n return (\n <Box\n display=\"grid\"\n maxWidth={600}\n p={1}\n style={{\n grid: 'auto-flow / repeat(3, 1fr)',\n gap: 16,\n }}\n >\n {Object.entries(legendMap).map(([label, dataRef]) => (\n <Box\n key={dataRef.id}\n display=\"flex\"\n style={{ gap: 8 }}\n alignItems=\"center\"\n >\n <Output dataRef={dataRef} />\n <Typography>{label}</Typography>\n </Box>\n ))}\n </Box>\n );\n}\n\nexport function DetailedVisualizer({ tree }: { tree: AppTree }) {\n return (\n <Box display=\"flex\" height=\"100%\" flex=\"1 1 100%\" flexDirection=\"column\">\n <Box flex=\"1 1 0\" overflow=\"auto\" ml={2} mt={2}>\n <Extension node={tree.root} depth={0} />\n </Box>\n\n <Box component={Paper} flex=\"0 0 auto\" m={1}>\n <Legend />\n </Box>\n </Box>\n );\n}\n"],"names":["getOutputColor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DetailedVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/DetailedVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppNode,\n AppTree,\n ExtensionDataRef,\n coreExtensionData,\n ApiBlueprint,\n NavItemBlueprint,\n ThemeBlueprint,\n useApi,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { Box, Flex, Link, Text, Tooltip, TooltipTrigger } from '@backstage/ui';\nimport {\n RiInputField as InputIcon,\n RiCloseCircleLine as DisabledIcon,\n} from '@remixicon/react';\nimport { Focusable } from 'react-aria-components';\n\nfunction getContrastColor(bgColor: string): string {\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substr(0, 2), 16);\n const g = parseInt(hex.substr(2, 2), 16);\n const b = parseInt(hex.substr(4, 2), 16);\n const brightness = (r * 299 + g * 587 + b * 114) / 1000;\n return brightness > 128 ? '#000000' : '#ffffff';\n}\n\nfunction createOutputColorGenerator(\n colorMap: { [extDataId: string]: string },\n availableColors: string[],\n) {\n const map = new Map<string, { backgroundColor: string; color: string }>();\n let i = 0;\n\n return function getOutputColor(id: string) {\n let backgroundColor: string;\n if (id in colorMap) {\n backgroundColor = colorMap[id];\n } else {\n const cached = map.get(id);\n if (cached) {\n return cached;\n }\n backgroundColor = availableColors[i];\n i += 1;\n if (i >= availableColors.length) {\n i = 0;\n }\n }\n const result = {\n backgroundColor,\n color: getContrastColor(backgroundColor),\n };\n map.set(id, result);\n return result;\n };\n}\n\nconst getOutputColor = createOutputColorGenerator(\n {\n [coreExtensionData.reactElement.id]: '#4caf50',\n [coreExtensionData.routePath.id]: '#ffeb3b',\n [coreExtensionData.routeRef.id]: '#9c27b0',\n [ApiBlueprint.dataRefs.factory.id]: '#2196f3',\n [ThemeBlueprint.dataRefs.theme.id]: '#cddc39',\n [NavItemBlueprint.dataRefs.target.id]: '#ff9800',\n },\n\n ['#90caf9', '#ffcc80', '#a5d6a7', '#ef9a9a', '#fff59d', '#ce93d8', '#e6ee9c'],\n);\n\n// Helper function to get border color based on depth\nfunction getBorderColor(depth: number): string {\n const greyLevels = [8, 7, 6, 5]; // darker levels that contrast well with background\n const index = depth % greyLevels.length;\n const level = greyLevels[index];\n return `var(--bui-gray-${level})`;\n}\n\nfunction getFullPath(node?: AppNode): string {\n if (!node) {\n return '';\n }\n const parent = node.edges.attachedTo?.node;\n const part = node.instance?.getData(coreExtensionData.routePath);\n if (!part) {\n return getFullPath(parent);\n }\n return getFullPath(parent) + part;\n}\n\nfunction Output(props: { dataRef: ExtensionDataRef<unknown>; node?: AppNode }) {\n const { dataRef, node } = props;\n const { id } = dataRef;\n const instance = node?.instance;\n\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const { backgroundColor, color } = getOutputColor(id);\n\n const chipStyle: React.CSSProperties = {\n height: 20,\n padding: '0 10px',\n borderRadius: '10px',\n color,\n backgroundColor,\n display: 'flex',\n alignItems: 'center',\n fontWeight:\n 'var(--bui-font-weight-regular)' as React.CSSProperties['fontWeight'],\n };\n\n if (id === coreExtensionData.routeRef.id && node) {\n try {\n const routeRef = props.node?.instance?.getData(\n coreExtensionData.routeRef,\n );\n const link = routeRef && routeResolutionApi.resolve(routeRef)?.();\n if (link) {\n return (\n <TooltipTrigger>\n <Link href={link} style={chipStyle}>\n link\n </Link>\n <Tooltip>{id}</Tooltip>\n </TooltipTrigger>\n );\n }\n } catch {\n /* ignore */\n }\n }\n\n let tooltip = id;\n let text: string | undefined = undefined;\n if (id === coreExtensionData.routePath.id) {\n text = String(instance?.getData(dataRef) ?? '');\n tooltip = getFullPath(node);\n }\n\n return (\n <TooltipTrigger>\n <Focusable>\n <Text style={{ ...chipStyle, cursor: 'help' }}>{text}</Text>\n </Focusable>\n <Tooltip style={{ maxWidth: 'unset' }}>{tooltip}</Tooltip>\n </TooltipTrigger>\n );\n}\n\nfunction Attachments(props: {\n node: AppNode;\n enabled: boolean;\n depth: number;\n}) {\n const { node, depth } = props;\n const { attachments } = node.edges;\n\n if (attachments.size === 0) {\n return null;\n }\n\n return (\n <Flex direction=\"column\" gap=\"4\">\n {[...attachments.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, children], idx) => {\n return (\n <Box key={key}>\n <Flex\n p=\"2\"\n align=\"center\"\n style={{\n borderTopWidth: 'var(--bui-space-1_5)',\n borderTopStyle: 'solid',\n borderTopColor: getBorderColor(depth),\n borderTop: idx === 0 ? 'none' : undefined,\n width: 'fit-content',\n }}\n >\n <InputIcon size={16} />\n <div style={{ marginLeft: 'var(--bui-space-2)' }}>{key}</div>\n </Flex>\n <Flex ml=\"2\" mb=\"2\" direction=\"column\" align=\"start\" gap=\"1\">\n {children.map(childNode => (\n <Extension\n key={childNode.spec.id}\n node={childNode}\n depth={depth + 1}\n />\n ))}\n </Flex>\n </Box>\n );\n })}\n </Flex>\n );\n}\n\nfunction Extension(props: { node: AppNode; depth: number }) {\n const { node, depth } = props;\n\n const enabled = Boolean(node.instance);\n const dataRefs = node.instance && [...node.instance.getDataRefs()];\n\n // Build tooltip text\n const tooltipParts = [];\n let currentNode = node;\n tooltipParts.push(currentNode.spec.id);\n while (currentNode.edges.attachedTo) {\n const input = currentNode.edges.attachedTo.input;\n currentNode = currentNode.edges.attachedTo.node;\n tooltipParts.push(`${currentNode.spec.id} [${input}]`);\n }\n tooltipParts.reverse();\n const tooltipText = tooltipParts.join('\\n');\n\n return (\n <Box\n key={node.spec.id}\n style={{\n borderLeftWidth: 'var(--bui-space-1_5)',\n borderLeftStyle: 'solid',\n borderLeftColor: getBorderColor(depth),\n }}\n >\n <Flex\n py=\"1\"\n px=\"2\"\n align=\"center\"\n style={{\n width: 'fit-content',\n color: enabled ? 'var(--bui-fg-primary)' : 'var(--bui-fg-disabled)',\n background: 'var(--bui-bg-surface-1)',\n borderTopRightRadius: 'var(--bui-radius-2)',\n borderBottomRightRadius: 'var(--bui-radius-2)',\n }}\n >\n <TooltipTrigger>\n <Focusable>\n <Text style={{ userSelect: 'all' }}>{node.spec.id}</Text>\n </Focusable>\n <Tooltip style={{ maxWidth: 'unset' }}>\n <Text style={{ whiteSpace: 'pre-wrap' }}>{tooltipText}</Text>\n </Tooltip>\n </TooltipTrigger>\n <Flex ml=\"2\" align=\"center\" gap=\"2\">\n {dataRefs &&\n dataRefs.length > 0 &&\n dataRefs\n .sort((a, b) => a.id.localeCompare(b.id))\n .map(ref => <Output key={ref.id} dataRef={ref} node={node} />)}\n {!enabled && <DisabledIcon size={16} />}\n </Flex>\n </Flex>\n <Attachments node={node} enabled={enabled} depth={depth} />\n </Box>\n );\n}\n\nconst legendMap = {\n 'React Element': coreExtensionData.reactElement,\n 'Utility API': ApiBlueprint.dataRefs.factory,\n 'Route Path': coreExtensionData.routePath,\n 'Route Ref': coreExtensionData.routeRef,\n 'Nav Target': NavItemBlueprint.dataRefs.target,\n Theme: ThemeBlueprint.dataRefs.theme,\n};\n\nfunction Legend() {\n return (\n <Box\n p=\"2\"\n style={{\n display: 'grid',\n maxWidth: 600,\n grid: 'auto-flow / repeat(3, 1fr)',\n gap: 'var(--bui-space-4)',\n }}\n >\n {Object.entries(legendMap).map(([label, dataRef]) => (\n <Flex key={dataRef.id} gap=\"2\" align=\"center\">\n <Output dataRef={dataRef} />\n <div>{label}</div>\n </Flex>\n ))}\n </Box>\n );\n}\n\nexport function DetailedVisualizer({ tree }: { tree: AppTree }) {\n return (\n <Flex direction=\"column\" style={{ height: '100%', flex: '1 1 100%' }}>\n <Box ml=\"4\" mt=\"4\" style={{ flex: '1 1 0', overflow: 'auto' }}>\n <Extension node={tree.root} depth={0} />\n </Box>\n\n <Box\n m=\"2\"\n style={{\n flex: '0 0 auto',\n background: 'var(--bui-bg-surface-1)',\n border: '1px solid var(--bui-border)',\n borderRadius: 'var(--bui-radius-2)',\n }}\n >\n <Legend />\n </Box>\n </Flex>\n );\n}\n"],"names":["getOutputColor","InputIcon","DisabledIcon"],"mappings":"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"}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import Box from '@
|
|
3
|
-
import Checkbox from '@material-ui/core/Checkbox';
|
|
4
|
-
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
|
5
|
-
import Paper from '@material-ui/core/Paper';
|
|
2
|
+
import { Box, Checkbox } from '@backstage/ui';
|
|
6
3
|
import { useState } from 'react';
|
|
7
4
|
|
|
8
5
|
function mkDiv(children, options) {
|
|
@@ -11,7 +8,7 @@ function mkDiv(children, options) {
|
|
|
11
8
|
{
|
|
12
9
|
style: {
|
|
13
10
|
color: options?.color,
|
|
14
|
-
marginLeft: options?.indent ?
|
|
11
|
+
marginLeft: options?.indent ? "var(--bui-space-4)" : void 0
|
|
15
12
|
},
|
|
16
13
|
children
|
|
17
14
|
},
|
|
@@ -50,35 +47,22 @@ function TextVisualizer({ tree }) {
|
|
|
50
47
|
const [showOutputs, setShowOutputs] = useState(false);
|
|
51
48
|
const [showDisabled, setShowDisabled] = useState(false);
|
|
52
49
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53
|
-
/* @__PURE__ */ jsx(Box, { style: { overflow: "auto", flex: "1 0 0" }, children: /* @__PURE__ */ jsx(
|
|
54
|
-
/* @__PURE__ */ jsxs(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
FormControlLabel,
|
|
70
|
-
{
|
|
71
|
-
control: /* @__PURE__ */ jsx(
|
|
72
|
-
Checkbox,
|
|
73
|
-
{
|
|
74
|
-
checked: showDisabled,
|
|
75
|
-
onChange: (_, value) => setShowDisabled(value)
|
|
76
|
-
}
|
|
77
|
-
),
|
|
78
|
-
label: "Show Disabled"
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
] })
|
|
50
|
+
/* @__PURE__ */ jsx(Box, { style: { overflow: "auto", flex: "1 0 0" }, children: /* @__PURE__ */ jsx(Box, { m: "4", style: { width: "max-content" }, children: nodeToText(tree.root, { showOutputs, showDisabled }) }) }),
|
|
51
|
+
/* @__PURE__ */ jsxs(
|
|
52
|
+
Box,
|
|
53
|
+
{
|
|
54
|
+
py: "2",
|
|
55
|
+
px: "4",
|
|
56
|
+
style: {
|
|
57
|
+
background: "var(--bui-bg-surface-1)",
|
|
58
|
+
borderTop: "1px solid var(--bui-border)"
|
|
59
|
+
},
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsx(Checkbox, { isSelected: showOutputs, onChange: setShowOutputs, children: "Show Outputs" }),
|
|
62
|
+
/* @__PURE__ */ jsx(Checkbox, { isSelected: showDisabled, onChange: setShowDisabled, children: "Show Disabled" })
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
)
|
|
82
66
|
] });
|
|
83
67
|
}
|
|
84
68
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/TextVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppNode, AppTree } from '@backstage/frontend-plugin-api';\nimport
|
|
1
|
+
{"version":3,"file":"TextVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/TextVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppNode, AppTree } from '@backstage/frontend-plugin-api';\nimport { Box, Checkbox } from '@backstage/ui';\nimport { ReactNode, useState } from 'react';\n\nfunction mkDiv(\n children: ReactNode,\n options?: { indent?: boolean; key?: string | number; color?: string },\n) {\n return (\n <div\n key={options?.key}\n style={{\n color: options?.color,\n marginLeft: options?.indent ? 'var(--bui-space-4)' : undefined,\n }}\n >\n {children}\n </div>\n );\n}\n\nfunction nodeToText(\n node: AppNode,\n options?: { showOutputs?: boolean; showDisabled?: boolean },\n): ReactNode {\n const dataRefIds =\n node.instance && [...node.instance.getDataRefs()].map(r => r.id);\n const out =\n options?.showOutputs && dataRefIds && dataRefIds.length > 0\n ? ` out=\"${[...dataRefIds].sort().join(', ')}\"`\n : '';\n const color = node.instance ? undefined : 'gray';\n\n if (node.edges.attachments.size === 0) {\n return mkDiv(`<${node.spec.id}${out}/>`, { color });\n }\n\n return mkDiv([\n mkDiv(`<${node.spec.id}${out}>`, { key: 'start', color }),\n ...[...node.edges.attachments.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, v]) => {\n const children = v\n .filter(e => options?.showDisabled || e.instance)\n .sort((a, b) => a.spec.id.localeCompare(b.spec.id));\n if (children.length === 0) {\n return mkDiv(`${key} []`, { key, indent: true });\n }\n return mkDiv(\n [\n mkDiv(`${key} [`, { key: 'start' }),\n ...children.map(e =>\n mkDiv(nodeToText(e, options), { indent: true, key: e.spec.id }),\n ),\n mkDiv(']', { key: 'end' }),\n ],\n { key, indent: true },\n );\n }),\n mkDiv(`</${node.spec.id}>`, { key: 'end', color }),\n ]);\n}\n\nexport function TextVisualizer({ tree }: { tree: AppTree }) {\n const [showOutputs, setShowOutputs] = useState(false);\n const [showDisabled, setShowDisabled] = useState(false);\n\n return (\n <>\n <Box style={{ overflow: 'auto', flex: '1 0 0' }}>\n <Box m=\"4\" style={{ width: 'max-content' }}>\n {nodeToText(tree.root, { showOutputs, showDisabled })}\n </Box>\n </Box>\n <Box\n py=\"2\"\n px=\"4\"\n style={{\n background: 'var(--bui-bg-surface-1)',\n borderTop: '1px solid var(--bui-border)',\n }}\n >\n <Checkbox isSelected={showOutputs} onChange={setShowOutputs}>\n Show Outputs\n </Checkbox>\n <Checkbox isSelected={showDisabled} onChange={setShowDisabled}>\n Show Disabled\n </Checkbox>\n </Box>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { DependencyGraph, DependencyGraphTypes } from '@backstage/core-components';
|
|
3
|
-
import
|
|
4
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
3
|
+
import { Flex } from '@backstage/ui';
|
|
5
4
|
import { useMemo, useState, useRef, useLayoutEffect } from 'react';
|
|
6
5
|
|
|
7
6
|
function inputId({ node, input }) {
|
|
@@ -50,18 +49,8 @@ function resolveGraphData(tree) {
|
|
|
50
49
|
]
|
|
51
50
|
};
|
|
52
51
|
}
|
|
53
|
-
const useStyles = makeStyles((theme) => ({
|
|
54
|
-
node: {
|
|
55
|
-
fill: (node) => node.type === "node" ? theme.palette.primary.light : theme.palette.grey[500],
|
|
56
|
-
stroke: (node) => node.type === "node" ? theme.palette.primary.main : theme.palette.grey[600]
|
|
57
|
-
},
|
|
58
|
-
text: {
|
|
59
|
-
fill: theme.palette.primary.contrastText
|
|
60
|
-
}
|
|
61
|
-
}));
|
|
62
52
|
function Node(props) {
|
|
63
53
|
const { node } = props;
|
|
64
|
-
const classes = useStyles(node);
|
|
65
54
|
const [width, setWidth] = useState(0);
|
|
66
55
|
const [height, setHeight] = useState(0);
|
|
67
56
|
const idRef = useRef(null);
|
|
@@ -79,11 +68,15 @@ function Node(props) {
|
|
|
79
68
|
const padding = 10;
|
|
80
69
|
const paddedWidth = width + padding * 2;
|
|
81
70
|
const paddedHeight = height + padding * 2;
|
|
71
|
+
const nodeFill = node.type === "node" ? "#90caf9" : "#9e9e9e";
|
|
72
|
+
const nodeStroke = node.type === "node" ? "#2196f3" : "#757575";
|
|
73
|
+
const textFill = "#000000";
|
|
82
74
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
83
75
|
/* @__PURE__ */ jsx(
|
|
84
76
|
"rect",
|
|
85
77
|
{
|
|
86
|
-
|
|
78
|
+
fill: nodeFill,
|
|
79
|
+
stroke: nodeStroke,
|
|
87
80
|
width: paddedWidth,
|
|
88
81
|
height: paddedHeight,
|
|
89
82
|
rx: node.type === "node" ? 0 : 20
|
|
@@ -93,7 +86,7 @@ function Node(props) {
|
|
|
93
86
|
"text",
|
|
94
87
|
{
|
|
95
88
|
ref: idRef,
|
|
96
|
-
|
|
89
|
+
fill: textFill,
|
|
97
90
|
y: paddedHeight / 2,
|
|
98
91
|
x: paddedWidth / 2,
|
|
99
92
|
textAnchor: "middle",
|
|
@@ -106,13 +99,14 @@ function Node(props) {
|
|
|
106
99
|
function TreeVisualizer({ tree }) {
|
|
107
100
|
const graphData = useMemo(() => resolveGraphData(tree), [tree]);
|
|
108
101
|
return /* @__PURE__ */ jsx(
|
|
109
|
-
|
|
102
|
+
Flex,
|
|
110
103
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
style: {
|
|
105
|
+
flex: "1 1 0",
|
|
106
|
+
overflow: "hidden",
|
|
107
|
+
justifyContent: "stretch",
|
|
108
|
+
alignItems: "stretch"
|
|
109
|
+
},
|
|
116
110
|
children: /* @__PURE__ */ jsx(
|
|
117
111
|
DependencyGraph,
|
|
118
112
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/TreeVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n} from '@backstage/core-components';\nimport { AppNode, AppTree } from '@backstage/frontend-plugin-api';\nimport
|
|
1
|
+
{"version":3,"file":"TreeVisualizer.esm.js","sources":["../../../src/components/AppVisualizerPage/TreeVisualizer.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n} from '@backstage/core-components';\nimport { AppNode, AppTree } from '@backstage/frontend-plugin-api';\nimport { Flex } from '@backstage/ui';\nimport { useLayoutEffect, useMemo, useRef, useState } from 'react';\n\ntype NodeType =\n | ({ type: 'node'; id: string } & AppNode)\n | { type: 'input'; id: string; name: string };\n\nfunction inputId({ node, input }: { node: AppNode; input: string }) {\n return `${node.spec.id}$$${input}`;\n}\n\nfunction trimNodeId(id: string) {\n let newId = id;\n if (newId.startsWith('apis.')) {\n newId = newId.slice('apis.'.length);\n }\n if (newId.startsWith('plugin.')) {\n newId = newId.slice('plugin.'.length);\n }\n if (newId.startsWith('catalog.filter.entity.')) {\n newId = newId.slice('catalog.filter.entity.'.length);\n }\n if (newId.endsWith('.nav.index')) {\n newId = newId.slice(0, -'.nav.index'.length);\n }\n return newId;\n}\n\nfunction resolveGraphData(tree: AppTree): {\n nodes: NodeType[];\n edges: { from: string; to: string }[];\n} {\n const nodes = [...tree.nodes.values()]\n .filter(node => node.instance)\n .map(node => ({ ...node, id: node.spec.id, type: 'node' as const }));\n\n return {\n nodes: [\n ...nodes,\n ...nodes.flatMap(node =>\n [...node.edges.attachments.keys()].map(input => ({\n id: inputId({ node, input }),\n type: 'input' as const,\n name: input,\n })),\n ),\n ],\n edges: [\n ...nodes\n .filter(node => node.edges.attachedTo)\n .map(node => ({\n from: inputId(node.edges.attachedTo!),\n to: node.spec.id,\n })),\n ...nodes.flatMap(node =>\n [...node.edges.attachments.keys()].map(input => ({\n from: node.spec.id,\n to: inputId({ node, input }),\n })),\n ),\n ],\n };\n}\n\n/** @public */\nexport function Node(props: { node: NodeType }) {\n const { node } = props;\n const [width, setWidth] = useState(0);\n const [height, setHeight] = useState(0);\n const idRef = useRef<SVGTextElement | null>(null);\n\n useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const padding = 10;\n const paddedWidth = width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n // Simple inline styles for SVG elements\n const nodeFill = node.type === 'node' ? '#90caf9' : '#9e9e9e';\n const nodeStroke = node.type === 'node' ? '#2196f3' : '#757575';\n const textFill = '#000000';\n\n return (\n <g>\n <rect\n fill={nodeFill}\n stroke={nodeStroke}\n width={paddedWidth}\n height={paddedHeight}\n rx={node.type === 'node' ? 0 : 20}\n />\n <text\n ref={idRef}\n fill={textFill}\n y={paddedHeight / 2}\n x={paddedWidth / 2}\n textAnchor=\"middle\"\n alignmentBaseline=\"middle\"\n >\n {node.type === 'node' ? trimNodeId(node.id) : node.name}\n </text>\n </g>\n );\n}\n\nexport function TreeVisualizer({ tree }: { tree: AppTree }) {\n const graphData = useMemo(() => resolveGraphData(tree), [tree]);\n\n return (\n <Flex\n style={{\n flex: '1 1 0',\n overflow: 'hidden',\n justifyContent: 'stretch',\n alignItems: 'stretch',\n }}\n >\n <DependencyGraph\n fit=\"contain\"\n {...graphData}\n nodeMargin={10}\n rankMargin={50}\n paddingX={50}\n renderNode={Node}\n ranker={DependencyGraphTypes.Ranker.TIGHT_TREE}\n direction={DependencyGraphTypes.Direction.LEFT_RIGHT}\n />\n </Flex>\n );\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
|
4
4
|
|
|
5
5
|
/** @public */
|
|
6
6
|
declare const visualizerPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{}, {}, {
|
|
7
|
-
"nav-item:app-visualizer": _backstage_frontend_plugin_api.
|
|
7
|
+
"nav-item:app-visualizer": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
8
8
|
kind: "nav-item";
|
|
9
9
|
name: undefined;
|
|
10
10
|
config: {};
|
|
@@ -21,7 +21,7 @@ declare const visualizerPlugin: _backstage_frontend_plugin_api.OverridableFronte
|
|
|
21
21
|
routeRef: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
22
22
|
};
|
|
23
23
|
}>;
|
|
24
|
-
"page:app-visualizer": _backstage_frontend_plugin_api.
|
|
24
|
+
"page:app-visualizer": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
25
25
|
kind: "page";
|
|
26
26
|
name: undefined;
|
|
27
27
|
config: {
|
package/dist/package.json.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "@backstage/plugin-app-visualizer";
|
|
2
|
-
var version = "0.1.25
|
|
2
|
+
var version = "0.1.25";
|
|
3
3
|
var description = "Visualizes the Backstage app structure";
|
|
4
4
|
var backstage = {
|
|
5
5
|
role: "frontend-plugin",
|
|
@@ -36,8 +36,9 @@ var dependencies = {
|
|
|
36
36
|
"@backstage/core-components": "workspace:^",
|
|
37
37
|
"@backstage/core-plugin-api": "workspace:^",
|
|
38
38
|
"@backstage/frontend-plugin-api": "workspace:^",
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
39
|
+
"@backstage/ui": "workspace:^",
|
|
40
|
+
"@remixicon/react": "^4.6.0",
|
|
41
|
+
"react-aria-components": "^1.13.0"
|
|
41
42
|
};
|
|
42
43
|
var devDependencies = {
|
|
43
44
|
"@backstage/cli": "workspace:^",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/plugin.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { createRouteRef, PageBlueprint, NavItemBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
3
|
-
import
|
|
3
|
+
import { RiEyeLine } from '@remixicon/react';
|
|
4
4
|
|
|
5
5
|
const rootRouteRef = createRouteRef();
|
|
6
6
|
const appVisualizerPage = PageBlueprint.make({
|
|
@@ -13,7 +13,7 @@ const appVisualizerPage = PageBlueprint.make({
|
|
|
13
13
|
const appVisualizerNavItem = NavItemBlueprint.make({
|
|
14
14
|
params: {
|
|
15
15
|
title: "Visualizer",
|
|
16
|
-
icon:
|
|
16
|
+
icon: () => /* @__PURE__ */ jsx(RiEyeLine, {}),
|
|
17
17
|
routeRef: rootRouteRef
|
|
18
18
|
}
|
|
19
19
|
});
|
package/dist/plugin.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFrontendPlugin,\n createRouteRef,\n NavItemBlueprint,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport VisualizerIcon from '@
|
|
1
|
+
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFrontendPlugin,\n createRouteRef,\n NavItemBlueprint,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport { RiEyeLine as VisualizerIcon } from '@remixicon/react';\n\nconst rootRouteRef = createRouteRef();\n\nconst appVisualizerPage = PageBlueprint.make({\n params: {\n path: '/visualizer',\n routeRef: rootRouteRef,\n loader: () =>\n import('./components/AppVisualizerPage').then(m => (\n <m.AppVisualizerPage />\n )),\n },\n});\n\nexport const appVisualizerNavItem = NavItemBlueprint.make({\n params: {\n title: 'Visualizer',\n icon: () => <VisualizerIcon />,\n routeRef: rootRouteRef,\n },\n});\n\n/** @public */\nexport const visualizerPlugin = createFrontendPlugin({\n pluginId: 'app-visualizer',\n info: { packageJson: () => import('../package.json') },\n extensions: [appVisualizerPage, appVisualizerNavItem],\n});\n"],"names":["VisualizerIcon"],"mappings":";;;;AAwBA,MAAM,eAAe,cAAA,EAAe;AAEpC,MAAM,iBAAA,GAAoB,cAAc,IAAA,CAAK;AAAA,EAC3C,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,aAAA;AAAA,IACN,QAAA,EAAU,YAAA;AAAA,IACV,MAAA,EAAQ,MACN,OAAO,6CAAgC,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAC5C,GAAA,CAAC,CAAA,CAAE,iBAAA,EAAF,EAAoB,CACtB;AAAA;AAEP,CAAC,CAAA;AAEM,MAAM,oBAAA,GAAuB,iBAAiB,IAAA,CAAK;AAAA,EACxD,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,IAAA,EAAM,sBAAM,GAAA,CAACA,SAAA,EAAA,EAAe,CAAA;AAAA,IAC5B,QAAA,EAAU;AAAA;AAEd,CAAC;AAGM,MAAM,mBAAmB,oBAAA,CAAqB;AAAA,EACnD,QAAA,EAAU,gBAAA;AAAA,EACV,MAAM,EAAE,WAAA,EAAa,MAAM,OAAO,uBAAiB,CAAA,EAAE;AAAA,EACrD,UAAA,EAAY,CAAC,iBAAA,EAAmB,oBAAoB;AACtD,CAAC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-app-visualizer",
|
|
3
|
-
"version": "0.1.25
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "Visualizes the Backstage app structure",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "frontend-plugin",
|
|
@@ -37,15 +37,16 @@
|
|
|
37
37
|
"test": "backstage-cli package test"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@backstage/core-components": "0.18.3
|
|
41
|
-
"@backstage/core-plugin-api": "1.
|
|
42
|
-
"@backstage/frontend-plugin-api": "0.
|
|
43
|
-
"@
|
|
44
|
-
"@
|
|
40
|
+
"@backstage/core-components": "^0.18.3",
|
|
41
|
+
"@backstage/core-plugin-api": "^1.12.0",
|
|
42
|
+
"@backstage/frontend-plugin-api": "^0.13.0",
|
|
43
|
+
"@backstage/ui": "^0.9.0",
|
|
44
|
+
"@remixicon/react": "^4.6.0",
|
|
45
|
+
"react-aria-components": "^1.13.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@backstage/cli": "0.34.5
|
|
48
|
-
"@backstage/frontend-defaults": "0.3.3
|
|
48
|
+
"@backstage/cli": "^0.34.5",
|
|
49
|
+
"@backstage/frontend-defaults": "^0.3.3",
|
|
49
50
|
"@types/react": "^18.0.0",
|
|
50
51
|
"react": "^18.0.2",
|
|
51
52
|
"react-dom": "^18.0.2",
|