@c2l2c/backstage-plugin-dora-metrics 0.1.0 → 0.3.2
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/README.md +108 -9
- package/config.d.ts +39 -9
- package/dist/api/DoraMetricsClient.esm.js +70 -17
- package/dist/api/DoraMetricsClient.esm.js.map +1 -1
- package/dist/api/MockDoraMetricsClient.esm.js +72 -0
- package/dist/api/MockDoraMetricsClient.esm.js.map +1 -0
- package/dist/api/types.esm.js.map +1 -1
- package/dist/components/DoraMetricsContent.esm.js +753 -948
- package/dist/components/DoraMetricsContent.esm.js.map +1 -1
- package/dist/components/ui/badge.esm.js +5 -5
- package/dist/components/ui/badge.esm.js.map +1 -1
- package/dist/components/ui/card.esm.js +14 -12
- package/dist/components/ui/card.esm.js.map +1 -1
- package/dist/components/ui/select.esm.js +23 -27
- package/dist/components/ui/select.esm.js.map +1 -1
- package/dist/extensions/api.esm.js +5 -1
- package/dist/extensions/api.esm.js.map +1 -1
- package/dist/extensions/entityContent.esm.js +2 -2
- package/dist/extensions/entityContent.esm.js.map +1 -1
- package/dist/index.d.ts +35 -8
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/package.json +14 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
const RATING_STYLES = {
|
|
4
4
|
elite: { background: "#14532d", color: "#86efac", border: "#166534" },
|
|
@@ -8,7 +8,7 @@ const RATING_STYLES = {
|
|
|
8
8
|
};
|
|
9
9
|
function RatingBadge({ rating }) {
|
|
10
10
|
const s = RATING_STYLES[rating];
|
|
11
|
-
return /* @__PURE__ */
|
|
11
|
+
return /* @__PURE__ */ React.createElement(
|
|
12
12
|
"span",
|
|
13
13
|
{
|
|
14
14
|
style: {
|
|
@@ -23,9 +23,9 @@ function RatingBadge({ rating }) {
|
|
|
23
23
|
fontWeight: 600,
|
|
24
24
|
letterSpacing: "0.06em",
|
|
25
25
|
textTransform: "uppercase"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
rating
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.esm.js","sources":["../../../src/components/ui/badge.tsx"],"sourcesContent":["import type { DoraRating } from '../../api/types';\n\nconst RATING_STYLES: Record<DoraRating, { background: string; color: string; border: string }> = {\n elite: { background: '#14532d', color: '#86efac', border: '#166534' },\n high: { background: '#1e3a5f', color: '#93c5fd', border: '#1d4ed8' },\n medium:{ background: '#451a03', color: '#fdba74', border: '#92400e' },\n low: { background: '#450a0a', color: '#fca5a5', border: '#991b1b' },\n};\n\nexport function RatingBadge({ rating }: { rating: DoraRating }) {\n const s = RATING_STYLES[rating];\n return (\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 8px',\n borderRadius: 9999,\n background: s.background,\n color: s.color,\n border: `1px solid ${s.border}`,\n fontSize: 11,\n fontWeight: 600,\n letterSpacing: '0.06em',\n textTransform: 'uppercase',\n }}\n >\n {rating}\n </span>\n );\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"badge.esm.js","sources":["../../../src/components/ui/badge.tsx"],"sourcesContent":["import React from 'react';\nimport type { DoraRating } from '../../api/types';\n\nconst RATING_STYLES: Record<DoraRating, { background: string; color: string; border: string }> = {\n elite: { background: '#14532d', color: '#86efac', border: '#166534' },\n high: { background: '#1e3a5f', color: '#93c5fd', border: '#1d4ed8' },\n medium:{ background: '#451a03', color: '#fdba74', border: '#92400e' },\n low: { background: '#450a0a', color: '#fca5a5', border: '#991b1b' },\n};\n\nexport function RatingBadge({ rating }: { rating: DoraRating }) {\n const s = RATING_STYLES[rating];\n return (\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 8px',\n borderRadius: 9999,\n background: s.background,\n color: s.color,\n border: `1px solid ${s.border}`,\n fontSize: 11,\n fontWeight: 600,\n letterSpacing: '0.06em',\n textTransform: 'uppercase',\n }}\n >\n {rating}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAGA,MAAM,aAAA,GAA2F;AAAA,EAC/F,OAAO,EAAE,UAAA,EAAY,WAAW,KAAA,EAAO,SAAA,EAAW,QAAQ,SAAA,EAAU;AAAA,EACpE,MAAO,EAAE,UAAA,EAAY,WAAW,KAAA,EAAO,SAAA,EAAW,QAAQ,SAAA,EAAU;AAAA,EACpE,QAAO,EAAE,UAAA,EAAY,WAAW,KAAA,EAAO,SAAA,EAAW,QAAQ,SAAA,EAAU;AAAA,EACpE,KAAO,EAAE,UAAA,EAAY,WAAW,KAAA,EAAO,SAAA,EAAW,QAAQ,SAAA;AAC5D,CAAA;AAEO,SAAS,WAAA,CAAY,EAAE,MAAA,EAAO,EAA2B;AAC9D,EAAA,MAAM,CAAA,GAAI,cAAc,MAAM,CAAA;AAC9B,EAAA,uBACE,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,aAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,OAAA,EAAS,SAAA;AAAA,QACT,YAAA,EAAc,IAAA;AAAA,QACd,YAAY,CAAA,CAAE,UAAA;AAAA,QACd,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,MAAA,EAAQ,CAAA,UAAA,EAAa,CAAA,CAAE,MAAM,CAAA,CAAA;AAAA,QAC7B,QAAA,EAAU,EAAA;AAAA,QACV,UAAA,EAAY,GAAA;AAAA,QACZ,aAAA,EAAe,QAAA;AAAA,QACf,aAAA,EAAe;AAAA;AACjB,KAAA;AAAA,IAEC;AAAA,GACH;AAEJ;;;;"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useState } from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
3
2
|
import { useTheme } from '@material-ui/core/styles';
|
|
4
3
|
|
|
5
4
|
function Card({
|
|
@@ -12,7 +11,7 @@ function Card({
|
|
|
12
11
|
const theme = useTheme();
|
|
13
12
|
const isDark = theme.palette.type === "dark";
|
|
14
13
|
const [hovered, setHovered] = useState(false);
|
|
15
|
-
return /* @__PURE__ */
|
|
14
|
+
return /* @__PURE__ */ React.createElement(
|
|
16
15
|
"div",
|
|
17
16
|
{
|
|
18
17
|
onMouseEnter: () => {
|
|
@@ -38,31 +37,34 @@ function Card({
|
|
|
38
37
|
boxShadow: hovered ? isDark ? "0 8px 24px rgba(0,0,0,0.4)" : "0 8px 24px rgba(0,0,0,0.08)" : "none",
|
|
39
38
|
transition: "transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease",
|
|
40
39
|
...style
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
children
|
|
44
43
|
);
|
|
45
44
|
}
|
|
46
45
|
function CardLabel({ children }) {
|
|
47
46
|
const theme = useTheme();
|
|
48
|
-
return /* @__PURE__ */
|
|
47
|
+
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
49
48
|
fontSize: 11,
|
|
50
49
|
fontWeight: 600,
|
|
51
50
|
color: theme.palette.text.secondary,
|
|
52
51
|
textTransform: "uppercase",
|
|
53
52
|
letterSpacing: "0.1em"
|
|
54
|
-
}, children
|
|
53
|
+
} }, children);
|
|
55
54
|
}
|
|
56
55
|
function CardFooter({ children }) {
|
|
57
56
|
const theme = useTheme();
|
|
58
57
|
const isDark = theme.palette.type === "dark";
|
|
59
|
-
return /* @__PURE__ */
|
|
58
|
+
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
60
59
|
fontSize: 12,
|
|
61
60
|
color: theme.palette.text.secondary,
|
|
62
61
|
borderTop: `1px solid ${isDark ? "#27272a" : "#e4e4e7"}`,
|
|
63
62
|
paddingTop: 10,
|
|
64
|
-
marginTop: 4
|
|
65
|
-
|
|
63
|
+
marginTop: 4,
|
|
64
|
+
display: "flex",
|
|
65
|
+
alignItems: "center",
|
|
66
|
+
gap: 8
|
|
67
|
+
} }, children);
|
|
66
68
|
}
|
|
67
69
|
function CardDescription({
|
|
68
70
|
children,
|
|
@@ -70,7 +72,7 @@ function CardDescription({
|
|
|
70
72
|
}) {
|
|
71
73
|
const theme = useTheme();
|
|
72
74
|
const isDark = theme.palette.type === "dark";
|
|
73
|
-
return /* @__PURE__ */
|
|
75
|
+
return /* @__PURE__ */ React.createElement("div", { style: { fontSize: 12, color: muted ? isDark ? "#3f3f46" : "#a1a1aa" : theme.palette.text.secondary } }, children);
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
export { Card, CardDescription, CardFooter, CardLabel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.esm.js","sources":["../../../src/components/ui/card.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { useTheme } from '@material-ui/core/styles';\n\nexport function Card({\n children, style, onClick, onMouseEnter, onMouseLeave,\n}: {\n children: React.ReactNode;\n style?: React.CSSProperties;\n onClick?: () => void;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n const [hovered, setHovered] = useState(false);\n\n return (\n <div\n onMouseEnter={() => { setHovered(true); onMouseEnter?.(); }}\n onMouseLeave={() => { setHovered(false); onMouseLeave?.(); }}\n onClick={onClick}\n style={{\n background: isDark ? '#0f0f12' : '#ffffff',\n border: `1px solid ${hovered\n ? (isDark ? '#3f3f46' : '#c4c4c8')\n : (isDark ? '#27272a' : '#e4e4e7')}`,\n borderRadius: 12,\n padding: '20px 24px',\n display: 'flex',\n flexDirection: 'column',\n gap: 10,\n flex: '1 1 200px',\n minWidth: 180,\n transform: hovered ? 'translateY(-2px)' : 'translateY(0)',\n boxShadow: hovered\n ? (isDark ? '0 8px 24px rgba(0,0,0,0.4)' : '0 8px 24px rgba(0,0,0,0.08)')\n : 'none',\n transition: 'transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease',\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nexport function CardLabel({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n return (\n <div style={{\n fontSize: 11,\n fontWeight: 600,\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n letterSpacing: '0.1em',\n }}>\n {children}\n </div>\n );\n}\n\nexport function CardValue({ value, unit }: { value: number | string; unit: string }) {\n const theme = useTheme();\n return (\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>\n <span style={{ fontSize: 36, fontWeight: 700, color: theme.palette.text.primary, lineHeight: 1 }}>\n {value}\n </span>\n <span style={{ fontSize: 14, color: theme.palette.text.secondary, fontWeight: 500 }}>{unit}</span>\n </div>\n );\n}\n\nexport function CardFooter({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <div style={{\n fontSize: 12,\n color: theme.palette.text.secondary,\n borderTop: `1px solid ${isDark ? '#27272a' : '#e4e4e7'}`,\n paddingTop: 10,\n marginTop: 4,\n }}>\n {children}\n </div>\n );\n}\n\nexport function CardDescription({\n children,\n muted = false,\n}: {\n children: React.ReactNode;\n muted?: boolean;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <div style={{ fontSize: 12, color: muted ? (isDark ? '#3f3f46' : '#a1a1aa') : theme.palette.text.secondary }}>\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"card.esm.js","sources":["../../../src/components/ui/card.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { useTheme } from '@material-ui/core/styles';\n\nexport function Card({\n children, style, onClick, onMouseEnter, onMouseLeave,\n}: {\n children: React.ReactNode;\n style?: React.CSSProperties;\n onClick?: () => void;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n const [hovered, setHovered] = useState(false);\n\n return (\n <div\n onMouseEnter={() => { setHovered(true); onMouseEnter?.(); }}\n onMouseLeave={() => { setHovered(false); onMouseLeave?.(); }}\n onClick={onClick}\n style={{\n background: isDark ? '#0f0f12' : '#ffffff',\n border: `1px solid ${hovered\n ? (isDark ? '#3f3f46' : '#c4c4c8')\n : (isDark ? '#27272a' : '#e4e4e7')}`,\n borderRadius: 12,\n padding: '20px 24px',\n display: 'flex',\n flexDirection: 'column',\n gap: 10,\n flex: '1 1 200px',\n minWidth: 180,\n transform: hovered ? 'translateY(-2px)' : 'translateY(0)',\n boxShadow: hovered\n ? (isDark ? '0 8px 24px rgba(0,0,0,0.4)' : '0 8px 24px rgba(0,0,0,0.08)')\n : 'none',\n transition: 'transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease',\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nexport function CardLabel({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n return (\n <div style={{\n fontSize: 11,\n fontWeight: 600,\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n letterSpacing: '0.1em',\n }}>\n {children}\n </div>\n );\n}\n\nexport function CardValue({ value, unit }: { value: number | string; unit: string }) {\n const theme = useTheme();\n return (\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>\n <span style={{ fontSize: 36, fontWeight: 700, color: theme.palette.text.primary, lineHeight: 1 }}>\n {value}\n </span>\n <span style={{ fontSize: 14, color: theme.palette.text.secondary, fontWeight: 500 }}>{unit}</span>\n </div>\n );\n}\n\nexport function CardFooter({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <div style={{\n fontSize: 12,\n color: theme.palette.text.secondary,\n borderTop: `1px solid ${isDark ? '#27272a' : '#e4e4e7'}`,\n paddingTop: 10,\n marginTop: 4,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n }}>\n {children}\n </div>\n );\n}\n\nexport function CardDescription({\n children,\n muted = false,\n}: {\n children: React.ReactNode;\n muted?: boolean;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <div style={{ fontSize: 12, color: muted ? (isDark ? '#3f3f46' : '#a1a1aa') : theme.palette.text.secondary }}>\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
3
3
|
import { useTheme } from '@material-ui/core/styles';
|
|
4
4
|
import { ChevronDown, Check } from 'lucide-react';
|
|
@@ -8,12 +8,12 @@ function Select({
|
|
|
8
8
|
onValueChange,
|
|
9
9
|
children
|
|
10
10
|
}) {
|
|
11
|
-
return /* @__PURE__ */
|
|
11
|
+
return /* @__PURE__ */ React.createElement(SelectPrimitive.Root, { value, onValueChange }, children);
|
|
12
12
|
}
|
|
13
13
|
function SelectTrigger({ children }) {
|
|
14
14
|
const theme = useTheme();
|
|
15
15
|
const isDark = theme.palette.type === "dark";
|
|
16
|
-
return /* @__PURE__ */
|
|
16
|
+
return /* @__PURE__ */ React.createElement(
|
|
17
17
|
SelectPrimitive.Trigger,
|
|
18
18
|
{
|
|
19
19
|
style: {
|
|
@@ -31,21 +31,19 @@ function SelectTrigger({ children }) {
|
|
|
31
31
|
cursor: "pointer",
|
|
32
32
|
minWidth: 180,
|
|
33
33
|
outline: "none"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
]
|
|
39
|
-
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
children,
|
|
37
|
+
/* @__PURE__ */ React.createElement(SelectPrimitive.Icon, { asChild: true }, /* @__PURE__ */ React.createElement(ChevronDown, { size: 14, style: { color: isDark ? "#a1a1aa" : "#71717a", flexShrink: 0 } }))
|
|
40
38
|
);
|
|
41
39
|
}
|
|
42
40
|
function SelectValue({ placeholder }) {
|
|
43
|
-
return /* @__PURE__ */
|
|
41
|
+
return /* @__PURE__ */ React.createElement(SelectPrimitive.Value, { placeholder });
|
|
44
42
|
}
|
|
45
43
|
function SelectContent({ children }) {
|
|
46
44
|
const theme = useTheme();
|
|
47
45
|
const isDark = theme.palette.type === "dark";
|
|
48
|
-
return /* @__PURE__ */
|
|
46
|
+
return /* @__PURE__ */ React.createElement(SelectPrimitive.Portal, null, /* @__PURE__ */ React.createElement(
|
|
49
47
|
SelectPrimitive.Content,
|
|
50
48
|
{
|
|
51
49
|
position: "popper",
|
|
@@ -58,10 +56,10 @@ function SelectContent({ children }) {
|
|
|
58
56
|
boxShadow: isDark ? "0 4px 24px rgba(0,0,0,0.4)" : "0 4px 24px rgba(0,0,0,0.12)",
|
|
59
57
|
zIndex: 9999,
|
|
60
58
|
minWidth: 180
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
/* @__PURE__ */ React.createElement(SelectPrimitive.Viewport, null, children)
|
|
62
|
+
));
|
|
65
63
|
}
|
|
66
64
|
function SelectItem({
|
|
67
65
|
value,
|
|
@@ -69,7 +67,7 @@ function SelectItem({
|
|
|
69
67
|
}) {
|
|
70
68
|
const theme = useTheme();
|
|
71
69
|
const isDark = theme.palette.type === "dark";
|
|
72
|
-
return /* @__PURE__ */
|
|
70
|
+
return /* @__PURE__ */ React.createElement(
|
|
73
71
|
SelectPrimitive.Item,
|
|
74
72
|
{
|
|
75
73
|
value,
|
|
@@ -91,18 +89,16 @@ function SelectItem({
|
|
|
91
89
|
},
|
|
92
90
|
onMouseLeave: (e) => {
|
|
93
91
|
e.currentTarget.style.background = "transparent";
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
/* @__PURE__ */ React.createElement(
|
|
95
|
+
SelectPrimitive.ItemIndicator,
|
|
96
|
+
{
|
|
97
|
+
style: { position: "absolute", right: 8, display: "flex" }
|
|
94
98
|
},
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
style: { position: "absolute", right: 8, display: "flex" },
|
|
100
|
-
children: /* @__PURE__ */ jsx(Check, { size: 12, style: { color: isDark ? "#a1a1aa" : "#71717a" } })
|
|
101
|
-
}
|
|
102
|
-
),
|
|
103
|
-
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
104
|
-
]
|
|
105
|
-
}
|
|
99
|
+
/* @__PURE__ */ React.createElement(Check, { size: 12, style: { color: isDark ? "#a1a1aa" : "#71717a" } })
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ React.createElement(SelectPrimitive.ItemText, null, children)
|
|
106
102
|
);
|
|
107
103
|
}
|
|
108
104
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.esm.js","sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["import React from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\nimport { useTheme } from '@material-ui/core/styles';\nimport { Check, ChevronDown } from 'lucide-react';\n\nexport function Select({\n value,\n onValueChange,\n children,\n}: {\n value: string;\n onValueChange: (v: string) => void;\n children: React.ReactNode;\n}) {\n return (\n <SelectPrimitive.Root value={value} onValueChange={onValueChange}>\n {children}\n </SelectPrimitive.Root>\n );\n}\n\nexport function SelectTrigger({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Trigger\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderRadius: 6,\n border: `1px solid ${isDark ? '#3f3f46' : '#d4d4d8'}`,\n background: isDark ? '#18181b' : '#ffffff',\n color: isDark ? '#f4f4f5' : '#111114',\n padding: '6px 12px',\n fontSize: 14,\n fontWeight: 500,\n cursor: 'pointer',\n minWidth: 180,\n outline: 'none',\n }}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown size={14} style={{ color: isDark ? '#a1a1aa' : '#71717a', flexShrink: 0 }} />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n}\n\nexport function SelectValue({ placeholder }: { placeholder?: string }) {\n return <SelectPrimitive.Value placeholder={placeholder} />;\n}\n\nexport function SelectContent({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n position=\"popper\"\n sideOffset={4}\n style={{\n background: isDark ? '#18181b' : '#ffffff',\n border: `1px solid ${isDark ? '#3f3f46' : '#e4e4e7'}`,\n borderRadius: 8,\n padding: 4,\n boxShadow: isDark\n ? '0 4px 24px rgba(0,0,0,0.4)'\n : '0 4px 24px rgba(0,0,0,0.12)',\n zIndex: 9999,\n minWidth: 180,\n }}\n >\n <SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n}\n\nexport function SelectItem({\n value,\n children,\n}: {\n value: string;\n children: React.ReactNode;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Item\n value={value}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '6px 28px 6px 8px',\n borderRadius: 4,\n fontSize: 14,\n color: isDark ? '#f4f4f5' : '#111114',\n cursor: 'pointer',\n outline: 'none',\n position: 'relative',\n userSelect: 'none',\n }}\n onMouseEnter={e => {\n (e.currentTarget as HTMLElement).style.background = isDark ? '#27272a' : '#f4f4f6';\n }}\n onMouseLeave={e => {\n (e.currentTarget as HTMLElement).style.background = 'transparent';\n }}\n >\n <SelectPrimitive.ItemIndicator\n style={{ position: 'absolute', right: 8, display: 'flex' }}\n >\n <Check size={12} style={{ color: isDark ? '#a1a1aa' : '#71717a' }} />\n </SelectPrimitive.ItemIndicator>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n"],"names":[],"mappings":";;;;;AAKO,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,
|
|
1
|
+
{"version":3,"file":"select.esm.js","sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["import React from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\nimport { useTheme } from '@material-ui/core/styles';\nimport { Check, ChevronDown } from 'lucide-react';\n\nexport function Select({\n value,\n onValueChange,\n children,\n}: {\n value: string;\n onValueChange: (v: string) => void;\n children: React.ReactNode;\n}) {\n return (\n <SelectPrimitive.Root value={value} onValueChange={onValueChange}>\n {children}\n </SelectPrimitive.Root>\n );\n}\n\nexport function SelectTrigger({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Trigger\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderRadius: 6,\n border: `1px solid ${isDark ? '#3f3f46' : '#d4d4d8'}`,\n background: isDark ? '#18181b' : '#ffffff',\n color: isDark ? '#f4f4f5' : '#111114',\n padding: '6px 12px',\n fontSize: 14,\n fontWeight: 500,\n cursor: 'pointer',\n minWidth: 180,\n outline: 'none',\n }}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown size={14} style={{ color: isDark ? '#a1a1aa' : '#71717a', flexShrink: 0 }} />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n}\n\nexport function SelectValue({ placeholder }: { placeholder?: string }) {\n return <SelectPrimitive.Value placeholder={placeholder} />;\n}\n\nexport function SelectContent({ children }: { children: React.ReactNode }) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n position=\"popper\"\n sideOffset={4}\n style={{\n background: isDark ? '#18181b' : '#ffffff',\n border: `1px solid ${isDark ? '#3f3f46' : '#e4e4e7'}`,\n borderRadius: 8,\n padding: 4,\n boxShadow: isDark\n ? '0 4px 24px rgba(0,0,0,0.4)'\n : '0 4px 24px rgba(0,0,0,0.12)',\n zIndex: 9999,\n minWidth: 180,\n }}\n >\n <SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n}\n\nexport function SelectItem({\n value,\n children,\n}: {\n value: string;\n children: React.ReactNode;\n}) {\n const theme = useTheme();\n const isDark = theme.palette.type === 'dark';\n return (\n <SelectPrimitive.Item\n value={value}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '6px 28px 6px 8px',\n borderRadius: 4,\n fontSize: 14,\n color: isDark ? '#f4f4f5' : '#111114',\n cursor: 'pointer',\n outline: 'none',\n position: 'relative',\n userSelect: 'none',\n }}\n onMouseEnter={e => {\n (e.currentTarget as HTMLElement).style.background = isDark ? '#27272a' : '#f4f4f6';\n }}\n onMouseLeave={e => {\n (e.currentTarget as HTMLElement).style.background = 'transparent';\n }}\n >\n <SelectPrimitive.ItemIndicator\n style={{ position: 'absolute', right: 8, display: 'flex' }}\n >\n <Check size={12} style={{ color: isDark ? '#a1a1aa' : '#71717a' }} />\n </SelectPrimitive.ItemIndicator>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { ApiBlueprint, createApiFactory, configApiRef } from '@backstage/fronten
|
|
|
2
2
|
import { githubAuthApiRef } from '@backstage/core-plugin-api';
|
|
3
3
|
import { doraMetricsApiRef } from '../api/types.esm.js';
|
|
4
4
|
import { DoraMetricsClient } from '../api/DoraMetricsClient.esm.js';
|
|
5
|
+
import { MockDoraMetricsClient } from '../api/MockDoraMetricsClient.esm.js';
|
|
5
6
|
|
|
6
7
|
const doraMetricsApiExtension = ApiBlueprint.make({
|
|
7
8
|
name: "dora-metrics",
|
|
@@ -12,7 +13,10 @@ const doraMetricsApiExtension = ApiBlueprint.make({
|
|
|
12
13
|
githubAuthApi: githubAuthApiRef,
|
|
13
14
|
configApi: configApiRef
|
|
14
15
|
},
|
|
15
|
-
factory: ({ githubAuthApi, configApi }) =>
|
|
16
|
+
factory: ({ githubAuthApi, configApi }) => {
|
|
17
|
+
const debug = configApi.getConfig("app").getOptionalConfig("doraMetrics")?.getOptionalBoolean("debug") ?? false;
|
|
18
|
+
return debug ? new MockDoraMetricsClient() : new DoraMetricsClient(githubAuthApi, configApi);
|
|
19
|
+
}
|
|
16
20
|
})
|
|
17
21
|
)
|
|
18
22
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.esm.js","sources":["../../src/extensions/api.ts"],"sourcesContent":["import {\n ApiBlueprint,\n createApiFactory,\n configApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { githubAuthApiRef} from '@backstage/core-plugin-api';\nimport { doraMetricsApiRef } from '../api/types';\nimport { DoraMetricsClient } from '../api/DoraMetricsClient';\n\nexport const doraMetricsApiExtension = ApiBlueprint.make({\n name: 'dora-metrics',\n params: createApi =>\n createApi(\n createApiFactory({\n api: doraMetricsApiRef,\n deps: {\n githubAuthApi: githubAuthApiRef,\n configApi: configApiRef,\n },\n factory: ({ githubAuthApi, configApi })
|
|
1
|
+
{"version":3,"file":"api.esm.js","sources":["../../src/extensions/api.ts"],"sourcesContent":["import {\n ApiBlueprint,\n createApiFactory,\n configApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { githubAuthApiRef} from '@backstage/core-plugin-api';\nimport { doraMetricsApiRef } from '../api/types';\nimport { DoraMetricsClient } from '../api/DoraMetricsClient';\nimport { MockDoraMetricsClient } from '../api/MockDoraMetricsClient';\n\nexport const doraMetricsApiExtension = ApiBlueprint.make({\n name: 'dora-metrics',\n params: createApi =>\n createApi(\n createApiFactory({\n api: doraMetricsApiRef,\n deps: {\n githubAuthApi: githubAuthApiRef,\n configApi: configApiRef,\n },\n factory: ({ githubAuthApi, configApi }) => {\n const debug = configApi\n .getConfig('app')\n .getOptionalConfig('doraMetrics')\n ?.getOptionalBoolean('debug') ?? false;\n\n return debug\n ? new MockDoraMetricsClient()\n : new DoraMetricsClient(githubAuthApi, configApi);\n },\n }),\n ),\n});\n"],"names":[],"mappings":";;;;;;AAUO,MAAM,uBAAA,GAA0B,aAAa,IAAA,CAAK;AAAA,EACvD,IAAA,EAAM,cAAA;AAAA,EACN,QAAQ,CAAA,SAAA,KACN,SAAA;AAAA,IACE,gBAAA,CAAiB;AAAA,MACf,GAAA,EAAK,iBAAA;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,aAAA,EAAe,gBAAA;AAAA,QACf,SAAA,EAAW;AAAA,OACb;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,aAAA,EAAe,WAAU,KAAM;AACzC,QAAA,MAAM,KAAA,GAAQ,SAAA,CACX,SAAA,CAAU,KAAK,CAAA,CACf,kBAAkB,aAAa,CAAA,EAC9B,kBAAA,CAAmB,OAAO,CAAA,IAAK,KAAA;AAEnC,QAAA,OAAO,QACH,IAAI,qBAAA,KACJ,IAAI,iBAAA,CAAkB,eAAe,SAAS,CAAA;AAAA,MACpD;AAAA,KACD;AAAA;AAEP,CAAC;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
|
|
3
3
|
|
|
4
4
|
const doraMetricsEntityContentExtension = EntityContentBlueprint.make({
|
|
@@ -6,7 +6,7 @@ const doraMetricsEntityContentExtension = EntityContentBlueprint.make({
|
|
|
6
6
|
path: "dora-metrics",
|
|
7
7
|
title: "DORA Metrics",
|
|
8
8
|
filter: (entity) => entity.spec?.type === "service" || Boolean(entity.metadata.annotations?.["github.com/project-slug"]),
|
|
9
|
-
loader: () => import('../components/DoraMetricsContent.esm.js').then((m) => /* @__PURE__ */
|
|
9
|
+
loader: () => import('../components/DoraMetricsContent.esm.js').then((m) => /* @__PURE__ */ React.createElement(m.DoraMetricsContent, null))
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityContent.esm.js","sources":["../../src/extensions/entityContent.tsx"],"sourcesContent":["import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\n\nexport const doraMetricsEntityContentExtension = EntityContentBlueprint.make({\n params: {\n path: 'dora-metrics',\n title: 'DORA Metrics',\n filter: entity =>\n entity.spec?.type === 'service' ||\n Boolean(entity.metadata.annotations?.['github.com/project-slug']),\n loader: () =>\n import('../components/DoraMetricsContent').then(m => (\n <m.DoraMetricsContent />\n )),\n },\n});\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"entityContent.esm.js","sources":["../../src/extensions/entityContent.tsx"],"sourcesContent":["import React from 'react';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\n\nexport const doraMetricsEntityContentExtension = EntityContentBlueprint.make({\n params: {\n path: 'dora-metrics',\n title: 'DORA Metrics',\n filter: entity =>\n entity.spec?.type === 'service' ||\n Boolean(entity.metadata.annotations?.['github.com/project-slug']),\n loader: () =>\n import('../components/DoraMetricsContent').then(m => (\n <m.DoraMetricsContent />\n )),\n },\n});\n"],"names":[],"mappings":";;;AAGO,MAAM,iCAAA,GAAoC,uBAAuB,IAAA,CAAK;AAAA,EAC3E,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO,cAAA;AAAA,IACP,MAAA,EAAQ,CAAA,MAAA,KACN,MAAA,CAAO,IAAA,EAAM,IAAA,KAAS,SAAA,IACtB,OAAA,CAAQ,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,yBAAyB,CAAC,CAAA;AAAA,IAClE,MAAA,EAAQ,MACN,OAAO,yCAAkC,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAC9C,KAAA,CAAA,aAAA,CAAC,CAAA,CAAE,kBAAA,EAAF,IAAqB,CACvB;AAAA;AAEP,CAAC;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export { default as doraMetricsPlugin } from './alpha.js';
|
|
2
|
-
import * as
|
|
2
|
+
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
3
3
|
import { OAuthApi, ConfigApi } from '@backstage/core-plugin-api';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import '@backstage/catalog-model';
|
|
6
6
|
import 'react';
|
|
7
7
|
import '@backstage/filter-predicates';
|
|
8
|
+
import '@backstage/frontend-plugin-api';
|
|
8
9
|
|
|
9
10
|
type DoraRating = 'elite' | 'high' | 'medium' | 'low';
|
|
10
11
|
interface PrDetail {
|
|
@@ -25,10 +26,21 @@ interface DoraMetricValue {
|
|
|
25
26
|
}
|
|
26
27
|
interface DoraEnvironment {
|
|
27
28
|
name: string;
|
|
29
|
+
/**
|
|
30
|
+
* Raw branch pattern as configured — a single branch name, a comma-separated
|
|
31
|
+
* list ("main,master"), or a JavaScript regex string ("^(main|master)$").
|
|
32
|
+
* The client resolves this to a concrete list of branches at query time.
|
|
33
|
+
*/
|
|
28
34
|
branch: string;
|
|
29
35
|
isProduction: boolean;
|
|
30
36
|
label: string;
|
|
31
37
|
}
|
|
38
|
+
interface DoraTargets {
|
|
39
|
+
deploymentFrequency: number;
|
|
40
|
+
leadTime: number;
|
|
41
|
+
changeFailureRate: number;
|
|
42
|
+
mttr: number;
|
|
43
|
+
}
|
|
32
44
|
interface DoraMetrics {
|
|
33
45
|
deploymentFrequency: DoraMetricValue;
|
|
34
46
|
leadTime: DoraMetricValue;
|
|
@@ -50,10 +62,11 @@ interface DoraHistoryPoint {
|
|
|
50
62
|
interface DoraMetricsApi {
|
|
51
63
|
getEnvironments(): DoraEnvironment[];
|
|
52
64
|
getDefaultDays(): number;
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
getTargets(): DoraTargets;
|
|
66
|
+
getMetrics(projectSlug: string, env: DoraEnvironment, days: number, targetsOverride?: Partial<DoraTargets>): Promise<DoraMetrics>;
|
|
67
|
+
getHistory(projectSlug: string, env: DoraEnvironment, days: number): Promise<DoraHistoryPoint[]>;
|
|
55
68
|
}
|
|
56
|
-
declare const doraMetricsApiRef:
|
|
69
|
+
declare const doraMetricsApiRef: _backstage_core_plugin_api.ApiRef<DoraMetricsApi>;
|
|
57
70
|
|
|
58
71
|
declare class DoraMetricsClient implements DoraMetricsApi {
|
|
59
72
|
private readonly githubAuthApi;
|
|
@@ -62,12 +75,26 @@ declare class DoraMetricsClient implements DoraMetricsApi {
|
|
|
62
75
|
private getConfig;
|
|
63
76
|
getEnvironments(): DoraEnvironment[];
|
|
64
77
|
getDefaultDays(): number;
|
|
78
|
+
getTargets(): DoraTargets;
|
|
65
79
|
private fetchWithAuth;
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Fetch all merged PRs for an environment, resolving branch patterns and
|
|
82
|
+
* deduplicating across multiple branches by PR number.
|
|
83
|
+
*/
|
|
84
|
+
private fetchMergedPRs;
|
|
85
|
+
getMetrics(projectSlug: string, env: DoraEnvironment, days: number, targetsOverride?: Partial<DoraTargets>): Promise<DoraMetrics>;
|
|
86
|
+
getHistory(projectSlug: string, env: DoraEnvironment, days: number): Promise<DoraHistoryPoint[]>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
declare class MockDoraMetricsClient implements DoraMetricsApi {
|
|
90
|
+
getEnvironments(): DoraEnvironment[];
|
|
91
|
+
getDefaultDays(): number;
|
|
92
|
+
getTargets(): DoraTargets;
|
|
93
|
+
getMetrics(_projectSlug: string, env: DoraEnvironment, _days: number, _targetsOverride?: Partial<DoraTargets>): Promise<DoraMetrics>;
|
|
94
|
+
getHistory(_projectSlug: string, env: DoraEnvironment, _days: number): Promise<DoraHistoryPoint[]>;
|
|
68
95
|
}
|
|
69
96
|
|
|
70
97
|
declare function DoraMetricsContent(): react_jsx_runtime.JSX.Element | null;
|
|
71
98
|
|
|
72
|
-
export { DoraMetricsClient, DoraMetricsContent, doraMetricsApiRef };
|
|
73
|
-
export type { DoraMetricValue, DoraMetrics, DoraMetricsApi, DoraRating };
|
|
99
|
+
export { DoraMetricsClient, DoraMetricsContent, MockDoraMetricsClient, doraMetricsApiRef };
|
|
100
|
+
export type { DoraEnvironment, DoraMetricValue, DoraMetrics, DoraMetricsApi, DoraRating, DoraTargets, PrDetail };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { doraMetricsPlugin } from './plugin.esm.js';
|
|
2
2
|
export { doraMetricsApiRef } from './api/types.esm.js';
|
|
3
3
|
export { DoraMetricsClient } from './api/DoraMetricsClient.esm.js';
|
|
4
|
+
export { MockDoraMetricsClient } from './api/MockDoraMetricsClient.esm.js';
|
|
4
5
|
export { DoraMetricsContent } from './components/DoraMetricsContent.esm.js';
|
|
5
6
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c2l2c/backstage-plugin-dora-metrics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "A Backstage frontend plugin that displays DORA metrics (Deployment Frequency, Lead Time, Change Failure Rate, MTTR) for catalog entities via the GitHub API.",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -10,17 +10,8 @@
|
|
|
10
10
|
"configSchema": "config.d.ts"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
|
-
".":
|
|
14
|
-
|
|
15
|
-
"import": "./dist/index.esm.js",
|
|
16
|
-
"require": "./dist/index.cjs.js"
|
|
17
|
-
},
|
|
18
|
-
"./alpha": {
|
|
19
|
-
"backstage": "@backstage/FrontendPlugin",
|
|
20
|
-
"types": "./dist/alpha.d.ts",
|
|
21
|
-
"import": "./dist/alpha.esm.js",
|
|
22
|
-
"require": "./dist/alpha.cjs.js"
|
|
23
|
-
},
|
|
13
|
+
".": "./src/index.ts",
|
|
14
|
+
"./alpha": "./src/alpha.ts",
|
|
24
15
|
"./package.json": "./package.json"
|
|
25
16
|
},
|
|
26
17
|
"files": [
|
|
@@ -63,15 +54,23 @@
|
|
|
63
54
|
"@backstage/config": "^1.3.2",
|
|
64
55
|
"@backstage/core-components": "^0.18.7",
|
|
65
56
|
"@backstage/core-plugin-api": "^1.12.3",
|
|
66
|
-
"@backstage/frontend-plugin-api": "^0.
|
|
57
|
+
"@backstage/frontend-plugin-api": "^0.15.1",
|
|
67
58
|
"@backstage/plugin-catalog-react": "^2.0.0",
|
|
59
|
+
"@material-ui/core": "^4.12.4",
|
|
68
60
|
"@radix-ui/react-select": "^2.2.6",
|
|
69
|
-
"lucide-react": "^
|
|
61
|
+
"lucide-react": "^1.7.0"
|
|
70
62
|
},
|
|
71
63
|
"devDependencies": {
|
|
72
|
-
"@backstage/cli": "^0.
|
|
64
|
+
"@backstage/cli": "^0.36.0",
|
|
65
|
+
"@backstage/cli-defaults": "^0.1.0",
|
|
66
|
+
"@types/react": "^18",
|
|
67
|
+
"jest": "^30",
|
|
68
|
+
"jest-environment-jsdom": "^30"
|
|
73
69
|
},
|
|
74
70
|
"peerDependencies": {
|
|
75
71
|
"react": "^17.0.0 || ^18.0.0"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=20"
|
|
76
75
|
}
|
|
77
76
|
}
|