@backstage-community/plugin-apiiro 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +91 -12
- package/config.d.ts +14 -0
- package/dist/App.esm.js +96 -4
- package/dist/App.esm.js.map +1 -1
- package/dist/api/index.esm.js +6 -0
- package/dist/api/index.esm.js.map +1 -1
- package/dist/assets/SettingIcon.esm.js +1 -0
- package/dist/assets/SettingIcon.esm.js.map +1 -1
- package/dist/components/ApiiroSidebar.esm.js.map +1 -1
- package/dist/components/CalendarDatePicker.esm.js.map +1 -1
- package/dist/components/DataGrid/DataGrid.esm.js +1 -0
- package/dist/components/DataGrid/DataGrid.esm.js.map +1 -1
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js +28 -4
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js.map +1 -1
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js +30 -7
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js.map +1 -1
- package/dist/components/RiskLevel.esm.js +1 -0
- package/dist/components/RiskLevel.esm.js.map +1 -1
- package/dist/components/charts/GaugeChart.esm.js +8 -6
- package/dist/components/charts/GaugeChart.esm.js.map +1 -1
- package/dist/components/common/StatusContainer.esm.js +123 -0
- package/dist/components/common/StatusContainer.esm.js.map +1 -0
- package/dist/components/filters/DiscoveredOnFilter.esm.js +1 -1
- package/dist/components/filters/DiscoveredOnFilter.esm.js.map +1 -1
- package/dist/components/tiles/MttrVsSLATile.esm.js +31 -14
- package/dist/components/tiles/MttrVsSLATile.esm.js.map +1 -1
- package/dist/components/tiles/RiskOverTimeTile.esm.js +15 -12
- package/dist/components/tiles/RiskOverTimeTile.esm.js.map +1 -1
- package/dist/components/tiles/SLAAdherenceTile.esm.js +15 -12
- package/dist/components/tiles/SLAAdherenceTile.esm.js.map +1 -1
- package/dist/components/tiles/StatusTile.esm.js +98 -66
- package/dist/components/tiles/StatusTile.esm.js.map +1 -1
- package/dist/components/tiles/TopLanguagesTile.esm.js +1 -0
- package/dist/components/tiles/TopLanguagesTile.esm.js.map +1 -1
- package/dist/components/tiles/TopRiskTile.esm.js +19 -16
- package/dist/components/tiles/TopRiskTile.esm.js.map +1 -1
- package/dist/index.d.ts +31 -6
- package/dist/index.esm.js +2 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/pages/Applications/Applications.esm.js +104 -0
- package/dist/pages/Applications/Applications.esm.js.map +1 -0
- package/dist/pages/Applications/tableConfig.esm.js +147 -0
- package/dist/pages/Applications/tableConfig.esm.js.map +1 -0
- package/dist/pages/Repositories/Repositories.esm.js +26 -26
- package/dist/pages/Repositories/Repositories.esm.js.map +1 -1
- package/dist/pages/Repositories/tableConfig.esm.js +3 -2
- package/dist/pages/Repositories/tableConfig.esm.js.map +1 -1
- package/dist/pages/Risks/Risks.esm.js +9 -3
- package/dist/pages/Risks/Risks.esm.js.map +1 -1
- package/dist/pages/Risks/tableConfig.esm.js +25 -11
- package/dist/pages/Risks/tableConfig.esm.js.map +1 -1
- package/dist/pages/tab/ComponentTab.esm.js +72 -0
- package/dist/pages/tab/ComponentTab.esm.js.map +1 -0
- package/dist/pages/tab/SystemTab.esm.js +159 -0
- package/dist/pages/tab/SystemTab.esm.js.map +1 -0
- package/dist/pages/tab/TabProvider.esm.js +9 -3
- package/dist/pages/tab/TabProvider.esm.js.map +1 -1
- package/dist/pages/widget/ComponentWidget.esm.js +67 -0
- package/dist/pages/widget/ComponentWidget.esm.js.map +1 -0
- package/dist/pages/widget/SystemWidget.esm.js +81 -0
- package/dist/pages/widget/SystemWidget.esm.js.map +1 -0
- package/dist/pages/widget/WidgetProvider.esm.js +9 -3
- package/dist/pages/widget/WidgetProvider.esm.js.map +1 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/queries/application.queries.esm.js +64 -0
- package/dist/queries/application.queries.esm.js.map +1 -0
- package/dist/queries/mttr-statistics.queries.esm.js +19 -12
- package/dist/queries/mttr-statistics.queries.esm.js.map +1 -1
- package/dist/queries/repository.queries.esm.js +19 -8
- package/dist/queries/repository.queries.esm.js.map +1 -1
- package/dist/queries/risk-score-over-time.queries.esm.js +19 -12
- package/dist/queries/risk-score-over-time.queries.esm.js.map +1 -1
- package/dist/queries/risks.queries.esm.js +19 -7
- package/dist/queries/risks.queries.esm.js.map +1 -1
- package/dist/queries/sla-breach.queries.esm.js +22 -11
- package/dist/queries/sla-breach.queries.esm.js.map +1 -1
- package/dist/queries/top-risks.queries.esm.js +19 -7
- package/dist/queries/top-risks.queries.esm.js.map +1 -1
- package/dist/theme/themeUtils.esm.js +5 -2
- package/dist/theme/themeUtils.esm.js.map +1 -1
- package/dist/utils/utils.esm.js +3 -2
- package/dist/utils/utils.esm.js.map +1 -1
- package/package.json +12 -12
- package/dist/pages/tab/Tab.esm.js +0 -147
- package/dist/pages/tab/Tab.esm.js.map +0 -1
- package/dist/pages/widget/Widget.esm.js +0 -161
- package/dist/pages/widget/Widget.esm.js.map +0 -1
|
@@ -10,6 +10,7 @@ import 'react';
|
|
|
10
10
|
import 'react-dom';
|
|
11
11
|
import { NotFound } from '../common/NotFound.esm.js';
|
|
12
12
|
import { SomethingWentWrong } from '../common/SomethingWentWrong.esm.js';
|
|
13
|
+
import '../common/StatusContainer.esm.js';
|
|
13
14
|
import { LogoSpinner } from '../common/logoSpinner.esm.js';
|
|
14
15
|
|
|
15
16
|
const GaugesGrid = styled(Box)(() => ({
|
|
@@ -17,10 +18,20 @@ const GaugesGrid = styled(Box)(() => ({
|
|
|
17
18
|
gridTemplateColumns: "1fr 1fr",
|
|
18
19
|
justifyItems: "center",
|
|
19
20
|
alignItems: "center",
|
|
20
|
-
gap: "
|
|
21
|
+
gap: "20px",
|
|
21
22
|
width: "fit-content",
|
|
22
23
|
maxWidth: "100%",
|
|
23
|
-
|
|
24
|
+
maxHeight: "280px",
|
|
25
|
+
overflowY: "auto",
|
|
26
|
+
overflowX: "hidden",
|
|
27
|
+
scrollbarWidth: "none",
|
|
28
|
+
// Firefox
|
|
29
|
+
msOverflowStyle: "none",
|
|
30
|
+
// IE and Edge
|
|
31
|
+
"&::-webkit-scrollbar": {
|
|
32
|
+
display: "none"
|
|
33
|
+
// Chrome, Safari, and Opera
|
|
34
|
+
},
|
|
24
35
|
"@media (max-width: 320px)": {
|
|
25
36
|
gridTemplateColumns: "1fr",
|
|
26
37
|
gap: "12px"
|
|
@@ -60,7 +71,7 @@ const transformMttrStatisticsToGauges = (statistics) => {
|
|
|
60
71
|
unit: "Hours"
|
|
61
72
|
};
|
|
62
73
|
};
|
|
63
|
-
const riskLevelOrder = ["Critical", "High", "Medium", "Low"];
|
|
74
|
+
const riskLevelOrder = ["Critical", "High", "Medium", "Low", "Informational"];
|
|
64
75
|
const sortedStatistics = statistics.sort((a, b) => {
|
|
65
76
|
const aIndex = riskLevelOrder.indexOf(a.riskLevel);
|
|
66
77
|
const bIndex = riskLevelOrder.indexOf(b.riskLevel);
|
|
@@ -70,23 +81,26 @@ const transformMttrStatisticsToGauges = (statistics) => {
|
|
|
70
81
|
});
|
|
71
82
|
return sortedStatistics.map((stat) => {
|
|
72
83
|
const meanTimeDisplay = convertHoursForDisplay(stat.meanTimeInHours);
|
|
73
|
-
const slaDisplay = convertHoursForDisplay(stat.slaInHours);
|
|
84
|
+
const slaDisplay = stat.slaInHours !== null ? convertHoursForDisplay(stat.slaInHours) : null;
|
|
74
85
|
const unit = meanTimeDisplay.unit;
|
|
75
|
-
const maxHours = Math.max(stat.meanTimeInHours, stat.slaInHours) + 24;
|
|
86
|
+
const maxHours = Math.max(stat.meanTimeInHours, stat.slaInHours || 0) + 24;
|
|
76
87
|
const maxDisplay = convertHoursForDisplay(maxHours);
|
|
88
|
+
let tickValue = null;
|
|
89
|
+
if (slaDisplay !== null && stat.slaInHours !== null) {
|
|
90
|
+
tickValue = unit === "Days" ? slaDisplay.displayValue * 24 : Math.ceil(stat.slaInHours);
|
|
91
|
+
}
|
|
77
92
|
return {
|
|
78
93
|
value: unit === "Days" ? meanTimeDisplay.displayValue * 24 : Math.ceil(stat.meanTimeInHours),
|
|
79
94
|
// Original hours for arc scaling
|
|
80
|
-
tickValue
|
|
81
|
-
// Original hours for arc scaling
|
|
95
|
+
tickValue,
|
|
82
96
|
minValue: 0,
|
|
83
97
|
maxValue: unit === "Days" ? maxDisplay.displayValue * 24 : Math.ceil(maxHours),
|
|
84
98
|
categoryLabel: stat.riskLevel,
|
|
85
|
-
tooltip: `View ${stat.riskLevel} risks out of SLA
|
|
99
|
+
tooltip: stat?.slaInHours ? `View ${stat.riskLevel} risks out of SLA` : "SLA is not defined",
|
|
86
100
|
unit,
|
|
87
101
|
displayValue: meanTimeDisplay.displayValue,
|
|
88
102
|
// Converted value for center display
|
|
89
|
-
displayTickValue: slaDisplay
|
|
103
|
+
displayTickValue: slaDisplay?.displayValue ?? null,
|
|
90
104
|
// Converted value for tick display
|
|
91
105
|
displayMinValue: 0,
|
|
92
106
|
// Min is always 0
|
|
@@ -102,7 +116,8 @@ const MttrVsSLATile = ({
|
|
|
102
116
|
footerText = "*SLA (days)",
|
|
103
117
|
width = "100%",
|
|
104
118
|
repoId,
|
|
105
|
-
entityRef
|
|
119
|
+
entityRef,
|
|
120
|
+
applicationId
|
|
106
121
|
}) => {
|
|
107
122
|
const connectBackendApi = useApi(apiiroApiRef);
|
|
108
123
|
const { fetch } = useApi(fetchApiRef);
|
|
@@ -113,10 +128,11 @@ const MttrVsSLATile = ({
|
|
|
113
128
|
} = useMttrStatisticsData({
|
|
114
129
|
connectApi: connectBackendApi,
|
|
115
130
|
fetchApi: fetch,
|
|
116
|
-
|
|
117
|
-
entityRef
|
|
131
|
+
repositoryId: repoId,
|
|
132
|
+
entityRef,
|
|
133
|
+
applicationId
|
|
118
134
|
});
|
|
119
|
-
const shouldUseApiData = !!repoId;
|
|
135
|
+
const shouldUseApiData = !!repoId || !!applicationId;
|
|
120
136
|
const apiGauges = shouldUseApiData && mttrStatisticsData ? transformMttrStatisticsToGauges(mttrStatisticsData) : null;
|
|
121
137
|
const finalGauges = apiGauges || gauges;
|
|
122
138
|
const footer = footerText && !mttrStatisticsDataLoading ? /* @__PURE__ */ jsx(FooterText, { children: footerText }) : void 0;
|
|
@@ -136,7 +152,7 @@ const MttrVsSLATile = ({
|
|
|
136
152
|
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
137
153
|
}
|
|
138
154
|
if (finalGauges.length === 0) {
|
|
139
|
-
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: repoId ? /* @__PURE__ */ jsx(NotFound, {}) : /* @__PURE__ */ jsx(NotFound, { message: "Please
|
|
155
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: repoId ? /* @__PURE__ */ jsx(NotFound, {}) : /* @__PURE__ */ jsx(NotFound, { message: "Please configure the apiiro annotation to access the data." }) });
|
|
140
156
|
}
|
|
141
157
|
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, footer, width, children: /* @__PURE__ */ jsx(GaugesGrid, { children: finalGauges.map((gauge, index) => /* @__PURE__ */ jsxs(GaugeContainer, { children: [
|
|
142
158
|
/* @__PURE__ */ jsx(
|
|
@@ -160,6 +176,7 @@ const MttrVsSLATile = ({
|
|
|
160
176
|
minValue: gauge.displayMinValue ?? gauge.minValue,
|
|
161
177
|
maxValue: gauge.displayMaxValue ?? gauge.maxValue,
|
|
162
178
|
categoryLabel: gauge.categoryLabel,
|
|
179
|
+
tickValue: gauge.tickValue,
|
|
163
180
|
width: "130px"
|
|
164
181
|
}
|
|
165
182
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MttrVsSLATile.esm.js","sources":["../../../src/components/tiles/MttrVsSLATile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport { styled } from '@mui/material/styles';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { ChartBox } from '../common/ChartBox';\nimport GaugeChart, { GaugeBottomLabels } from '../charts/GaugeChart';\nimport { useMttrStatisticsData } from '../../queries/mttr-statistics.queries';\nimport { apiiroApiRef } from '../../api';\nimport { MttrStatistic } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\n\ninterface GaugeData {\n value: number;\n tickValue: number;\n minValue: number;\n maxValue: number;\n categoryLabel: string;\n tooltip?: string;\n unit?: string;\n displayValue?: number;\n displayTickValue?: number;\n displayMinValue?: number;\n displayMaxValue?: number;\n}\n\ninterface MttrVsSLATileProps {\n title?: string;\n tooltip?: string;\n gauges?: GaugeData[];\n footerText?: string;\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n}\n\nconst GaugesGrid = styled(Box)(() => ({\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n justifyItems: 'center',\n alignItems: 'center',\n gap: '8px',\n width: 'fit-content',\n maxWidth: '100%',\n margin: '0 auto',\n '@media (max-width: 320px)': {\n gridTemplateColumns: '1fr',\n gap: '12px',\n },\n}));\n\nconst GaugeContainer = styled(Box)(() => ({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n minWidth: 0,\n position: 'relative',\n '&:hover': {\n zIndex: 10,\n },\n}));\n\nconst FooterText = styled('p')(({ theme }) => ({\n fontSize: '11px',\n color: theme.palette.text.secondary,\n fontWeight: 400,\n lineHeight: 1.2,\n margin: 0,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n textAlign: 'center',\n}));\n\nconst transformMttrStatisticsToGauges = (\n statistics: MttrStatistic[],\n): GaugeData[] => {\n const convertHoursForDisplay = (\n hours: number,\n ): { displayValue: number; unit: string } => {\n if (hours > 23) {\n return {\n displayValue: Math.ceil(hours / 24),\n unit: 'Days',\n };\n }\n return {\n displayValue: Math.ceil(hours),\n unit: 'Hours',\n };\n };\n\n // Define the desired order: Medium, Low, High, Critical\n const riskLevelOrder = ['Critical', 'High', 'Medium', 'Low'];\n\n // Sort statistics according to the desired order\n const sortedStatistics = statistics.sort((a, b) => {\n const aIndex = riskLevelOrder.indexOf(a.riskLevel);\n const bIndex = riskLevelOrder.indexOf(b.riskLevel);\n\n // If risk level not found in order array, put it at the end\n const aOrder = aIndex === -1 ? riskLevelOrder.length : aIndex;\n const bOrder = bIndex === -1 ? riskLevelOrder.length : bIndex;\n\n return aOrder - bOrder;\n });\n\n return sortedStatistics.map(stat => {\n const meanTimeDisplay = convertHoursForDisplay(stat.meanTimeInHours);\n const slaDisplay = convertHoursForDisplay(stat.slaInHours);\n\n // Use the unit from the mean time (primary value)\n const unit = meanTimeDisplay.unit;\n\n // Use original hours for arc scaling, but display converted values for labels\n const maxHours = Math.max(stat.meanTimeInHours, stat.slaInHours) + 24;\n const maxDisplay = convertHoursForDisplay(maxHours);\n\n return {\n value:\n unit === 'Days'\n ? meanTimeDisplay.displayValue * 24\n : Math.ceil(stat.meanTimeInHours), // Original hours for arc scaling\n tickValue:\n unit === 'Days'\n ? slaDisplay.displayValue * 24\n : Math.ceil(stat.slaInHours), // Original hours for arc scaling\n minValue: 0,\n maxValue:\n unit === 'Days' ? maxDisplay.displayValue * 24 : Math.ceil(maxHours),\n categoryLabel: stat.riskLevel,\n tooltip: `View ${stat.riskLevel} risks out of SLA`,\n unit: unit,\n displayValue: meanTimeDisplay.displayValue, // Converted value for center display\n displayTickValue: slaDisplay.displayValue, // Converted value for tick display\n displayMinValue: 0, // Min is always 0\n displayMaxValue: maxDisplay.displayValue, // Converted max value for bottom labels\n };\n });\n};\n\nexport const MttrVsSLATile = ({\n title = 'MTTR vs. SLA',\n tooltip = 'The scale is set dynamically according to the SLA definition',\n gauges = [],\n footerText = '*SLA (days)',\n width = '100%',\n repoId,\n entityRef,\n}: MttrVsSLATileProps) => {\n // Use API hooks internally\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n // Always call the hook, but conditionally use the result\n const {\n mttrStatisticsData,\n mttrStatisticsDataError,\n mttrStatisticsDataLoading,\n } = useMttrStatisticsData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repositoryKey: repoId,\n entityRef: entityRef,\n });\n // Only use API data if repositoryKey is provided\n const shouldUseApiData = !!repoId;\n\n // Transform API data to gauge data if available and should be used\n const apiGauges =\n shouldUseApiData && mttrStatisticsData\n ? transformMttrStatisticsToGauges(mttrStatisticsData)\n : null;\n\n // Use API data if available, otherwise fall back to provided gauges\n const finalGauges = apiGauges || gauges;\n\n const footer =\n footerText && !mttrStatisticsDataLoading ? (\n <FooterText>{footerText}</FooterText>\n ) : undefined;\n\n // Show loading state if API is being used and data is loading\n if (shouldUseApiData && mttrStatisticsDataLoading) {\n return (\n <ChartBox title={title} tooltip={tooltip} footer={footer} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"250px\"\n >\n <LogoSpinner />\n </Box>\n </ChartBox>\n );\n }\n\n // Show error state if API is being used and there's an error\n if (shouldUseApiData && mttrStatisticsDataError) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <SomethingWentWrong />\n </ChartBox>\n );\n }\n\n // Show message when no data is available\n if (finalGauges.length === 0) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n {repoId ? (\n <NotFound />\n ) : (\n <NotFound message=\"Please provide the repository details to access the data.\" />\n )}\n </ChartBox>\n );\n }\n\n return (\n <ChartBox title={title} tooltip={tooltip} footer={footer} width={width}>\n <GaugesGrid>\n {finalGauges.map((gauge, index) => (\n <GaugeContainer key={index}>\n <GaugeChart\n width={200}\n height={180}\n value={gauge.value}\n tickValue={gauge.tickValue}\n minValue={gauge.minValue}\n maxValue={gauge.maxValue}\n tooltip={gauge.tooltip}\n unit={gauge.unit}\n displayValue={gauge.displayValue}\n displayTickValue={gauge.displayTickValue}\n />\n <GaugeBottomLabels\n minValue={gauge.displayMinValue ?? gauge.minValue}\n maxValue={gauge.displayMaxValue ?? gauge.maxValue}\n categoryLabel={gauge.categoryLabel}\n width=\"130px\"\n />\n </GaugeContainer>\n ))}\n </GaugesGrid>\n </ChartBox>\n );\n};\n\nexport default MttrVsSLATile;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MttrVsSLATile.esm.js","sources":["../../../src/components/tiles/MttrVsSLATile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport { styled } from '@mui/material/styles';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { ChartBox } from '../common/ChartBox';\nimport GaugeChart, { GaugeBottomLabels } from '../charts/GaugeChart';\nimport { useMttrStatisticsData } from '../../queries/mttr-statistics.queries';\nimport { apiiroApiRef } from '../../api';\nimport { MttrStatistic } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\n\ninterface GaugeData {\n value: number;\n tickValue: number | null;\n minValue: number;\n maxValue: number;\n categoryLabel: string;\n tooltip?: string;\n unit?: string;\n displayValue?: number;\n displayTickValue?: number | null;\n displayMinValue?: number;\n displayMaxValue?: number;\n}\n\ninterface MttrVsSLATileProps {\n title?: string;\n tooltip?: string;\n gauges?: GaugeData[];\n footerText?: string;\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n applicationId?: string;\n}\n\nconst GaugesGrid = styled(Box)(() => ({\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n justifyItems: 'center',\n alignItems: 'center',\n gap: '20px',\n width: 'fit-content',\n maxWidth: '100%',\n maxHeight: '280px',\n overflowY: 'auto',\n overflowX: 'hidden',\n scrollbarWidth: 'none', // Firefox\n msOverflowStyle: 'none', // IE and Edge\n '&::-webkit-scrollbar': {\n display: 'none', // Chrome, Safari, and Opera\n },\n '@media (max-width: 320px)': {\n gridTemplateColumns: '1fr',\n gap: '12px',\n },\n}));\n\nconst GaugeContainer = styled(Box)(() => ({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n minWidth: 0,\n position: 'relative',\n '&:hover': {\n zIndex: 10,\n },\n}));\n\nconst FooterText = styled('p')(({ theme }) => ({\n fontSize: '11px',\n color: theme.palette.text.secondary,\n fontWeight: 400,\n lineHeight: 1.2,\n margin: 0,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n textAlign: 'center',\n}));\n\nconst transformMttrStatisticsToGauges = (\n statistics: MttrStatistic[],\n): GaugeData[] => {\n const convertHoursForDisplay = (\n hours: number,\n ): { displayValue: number; unit: string } => {\n if (hours > 23) {\n return {\n displayValue: Math.ceil(hours / 24),\n unit: 'Days',\n };\n }\n return {\n displayValue: Math.ceil(hours),\n unit: 'Hours',\n };\n };\n\n // Define the desired order: Medium, Low, High, Critical\n const riskLevelOrder = ['Critical', 'High', 'Medium', 'Low', 'Informational'];\n\n // Sort statistics according to the desired order\n const sortedStatistics = statistics.sort((a, b) => {\n const aIndex = riskLevelOrder.indexOf(a.riskLevel);\n const bIndex = riskLevelOrder.indexOf(b.riskLevel);\n\n // If risk level not found in order array, put it at the end\n const aOrder = aIndex === -1 ? riskLevelOrder.length : aIndex;\n const bOrder = bIndex === -1 ? riskLevelOrder.length : bIndex;\n\n return aOrder - bOrder;\n });\n\n return sortedStatistics.map(stat => {\n const meanTimeDisplay = convertHoursForDisplay(stat.meanTimeInHours);\n const slaDisplay =\n stat.slaInHours !== null ? convertHoursForDisplay(stat.slaInHours) : null;\n\n // Use the unit from the mean time (primary value)\n const unit = meanTimeDisplay.unit;\n\n // Use original hours for arc scaling, but display converted values for labels\n const maxHours = Math.max(stat.meanTimeInHours, stat.slaInHours || 0) + 24;\n const maxDisplay = convertHoursForDisplay(maxHours);\n\n let tickValue: number | null = null;\n if (slaDisplay !== null && stat.slaInHours !== null) {\n tickValue =\n unit === 'Days'\n ? slaDisplay.displayValue * 24\n : Math.ceil(stat.slaInHours);\n }\n\n return {\n value:\n unit === 'Days'\n ? meanTimeDisplay.displayValue * 24\n : Math.ceil(stat.meanTimeInHours), // Original hours for arc scaling\n tickValue,\n minValue: 0,\n maxValue:\n unit === 'Days' ? maxDisplay.displayValue * 24 : Math.ceil(maxHours),\n categoryLabel: stat.riskLevel,\n tooltip: stat?.slaInHours\n ? `View ${stat.riskLevel} risks out of SLA`\n : 'SLA is not defined',\n unit: unit,\n displayValue: meanTimeDisplay.displayValue, // Converted value for center display\n displayTickValue: slaDisplay?.displayValue ?? null, // Converted value for tick display\n displayMinValue: 0, // Min is always 0\n displayMaxValue: maxDisplay.displayValue, // Converted max value for bottom labels\n };\n });\n};\n\nexport const MttrVsSLATile = ({\n title = 'MTTR vs. SLA',\n tooltip = 'The scale is set dynamically according to the SLA definition',\n gauges = [],\n footerText = '*SLA (days)',\n width = '100%',\n repoId,\n entityRef,\n applicationId,\n}: MttrVsSLATileProps) => {\n // Use API hooks internally\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n // Always call the hook, but conditionally use the result\n const {\n mttrStatisticsData,\n mttrStatisticsDataError,\n mttrStatisticsDataLoading,\n } = useMttrStatisticsData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repositoryId: repoId,\n entityRef: entityRef,\n applicationId: applicationId,\n });\n // Only use API data if repositoryId or applicationId is provided\n const shouldUseApiData = !!repoId || !!applicationId;\n\n // Transform API data to gauge data if available and should be used\n const apiGauges =\n shouldUseApiData && mttrStatisticsData\n ? transformMttrStatisticsToGauges(mttrStatisticsData)\n : null;\n\n // Use API data if available, otherwise fall back to provided gauges\n const finalGauges = apiGauges || gauges;\n\n const footer =\n footerText && !mttrStatisticsDataLoading ? (\n <FooterText>{footerText}</FooterText>\n ) : undefined;\n\n // Show loading state if API is being used and data is loading\n if (shouldUseApiData && mttrStatisticsDataLoading) {\n return (\n <ChartBox title={title} tooltip={tooltip} footer={footer} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"250px\"\n >\n <LogoSpinner />\n </Box>\n </ChartBox>\n );\n }\n\n // Show error state if API is being used and there's an error\n if (shouldUseApiData && mttrStatisticsDataError) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <SomethingWentWrong />\n </ChartBox>\n );\n }\n\n // Show message when no data is available\n if (finalGauges.length === 0) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n {repoId ? (\n <NotFound />\n ) : (\n <NotFound message=\"Please configure the apiiro annotation to access the data.\" />\n )}\n </ChartBox>\n );\n }\n\n return (\n <ChartBox title={title} tooltip={tooltip} footer={footer} width={width}>\n <GaugesGrid>\n {finalGauges.map((gauge, index) => (\n <GaugeContainer key={index}>\n <GaugeChart\n width={200}\n height={180}\n value={gauge.value}\n tickValue={gauge.tickValue}\n minValue={gauge.minValue}\n maxValue={gauge.maxValue}\n tooltip={gauge.tooltip}\n unit={gauge.unit}\n displayValue={gauge.displayValue}\n displayTickValue={gauge.displayTickValue}\n />\n <GaugeBottomLabels\n minValue={gauge.displayMinValue ?? gauge.minValue}\n maxValue={gauge.displayMaxValue ?? gauge.maxValue}\n categoryLabel={gauge.categoryLabel}\n tickValue={gauge.tickValue}\n width=\"130px\"\n />\n </GaugeContainer>\n ))}\n </GaugesGrid>\n </ChartBox>\n );\n};\n\nexport default MttrVsSLATile;\n"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ import 'react';
|
|
|
15
15
|
import 'react-dom';
|
|
16
16
|
import { NotFound } from '../common/NotFound.esm.js';
|
|
17
17
|
import { SomethingWentWrong } from '../common/SomethingWentWrong.esm.js';
|
|
18
|
+
import '../common/StatusContainer.esm.js';
|
|
18
19
|
import { LogoSpinner } from '../common/logoSpinner.esm.js';
|
|
19
20
|
import { formatNumberWithSuffix } from '../../utils/numberFormatter.esm.js';
|
|
20
21
|
|
|
@@ -87,7 +88,8 @@ const RiskOverTimeTile = ({
|
|
|
87
88
|
tooltip = "Track risk score changes over time",
|
|
88
89
|
width = "100%",
|
|
89
90
|
repoId,
|
|
90
|
-
entityRef
|
|
91
|
+
entityRef,
|
|
92
|
+
applicationId
|
|
91
93
|
}) => {
|
|
92
94
|
const theme = useTheme();
|
|
93
95
|
const trendColors = getTrendColors(theme);
|
|
@@ -100,36 +102,37 @@ const RiskOverTimeTile = ({
|
|
|
100
102
|
} = useRiskScoreOverTimeData({
|
|
101
103
|
connectApi: connectBackendApi,
|
|
102
104
|
fetchApi: fetch,
|
|
103
|
-
|
|
104
|
-
entityRef
|
|
105
|
+
repositoryId: repoId,
|
|
106
|
+
entityRef,
|
|
107
|
+
applicationId
|
|
105
108
|
});
|
|
106
|
-
if (
|
|
109
|
+
if (!repoId && !applicationId) {
|
|
107
110
|
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: /* @__PURE__ */ jsx(
|
|
108
111
|
Box,
|
|
109
112
|
{
|
|
110
113
|
display: "flex",
|
|
111
114
|
justifyContent: "center",
|
|
112
115
|
alignItems: "center",
|
|
113
|
-
minHeight: "
|
|
114
|
-
children: /* @__PURE__ */ jsx(
|
|
116
|
+
minHeight: "300px",
|
|
117
|
+
children: /* @__PURE__ */ jsx(NotFound, { message: "Please configure the apiiro annotation to access the data." })
|
|
115
118
|
}
|
|
116
119
|
) });
|
|
117
120
|
}
|
|
118
|
-
if (
|
|
119
|
-
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
120
|
-
}
|
|
121
|
-
if (!repoId) {
|
|
121
|
+
if (riskScoreOverTimeDataLoading) {
|
|
122
122
|
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: /* @__PURE__ */ jsx(
|
|
123
123
|
Box,
|
|
124
124
|
{
|
|
125
125
|
display: "flex",
|
|
126
126
|
justifyContent: "center",
|
|
127
127
|
alignItems: "center",
|
|
128
|
-
minHeight: "
|
|
129
|
-
children: /* @__PURE__ */ jsx(
|
|
128
|
+
minHeight: "250px",
|
|
129
|
+
children: /* @__PURE__ */ jsx(LogoSpinner, {})
|
|
130
130
|
}
|
|
131
131
|
) });
|
|
132
132
|
}
|
|
133
|
+
if (riskScoreOverTimeDataError) {
|
|
134
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, tooltip, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
135
|
+
}
|
|
133
136
|
const finalData = riskScoreOverTimeData ? riskScoreOverTimeData.map((point) => ({
|
|
134
137
|
date: point.date,
|
|
135
138
|
riskScore: point.count
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RiskOverTimeTile.esm.js","sources":["../../../src/components/tiles/RiskOverTimeTile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled, useTheme } from '@mui/material/styles';\nimport { getTrendColors } from '../../theme/themeUtils';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { ChartBox } from '../common/ChartBox';\nimport { LineChart, LineChartSeries } from '../charts/LineChart';\nimport TrendingUpIcon from '@mui/icons-material/TrendingUp';\nimport TrendingDownIcon from '@mui/icons-material/TrendingDown';\nimport RemoveIcon from '@mui/icons-material/Remove';\nimport { useRiskScoreOverTimeData } from '../../queries/risk-score-over-time.queries';\nimport { apiiroApiRef } from '../../api';\nimport { RiskScoreOverTimeDataPoint } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\nimport { formatNumberWithSuffix } from '../../utils/numberFormatter';\n\ninterface RiskDataPoint {\n date: string;\n riskScore: number;\n}\n\ninterface RiskOverTimeTileProps {\n title?: string;\n tooltip?: string;\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n}\n\nconst HeaderContainer = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '16px',\n width: '100%',\n}));\n\nconst TitleContainer = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n}));\n\nconst StyledTitle = styled(Typography)(({ theme }) => ({\n fontWeight: 400,\n fontSize: '16px',\n lineHeight: '24px',\n color: theme.palette.text.primary,\n}));\n\nconst PercentageContainer = styled(Box)<{\n backgroundColor: string;\n textColor: string;\n}>(({ backgroundColor, textColor }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n backgroundColor: backgroundColor,\n padding: '4px 8px',\n borderRadius: '12px',\n color: textColor,\n fontSize: '14px',\n fontWeight: 500,\n}));\n\n// Custom date sorting function for YYYY-MM-DD format\nconst sortDateStrings = (dates: string[]): string[] => {\n return dates.sort((a, b) => {\n const dateA = new Date(a).getTime();\n const dateB = new Date(b).getTime();\n // Handle invalid dates by putting them at the end\n if (isNaN(dateA) && isNaN(dateB)) return 0;\n if (isNaN(dateA)) return 1;\n if (isNaN(dateB)) return -1;\n return dateA - dateB;\n });\n};\n\nconst formatRiskScore = (value: number): string => {\n return formatNumberWithSuffix(value, 1);\n};\n\n// Format X-axis ticks to show only MM/DD\nconst formatXAxisDate = (dateStr: string | number): string => {\n if (typeof dateStr !== 'string') return String(dateStr);\n const date = new Date(dateStr);\n // Handle invalid dates\n if (isNaN(date.getTime())) {\n return String(dateStr);\n }\n const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n return `${month}/${day}`;\n};\n\n// Format tooltip header as \"D MMM YYYY\" (e.g., 7 Oct 2025) with day first and no comma\nconst formatTooltipDate = (dateStr: string | number): string => {\n if (typeof dateStr !== 'string') return String(dateStr);\n const date = new Date(dateStr);\n // Handle invalid dates\n if (isNaN(date.getTime())) {\n return String(dateStr);\n }\n // Use en-GB to ensure day-first order without comma\n return date.toLocaleDateString('en-GB', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n });\n};\n\nexport const RiskOverTimeTile = ({\n title = 'Risk score over time',\n tooltip = 'Track risk score changes over time',\n width = '100%',\n repoId,\n entityRef,\n}: RiskOverTimeTileProps) => {\n // Use API hooks internally\n const theme = useTheme();\n const trendColors = getTrendColors(theme);\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n // Always call the hook, but conditionally use the result\n const {\n riskScoreOverTimeData,\n riskScoreOverTimeDataError,\n riskScoreOverTimeDataLoading,\n } = useRiskScoreOverTimeData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repositoryKey: repoId,\n entityRef: entityRef,\n });\n\n // Show loading state while data is loading (Query check - loading)\n if (riskScoreOverTimeDataLoading) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"250px\"\n >\n <LogoSpinner />\n </Box>\n </ChartBox>\n );\n }\n\n // Show error state if there's an error (Query check - error)\n if (riskScoreOverTimeDataError) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <SomethingWentWrong />\n </ChartBox>\n );\n }\n\n // Show message when no repository key is provided\n if (!repoId) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"300px\"\n >\n <NotFound message=\"Please provide the repository details to access the data.\" />\n </Box>\n </ChartBox>\n );\n }\n\n // Transform API data to component data format\n const finalData: RiskDataPoint[] = riskScoreOverTimeData\n ? riskScoreOverTimeData.map((point: RiskScoreOverTimeDataPoint) => ({\n date: point.date,\n riskScore: point.count,\n }))\n : [];\n\n // Total data length check\n if (finalData.length === 0) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Check if all data points have zero count\n const hasAllZeroValues = riskScoreOverTimeData!.every(\n (point: RiskScoreOverTimeDataPoint) => point.count === 0,\n );\n\n // If all zero, send NotFound\n if (hasAllZeroValues) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Calculate percentage change from API data (only when we have valid data)\n const calculatePercentageChange = (data: RiskDataPoint[]): number => {\n if (data.length <= 1) return 0;\n\n const firstValue = data[0].riskScore ?? 0;\n const lastValue = data[data.length - 1].riskScore ?? 0;\n const difference = lastValue - firstValue;\n\n // Avoid division by zero\n if (firstValue === 0) {\n return lastValue > 0 ? 100 : 0;\n }\n\n // Handle negative firstValue edge case\n if (firstValue < 0) {\n // If first value is negative and last is positive, return positive change\n if (lastValue > 0) return 100;\n // If both are negative, calculate relative change\n return (difference / Math.abs(firstValue)) * 100;\n }\n\n return (difference / firstValue) * 100;\n };\n\n const calculatedPercentageChange = calculatePercentageChange(finalData);\n\n // Determine colors based on percentage change\n const isNeutralChange = calculatedPercentageChange === 0;\n const isPositiveChange = calculatedPercentageChange > 0;\n\n // Set colors based on change type using theme-aware colors\n let lineColor: string;\n let indicatorColor: string;\n let indicatorTextColor: string;\n let TrendIcon: typeof TrendingUpIcon;\n\n if (isNeutralChange) {\n lineColor = trendColors.neutral.line;\n indicatorColor = trendColors.neutral.background;\n indicatorTextColor = trendColors.neutral.text;\n TrendIcon = RemoveIcon; // Minus/horizontal icon for no trend\n } else if (isPositiveChange) {\n lineColor = trendColors.positive.line;\n indicatorColor = trendColors.positive.background;\n indicatorTextColor = trendColors.positive.text;\n TrendIcon = TrendingUpIcon; // Up icon for positive\n } else {\n lineColor = trendColors.negative.line;\n indicatorColor = trendColors.negative.background;\n indicatorTextColor = trendColors.negative.text;\n TrendIcon = TrendingDownIcon; // Down icon for negative\n }\n\n // Calculate y-axis range with exactly 6 ticks; top tick equals data maximum\n const calculateYAxisRange = (data: RiskDataPoint[]) => {\n // Safety check: ensure we have data\n if (!data || data.length === 0) {\n return { yMin: 0, yMax: 100 };\n }\n\n const values = data\n .map(d => d.riskScore)\n .filter(v => !isNaN(v) && isFinite(v));\n\n // Safety check: ensure we have valid numeric values\n if (values.length === 0) {\n return { yMin: 0, yMax: 100 };\n }\n\n const minValue = Math.min(...values);\n const maxValue = Math.max(...values);\n\n // Edge case: both values are zero\n if (minValue === 0 && maxValue === 0) {\n return { yMin: 0, yMax: 10 };\n }\n\n // Edge case: maxValue is zero but minValue is not (shouldn't happen, but handle it)\n if (maxValue === 0 && minValue < 0) {\n return { yMin: minValue * 1.2, yMax: 10 };\n }\n\n // Calculate yMin: subtract 15% from minValue, but ensure it doesn't go below 0 for non-negative data\n // If minValue is negative, allow yMin to be negative\n let yMin: number;\n if (minValue >= 0) {\n yMin = Math.max(0, minValue - minValue * 0.15);\n } else {\n yMin = minValue - minValue * 0.15;\n }\n\n // Calculate yMax: add 1% to maxValue\n // Handle edge case where maxValue is very small (near zero)\n let yMax: number;\n if (maxValue === 0) {\n yMax = 10;\n } else {\n yMax = maxValue + maxValue * 0.01;\n }\n\n // Edge case: ensure yMin < yMax (shouldn't happen with current logic, but safety check)\n if (yMin >= yMax) {\n if (maxValue === 0) {\n return { yMin: 0, yMax: 10 };\n }\n // If they're equal or reversed, create a small range around maxValue\n yMin = Math.max(0, maxValue * 0.9);\n yMax = maxValue * 1.1;\n }\n\n return { yMin, yMax };\n };\n\n const { yMin, yMax } = calculateYAxisRange(finalData);\n\n // Build exactly 6 ticks between yMin and yMax (inclusive)\n const yTicks: number[] = (() => {\n const count = 6;\n const ticks: number[] = [];\n\n // Edge case: yMin and yMax are equal (or very close due to floating point)\n if (Math.abs(yMax - yMin) < Number.EPSILON) {\n for (let i = 0; i < count; i++) ticks.push(yMin);\n return ticks;\n }\n\n // Edge case: yMin > yMax (shouldn't happen, but handle it)\n if (yMin > yMax) {\n // Reverse the range\n const step = (yMin - yMax) / (count - 1);\n for (let i = 0; i < count; i++) {\n ticks.push(yMax + i * step);\n }\n return ticks.reverse();\n }\n\n // Normal case: calculate evenly spaced ticks\n const step = (yMax - yMin) / (count - 1);\n for (let i = 0; i < count; i++) {\n // Use toFixed and parseFloat to handle floating point precision issues\n const tickValue = yMin + i * step;\n // Round to reasonable precision (10 decimal places max)\n ticks.push(parseFloat(tickValue.toFixed(10)));\n }\n\n // Ensure the last tick is exactly yMax to avoid floating point drift\n ticks[count - 1] = yMax;\n\n return ticks;\n })();\n\n const series: LineChartSeries[] = [\n {\n id: 'riskScore',\n label: 'Risk score',\n data: finalData.map(point => ({\n x: point.date,\n y: point.riskScore,\n })),\n color: lineColor, // Dynamic color based on percentage change\n },\n ];\n\n const customHeader = (\n <HeaderContainer>\n <TitleContainer>\n <StyledTitle>{title}</StyledTitle>\n </TitleContainer>\n <PercentageContainer\n backgroundColor={indicatorColor}\n textColor={indicatorTextColor}\n >\n <TrendIcon sx={{ fontSize: '16px', color: indicatorTextColor }} />\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 500, color: indicatorTextColor }}\n >\n {calculatedPercentageChange > 0 ? '+' : ''}\n {calculatedPercentageChange.toFixed(1)}%\n </Typography>\n </PercentageContainer>\n </HeaderContainer>\n );\n\n return (\n <ChartBox\n title={title}\n tooltip={tooltip}\n width={width}\n customHeader={customHeader}\n >\n <LineChart\n series={series}\n width=\"100%\"\n height={300}\n showLegend\n legendPosition=\"bottom\"\n showGrid\n formatYValue={formatRiskScore}\n formatXValue={formatXAxisDate}\n formatTooltipXValue={formatTooltipDate}\n showDataPoints={false}\n customXSort={values => sortDateStrings(values as string[])}\n yAxisMin={yMin}\n yAxisMax={yMax}\n yAxisTicks={yTicks}\n />\n </ChartBox>\n );\n};\n\nexport default RiskOverTimeTile;\n"],"names":["yMin","yMax","step"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RiskOverTimeTile.esm.js","sources":["../../../src/components/tiles/RiskOverTimeTile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled, useTheme } from '@mui/material/styles';\nimport { getTrendColors } from '../../theme/themeUtils';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { ChartBox } from '../common/ChartBox';\nimport { LineChart, LineChartSeries } from '../charts/LineChart';\nimport TrendingUpIcon from '@mui/icons-material/TrendingUp';\nimport TrendingDownIcon from '@mui/icons-material/TrendingDown';\nimport RemoveIcon from '@mui/icons-material/Remove';\nimport { useRiskScoreOverTimeData } from '../../queries/risk-score-over-time.queries';\nimport { apiiroApiRef } from '../../api';\nimport { RiskScoreOverTimeDataPoint } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\nimport { formatNumberWithSuffix } from '../../utils/numberFormatter';\n\ninterface RiskDataPoint {\n date: string;\n riskScore: number;\n}\n\ninterface RiskOverTimeTileProps {\n title?: string;\n tooltip?: string;\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n applicationId?: string;\n}\n\nconst HeaderContainer = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '16px',\n width: '100%',\n}));\n\nconst TitleContainer = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n}));\n\nconst StyledTitle = styled(Typography)(({ theme }) => ({\n fontWeight: 400,\n fontSize: '16px',\n lineHeight: '24px',\n color: theme.palette.text.primary,\n}));\n\nconst PercentageContainer = styled(Box)<{\n backgroundColor: string;\n textColor: string;\n}>(({ backgroundColor, textColor }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n backgroundColor: backgroundColor,\n padding: '4px 8px',\n borderRadius: '12px',\n color: textColor,\n fontSize: '14px',\n fontWeight: 500,\n}));\n\n// Custom date sorting function for YYYY-MM-DD format\nconst sortDateStrings = (dates: string[]): string[] => {\n return dates.sort((a, b) => {\n const dateA = new Date(a).getTime();\n const dateB = new Date(b).getTime();\n // Handle invalid dates by putting them at the end\n if (isNaN(dateA) && isNaN(dateB)) return 0;\n if (isNaN(dateA)) return 1;\n if (isNaN(dateB)) return -1;\n return dateA - dateB;\n });\n};\n\nconst formatRiskScore = (value: number): string => {\n return formatNumberWithSuffix(value, 1);\n};\n\n// Format X-axis ticks to show only MM/DD\nconst formatXAxisDate = (dateStr: string | number): string => {\n if (typeof dateStr !== 'string') return String(dateStr);\n const date = new Date(dateStr);\n // Handle invalid dates\n if (isNaN(date.getTime())) {\n return String(dateStr);\n }\n const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n return `${month}/${day}`;\n};\n\n// Format tooltip header as \"D MMM YYYY\" (e.g., 7 Oct 2025) with day first and no comma\nconst formatTooltipDate = (dateStr: string | number): string => {\n if (typeof dateStr !== 'string') return String(dateStr);\n const date = new Date(dateStr);\n // Handle invalid dates\n if (isNaN(date.getTime())) {\n return String(dateStr);\n }\n // Use en-GB to ensure day-first order without comma\n return date.toLocaleDateString('en-GB', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n });\n};\n\nexport const RiskOverTimeTile = ({\n title = 'Risk score over time',\n tooltip = 'Track risk score changes over time',\n width = '100%',\n repoId,\n entityRef,\n applicationId,\n}: RiskOverTimeTileProps) => {\n // Use API hooks internally\n const theme = useTheme();\n const trendColors = getTrendColors(theme);\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n const {\n riskScoreOverTimeData,\n riskScoreOverTimeDataError,\n riskScoreOverTimeDataLoading,\n } = useRiskScoreOverTimeData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repositoryId: repoId,\n entityRef: entityRef,\n applicationId: applicationId,\n });\n\n // Show message when repository key or application key is not provided\n if (!repoId && !applicationId) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"300px\"\n >\n <NotFound message=\"Please configure the apiiro annotation to access the data.\" />\n </Box>\n </ChartBox>\n );\n }\n\n // Show loading state while data is loading (Query check - loading)\n if (riskScoreOverTimeDataLoading) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"250px\"\n >\n <LogoSpinner />\n </Box>\n </ChartBox>\n );\n }\n\n // Show error state if there's an error (Query check - error)\n if (riskScoreOverTimeDataError) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <SomethingWentWrong />\n </ChartBox>\n );\n }\n\n // Transform API data to component data format\n const finalData: RiskDataPoint[] = riskScoreOverTimeData\n ? riskScoreOverTimeData.map((point: RiskScoreOverTimeDataPoint) => ({\n date: point.date,\n riskScore: point.count,\n }))\n : [];\n\n // Total data length check\n if (finalData.length === 0) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Check if all data points have zero count\n const hasAllZeroValues = riskScoreOverTimeData!.every(\n (point: RiskScoreOverTimeDataPoint) => point.count === 0,\n );\n\n // If all zero, send NotFound\n if (hasAllZeroValues) {\n return (\n <ChartBox title={title} tooltip={tooltip} width={width}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Calculate percentage change from API data (only when we have valid data)\n const calculatePercentageChange = (data: RiskDataPoint[]): number => {\n if (data.length <= 1) return 0;\n\n const firstValue = data[0].riskScore ?? 0;\n const lastValue = data[data.length - 1].riskScore ?? 0;\n const difference = lastValue - firstValue;\n\n // Avoid division by zero\n if (firstValue === 0) {\n return lastValue > 0 ? 100 : 0;\n }\n\n // Handle negative firstValue edge case\n if (firstValue < 0) {\n // If first value is negative and last is positive, return positive change\n if (lastValue > 0) return 100;\n // If both are negative, calculate relative change\n return (difference / Math.abs(firstValue)) * 100;\n }\n\n return (difference / firstValue) * 100;\n };\n\n const calculatedPercentageChange = calculatePercentageChange(finalData);\n\n // Determine colors based on percentage change\n const isNeutralChange = calculatedPercentageChange === 0;\n const isPositiveChange = calculatedPercentageChange > 0;\n\n // Set colors based on change type using theme-aware colors\n let lineColor: string;\n let indicatorColor: string;\n let indicatorTextColor: string;\n let TrendIcon: typeof TrendingUpIcon;\n\n if (isNeutralChange) {\n lineColor = trendColors.neutral.line;\n indicatorColor = trendColors.neutral.background;\n indicatorTextColor = trendColors.neutral.text;\n TrendIcon = RemoveIcon; // Minus/horizontal icon for no trend\n } else if (isPositiveChange) {\n lineColor = trendColors.positive.line;\n indicatorColor = trendColors.positive.background;\n indicatorTextColor = trendColors.positive.text;\n TrendIcon = TrendingUpIcon; // Up icon for positive\n } else {\n lineColor = trendColors.negative.line;\n indicatorColor = trendColors.negative.background;\n indicatorTextColor = trendColors.negative.text;\n TrendIcon = TrendingDownIcon; // Down icon for negative\n }\n\n // Calculate y-axis range with exactly 6 ticks; top tick equals data maximum\n const calculateYAxisRange = (data: RiskDataPoint[]) => {\n // Safety check: ensure we have data\n if (!data || data.length === 0) {\n return { yMin: 0, yMax: 100 };\n }\n\n const values = data\n .map(d => d.riskScore)\n .filter(v => !isNaN(v) && isFinite(v));\n\n // Safety check: ensure we have valid numeric values\n if (values.length === 0) {\n return { yMin: 0, yMax: 100 };\n }\n\n const minValue = Math.min(...values);\n const maxValue = Math.max(...values);\n\n // Edge case: both values are zero\n if (minValue === 0 && maxValue === 0) {\n return { yMin: 0, yMax: 10 };\n }\n\n // Edge case: maxValue is zero but minValue is not (shouldn't happen, but handle it)\n if (maxValue === 0 && minValue < 0) {\n return { yMin: minValue * 1.2, yMax: 10 };\n }\n\n // Calculate yMin: subtract 15% from minValue, but ensure it doesn't go below 0 for non-negative data\n // If minValue is negative, allow yMin to be negative\n let yMin: number;\n if (minValue >= 0) {\n yMin = Math.max(0, minValue - minValue * 0.15);\n } else {\n yMin = minValue - minValue * 0.15;\n }\n\n // Calculate yMax: add 1% to maxValue\n // Handle edge case where maxValue is very small (near zero)\n let yMax: number;\n if (maxValue === 0) {\n yMax = 10;\n } else {\n yMax = maxValue + maxValue * 0.01;\n }\n\n // Edge case: ensure yMin < yMax (shouldn't happen with current logic, but safety check)\n if (yMin >= yMax) {\n if (maxValue === 0) {\n return { yMin: 0, yMax: 10 };\n }\n // If they're equal or reversed, create a small range around maxValue\n yMin = Math.max(0, maxValue * 0.9);\n yMax = maxValue * 1.1;\n }\n\n return { yMin, yMax };\n };\n\n const { yMin, yMax } = calculateYAxisRange(finalData);\n\n // Build exactly 6 ticks between yMin and yMax (inclusive)\n const yTicks: number[] = (() => {\n const count = 6;\n const ticks: number[] = [];\n\n // Edge case: yMin and yMax are equal (or very close due to floating point)\n if (Math.abs(yMax - yMin) < Number.EPSILON) {\n for (let i = 0; i < count; i++) ticks.push(yMin);\n return ticks;\n }\n\n // Edge case: yMin > yMax (shouldn't happen, but handle it)\n if (yMin > yMax) {\n // Reverse the range\n const step = (yMin - yMax) / (count - 1);\n for (let i = 0; i < count; i++) {\n ticks.push(yMax + i * step);\n }\n return ticks.reverse();\n }\n\n // Normal case: calculate evenly spaced ticks\n const step = (yMax - yMin) / (count - 1);\n for (let i = 0; i < count; i++) {\n // Use toFixed and parseFloat to handle floating point precision issues\n const tickValue = yMin + i * step;\n // Round to reasonable precision (10 decimal places max)\n ticks.push(parseFloat(tickValue.toFixed(10)));\n }\n\n // Ensure the last tick is exactly yMax to avoid floating point drift\n ticks[count - 1] = yMax;\n\n return ticks;\n })();\n\n const series: LineChartSeries[] = [\n {\n id: 'riskScore',\n label: 'Risk score',\n data: finalData.map(point => ({\n x: point.date,\n y: point.riskScore,\n })),\n color: lineColor, // Dynamic color based on percentage change\n },\n ];\n\n const customHeader = (\n <HeaderContainer>\n <TitleContainer>\n <StyledTitle>{title}</StyledTitle>\n </TitleContainer>\n <PercentageContainer\n backgroundColor={indicatorColor}\n textColor={indicatorTextColor}\n >\n <TrendIcon sx={{ fontSize: '16px', color: indicatorTextColor }} />\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 500, color: indicatorTextColor }}\n >\n {calculatedPercentageChange > 0 ? '+' : ''}\n {calculatedPercentageChange.toFixed(1)}%\n </Typography>\n </PercentageContainer>\n </HeaderContainer>\n );\n\n return (\n <ChartBox\n title={title}\n tooltip={tooltip}\n width={width}\n customHeader={customHeader}\n >\n <LineChart\n series={series}\n width=\"100%\"\n height={300}\n showLegend\n legendPosition=\"bottom\"\n showGrid\n formatYValue={formatRiskScore}\n formatXValue={formatXAxisDate}\n formatTooltipXValue={formatTooltipDate}\n showDataPoints={false}\n customXSort={values => sortDateStrings(values as string[])}\n yAxisMin={yMin}\n yAxisMax={yMax}\n yAxisTicks={yTicks}\n />\n </ChartBox>\n );\n};\n\nexport default RiskOverTimeTile;\n"],"names":["yMin","yMax","step"],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ import 'react';
|
|
|
11
11
|
import 'react-dom';
|
|
12
12
|
import { NotFound } from '../common/NotFound.esm.js';
|
|
13
13
|
import { SomethingWentWrong } from '../common/SomethingWentWrong.esm.js';
|
|
14
|
+
import '../common/StatusContainer.esm.js';
|
|
14
15
|
import { LogoSpinner } from '../common/logoSpinner.esm.js';
|
|
15
16
|
|
|
16
17
|
const SLAAdherenceTile = ({
|
|
@@ -19,7 +20,8 @@ const SLAAdherenceTile = ({
|
|
|
19
20
|
width = "100%",
|
|
20
21
|
height = "366px",
|
|
21
22
|
repoId,
|
|
22
|
-
entityRef
|
|
23
|
+
entityRef,
|
|
24
|
+
applicationId
|
|
23
25
|
}) => {
|
|
24
26
|
const theme = useTheme();
|
|
25
27
|
const slaColors = getSlaColors(theme);
|
|
@@ -28,36 +30,37 @@ const SLAAdherenceTile = ({
|
|
|
28
30
|
const { slaBreachData, slaBreachDataError, slaBreachDataLoading } = useSlaBreachData({
|
|
29
31
|
connectApi: connectBackendApi,
|
|
30
32
|
fetchApi: fetch,
|
|
31
|
-
|
|
32
|
-
entityRef
|
|
33
|
+
repositoryId: repoId,
|
|
34
|
+
entityRef,
|
|
35
|
+
applicationId
|
|
33
36
|
});
|
|
34
|
-
if (
|
|
37
|
+
if (!repoId && !applicationId) {
|
|
35
38
|
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(
|
|
36
39
|
Box,
|
|
37
40
|
{
|
|
38
41
|
display: "flex",
|
|
39
42
|
justifyContent: "center",
|
|
40
43
|
alignItems: "center",
|
|
41
|
-
minHeight: "
|
|
42
|
-
children: /* @__PURE__ */ jsx(
|
|
44
|
+
minHeight: "300px",
|
|
45
|
+
children: /* @__PURE__ */ jsx(NotFound, { message: "Please configure the apiiro annotation to access the data." })
|
|
43
46
|
}
|
|
44
47
|
) });
|
|
45
48
|
}
|
|
46
|
-
if (
|
|
47
|
-
return /* @__PURE__ */ jsx(ChartBox, { title, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
48
|
-
}
|
|
49
|
-
if (!repoId) {
|
|
49
|
+
if (slaBreachDataLoading) {
|
|
50
50
|
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(
|
|
51
51
|
Box,
|
|
52
52
|
{
|
|
53
53
|
display: "flex",
|
|
54
54
|
justifyContent: "center",
|
|
55
55
|
alignItems: "center",
|
|
56
|
-
minHeight: "
|
|
57
|
-
children: /* @__PURE__ */ jsx(
|
|
56
|
+
minHeight: "250px",
|
|
57
|
+
children: /* @__PURE__ */ jsx(LogoSpinner, {})
|
|
58
58
|
}
|
|
59
59
|
) });
|
|
60
60
|
}
|
|
61
|
+
if (slaBreachDataError) {
|
|
62
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
63
|
+
}
|
|
61
64
|
const finalData = slaBreachData ? slaBreachData.map((point) => ({
|
|
62
65
|
category: point.riskLevel,
|
|
63
66
|
slaBreaches: point.slaBreach,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SLAAdherenceTile.esm.js","sources":["../../../src/components/tiles/SLAAdherenceTile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport { useTheme } from '@mui/material/styles';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { getSlaColors } from '../../theme/themeUtils';\nimport { ChartBox } from '../common/ChartBox';\nimport ColumnChart, { ColumnData } from '../charts/ColumnChart';\nimport { useSlaBreachData } from '../../queries/sla-breach.queries';\nimport { apiiroApiRef } from '../../api';\nimport { SlaBreachDataPoint } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\n\nexport interface SLAAdherenceData {\n category: string;\n slaBreaches: number;\n slaAdherence: number;\n dueDateNotSet: number;\n}\n\nexport interface SLAAdherenceTileProps {\n title?: string;\n tooltip?: string;\n data?: SLAAdherenceData[];\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n}\n\nexport const SLAAdherenceTile = ({\n title = 'SLA adherence',\n data = [],\n width = '100%',\n height = '366px',\n repoId,\n entityRef,\n}: SLAAdherenceTileProps) => {\n // Use API hooks internally\n const theme = useTheme();\n const slaColors = getSlaColors(theme);\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n
|
|
1
|
+
{"version":3,"file":"SLAAdherenceTile.esm.js","sources":["../../../src/components/tiles/SLAAdherenceTile.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport Box from '@mui/material/Box';\nimport { useTheme } from '@mui/material/styles';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { getSlaColors } from '../../theme/themeUtils';\nimport { ChartBox } from '../common/ChartBox';\nimport ColumnChart, { ColumnData } from '../charts/ColumnChart';\nimport { useSlaBreachData } from '../../queries/sla-breach.queries';\nimport { apiiroApiRef } from '../../api';\nimport { SlaBreachDataPoint } from '../../queries/queries.type';\nimport { NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\n\nexport interface SLAAdherenceData {\n category: string;\n slaBreaches: number;\n slaAdherence: number;\n dueDateNotSet: number;\n}\n\nexport interface SLAAdherenceTileProps {\n title?: string;\n tooltip?: string;\n data?: SLAAdherenceData[];\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n applicationId?: string;\n}\n\nexport const SLAAdherenceTile = ({\n title = 'SLA adherence',\n data = [],\n width = '100%',\n height = '366px',\n repoId,\n entityRef,\n applicationId,\n}: SLAAdherenceTileProps) => {\n // Use API hooks internally\n const theme = useTheme();\n const slaColors = getSlaColors(theme);\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n const { slaBreachData, slaBreachDataError, slaBreachDataLoading } =\n useSlaBreachData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repositoryId: repoId,\n entityRef: entityRef,\n applicationId: applicationId,\n });\n\n // Show message when repository key or application key is not provided\n if (!repoId && !applicationId) {\n return (\n <ChartBox title={title} width={width} height={height}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"300px\"\n >\n <NotFound message=\"Please configure the apiiro annotation to access the data.\" />\n </Box>\n </ChartBox>\n );\n }\n\n // Show loading state while data is loading (Query check - loading)\n if (slaBreachDataLoading) {\n return (\n <ChartBox title={title} width={width} height={height}>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"250px\"\n >\n <LogoSpinner />\n </Box>\n </ChartBox>\n );\n }\n\n // Show error state if there's an error (Query check - error)\n if (slaBreachDataError) {\n return (\n <ChartBox title={title} width={width}>\n <SomethingWentWrong />\n </ChartBox>\n );\n }\n\n // Transform API data to component data format\n const finalData: SLAAdherenceData[] = slaBreachData\n ? slaBreachData.map((point: SlaBreachDataPoint) => ({\n category: point.riskLevel,\n slaBreaches: point.slaBreach,\n slaAdherence: point.slaAdherence,\n dueDateNotSet: point.unsetDueDate,\n }))\n : data;\n\n // Total data length check\n if (finalData.length === 0) {\n return (\n <ChartBox title={title} width={width} height={height}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Check if all values are zero (slaBreach, slaAdherence, and unsetDueDate)\n const hasAllZeroValues = slaBreachData!.every(\n (point: SlaBreachDataPoint) =>\n point.slaBreach === 0 &&\n point.slaAdherence === 0 &&\n point.unsetDueDate === 0,\n );\n\n // If all zero, send NotFound\n if (hasAllZeroValues) {\n return (\n <ChartBox title={title} width={width} height={height}>\n <NotFound />\n </ChartBox>\n );\n }\n\n // Calculate chart width based on container\n const getChartWidth = () => {\n if (typeof width === 'string' && width.includes('%')) {\n // For percentage widths, assume a reasonable container width\n return 400; // This will be responsive within the container\n }\n return typeof width === 'number' ? width - 40 : 400; // Leave some padding\n };\n\n // Transform data for ColumnChart\n const columnData: ColumnData[] = finalData.map(item => ({\n category: item.category,\n values: [\n {\n label: 'SLA breaches',\n value: item.slaBreaches,\n color: slaColors.breach,\n },\n {\n label: 'SLA adherence',\n value: item.slaAdherence,\n color: slaColors.adherence,\n },\n {\n label: 'Due date not set',\n value: item.dueDateNotSet,\n color: slaColors.notSet,\n },\n ],\n }));\n\n return (\n <ChartBox title={title} width={width} height={height}>\n <ColumnChart\n data={columnData}\n width={getChartWidth()}\n height={300}\n showLegend\n legendPosition=\"bottom\"\n />\n </ChartBox>\n );\n};\n\nexport default SLAAdherenceTile;\n"],"names":[],"mappings":"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"}
|