@backstage-community/plugin-apiiro 0.1.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 +12 -0
- package/README.md +232 -0
- package/config.d.ts +30 -0
- package/dist/App.esm.js +12 -0
- package/dist/App.esm.js.map +1 -0
- package/dist/api/index.esm.js +71 -0
- package/dist/api/index.esm.js.map +1 -0
- package/dist/assets/BulleyeIcon.esm.js +454 -0
- package/dist/assets/BulleyeIcon.esm.js.map +1 -0
- package/dist/assets/NoResultIcon.esm.js +146 -0
- package/dist/assets/NoResultIcon.esm.js.map +1 -0
- package/dist/assets/RiskIcon.esm.js +27 -0
- package/dist/assets/RiskIcon.esm.js.map +1 -0
- package/dist/assets/SettingIcon.esm.js +49 -0
- package/dist/assets/SettingIcon.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroLogo.esm.js +21 -0
- package/dist/assets/apiiroLogo/apiiroLogo.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroSidebar.esm.js +23 -0
- package/dist/assets/apiiroLogo/apiiroSidebar.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroSmall.esm.js +19 -0
- package/dist/assets/apiiroLogo/apiiroSmall.esm.js.map +1 -0
- package/dist/assets/languageIcons/C.esm.js +7 -0
- package/dist/assets/languageIcons/C.esm.js.map +1 -0
- package/dist/assets/languageIcons/Cicd.esm.js +7 -0
- package/dist/assets/languageIcons/Cicd.esm.js.map +1 -0
- package/dist/assets/languageIcons/Clojure.esm.js +7 -0
- package/dist/assets/languageIcons/Clojure.esm.js.map +1 -0
- package/dist/assets/languageIcons/Cpp.esm.js +7 -0
- package/dist/assets/languageIcons/Cpp.esm.js.map +1 -0
- package/dist/assets/languageIcons/Csharp.esm.js +7 -0
- package/dist/assets/languageIcons/Csharp.esm.js.map +1 -0
- package/dist/assets/languageIcons/Dart.esm.js +7 -0
- package/dist/assets/languageIcons/Dart.esm.js.map +1 -0
- package/dist/assets/languageIcons/Go.esm.js +7 -0
- package/dist/assets/languageIcons/Go.esm.js.map +1 -0
- package/dist/assets/languageIcons/Groovy.esm.js +7 -0
- package/dist/assets/languageIcons/Groovy.esm.js.map +1 -0
- package/dist/assets/languageIcons/HTML.esm.js +7 -0
- package/dist/assets/languageIcons/HTML.esm.js.map +1 -0
- package/dist/assets/languageIcons/HclLanguage.esm.js +7 -0
- package/dist/assets/languageIcons/HclLanguage.esm.js.map +1 -0
- package/dist/assets/languageIcons/Java.esm.js +7 -0
- package/dist/assets/languageIcons/Java.esm.js.map +1 -0
- package/dist/assets/languageIcons/Javascript.esm.js +7 -0
- package/dist/assets/languageIcons/Javascript.esm.js.map +1 -0
- package/dist/assets/languageIcons/Kotlin.esm.js +7 -0
- package/dist/assets/languageIcons/Kotlin.esm.js.map +1 -0
- package/dist/assets/languageIcons/ObjectiveC.esm.js +7 -0
- package/dist/assets/languageIcons/ObjectiveC.esm.js.map +1 -0
- package/dist/assets/languageIcons/PHP.esm.js +7 -0
- package/dist/assets/languageIcons/PHP.esm.js.map +1 -0
- package/dist/assets/languageIcons/Perl.esm.js +13 -0
- package/dist/assets/languageIcons/Perl.esm.js.map +1 -0
- package/dist/assets/languageIcons/Python.esm.js +7 -0
- package/dist/assets/languageIcons/Python.esm.js.map +1 -0
- package/dist/assets/languageIcons/Ruby.esm.js +7 -0
- package/dist/assets/languageIcons/Ruby.esm.js.map +1 -0
- package/dist/assets/languageIcons/Rust.esm.js +7 -0
- package/dist/assets/languageIcons/Rust.esm.js.map +1 -0
- package/dist/assets/languageIcons/Scala.esm.js +7 -0
- package/dist/assets/languageIcons/Scala.esm.js.map +1 -0
- package/dist/assets/languageIcons/Swift.esm.js +7 -0
- package/dist/assets/languageIcons/Swift.esm.js.map +1 -0
- package/dist/assets/languageIcons/Terraform.esm.js +7 -0
- package/dist/assets/languageIcons/Terraform.esm.js.map +1 -0
- package/dist/assets/languageIcons/Typescript.esm.js +7 -0
- package/dist/assets/languageIcons/Typescript.esm.js.map +1 -0
- package/dist/assets/languageIcons/Unknown.esm.js +7 -0
- package/dist/assets/languageIcons/Unknown.esm.js.map +1 -0
- package/dist/assets/languageIcons/VB.esm.js +10 -0
- package/dist/assets/languageIcons/VB.esm.js.map +1 -0
- package/dist/assets/languageIcons/YAML.esm.js +7 -0
- package/dist/assets/languageIcons/YAML.esm.js.map +1 -0
- package/dist/assets/providerIcons/Azure.esm.js +7 -0
- package/dist/assets/providerIcons/Azure.esm.js.map +1 -0
- package/dist/assets/providerIcons/Bitbucket.esm.js +7 -0
- package/dist/assets/providerIcons/Bitbucket.esm.js.map +1 -0
- package/dist/assets/providerIcons/Gitlab.esm.js +7 -0
- package/dist/assets/providerIcons/Gitlab.esm.js.map +1 -0
- package/dist/components/ApiiroSidebar.esm.js +10 -0
- package/dist/components/ApiiroSidebar.esm.js.map +1 -0
- package/dist/components/ApplicationsList/ApplicationsList.esm.js +196 -0
- package/dist/components/ApplicationsList/ApplicationsList.esm.js.map +1 -0
- package/dist/components/CalendarDatePicker.esm.js +154 -0
- package/dist/components/CalendarDatePicker.esm.js.map +1 -0
- package/dist/components/CalendarDatePicker.styles.esm.js +198 -0
- package/dist/components/CalendarDatePicker.styles.esm.js.map +1 -0
- package/dist/components/Chip.esm.js +60 -0
- package/dist/components/Chip.esm.js.map +1 -0
- package/dist/components/ChipsList.esm.js +207 -0
- package/dist/components/ChipsList.esm.js.map +1 -0
- package/dist/components/ComponentDisplay.esm.js +42 -0
- package/dist/components/ComponentDisplay.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomColumnMenu.esm.js +29 -0
- package/dist/components/DataGrid/CustomColumnMenu.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomPagination.esm.js +113 -0
- package/dist/components/DataGrid/CustomPagination.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomSearchToolbar.esm.js +117 -0
- package/dist/components/DataGrid/CustomSearchToolbar.esm.js.map +1 -0
- package/dist/components/DataGrid/DataGrid.esm.js +336 -0
- package/dist/components/DataGrid/DataGrid.esm.js.map +1 -0
- package/dist/components/DataGrid/PinColumnMenuItem.esm.js +24 -0
- package/dist/components/DataGrid/PinColumnMenuItem.esm.js.map +1 -0
- package/dist/components/DueDate.esm.js +34 -0
- package/dist/components/DueDate.esm.js.map +1 -0
- package/dist/components/Header.esm.js +27 -0
- package/dist/components/Header.esm.js.map +1 -0
- package/dist/components/MainContributors/MainContributors.esm.js +62 -0
- package/dist/components/MainContributors/MainContributors.esm.js.map +1 -0
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js +37 -0
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js.map +1 -0
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js +36 -0
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js.map +1 -0
- package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js +121 -0
- package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js.map +1 -0
- package/dist/components/RiskLevel.esm.js +88 -0
- package/dist/components/RiskLevel.esm.js.map +1 -0
- package/dist/components/RiskStatus.esm.js +58 -0
- package/dist/components/RiskStatus.esm.js.map +1 -0
- package/dist/components/SimpleTooltip.esm.js +24 -0
- package/dist/components/SimpleTooltip.esm.js.map +1 -0
- package/dist/components/SourcesDisplay.esm.js +47 -0
- package/dist/components/SourcesDisplay.esm.js.map +1 -0
- package/dist/components/TagsList/TagsList.esm.js +38 -0
- package/dist/components/TagsList/TagsList.esm.js.map +1 -0
- package/dist/components/TeamsDisplay.esm.js +47 -0
- package/dist/components/TeamsDisplay.esm.js.map +1 -0
- package/dist/components/charts/ColumnChart.esm.js +402 -0
- package/dist/components/charts/ColumnChart.esm.js.map +1 -0
- package/dist/components/charts/GaugeChart.esm.js +249 -0
- package/dist/components/charts/GaugeChart.esm.js.map +1 -0
- package/dist/components/charts/LineChart.esm.js +328 -0
- package/dist/components/charts/LineChart.esm.js.map +1 -0
- package/dist/components/charts/PieChart.esm.js +233 -0
- package/dist/components/charts/PieChart.esm.js.map +1 -0
- package/dist/components/common/ChartBox.esm.js +88 -0
- package/dist/components/common/ChartBox.esm.js.map +1 -0
- package/dist/components/common/CustomTooltip.esm.js +255 -0
- package/dist/components/common/CustomTooltip.esm.js.map +1 -0
- package/dist/components/common/ErrorSnackbar.esm.js +39 -0
- package/dist/components/common/ErrorSnackbar.esm.js.map +1 -0
- package/dist/components/common/NotFound.esm.js +30 -0
- package/dist/components/common/NotFound.esm.js.map +1 -0
- package/dist/components/common/SomethingWentWrong.esm.js +35 -0
- package/dist/components/common/SomethingWentWrong.esm.js.map +1 -0
- package/dist/components/common/languageIcons.esm.js +61 -0
- package/dist/components/common/languageIcons.esm.js.map +1 -0
- package/dist/components/common/logoSpinner.esm.js +28 -0
- package/dist/components/common/logoSpinner.esm.js.map +1 -0
- package/dist/components/common/scmProviders.esm.js +41 -0
- package/dist/components/common/scmProviders.esm.js.map +1 -0
- package/dist/components/filters/DiscoveredOnFilter.esm.js +284 -0
- package/dist/components/filters/DiscoveredOnFilter.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdown.esm.js +325 -0
- package/dist/components/filters/FilterDropdown.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownClear.esm.js +45 -0
- package/dist/components/filters/FilterDropdownClear.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownList.esm.js +102 -0
- package/dist/components/filters/FilterDropdownList.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownSearch.esm.js +65 -0
- package/dist/components/filters/FilterDropdownSearch.esm.js.map +1 -0
- package/dist/components/filters/RiskInsightFilter.esm.js +579 -0
- package/dist/components/filters/RiskInsightFilter.esm.js.map +1 -0
- package/dist/components/tiles/MttrVsSLATile.esm.js +170 -0
- package/dist/components/tiles/MttrVsSLATile.esm.js.map +1 -0
- package/dist/components/tiles/RiskOverTimeTile.esm.js +311 -0
- package/dist/components/tiles/RiskOverTimeTile.esm.js.map +1 -0
- package/dist/components/tiles/SLAAdherenceTile.esm.js +115 -0
- package/dist/components/tiles/SLAAdherenceTile.esm.js.map +1 -0
- package/dist/components/tiles/StatusTile.esm.js +235 -0
- package/dist/components/tiles/StatusTile.esm.js.map +1 -0
- package/dist/components/tiles/TopLanguagesTile.esm.js +234 -0
- package/dist/components/tiles/TopLanguagesTile.esm.js.map +1 -0
- package/dist/components/tiles/TopRiskTile.esm.js +208 -0
- package/dist/components/tiles/TopRiskTile.esm.js.map +1 -0
- package/dist/hooks/useUrlFilters.esm.js +102 -0
- package/dist/hooks/useUrlFilters.esm.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.esm.js +42 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/pages/Repositories/Repositories.esm.js +102 -0
- package/dist/pages/Repositories/Repositories.esm.js.map +1 -0
- package/dist/pages/Repositories/tableConfig.esm.js +294 -0
- package/dist/pages/Repositories/tableConfig.esm.js.map +1 -0
- package/dist/pages/Risks/Risks.esm.js +258 -0
- package/dist/pages/Risks/Risks.esm.js.map +1 -0
- package/dist/pages/Risks/tableConfig.esm.js +305 -0
- package/dist/pages/Risks/tableConfig.esm.js.map +1 -0
- package/dist/pages/tab/Tab.esm.js +147 -0
- package/dist/pages/tab/Tab.esm.js.map +1 -0
- package/dist/pages/tab/TabProvider.esm.js +11 -0
- package/dist/pages/tab/TabProvider.esm.js.map +1 -0
- package/dist/pages/widget/Widget.esm.js +161 -0
- package/dist/pages/widget/Widget.esm.js.map +1 -0
- package/dist/pages/widget/WidgetProvider.esm.js +12 -0
- package/dist/pages/widget/WidgetProvider.esm.js.map +1 -0
- package/dist/plugin.esm.js +30 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/queries/filterOptions.queries.esm.js +46 -0
- package/dist/queries/filterOptions.queries.esm.js.map +1 -0
- package/dist/queries/mttr-statistics.queries.esm.js +61 -0
- package/dist/queries/mttr-statistics.queries.esm.js.map +1 -0
- package/dist/queries/repository.queries.esm.js +60 -0
- package/dist/queries/repository.queries.esm.js.map +1 -0
- package/dist/queries/risk-score-over-time.queries.esm.js +61 -0
- package/dist/queries/risk-score-over-time.queries.esm.js.map +1 -0
- package/dist/queries/risks.queries.esm.js +65 -0
- package/dist/queries/risks.queries.esm.js.map +1 -0
- package/dist/queries/sla-breach.queries.esm.js +57 -0
- package/dist/queries/sla-breach.queries.esm.js.map +1 -0
- package/dist/queries/top-risks.queries.esm.js +47 -0
- package/dist/queries/top-risks.queries.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/theme/themeUtils.esm.js +290 -0
- package/dist/theme/themeUtils.esm.js.map +1 -0
- package/dist/utils/dateFormatter.esm.js +67 -0
- package/dist/utils/dateFormatter.esm.js.map +1 -0
- package/dist/utils/numberFormatter.esm.js +21 -0
- package/dist/utils/numberFormatter.esm.js.map +1 -0
- package/dist/utils/utils.esm.js +27 -0
- package/dist/utils/utils.esm.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import { useTheme } from '@mui/material/styles';
|
|
4
|
+
import { useApi, fetchApiRef } from '@backstage/core-plugin-api';
|
|
5
|
+
import { getSlaColors } from '../../theme/themeUtils.esm.js';
|
|
6
|
+
import { ChartBox } from '../common/ChartBox.esm.js';
|
|
7
|
+
import { ColumnChart } from '../charts/ColumnChart.esm.js';
|
|
8
|
+
import { useSlaBreachData } from '../../queries/sla-breach.queries.esm.js';
|
|
9
|
+
import { apiiroApiRef } from '../../api/index.esm.js';
|
|
10
|
+
import 'react';
|
|
11
|
+
import 'react-dom';
|
|
12
|
+
import { NotFound } from '../common/NotFound.esm.js';
|
|
13
|
+
import { SomethingWentWrong } from '../common/SomethingWentWrong.esm.js';
|
|
14
|
+
import { LogoSpinner } from '../common/logoSpinner.esm.js';
|
|
15
|
+
|
|
16
|
+
const SLAAdherenceTile = ({
|
|
17
|
+
title = "SLA adherence",
|
|
18
|
+
data = [],
|
|
19
|
+
width = "100%",
|
|
20
|
+
height = "366px",
|
|
21
|
+
repoId,
|
|
22
|
+
entityRef
|
|
23
|
+
}) => {
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const slaColors = getSlaColors(theme);
|
|
26
|
+
const connectBackendApi = useApi(apiiroApiRef);
|
|
27
|
+
const { fetch } = useApi(fetchApiRef);
|
|
28
|
+
const { slaBreachData, slaBreachDataError, slaBreachDataLoading } = useSlaBreachData({
|
|
29
|
+
connectApi: connectBackendApi,
|
|
30
|
+
fetchApi: fetch,
|
|
31
|
+
repositoryKey: repoId,
|
|
32
|
+
entityRef
|
|
33
|
+
});
|
|
34
|
+
if (slaBreachDataLoading) {
|
|
35
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(
|
|
36
|
+
Box,
|
|
37
|
+
{
|
|
38
|
+
display: "flex",
|
|
39
|
+
justifyContent: "center",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
minHeight: "250px",
|
|
42
|
+
children: /* @__PURE__ */ jsx(LogoSpinner, {})
|
|
43
|
+
}
|
|
44
|
+
) });
|
|
45
|
+
}
|
|
46
|
+
if (slaBreachDataError) {
|
|
47
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, children: /* @__PURE__ */ jsx(SomethingWentWrong, {}) });
|
|
48
|
+
}
|
|
49
|
+
if (!repoId) {
|
|
50
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(
|
|
51
|
+
Box,
|
|
52
|
+
{
|
|
53
|
+
display: "flex",
|
|
54
|
+
justifyContent: "center",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
minHeight: "300px",
|
|
57
|
+
children: /* @__PURE__ */ jsx(NotFound, { message: "Please provide the repository details to access the data." })
|
|
58
|
+
}
|
|
59
|
+
) });
|
|
60
|
+
}
|
|
61
|
+
const finalData = slaBreachData ? slaBreachData.map((point) => ({
|
|
62
|
+
category: point.riskLevel,
|
|
63
|
+
slaBreaches: point.slaBreach,
|
|
64
|
+
slaAdherence: point.slaAdherence,
|
|
65
|
+
dueDateNotSet: point.unsetDueDate
|
|
66
|
+
})) : data;
|
|
67
|
+
if (finalData.length === 0) {
|
|
68
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(NotFound, {}) });
|
|
69
|
+
}
|
|
70
|
+
const hasAllZeroValues = slaBreachData.every(
|
|
71
|
+
(point) => point.slaBreach === 0 && point.slaAdherence === 0 && point.unsetDueDate === 0
|
|
72
|
+
);
|
|
73
|
+
if (hasAllZeroValues) {
|
|
74
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(NotFound, {}) });
|
|
75
|
+
}
|
|
76
|
+
const getChartWidth = () => {
|
|
77
|
+
if (typeof width === "string" && width.includes("%")) {
|
|
78
|
+
return 400;
|
|
79
|
+
}
|
|
80
|
+
return typeof width === "number" ? width - 40 : 400;
|
|
81
|
+
};
|
|
82
|
+
const columnData = finalData.map((item) => ({
|
|
83
|
+
category: item.category,
|
|
84
|
+
values: [
|
|
85
|
+
{
|
|
86
|
+
label: "SLA breaches",
|
|
87
|
+
value: item.slaBreaches,
|
|
88
|
+
color: slaColors.breach
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
label: "SLA adherence",
|
|
92
|
+
value: item.slaAdherence,
|
|
93
|
+
color: slaColors.adherence
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: "Due date not set",
|
|
97
|
+
value: item.dueDateNotSet,
|
|
98
|
+
color: slaColors.notSet
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}));
|
|
102
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, height, children: /* @__PURE__ */ jsx(
|
|
103
|
+
ColumnChart,
|
|
104
|
+
{
|
|
105
|
+
data: columnData,
|
|
106
|
+
width: getChartWidth(),
|
|
107
|
+
height: 300,
|
|
108
|
+
showLegend: true,
|
|
109
|
+
legendPosition: "bottom"
|
|
110
|
+
}
|
|
111
|
+
) });
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export { SLAAdherenceTile, SLAAdherenceTile as default };
|
|
115
|
+
//# sourceMappingURL=SLAAdherenceTile.esm.js.map
|
|
@@ -0,0 +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 // Always call the hook, but conditionally use the result\n const { slaBreachData, slaBreachDataError, slaBreachDataLoading } =\n useSlaBreachData({\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 (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 // Show message when no repository key is provided\n if (!repoId) {\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 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: 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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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import Typography from '@mui/material/Typography';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
|
+
import { getActivityStatusColors, getLogoContainerColors } from '../../theme/themeUtils.esm.js';
|
|
6
|
+
import { Link } from 'react-router-dom';
|
|
7
|
+
import { ApiiroLogo } from '../../assets/apiiroLogo/apiiroLogo.esm.js';
|
|
8
|
+
import '@mui/material/SvgIcon';
|
|
9
|
+
import { formatNumberWithSuffix } from '../../utils/numberFormatter.esm.js';
|
|
10
|
+
import { formatActivityTooltip, getDevelopmentDuration } from '../../utils/dateFormatter.esm.js';
|
|
11
|
+
import '@mui/icons-material';
|
|
12
|
+
import 'react-icons/vsc';
|
|
13
|
+
import 'react-icons/si';
|
|
14
|
+
import { APIIRO_DEFAULT_BASE_URL } from '@backstage-community/plugin-apiiro-common';
|
|
15
|
+
import '../common/ChartBox.esm.js';
|
|
16
|
+
import { CustomTooltip } from '../common/CustomTooltip.esm.js';
|
|
17
|
+
import { NotFound } from '../common/NotFound.esm.js';
|
|
18
|
+
import { scmProviderIcons, generateRepoURL } from '../common/scmProviders.esm.js';
|
|
19
|
+
import { SettingIcon } from '../../assets/SettingIcon.esm.js';
|
|
20
|
+
|
|
21
|
+
const ThemedIcon = styled("span")(({ theme }) => ({
|
|
22
|
+
display: "inline-flex",
|
|
23
|
+
"& svg": {
|
|
24
|
+
color: theme.palette.text.primary,
|
|
25
|
+
flexShrink: 0
|
|
26
|
+
},
|
|
27
|
+
"&:hover svg": {
|
|
28
|
+
color: theme.palette.primary.main
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
const StatusIndicator = styled("span")(
|
|
32
|
+
({ theme, isActive }) => {
|
|
33
|
+
const activityColors = getActivityStatusColors(theme);
|
|
34
|
+
return {
|
|
35
|
+
display: "inline-block",
|
|
36
|
+
width: 8,
|
|
37
|
+
height: 8,
|
|
38
|
+
borderRadius: "50%",
|
|
39
|
+
backgroundColor: isActive ? activityColors.active : activityColors.inactive,
|
|
40
|
+
marginRight: 8
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
const StatusBox = styled(Box)(({ theme, width, height }) => ({
|
|
45
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
46
|
+
borderRadius: "12px",
|
|
47
|
+
backgroundColor: theme.palette.background.paper,
|
|
48
|
+
boxShadow: theme.shadows[1],
|
|
49
|
+
width: width || "fit-content",
|
|
50
|
+
height: height || "auto",
|
|
51
|
+
margin: width === "100%" ? "0" : "0 auto",
|
|
52
|
+
maxWidth: "100%",
|
|
53
|
+
display: "flex",
|
|
54
|
+
flexDirection: "column",
|
|
55
|
+
boxSizing: "border-box"
|
|
56
|
+
}));
|
|
57
|
+
const StatusContent = styled(Box)(() => ({
|
|
58
|
+
display: "flex",
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
alignItems: "flex-start",
|
|
61
|
+
gap: "12px",
|
|
62
|
+
padding: "16px"
|
|
63
|
+
}));
|
|
64
|
+
const StatusRow = styled(Box)(() => ({
|
|
65
|
+
display: "flex",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
gap: "8px"
|
|
68
|
+
}));
|
|
69
|
+
const StatusLabel = styled(Typography)(({ theme }) => ({
|
|
70
|
+
fontSize: "16px",
|
|
71
|
+
fontWeight: 400,
|
|
72
|
+
color: theme.palette.text.secondary
|
|
73
|
+
}));
|
|
74
|
+
const StatusValue = styled(Typography)(({ theme }) => ({
|
|
75
|
+
fontSize: "16px",
|
|
76
|
+
fontWeight: 400,
|
|
77
|
+
color: theme.palette.text.primary
|
|
78
|
+
}));
|
|
79
|
+
const BranchLink = styled(Link)(({ theme }) => ({
|
|
80
|
+
display: "flex",
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
gap: "8px",
|
|
83
|
+
fontSize: "16px",
|
|
84
|
+
fontWeight: 400,
|
|
85
|
+
color: theme.palette.info.main,
|
|
86
|
+
textDecoration: "underline",
|
|
87
|
+
cursor: "pointer"
|
|
88
|
+
}));
|
|
89
|
+
const ActionLinks = styled(Box)(() => ({
|
|
90
|
+
display: "flex",
|
|
91
|
+
gap: "16px",
|
|
92
|
+
marginTop: "8px"
|
|
93
|
+
}));
|
|
94
|
+
const ActionLink = styled(Link)(({ theme }) => ({
|
|
95
|
+
fontSize: "16px",
|
|
96
|
+
fontWeight: 400,
|
|
97
|
+
color: theme.palette.info.main,
|
|
98
|
+
textDecoration: "none",
|
|
99
|
+
cursor: "pointer"
|
|
100
|
+
}));
|
|
101
|
+
const CustomHeader = styled(Box)(() => ({
|
|
102
|
+
display: "flex",
|
|
103
|
+
alignItems: "center",
|
|
104
|
+
justifyContent: "space-between",
|
|
105
|
+
marginBottom: "12px"
|
|
106
|
+
}));
|
|
107
|
+
const TitleContainer = styled(Box)(() => ({
|
|
108
|
+
display: "flex",
|
|
109
|
+
alignItems: "center",
|
|
110
|
+
gap: "8px",
|
|
111
|
+
paddingLeft: "16px",
|
|
112
|
+
paddingTop: "16px"
|
|
113
|
+
}));
|
|
114
|
+
const StyledTitle = styled(Typography)(({ theme }) => ({
|
|
115
|
+
fontWeight: 400,
|
|
116
|
+
fontSize: "16px",
|
|
117
|
+
lineHeight: "24px",
|
|
118
|
+
color: theme.palette.text.primary
|
|
119
|
+
}));
|
|
120
|
+
const LogoContainer = styled(Box)(({ theme }) => {
|
|
121
|
+
const logoColors = getLogoContainerColors(theme);
|
|
122
|
+
return {
|
|
123
|
+
display: "flex",
|
|
124
|
+
flexDirection: "row",
|
|
125
|
+
justifyContent: "center",
|
|
126
|
+
alignItems: "center",
|
|
127
|
+
padding: "12px 15px",
|
|
128
|
+
gap: "10px",
|
|
129
|
+
width: "109px",
|
|
130
|
+
height: "40px",
|
|
131
|
+
background: logoColors.background,
|
|
132
|
+
borderRadius: "10px",
|
|
133
|
+
"& svg": {
|
|
134
|
+
width: "79px",
|
|
135
|
+
height: "22px",
|
|
136
|
+
"& path": {
|
|
137
|
+
fill: logoColors.logoFill
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
const CustomHeaderData = ({ title }) => /* @__PURE__ */ jsxs(CustomHeader, { children: [
|
|
143
|
+
/* @__PURE__ */ jsx(TitleContainer, { children: /* @__PURE__ */ jsx(StyledTitle, { children: title }) }),
|
|
144
|
+
/* @__PURE__ */ jsx(LogoContainer, { children: /* @__PURE__ */ jsx(ApiiroLogo, {}) })
|
|
145
|
+
] });
|
|
146
|
+
const StatusTile = ({
|
|
147
|
+
title = "Status",
|
|
148
|
+
width = "100%",
|
|
149
|
+
height = "auto",
|
|
150
|
+
repository,
|
|
151
|
+
detailViewLink = null,
|
|
152
|
+
allowViewChart = true
|
|
153
|
+
}) => {
|
|
154
|
+
if (Object.keys(repository).length === 0) {
|
|
155
|
+
return /* @__PURE__ */ jsxs(StatusBox, { width, height, alignContent: "flex-start", children: [
|
|
156
|
+
/* @__PURE__ */ jsx(CustomHeaderData, { title: "" }),
|
|
157
|
+
/* @__PURE__ */ jsx(NotFound, { message: "Results for this repository are either unavailable on Apiiro or cannot be accessed." })
|
|
158
|
+
] });
|
|
159
|
+
}
|
|
160
|
+
const ProviderIconComponent = scmProviderIcons[repository.provider];
|
|
161
|
+
const apiiroRepoUrl = `${APIIRO_DEFAULT_BASE_URL}/profiles/repositories/${repository.key}`;
|
|
162
|
+
const settingsUrl = `${apiiroRepoUrl}/profile/${repository.scmRepositoryKey}/multi-branch`;
|
|
163
|
+
return /* @__PURE__ */ jsxs(StatusBox, { width, height, alignContent: "flex-start", children: [
|
|
164
|
+
/* @__PURE__ */ jsx(CustomHeaderData, { title }),
|
|
165
|
+
/* @__PURE__ */ jsxs(StatusContent, { children: [
|
|
166
|
+
repository?.lastActivity && repository?.activeSince && /* @__PURE__ */ jsx(
|
|
167
|
+
CustomTooltip,
|
|
168
|
+
{
|
|
169
|
+
title: formatActivityTooltip(
|
|
170
|
+
repository.lastActivity,
|
|
171
|
+
repository.activeSince
|
|
172
|
+
),
|
|
173
|
+
placement: "bottom",
|
|
174
|
+
children: /* @__PURE__ */ jsxs(StatusRow, { children: [
|
|
175
|
+
/* @__PURE__ */ jsx(StatusLabel, { children: "Activity:" }),
|
|
176
|
+
/* @__PURE__ */ jsx(StatusValue, { children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center" }, children: [
|
|
177
|
+
/* @__PURE__ */ jsx(StatusIndicator, { isActive: repository.isActive }),
|
|
178
|
+
repository.isActive ? `In development for ${getDevelopmentDuration(
|
|
179
|
+
repository.activeSince
|
|
180
|
+
)}` : "Inactive"
|
|
181
|
+
] }) })
|
|
182
|
+
] })
|
|
183
|
+
}
|
|
184
|
+
),
|
|
185
|
+
/* @__PURE__ */ jsx(
|
|
186
|
+
CustomTooltip,
|
|
187
|
+
{
|
|
188
|
+
title: "A weighted value based on the number of risks at each severity level.",
|
|
189
|
+
placement: "top",
|
|
190
|
+
children: /* @__PURE__ */ jsxs(StatusRow, { children: [
|
|
191
|
+
/* @__PURE__ */ jsx(StatusLabel, { children: "Risk score:" }),
|
|
192
|
+
/* @__PURE__ */ jsx(StatusValue, { children: formatNumberWithSuffix(repository.riskScore) })
|
|
193
|
+
] })
|
|
194
|
+
}
|
|
195
|
+
),
|
|
196
|
+
/* @__PURE__ */ jsxs(StatusRow, { children: [
|
|
197
|
+
ProviderIconComponent && /* @__PURE__ */ jsx(ThemedIcon, { children: /* @__PURE__ */ jsx(ProviderIconComponent, {}) }),
|
|
198
|
+
/* @__PURE__ */ jsx(
|
|
199
|
+
BranchLink,
|
|
200
|
+
{
|
|
201
|
+
to: generateRepoURL(repository) || "",
|
|
202
|
+
target: "_blank",
|
|
203
|
+
rel: "noopener noreferrer",
|
|
204
|
+
children: `Analyzing ${repository.branchName} branch`
|
|
205
|
+
}
|
|
206
|
+
),
|
|
207
|
+
/* @__PURE__ */ jsx(
|
|
208
|
+
Link,
|
|
209
|
+
{
|
|
210
|
+
to: settingsUrl,
|
|
211
|
+
target: "_blank",
|
|
212
|
+
rel: "noopener noreferrer",
|
|
213
|
+
style: { display: "inline-flex", marginLeft: "4px" },
|
|
214
|
+
children: /* @__PURE__ */ jsx(SettingIcon, {})
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
] }),
|
|
218
|
+
/* @__PURE__ */ jsxs(ActionLinks, { children: [
|
|
219
|
+
allowViewChart && /* @__PURE__ */ jsx(
|
|
220
|
+
ActionLink,
|
|
221
|
+
{
|
|
222
|
+
to: apiiroRepoUrl,
|
|
223
|
+
target: "_blank",
|
|
224
|
+
rel: "noopener noreferrer",
|
|
225
|
+
children: "Go to Apiiro \u2192"
|
|
226
|
+
}
|
|
227
|
+
),
|
|
228
|
+
detailViewLink && /* @__PURE__ */ jsx(ActionLink, { to: detailViewLink, children: "Detail View \u2192" })
|
|
229
|
+
] })
|
|
230
|
+
] })
|
|
231
|
+
] });
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
export { StatusBox, StatusTile, StatusTile as default };
|
|
235
|
+
//# sourceMappingURL=StatusTile.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusTile.esm.js","sources":["../../../src/components/tiles/StatusTile.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 } from '@mui/material/styles';\nimport {\n getActivityStatusColors,\n getLogoContainerColors,\n} from '../../theme/themeUtils';\nimport { Link } from 'react-router-dom';\nimport { ApiiroLogo } from '../../assets/apiiroLogo';\nimport { formatNumberWithSuffix } from '../../utils';\nimport {\n formatActivityTooltip,\n getDevelopmentDuration,\n} from '../../utils/dateFormatter';\nimport { RepositoryType } from '../../queries/queries.type';\nimport { CustomTooltip, NotFound } from '../common';\nimport { generateRepoURL, scmProviderIcons } from '../common/scmProviders';\nimport { APIIRO_DEFAULT_BASE_URL } from '@backstage-community/plugin-apiiro-common';\nimport SettingIcon from '../../assets/SettingIcon';\n\nconst ThemedIcon = styled('span')(({ theme }) => ({\n display: 'inline-flex',\n '& svg': {\n color: theme.palette.text.primary,\n flexShrink: 0,\n },\n '&:hover svg': {\n color: theme.palette.primary.main,\n },\n}));\n\nconst StatusIndicator = styled('span')<{ isActive: boolean }>(\n ({ theme, isActive }) => {\n const activityColors = getActivityStatusColors(theme);\n return {\n display: 'inline-block',\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: isActive\n ? activityColors.active\n : activityColors.inactive,\n marginRight: 8,\n };\n },\n);\n\nexport interface StatusTileProps {\n title?: string;\n width?: string | number;\n height?: string | number;\n repository: RepositoryType;\n detailViewLink?: string | null;\n allowViewChart?: boolean;\n}\n\nexport const StatusBox = styled(Box)<{\n width?: string | number;\n height?: string | number;\n}>(({ theme, width, height }) => ({\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: '12px',\n backgroundColor: theme.palette.background.paper,\n boxShadow: theme.shadows[1],\n width: width || 'fit-content',\n height: height || 'auto',\n margin: width === '100%' ? '0' : '0 auto',\n maxWidth: '100%',\n display: 'flex',\n flexDirection: 'column',\n boxSizing: 'border-box',\n}));\n\nconst StatusContent = styled(Box)(() => ({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: '12px',\n padding: '16px',\n}));\n\nconst StatusRow = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n}));\n\nconst StatusLabel = styled(Typography)(({ theme }) => ({\n fontSize: '16px',\n fontWeight: 400,\n color: theme.palette.text.secondary,\n}));\n\nconst StatusValue = styled(Typography)(({ theme }) => ({\n fontSize: '16px',\n fontWeight: 400,\n color: theme.palette.text.primary,\n}));\n\nconst BranchLink = styled(Link)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n fontSize: '16px',\n fontWeight: 400,\n color: theme.palette.info.main,\n textDecoration: 'underline',\n cursor: 'pointer',\n}));\n\nconst ActionLinks = styled(Box)(() => ({\n display: 'flex',\n gap: '16px',\n marginTop: '8px',\n}));\n\nconst ActionLink = styled(Link)(({ theme }) => ({\n fontSize: '16px',\n fontWeight: 400,\n color: theme.palette.info.main,\n textDecoration: 'none',\n cursor: 'pointer',\n}));\n\nconst CustomHeader = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '12px',\n}));\n\nconst TitleContainer = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n paddingLeft: '16px',\n paddingTop: '16px',\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 LogoContainer = styled(Box)(({ theme }) => {\n const logoColors = getLogoContainerColors(theme);\n return {\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '12px 15px',\n gap: '10px',\n width: '109px',\n height: '40px',\n background: logoColors.background,\n borderRadius: '10px',\n '& svg': {\n width: '79px',\n height: '22px',\n '& path': {\n fill: logoColors.logoFill,\n },\n },\n };\n});\n\nconst CustomHeaderData = ({ title }: { title: string }) => (\n <CustomHeader>\n <TitleContainer>\n <StyledTitle>{title}</StyledTitle>\n </TitleContainer>\n <LogoContainer>\n <ApiiroLogo />\n </LogoContainer>\n </CustomHeader>\n);\n\nexport const StatusTile = ({\n title = 'Status',\n width = '100%',\n height = 'auto',\n repository,\n detailViewLink = null,\n allowViewChart = true,\n}: StatusTileProps) => {\n // Show message when no data is available\n if (Object.keys(repository).length === 0) {\n return (\n <StatusBox width={width} height={height} alignContent=\"flex-start\">\n <CustomHeaderData title=\"\" />\n <NotFound message=\"Results for this repository are either unavailable on Apiiro or cannot be accessed.\" />\n </StatusBox>\n );\n }\n\n const ProviderIconComponent = scmProviderIcons[repository.provider as string];\n const apiiroRepoUrl = `${APIIRO_DEFAULT_BASE_URL}/profiles/repositories/${repository.key}`;\n const settingsUrl = `${apiiroRepoUrl}/profile/${repository.scmRepositoryKey}/multi-branch`;\n\n return (\n <StatusBox width={width} height={height} alignContent=\"flex-start\">\n <CustomHeaderData title={title} />\n <StatusContent>\n {repository?.lastActivity && repository?.activeSince && (\n <CustomTooltip\n title={formatActivityTooltip(\n repository.lastActivity,\n repository.activeSince,\n )}\n placement=\"bottom\"\n >\n <StatusRow>\n <StatusLabel>Activity:</StatusLabel>\n <StatusValue>\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <StatusIndicator isActive={repository.isActive} />\n {repository.isActive\n ? `In development for ${getDevelopmentDuration(\n repository.activeSince,\n )}`\n : 'Inactive'}\n </Box>\n </StatusValue>\n </StatusRow>\n </CustomTooltip>\n )}\n <CustomTooltip\n title=\"A weighted value based on the number of risks at each severity level.\"\n placement=\"top\"\n >\n <StatusRow>\n <StatusLabel>Risk score:</StatusLabel>\n <StatusValue>\n {formatNumberWithSuffix(repository.riskScore)}\n </StatusValue>\n </StatusRow>\n </CustomTooltip>\n <StatusRow>\n {ProviderIconComponent && (\n <ThemedIcon>\n <ProviderIconComponent />\n </ThemedIcon>\n )}\n <BranchLink\n to={generateRepoURL(repository) || ''}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {`Analyzing ${repository.branchName} branch`}\n </BranchLink>\n <Link\n to={settingsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ display: 'inline-flex', marginLeft: '4px' }}\n >\n <SettingIcon />\n </Link>\n </StatusRow>\n <ActionLinks>\n {allowViewChart && (\n <ActionLink\n to={apiiroRepoUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Go to Apiiro →\n </ActionLink>\n )}\n {detailViewLink && (\n <ActionLink to={detailViewLink}>Detail View →</ActionLink>\n )}\n </ActionLinks>\n </StatusContent>\n </StatusBox>\n );\n};\n\nexport default StatusTile;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,aAAa,MAAA,CAAO,MAAM,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EAChD,OAAA,EAAS,aAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,OAAA;AAAA,IAC1B,UAAA,EAAY;AAAA,GACd;AAAA,EACA,aAAA,EAAe;AAAA,IACb,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ;AAAA;AAEjC,CAAA,CAAE,CAAA;AAEF,MAAM,eAAA,GAAkB,OAAO,MAAM,CAAA;AAAA,EACnC,CAAC,EAAE,KAAA,EAAO,QAAA,EAAS,KAAM;AACvB,IAAA,MAAM,cAAA,GAAiB,wBAAwB,KAAK,CAAA;AACpD,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,cAAA;AAAA,MACT,KAAA,EAAO,CAAA;AAAA,MACP,MAAA,EAAQ,CAAA;AAAA,MACR,YAAA,EAAc,KAAA;AAAA,MACd,eAAA,EAAiB,QAAA,GACb,cAAA,CAAe,MAAA,GACf,cAAA,CAAe,QAAA;AAAA,MACnB,WAAA,EAAa;AAAA,KACf;AAAA,EACF;AACF,CAAA;AAWO,MAAM,SAAA,GAAY,OAAO,GAAG,CAAA,CAGhC,CAAC,EAAE,KAAA,EAAO,KAAA,EAAO,MAAA,EAAO,MAAO;AAAA,EAChC,MAAA,EAAQ,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,EAC1C,YAAA,EAAc,MAAA;AAAA,EACd,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAA;AAAA,EAC1C,SAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,EAC1B,OAAO,KAAA,IAAS,aAAA;AAAA,EAChB,QAAQ,MAAA,IAAU,MAAA;AAAA,EAClB,MAAA,EAAQ,KAAA,KAAU,MAAA,GAAS,GAAA,GAAM,QAAA;AAAA,EACjC,QAAA,EAAU,MAAA;AAAA,EACV,OAAA,EAAS,MAAA;AAAA,EACT,aAAA,EAAe,QAAA;AAAA,EACf,SAAA,EAAW;AACb,CAAA,CAAE;AAEF,MAAM,aAAA,GAAgB,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACvC,OAAA,EAAS,MAAA;AAAA,EACT,aAAA,EAAe,QAAA;AAAA,EACf,UAAA,EAAY,YAAA;AAAA,EACZ,GAAA,EAAK,MAAA;AAAA,EACL,OAAA,EAAS;AACX,CAAA,CAAE,CAAA;AAEF,MAAM,SAAA,GAAY,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACnC,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,GAAA,EAAK;AACP,CAAA,CAAE,CAAA;AAEF,MAAM,cAAc,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EACrD,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAC5B,CAAA,CAAE,CAAA;AAEF,MAAM,cAAc,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EACrD,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAC5B,CAAA,CAAE,CAAA;AAEF,MAAM,aAAa,MAAA,CAAO,IAAI,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EAC9C,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,GAAA,EAAK,KAAA;AAAA,EACL,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,IAAA;AAAA,EAC1B,cAAA,EAAgB,WAAA;AAAA,EAChB,MAAA,EAAQ;AACV,CAAA,CAAE,CAAA;AAEF,MAAM,WAAA,GAAc,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACrC,OAAA,EAAS,MAAA;AAAA,EACT,GAAA,EAAK,MAAA;AAAA,EACL,SAAA,EAAW;AACb,CAAA,CAAE,CAAA;AAEF,MAAM,aAAa,MAAA,CAAO,IAAI,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EAC9C,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,IAAA;AAAA,EAC1B,cAAA,EAAgB,MAAA;AAAA,EAChB,MAAA,EAAQ;AACV,CAAA,CAAE,CAAA;AAEF,MAAM,YAAA,GAAe,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACtC,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,cAAA,EAAgB,eAAA;AAAA,EAChB,YAAA,EAAc;AAChB,CAAA,CAAE,CAAA;AAEF,MAAM,cAAA,GAAiB,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACxC,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,GAAA,EAAK,KAAA;AAAA,EACL,WAAA,EAAa,MAAA;AAAA,EACb,UAAA,EAAY;AACd,CAAA,CAAE,CAAA;AAEF,MAAM,cAAc,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EACrD,UAAA,EAAY,GAAA;AAAA,EACZ,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,MAAA;AAAA,EACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAC5B,CAAA,CAAE,CAAA;AAEF,MAAM,gBAAgB,MAAA,CAAO,GAAG,EAAE,CAAC,EAAE,OAAM,KAAM;AAC/C,EAAA,MAAM,UAAA,GAAa,uBAAuB,KAAK,CAAA;AAC/C,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,MAAA;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,QAAA;AAAA,IAChB,UAAA,EAAY,QAAA;AAAA,IACZ,OAAA,EAAS,WAAA;AAAA,IACT,GAAA,EAAK,MAAA;AAAA,IACL,KAAA,EAAO,OAAA;AAAA,IACP,MAAA,EAAQ,MAAA;AAAA,IACR,YAAY,UAAA,CAAW,UAAA;AAAA,IACvB,YAAA,EAAc,MAAA;AAAA,IACd,OAAA,EAAS;AAAA,MACP,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ,MAAA;AAAA,MACR,QAAA,EAAU;AAAA,QACR,MAAM,UAAA,CAAW;AAAA;AACnB;AACF,GACF;AACF,CAAC,CAAA;AAED,MAAM,mBAAmB,CAAC,EAAE,KAAA,EAAM,0BAC/B,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,cAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAa,QAAA,EAAA,KAAA,EAAM,CAAA,EACtB,CAAA;AAAA,kBACA,GAAA,CAAC,aAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,CAAA,EACd;AAAA,CAAA,EACF,CAAA;AAGK,MAAM,aAAa,CAAC;AAAA,EACzB,KAAA,GAAQ,QAAA;AAAA,EACR,KAAA,GAAQ,MAAA;AAAA,EACR,MAAA,GAAS,MAAA;AAAA,EACT,UAAA;AAAA,EACA,cAAA,GAAiB,IAAA;AAAA,EACjB,cAAA,GAAiB;AACnB,CAAA,KAAuB;AAErB,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,WAAW,CAAA,EAAG;AACxC,IAAA,uBACE,IAAA,CAAC,SAAA,EAAA,EAAU,KAAA,EAAc,MAAA,EAAgB,cAAa,YAAA,EACpD,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,gBAAA,EAAA,EAAiB,OAAM,EAAA,EAAG,CAAA;AAAA,sBAC3B,GAAA,CAAC,QAAA,EAAA,EAAS,OAAA,EAAQ,qFAAA,EAAsF;AAAA,KAAA,EAC1G,CAAA;AAAA,EAEJ;AAEA,EAAA,MAAM,qBAAA,GAAwB,gBAAA,CAAiB,UAAA,CAAW,QAAkB,CAAA;AAC5E,EAAA,MAAM,aAAA,GAAgB,CAAA,EAAG,uBAAuB,CAAA,uBAAA,EAA0B,WAAW,GAAG,CAAA,CAAA;AACxF,EAAA,MAAM,WAAA,GAAc,CAAA,EAAG,aAAa,CAAA,SAAA,EAAY,WAAW,gBAAgB,CAAA,aAAA,CAAA;AAE3E,EAAA,uBACE,IAAA,CAAC,SAAA,EAAA,EAAU,KAAA,EAAc,MAAA,EAAgB,cAAa,YAAA,EACpD,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,oBAAiB,KAAA,EAAc,CAAA;AAAA,yBAC/B,aAAA,EAAA,EACE,QAAA,EAAA;AAAA,MAAA,UAAA,EAAY,YAAA,IAAgB,YAAY,WAAA,oBACvC,GAAA;AAAA,QAAC,aAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,qBAAA;AAAA,YACL,UAAA,CAAW,YAAA;AAAA,YACX,UAAA,CAAW;AAAA,WACb;AAAA,UACA,SAAA,EAAU,QAAA;AAAA,UAEV,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,eAAY,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,4BACtB,GAAA,CAAC,WAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,GAAA,EAAA,EAAI,EAAA,EAAI,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAS,EAC/C,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,eAAA,EAAA,EAAgB,QAAA,EAAU,UAAA,CAAW,QAAA,EAAU,CAAA;AAAA,cAC/C,UAAA,CAAW,WACR,CAAA,mBAAA,EAAsB,sBAAA;AAAA,gBACpB,UAAA,CAAW;AAAA,eACZ,CAAA,CAAA,GACD;AAAA,aAAA,EACN,CAAA,EACF;AAAA,WAAA,EACF;AAAA;AAAA,OACF;AAAA,sBAEF,GAAA;AAAA,QAAC,aAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,uEAAA;AAAA,UACN,SAAA,EAAU,KAAA;AAAA,UAEV,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,eAAY,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,4BACxB,GAAA,CAAC,WAAA,EAAA,EACE,QAAA,EAAA,sBAAA,CAAuB,UAAA,CAAW,SAAS,CAAA,EAC9C;AAAA,WAAA,EACF;AAAA;AAAA,OACF;AAAA,2BACC,SAAA,EAAA,EACE,QAAA,EAAA;AAAA,QAAA,qBAAA,oBACC,GAAA,CAAC,UAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,CAAA,EACzB,CAAA;AAAA,wBAEF,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI,eAAA,CAAgB,UAAU,CAAA,IAAK,EAAA;AAAA,YACnC,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YAEH,QAAA,EAAA,CAAA,UAAA,EAAa,WAAW,UAAU,CAAA,OAAA;AAAA;AAAA,SACrC;AAAA,wBACA,GAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI,WAAA;AAAA,YACJ,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YACJ,KAAA,EAAO,EAAE,OAAA,EAAS,aAAA,EAAe,YAAY,KAAA,EAAM;AAAA,YAEnD,8BAAC,WAAA,EAAA,EAAY;AAAA;AAAA;AACf,OAAA,EACF,CAAA;AAAA,2BACC,WAAA,EAAA,EACE,QAAA,EAAA;AAAA,QAAA,cAAA,oBACC,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI,aAAA;AAAA,YACJ,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YACL,QAAA,EAAA;AAAA;AAAA,SAED;AAAA,QAED,cAAA,oBACC,GAAA,CAAC,UAAA,EAAA,EAAW,EAAA,EAAI,gBAAgB,QAAA,EAAA,oBAAA,EAAa;AAAA,OAAA,EAEjD;AAAA,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { styled, useTheme } from '@mui/material/styles';
|
|
3
|
+
import { getBlueColorVariants, getOtherColor } from '../../theme/themeUtils.esm.js';
|
|
4
|
+
import Box from '@mui/material/Box';
|
|
5
|
+
import Typography from '@mui/material/Typography';
|
|
6
|
+
import List from '@mui/material/List';
|
|
7
|
+
import ListItem from '@mui/material/ListItem';
|
|
8
|
+
import { languageIconMap } from '../common/languageIcons.esm.js';
|
|
9
|
+
import { ChartBox } from '../common/ChartBox.esm.js';
|
|
10
|
+
import { CustomTooltip } from '../common/CustomTooltip.esm.js';
|
|
11
|
+
import { NotFound } from '../common/NotFound.esm.js';
|
|
12
|
+
import { useMemo, useState, useEffect, useCallback } from 'react';
|
|
13
|
+
import { PieChart } from '../charts/PieChart.esm.js';
|
|
14
|
+
import '@mui/material/SvgIcon';
|
|
15
|
+
import { ApiiroSmall } from '../../assets/apiiroLogo/apiiroSmall.esm.js';
|
|
16
|
+
import Divider from '@mui/material/Divider';
|
|
17
|
+
|
|
18
|
+
const LegendContainer = styled(Box)(() => ({
|
|
19
|
+
display: "flex",
|
|
20
|
+
flexWrap: "wrap",
|
|
21
|
+
justifyContent: "center",
|
|
22
|
+
gap: "6px"
|
|
23
|
+
}));
|
|
24
|
+
const LegendItem = styled(Box)(({ theme }) => ({
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
gap: "6px",
|
|
28
|
+
fontSize: "12px",
|
|
29
|
+
color: theme.palette.text.secondary
|
|
30
|
+
}));
|
|
31
|
+
const LegendColor = styled("div")(({ color }) => ({
|
|
32
|
+
width: "8px",
|
|
33
|
+
height: "8px",
|
|
34
|
+
borderRadius: "50%",
|
|
35
|
+
backgroundColor: color,
|
|
36
|
+
flexShrink: 0
|
|
37
|
+
}));
|
|
38
|
+
const CustomHeader = styled(Box)(() => ({
|
|
39
|
+
display: "flex",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
justifyContent: "space-between",
|
|
42
|
+
marginBottom: "12px"
|
|
43
|
+
}));
|
|
44
|
+
const TitleContainer = styled(Box)(() => ({
|
|
45
|
+
display: "flex",
|
|
46
|
+
alignItems: "center",
|
|
47
|
+
gap: "8px"
|
|
48
|
+
}));
|
|
49
|
+
const StyledTitle = styled(Typography)(({ theme }) => ({
|
|
50
|
+
fontWeight: 400,
|
|
51
|
+
fontSize: "16px",
|
|
52
|
+
lineHeight: "24px",
|
|
53
|
+
color: theme.palette.text.primary
|
|
54
|
+
}));
|
|
55
|
+
const mapLanguagePercentagesToPieData = (languagePercentages) => Object.entries(languagePercentages).map(([language, value], index) => {
|
|
56
|
+
const numericValue = typeof value === "number" && !isNaN(value) ? value : 0;
|
|
57
|
+
return {
|
|
58
|
+
id: `${language.toLowerCase().replace(/[^a-z0-9]+/g, "-")}-${index}`,
|
|
59
|
+
label: language,
|
|
60
|
+
value: numericValue
|
|
61
|
+
};
|
|
62
|
+
}).filter((item) => item.value > 0);
|
|
63
|
+
const TopLanguagesTile = ({
|
|
64
|
+
title = "Top languages",
|
|
65
|
+
data = {},
|
|
66
|
+
width = "100%"
|
|
67
|
+
}) => {
|
|
68
|
+
const theme = useTheme();
|
|
69
|
+
const blueColorVariants = getBlueColorVariants(theme);
|
|
70
|
+
const otherColor = getOtherColor(theme);
|
|
71
|
+
const chartData = useMemo(() => {
|
|
72
|
+
if (data && Object.keys(data).length > 0) {
|
|
73
|
+
const mappedData = mapLanguagePercentagesToPieData(data);
|
|
74
|
+
if (mappedData.length > 0) {
|
|
75
|
+
return mappedData;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
}, [data]);
|
|
80
|
+
const [processedData, setProcessedData] = useState(chartData);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
setProcessedData(chartData);
|
|
83
|
+
}, [chartData]);
|
|
84
|
+
const customHeader = /* @__PURE__ */ jsx(CustomHeader, { children: /* @__PURE__ */ jsxs(TitleContainer, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(StyledTitle, { children: title }),
|
|
86
|
+
/* @__PURE__ */ jsx(ApiiroSmall, { sx: { width: 20, height: 20, color: "text.primary" } })
|
|
87
|
+
] }) });
|
|
88
|
+
const generateColor = useCallback(
|
|
89
|
+
(index, itemId) => {
|
|
90
|
+
if (itemId === "other") {
|
|
91
|
+
return otherColor;
|
|
92
|
+
}
|
|
93
|
+
if (index < blueColorVariants.length) {
|
|
94
|
+
return blueColorVariants[index];
|
|
95
|
+
}
|
|
96
|
+
return otherColor;
|
|
97
|
+
},
|
|
98
|
+
[blueColorVariants, otherColor]
|
|
99
|
+
);
|
|
100
|
+
const legend = /* @__PURE__ */ jsxs(LegendContainer, { children: [
|
|
101
|
+
processedData.slice(0, 5).map((item, index) => /* @__PURE__ */ jsxs(LegendItem, { children: [
|
|
102
|
+
/* @__PURE__ */ jsx(LegendColor, { color: item.color || generateColor(index, item.id) }),
|
|
103
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", children: item.label })
|
|
104
|
+
] }, item.id)),
|
|
105
|
+
processedData.length > 5 && /* @__PURE__ */ jsx(
|
|
106
|
+
CustomTooltip,
|
|
107
|
+
{
|
|
108
|
+
title: /* @__PURE__ */ jsxs(List, { dense: true, disablePadding: true, children: [
|
|
109
|
+
processedData.slice(5).map((item) => {
|
|
110
|
+
const LanguageIcon = languageIconMap[item.label] || languageIconMap["Unknown"];
|
|
111
|
+
return /* @__PURE__ */ jsx(
|
|
112
|
+
ListItem,
|
|
113
|
+
{
|
|
114
|
+
disableGutters: true,
|
|
115
|
+
disablePadding: true,
|
|
116
|
+
sx: { py: 0.5, px: 1, minWidth: 200 },
|
|
117
|
+
children: /* @__PURE__ */ jsxs(
|
|
118
|
+
Box,
|
|
119
|
+
{
|
|
120
|
+
sx: {
|
|
121
|
+
display: "flex",
|
|
122
|
+
alignItems: "center",
|
|
123
|
+
width: "100%",
|
|
124
|
+
justifyContent: "space-between"
|
|
125
|
+
},
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsxs(
|
|
128
|
+
Box,
|
|
129
|
+
{
|
|
130
|
+
sx: { display: "flex", alignItems: "center", gap: 1 },
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ jsx(
|
|
133
|
+
Box,
|
|
134
|
+
{
|
|
135
|
+
sx: {
|
|
136
|
+
width: 24,
|
|
137
|
+
height: 24,
|
|
138
|
+
display: "flex",
|
|
139
|
+
alignItems: "center",
|
|
140
|
+
justifyContent: "center"
|
|
141
|
+
},
|
|
142
|
+
children: /* @__PURE__ */ jsx(LanguageIcon, {})
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
Typography,
|
|
147
|
+
{
|
|
148
|
+
variant: "body2",
|
|
149
|
+
sx: { fontSize: "12px", color: "text.primary" },
|
|
150
|
+
children: item.label
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
/* @__PURE__ */ jsxs(
|
|
157
|
+
Typography,
|
|
158
|
+
{
|
|
159
|
+
variant: "body2",
|
|
160
|
+
sx: {
|
|
161
|
+
fontSize: "12px",
|
|
162
|
+
color: "text.primary",
|
|
163
|
+
fontWeight: 400
|
|
164
|
+
},
|
|
165
|
+
children: [
|
|
166
|
+
Math.round(item.value),
|
|
167
|
+
"%"
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
},
|
|
175
|
+
item.id
|
|
176
|
+
);
|
|
177
|
+
}),
|
|
178
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
179
|
+
/* @__PURE__ */ jsx(
|
|
180
|
+
Typography,
|
|
181
|
+
{
|
|
182
|
+
variant: "body2",
|
|
183
|
+
sx: { py: 1, fontSize: "12px", color: "text.primary" },
|
|
184
|
+
children: "Less then 0.1%"
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
] }),
|
|
188
|
+
placement: "top",
|
|
189
|
+
children: /* @__PURE__ */ jsxs(LegendItem, { children: [
|
|
190
|
+
/* @__PURE__ */ jsx(LegendColor, { color: generateColor(-1, "other") }),
|
|
191
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", children: "Other" })
|
|
192
|
+
] })
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] });
|
|
196
|
+
if (Object.keys(data).length === 0 || processedData.length === 0) {
|
|
197
|
+
return /* @__PURE__ */ jsx(ChartBox, { title, width, customHeader, children: /* @__PURE__ */ jsx(NotFound, {}) });
|
|
198
|
+
}
|
|
199
|
+
return /* @__PURE__ */ jsx(
|
|
200
|
+
ChartBox,
|
|
201
|
+
{
|
|
202
|
+
title,
|
|
203
|
+
width,
|
|
204
|
+
footer: legend,
|
|
205
|
+
customHeader,
|
|
206
|
+
children: /* @__PURE__ */ jsx(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
style: {
|
|
210
|
+
display: "flex",
|
|
211
|
+
justifyContent: "center",
|
|
212
|
+
alignItems: "center",
|
|
213
|
+
width: "100%",
|
|
214
|
+
flex: 1,
|
|
215
|
+
minHeight: 0
|
|
216
|
+
},
|
|
217
|
+
children: /* @__PURE__ */ jsx(
|
|
218
|
+
PieChart,
|
|
219
|
+
{
|
|
220
|
+
data: chartData,
|
|
221
|
+
width: 310,
|
|
222
|
+
height: 310,
|
|
223
|
+
generateColor,
|
|
224
|
+
onDataProcessed: setProcessedData
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export { TopLanguagesTile, TopLanguagesTile as default };
|
|
234
|
+
//# sourceMappingURL=TopLanguagesTile.esm.js.map
|