@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.
Files changed (223) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +232 -0
  3. package/config.d.ts +30 -0
  4. package/dist/App.esm.js +12 -0
  5. package/dist/App.esm.js.map +1 -0
  6. package/dist/api/index.esm.js +71 -0
  7. package/dist/api/index.esm.js.map +1 -0
  8. package/dist/assets/BulleyeIcon.esm.js +454 -0
  9. package/dist/assets/BulleyeIcon.esm.js.map +1 -0
  10. package/dist/assets/NoResultIcon.esm.js +146 -0
  11. package/dist/assets/NoResultIcon.esm.js.map +1 -0
  12. package/dist/assets/RiskIcon.esm.js +27 -0
  13. package/dist/assets/RiskIcon.esm.js.map +1 -0
  14. package/dist/assets/SettingIcon.esm.js +49 -0
  15. package/dist/assets/SettingIcon.esm.js.map +1 -0
  16. package/dist/assets/apiiroLogo/apiiroLogo.esm.js +21 -0
  17. package/dist/assets/apiiroLogo/apiiroLogo.esm.js.map +1 -0
  18. package/dist/assets/apiiroLogo/apiiroSidebar.esm.js +23 -0
  19. package/dist/assets/apiiroLogo/apiiroSidebar.esm.js.map +1 -0
  20. package/dist/assets/apiiroLogo/apiiroSmall.esm.js +19 -0
  21. package/dist/assets/apiiroLogo/apiiroSmall.esm.js.map +1 -0
  22. package/dist/assets/languageIcons/C.esm.js +7 -0
  23. package/dist/assets/languageIcons/C.esm.js.map +1 -0
  24. package/dist/assets/languageIcons/Cicd.esm.js +7 -0
  25. package/dist/assets/languageIcons/Cicd.esm.js.map +1 -0
  26. package/dist/assets/languageIcons/Clojure.esm.js +7 -0
  27. package/dist/assets/languageIcons/Clojure.esm.js.map +1 -0
  28. package/dist/assets/languageIcons/Cpp.esm.js +7 -0
  29. package/dist/assets/languageIcons/Cpp.esm.js.map +1 -0
  30. package/dist/assets/languageIcons/Csharp.esm.js +7 -0
  31. package/dist/assets/languageIcons/Csharp.esm.js.map +1 -0
  32. package/dist/assets/languageIcons/Dart.esm.js +7 -0
  33. package/dist/assets/languageIcons/Dart.esm.js.map +1 -0
  34. package/dist/assets/languageIcons/Go.esm.js +7 -0
  35. package/dist/assets/languageIcons/Go.esm.js.map +1 -0
  36. package/dist/assets/languageIcons/Groovy.esm.js +7 -0
  37. package/dist/assets/languageIcons/Groovy.esm.js.map +1 -0
  38. package/dist/assets/languageIcons/HTML.esm.js +7 -0
  39. package/dist/assets/languageIcons/HTML.esm.js.map +1 -0
  40. package/dist/assets/languageIcons/HclLanguage.esm.js +7 -0
  41. package/dist/assets/languageIcons/HclLanguage.esm.js.map +1 -0
  42. package/dist/assets/languageIcons/Java.esm.js +7 -0
  43. package/dist/assets/languageIcons/Java.esm.js.map +1 -0
  44. package/dist/assets/languageIcons/Javascript.esm.js +7 -0
  45. package/dist/assets/languageIcons/Javascript.esm.js.map +1 -0
  46. package/dist/assets/languageIcons/Kotlin.esm.js +7 -0
  47. package/dist/assets/languageIcons/Kotlin.esm.js.map +1 -0
  48. package/dist/assets/languageIcons/ObjectiveC.esm.js +7 -0
  49. package/dist/assets/languageIcons/ObjectiveC.esm.js.map +1 -0
  50. package/dist/assets/languageIcons/PHP.esm.js +7 -0
  51. package/dist/assets/languageIcons/PHP.esm.js.map +1 -0
  52. package/dist/assets/languageIcons/Perl.esm.js +13 -0
  53. package/dist/assets/languageIcons/Perl.esm.js.map +1 -0
  54. package/dist/assets/languageIcons/Python.esm.js +7 -0
  55. package/dist/assets/languageIcons/Python.esm.js.map +1 -0
  56. package/dist/assets/languageIcons/Ruby.esm.js +7 -0
  57. package/dist/assets/languageIcons/Ruby.esm.js.map +1 -0
  58. package/dist/assets/languageIcons/Rust.esm.js +7 -0
  59. package/dist/assets/languageIcons/Rust.esm.js.map +1 -0
  60. package/dist/assets/languageIcons/Scala.esm.js +7 -0
  61. package/dist/assets/languageIcons/Scala.esm.js.map +1 -0
  62. package/dist/assets/languageIcons/Swift.esm.js +7 -0
  63. package/dist/assets/languageIcons/Swift.esm.js.map +1 -0
  64. package/dist/assets/languageIcons/Terraform.esm.js +7 -0
  65. package/dist/assets/languageIcons/Terraform.esm.js.map +1 -0
  66. package/dist/assets/languageIcons/Typescript.esm.js +7 -0
  67. package/dist/assets/languageIcons/Typescript.esm.js.map +1 -0
  68. package/dist/assets/languageIcons/Unknown.esm.js +7 -0
  69. package/dist/assets/languageIcons/Unknown.esm.js.map +1 -0
  70. package/dist/assets/languageIcons/VB.esm.js +10 -0
  71. package/dist/assets/languageIcons/VB.esm.js.map +1 -0
  72. package/dist/assets/languageIcons/YAML.esm.js +7 -0
  73. package/dist/assets/languageIcons/YAML.esm.js.map +1 -0
  74. package/dist/assets/providerIcons/Azure.esm.js +7 -0
  75. package/dist/assets/providerIcons/Azure.esm.js.map +1 -0
  76. package/dist/assets/providerIcons/Bitbucket.esm.js +7 -0
  77. package/dist/assets/providerIcons/Bitbucket.esm.js.map +1 -0
  78. package/dist/assets/providerIcons/Gitlab.esm.js +7 -0
  79. package/dist/assets/providerIcons/Gitlab.esm.js.map +1 -0
  80. package/dist/components/ApiiroSidebar.esm.js +10 -0
  81. package/dist/components/ApiiroSidebar.esm.js.map +1 -0
  82. package/dist/components/ApplicationsList/ApplicationsList.esm.js +196 -0
  83. package/dist/components/ApplicationsList/ApplicationsList.esm.js.map +1 -0
  84. package/dist/components/CalendarDatePicker.esm.js +154 -0
  85. package/dist/components/CalendarDatePicker.esm.js.map +1 -0
  86. package/dist/components/CalendarDatePicker.styles.esm.js +198 -0
  87. package/dist/components/CalendarDatePicker.styles.esm.js.map +1 -0
  88. package/dist/components/Chip.esm.js +60 -0
  89. package/dist/components/Chip.esm.js.map +1 -0
  90. package/dist/components/ChipsList.esm.js +207 -0
  91. package/dist/components/ChipsList.esm.js.map +1 -0
  92. package/dist/components/ComponentDisplay.esm.js +42 -0
  93. package/dist/components/ComponentDisplay.esm.js.map +1 -0
  94. package/dist/components/DataGrid/CustomColumnMenu.esm.js +29 -0
  95. package/dist/components/DataGrid/CustomColumnMenu.esm.js.map +1 -0
  96. package/dist/components/DataGrid/CustomPagination.esm.js +113 -0
  97. package/dist/components/DataGrid/CustomPagination.esm.js.map +1 -0
  98. package/dist/components/DataGrid/CustomSearchToolbar.esm.js +117 -0
  99. package/dist/components/DataGrid/CustomSearchToolbar.esm.js.map +1 -0
  100. package/dist/components/DataGrid/DataGrid.esm.js +336 -0
  101. package/dist/components/DataGrid/DataGrid.esm.js.map +1 -0
  102. package/dist/components/DataGrid/PinColumnMenuItem.esm.js +24 -0
  103. package/dist/components/DataGrid/PinColumnMenuItem.esm.js.map +1 -0
  104. package/dist/components/DueDate.esm.js +34 -0
  105. package/dist/components/DueDate.esm.js.map +1 -0
  106. package/dist/components/Header.esm.js +27 -0
  107. package/dist/components/Header.esm.js.map +1 -0
  108. package/dist/components/MainContributors/MainContributors.esm.js +62 -0
  109. package/dist/components/MainContributors/MainContributors.esm.js.map +1 -0
  110. package/dist/components/MetricsGroup/TabMetricsGroup.esm.js +37 -0
  111. package/dist/components/MetricsGroup/TabMetricsGroup.esm.js.map +1 -0
  112. package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js +36 -0
  113. package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js.map +1 -0
  114. package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js +121 -0
  115. package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js.map +1 -0
  116. package/dist/components/RiskLevel.esm.js +88 -0
  117. package/dist/components/RiskLevel.esm.js.map +1 -0
  118. package/dist/components/RiskStatus.esm.js +58 -0
  119. package/dist/components/RiskStatus.esm.js.map +1 -0
  120. package/dist/components/SimpleTooltip.esm.js +24 -0
  121. package/dist/components/SimpleTooltip.esm.js.map +1 -0
  122. package/dist/components/SourcesDisplay.esm.js +47 -0
  123. package/dist/components/SourcesDisplay.esm.js.map +1 -0
  124. package/dist/components/TagsList/TagsList.esm.js +38 -0
  125. package/dist/components/TagsList/TagsList.esm.js.map +1 -0
  126. package/dist/components/TeamsDisplay.esm.js +47 -0
  127. package/dist/components/TeamsDisplay.esm.js.map +1 -0
  128. package/dist/components/charts/ColumnChart.esm.js +402 -0
  129. package/dist/components/charts/ColumnChart.esm.js.map +1 -0
  130. package/dist/components/charts/GaugeChart.esm.js +249 -0
  131. package/dist/components/charts/GaugeChart.esm.js.map +1 -0
  132. package/dist/components/charts/LineChart.esm.js +328 -0
  133. package/dist/components/charts/LineChart.esm.js.map +1 -0
  134. package/dist/components/charts/PieChart.esm.js +233 -0
  135. package/dist/components/charts/PieChart.esm.js.map +1 -0
  136. package/dist/components/common/ChartBox.esm.js +88 -0
  137. package/dist/components/common/ChartBox.esm.js.map +1 -0
  138. package/dist/components/common/CustomTooltip.esm.js +255 -0
  139. package/dist/components/common/CustomTooltip.esm.js.map +1 -0
  140. package/dist/components/common/ErrorSnackbar.esm.js +39 -0
  141. package/dist/components/common/ErrorSnackbar.esm.js.map +1 -0
  142. package/dist/components/common/NotFound.esm.js +30 -0
  143. package/dist/components/common/NotFound.esm.js.map +1 -0
  144. package/dist/components/common/SomethingWentWrong.esm.js +35 -0
  145. package/dist/components/common/SomethingWentWrong.esm.js.map +1 -0
  146. package/dist/components/common/languageIcons.esm.js +61 -0
  147. package/dist/components/common/languageIcons.esm.js.map +1 -0
  148. package/dist/components/common/logoSpinner.esm.js +28 -0
  149. package/dist/components/common/logoSpinner.esm.js.map +1 -0
  150. package/dist/components/common/scmProviders.esm.js +41 -0
  151. package/dist/components/common/scmProviders.esm.js.map +1 -0
  152. package/dist/components/filters/DiscoveredOnFilter.esm.js +284 -0
  153. package/dist/components/filters/DiscoveredOnFilter.esm.js.map +1 -0
  154. package/dist/components/filters/FilterDropdown.esm.js +325 -0
  155. package/dist/components/filters/FilterDropdown.esm.js.map +1 -0
  156. package/dist/components/filters/FilterDropdownClear.esm.js +45 -0
  157. package/dist/components/filters/FilterDropdownClear.esm.js.map +1 -0
  158. package/dist/components/filters/FilterDropdownList.esm.js +102 -0
  159. package/dist/components/filters/FilterDropdownList.esm.js.map +1 -0
  160. package/dist/components/filters/FilterDropdownSearch.esm.js +65 -0
  161. package/dist/components/filters/FilterDropdownSearch.esm.js.map +1 -0
  162. package/dist/components/filters/RiskInsightFilter.esm.js +579 -0
  163. package/dist/components/filters/RiskInsightFilter.esm.js.map +1 -0
  164. package/dist/components/tiles/MttrVsSLATile.esm.js +170 -0
  165. package/dist/components/tiles/MttrVsSLATile.esm.js.map +1 -0
  166. package/dist/components/tiles/RiskOverTimeTile.esm.js +311 -0
  167. package/dist/components/tiles/RiskOverTimeTile.esm.js.map +1 -0
  168. package/dist/components/tiles/SLAAdherenceTile.esm.js +115 -0
  169. package/dist/components/tiles/SLAAdherenceTile.esm.js.map +1 -0
  170. package/dist/components/tiles/StatusTile.esm.js +235 -0
  171. package/dist/components/tiles/StatusTile.esm.js.map +1 -0
  172. package/dist/components/tiles/TopLanguagesTile.esm.js +234 -0
  173. package/dist/components/tiles/TopLanguagesTile.esm.js.map +1 -0
  174. package/dist/components/tiles/TopRiskTile.esm.js +208 -0
  175. package/dist/components/tiles/TopRiskTile.esm.js.map +1 -0
  176. package/dist/hooks/useUrlFilters.esm.js +102 -0
  177. package/dist/hooks/useUrlFilters.esm.js.map +1 -0
  178. package/dist/index.d.ts +28 -0
  179. package/dist/index.esm.js +42 -0
  180. package/dist/index.esm.js.map +1 -0
  181. package/dist/pages/Repositories/Repositories.esm.js +102 -0
  182. package/dist/pages/Repositories/Repositories.esm.js.map +1 -0
  183. package/dist/pages/Repositories/tableConfig.esm.js +294 -0
  184. package/dist/pages/Repositories/tableConfig.esm.js.map +1 -0
  185. package/dist/pages/Risks/Risks.esm.js +258 -0
  186. package/dist/pages/Risks/Risks.esm.js.map +1 -0
  187. package/dist/pages/Risks/tableConfig.esm.js +305 -0
  188. package/dist/pages/Risks/tableConfig.esm.js.map +1 -0
  189. package/dist/pages/tab/Tab.esm.js +147 -0
  190. package/dist/pages/tab/Tab.esm.js.map +1 -0
  191. package/dist/pages/tab/TabProvider.esm.js +11 -0
  192. package/dist/pages/tab/TabProvider.esm.js.map +1 -0
  193. package/dist/pages/widget/Widget.esm.js +161 -0
  194. package/dist/pages/widget/Widget.esm.js.map +1 -0
  195. package/dist/pages/widget/WidgetProvider.esm.js +12 -0
  196. package/dist/pages/widget/WidgetProvider.esm.js.map +1 -0
  197. package/dist/plugin.esm.js +30 -0
  198. package/dist/plugin.esm.js.map +1 -0
  199. package/dist/queries/filterOptions.queries.esm.js +46 -0
  200. package/dist/queries/filterOptions.queries.esm.js.map +1 -0
  201. package/dist/queries/mttr-statistics.queries.esm.js +61 -0
  202. package/dist/queries/mttr-statistics.queries.esm.js.map +1 -0
  203. package/dist/queries/repository.queries.esm.js +60 -0
  204. package/dist/queries/repository.queries.esm.js.map +1 -0
  205. package/dist/queries/risk-score-over-time.queries.esm.js +61 -0
  206. package/dist/queries/risk-score-over-time.queries.esm.js.map +1 -0
  207. package/dist/queries/risks.queries.esm.js +65 -0
  208. package/dist/queries/risks.queries.esm.js.map +1 -0
  209. package/dist/queries/sla-breach.queries.esm.js +57 -0
  210. package/dist/queries/sla-breach.queries.esm.js.map +1 -0
  211. package/dist/queries/top-risks.queries.esm.js +47 -0
  212. package/dist/queries/top-risks.queries.esm.js.map +1 -0
  213. package/dist/routes.esm.js +8 -0
  214. package/dist/routes.esm.js.map +1 -0
  215. package/dist/theme/themeUtils.esm.js +290 -0
  216. package/dist/theme/themeUtils.esm.js.map +1 -0
  217. package/dist/utils/dateFormatter.esm.js +67 -0
  218. package/dist/utils/dateFormatter.esm.js.map +1 -0
  219. package/dist/utils/numberFormatter.esm.js +21 -0
  220. package/dist/utils/numberFormatter.esm.js.map +1 -0
  221. package/dist/utils/utils.esm.js +27 -0
  222. package/dist/utils/utils.esm.js.map +1 -0
  223. package/package.json +90 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopLanguagesTile.esm.js","sources":["../../../src/components/tiles/TopLanguagesTile.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 { styled, useTheme } from '@mui/material/styles';\nimport { getBlueColorVariants, getOtherColor } from '../../theme/themeUtils';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport List from '@mui/material/List';\nimport ListItem from '@mui/material/ListItem';\nimport { languageIconMap, LanguageKey } from '../common/languageIcons';\nimport { CustomTooltip } from '../common';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { ChartBox } from '../common/ChartBox';\nimport PieChart, { PieChartData } from '../charts/PieChart';\nimport { ApiiroSmall } from '../../assets/apiiroLogo';\nimport { NotFound } from '../common';\nimport Divider from '@mui/material/Divider';\n\nexport interface TopLanguagesTileProps {\n title?: string;\n tooltip?: string;\n data?: Record<string, number> | undefined;\n width?: string | number;\n height?: string | number;\n}\n\nconst LegendContainer = styled(Box)(() => ({\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'center',\n gap: '6px',\n}));\n\nconst LegendItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n fontSize: '12px',\n color: theme.palette.text.secondary,\n}));\n\nconst LegendColor = styled('div')<{ color: string }>(({ color }) => ({\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: color,\n flexShrink: 0,\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}));\n\nconst StyledTitle = styled(Typography)(({ theme }) => ({\n fontWeight: 400,\n fontSize: '16px',\n lineHeight: '24px',\n color: theme.palette.text.primary,\n}));\n\nconst mapLanguagePercentagesToPieData = (\n languagePercentages: Record<string, number>,\n): PieChartData[] =>\n Object.entries(languagePercentages)\n .map(([language, value], index) => {\n // Ensure value is a valid number, default to 0 if not\n const numericValue =\n typeof value === 'number' && !isNaN(value) ? value : 0;\n return {\n id: `${language.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${index}`,\n label: language,\n value: numericValue,\n };\n })\n .filter(item => item.value > 0);\n\nexport const TopLanguagesTile = ({\n title = 'Top languages',\n data = {},\n width = '100%',\n}: TopLanguagesTileProps) => {\n const theme = useTheme();\n const blueColorVariants = getBlueColorVariants(theme);\n const otherColor = getOtherColor(theme);\n\n const chartData = useMemo(() => {\n if (data && Object.keys(data).length > 0) {\n const mappedData = mapLanguagePercentagesToPieData(data);\n if (mappedData.length > 0) {\n return mappedData;\n }\n }\n\n return [];\n }, [data]);\n\n const [processedData, setProcessedData] = useState<PieChartData[]>(chartData);\n\n useEffect(() => {\n setProcessedData(chartData);\n }, [chartData]);\n\n const customHeader = (\n <CustomHeader>\n <TitleContainer>\n <StyledTitle>{title}</StyledTitle>\n <ApiiroSmall sx={{ width: 20, height: 20, color: 'text.primary' }} />\n </TitleContainer>\n </CustomHeader>\n );\n // Generate colors for legend items based on data length\n const generateColor = useCallback(\n (index: number, itemId: string): string => {\n // If item id is \"other\", always use the other color\n if (itemId === 'other') {\n return otherColor;\n }\n\n // If index is within blue variants, use blue colors\n if (index < blueColorVariants.length) {\n return blueColorVariants[index];\n }\n\n // For additional items beyond blue variants, use the other color\n return otherColor;\n },\n [blueColorVariants, otherColor],\n );\n\n const legend = (\n <LegendContainer>\n {processedData.slice(0, 5).map((item, index) => (\n <LegendItem key={item.id}>\n <LegendColor color={item.color || generateColor(index, item.id)} />\n <Typography variant=\"caption\">{item.label}</Typography>\n </LegendItem>\n ))}\n {processedData.length > 5 && (\n <CustomTooltip\n title={\n <List dense disablePadding>\n {processedData.slice(5).map(item => {\n const LanguageIcon =\n languageIconMap[item.label as LanguageKey] ||\n languageIconMap['Unknown' as LanguageKey];\n\n return (\n <ListItem\n key={item.id}\n disableGutters\n disablePadding\n sx={{ py: 0.5, px: 1, minWidth: 200 }}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n justifyContent: 'space-between',\n }}\n >\n <Box\n sx={{ display: 'flex', alignItems: 'center', gap: 1 }}\n >\n <Box\n sx={{\n width: 24,\n height: 24,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <LanguageIcon />\n </Box>\n <Typography\n variant=\"body2\"\n sx={{ fontSize: '12px', color: 'text.primary' }}\n >\n {item.label}\n </Typography>\n </Box>\n <Typography\n variant=\"body2\"\n sx={{\n fontSize: '12px',\n color: 'text.primary',\n fontWeight: 400,\n }}\n >\n {Math.round(item.value)}%\n </Typography>\n </Box>\n </ListItem>\n );\n })}\n <Divider />\n <Typography\n variant=\"body2\"\n sx={{ py: 1, fontSize: '12px', color: 'text.primary' }}\n >\n Less then 0.1%\n </Typography>\n </List>\n }\n placement=\"top\"\n >\n <LegendItem>\n <LegendColor color={generateColor(-1, 'other')} />\n <Typography variant=\"caption\">Other</Typography>\n </LegendItem>\n </CustomTooltip>\n )}\n </LegendContainer>\n );\n\n // Show message when no data is available\n if (Object.keys(data).length === 0 || processedData.length === 0) {\n return (\n <ChartBox title={title} width={width} customHeader={customHeader}>\n <NotFound />\n </ChartBox>\n );\n }\n\n return (\n <ChartBox\n title={title}\n width={width}\n footer={legend}\n customHeader={customHeader}\n >\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n width: '100%',\n flex: 1,\n minHeight: 0,\n }}\n >\n <PieChart\n data={chartData}\n width={310}\n height={310}\n generateColor={generateColor}\n onDataProcessed={setProcessedData}\n />\n </div>\n </ChartBox>\n );\n};\n\nexport default TopLanguagesTile;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAsCA,MAAM,eAAA,GAAkB,MAAA,CAAO,GAAG,CAAA,CAAE,OAAO;AAAA,EACzC,OAAA,EAAS,MAAA;AAAA,EACT,QAAA,EAAU,MAAA;AAAA,EACV,cAAA,EAAgB,QAAA;AAAA,EAChB,GAAA,EAAK;AACP,CAAA,CAAE,CAAA;AAEF,MAAM,aAAa,MAAA,CAAO,GAAG,EAAE,CAAC,EAAE,OAAM,MAAO;AAAA,EAC7C,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,GAAA,EAAK,KAAA;AAAA,EACL,QAAA,EAAU,MAAA;AAAA,EACV,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAC5B,CAAA,CAAE,CAAA;AAEF,MAAM,cAAc,MAAA,CAAO,KAAK,EAAqB,CAAC,EAAE,OAAM,MAAO;AAAA,EACnE,KAAA,EAAO,KAAA;AAAA,EACP,MAAA,EAAQ,KAAA;AAAA,EACR,YAAA,EAAc,KAAA;AAAA,EACd,eAAA,EAAiB,KAAA;AAAA,EACjB,UAAA,EAAY;AACd,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;AACP,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,+BAAA,GAAkC,CACtC,mBAAA,KAEA,MAAA,CAAO,OAAA,CAAQ,mBAAmB,CAAA,CAC/B,GAAA,CAAI,CAAC,CAAC,QAAA,EAAU,KAAK,GAAG,KAAA,KAAU;AAEjC,EAAA,MAAM,YAAA,GACJ,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,KAAK,IAAI,KAAA,GAAQ,CAAA;AACvD,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,CAAA,EAAG,QAAA,CAAS,WAAA,EAAY,CAAE,QAAQ,aAAA,EAAe,GAAG,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,IAClE,KAAA,EAAO,QAAA;AAAA,IACP,KAAA,EAAO;AAAA,GACT;AACF,CAAC,CAAA,CACA,MAAA,CAAO,CAAA,IAAA,KAAQ,IAAA,CAAK,QAAQ,CAAC,CAAA;AAE3B,MAAM,mBAAmB,CAAC;AAAA,EAC/B,KAAA,GAAQ,eAAA;AAAA,EACR,OAAO,EAAC;AAAA,EACR,KAAA,GAAQ;AACV,CAAA,KAA6B;AAC3B,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,iBAAA,GAAoB,qBAAqB,KAAK,CAAA;AACpD,EAAA,MAAM,UAAA,GAAa,cAAc,KAAK,CAAA;AAEtC,EAAA,MAAM,SAAA,GAAY,QAAQ,MAAM;AAC9B,IAAA,IAAI,QAAQ,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,CAAA,EAAG;AACxC,MAAA,MAAM,UAAA,GAAa,gCAAgC,IAAI,CAAA;AACvD,MAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF;AAEA,IAAA,OAAO,EAAC;AAAA,EACV,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAyB,SAAS,CAAA;AAE5E,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,gBAAA,CAAiB,SAAS,CAAA;AAAA,EAC5B,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,YAAA,mBACJ,GAAA,CAAC,YAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,cAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,eAAa,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,oBACpB,GAAA,CAAC,WAAA,EAAA,EAAY,EAAA,EAAI,EAAE,KAAA,EAAO,IAAI,MAAA,EAAQ,EAAA,EAAI,KAAA,EAAO,cAAA,EAAe,EAAG;AAAA,GAAA,EACrE,CAAA,EACF,CAAA;AAGF,EAAA,MAAM,aAAA,GAAgB,WAAA;AAAA,IACpB,CAAC,OAAe,MAAA,KAA2B;AAEzC,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,OAAO,UAAA;AAAA,MACT;AAGA,MAAA,IAAI,KAAA,GAAQ,kBAAkB,MAAA,EAAQ;AACpC,QAAA,OAAO,kBAAkB,KAAK,CAAA;AAAA,MAChC;AAGA,MAAA,OAAO,UAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,mBAAmB,UAAU;AAAA,GAChC;AAEA,EAAA,MAAM,MAAA,wBACH,eAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,aAAA,CAAc,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,IAAI,CAAC,IAAA,EAAM,KAAA,qBACpC,IAAA,CAAC,UAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,OAAO,IAAA,CAAK,KAAA,IAAS,cAAc,KAAA,EAAO,IAAA,CAAK,EAAE,CAAA,EAAG,CAAA;AAAA,sBACjE,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,SAAA,EAAW,eAAK,KAAA,EAAM;AAAA,KAAA,EAAA,EAF3B,IAAA,CAAK,EAGtB,CACD,CAAA;AAAA,IACA,aAAA,CAAc,SAAS,CAAA,oBACtB,GAAA;AAAA,MAAC,aAAA;AAAA,MAAA;AAAA,QACC,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAK,IAAA,EAAC,gBAAc,IAAA,EACvB,QAAA,EAAA;AAAA,UAAA,aAAA,CAAc,KAAA,CAAM,CAAC,CAAA,CAAE,GAAA,CAAI,CAAA,IAAA,KAAQ;AAClC,YAAA,MAAM,eACJ,eAAA,CAAgB,IAAA,CAAK,KAAoB,CAAA,IACzC,gBAAgB,SAAwB,CAAA;AAE1C,YAAA,uBACE,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBAEC,cAAA,EAAc,IAAA;AAAA,gBACd,cAAA,EAAc,IAAA;AAAA,gBACd,IAAI,EAAE,EAAA,EAAI,KAAK,EAAA,EAAI,CAAA,EAAG,UAAU,GAAA,EAAI;AAAA,gBAEpC,QAAA,kBAAA,IAAA;AAAA,kBAAC,GAAA;AAAA,kBAAA;AAAA,oBACC,EAAA,EAAI;AAAA,sBACF,OAAA,EAAS,MAAA;AAAA,sBACT,UAAA,EAAY,QAAA;AAAA,sBACZ,KAAA,EAAO,MAAA;AAAA,sBACP,cAAA,EAAgB;AAAA,qBAClB;AAAA,oBAEA,QAAA,EAAA;AAAA,sCAAA,IAAA;AAAA,wBAAC,GAAA;AAAA,wBAAA;AAAA,0BACC,IAAI,EAAE,OAAA,EAAS,QAAQ,UAAA,EAAY,QAAA,EAAU,KAAK,CAAA,EAAE;AAAA,0BAEpD,QAAA,EAAA;AAAA,4CAAA,GAAA;AAAA,8BAAC,GAAA;AAAA,8BAAA;AAAA,gCACC,EAAA,EAAI;AAAA,kCACF,KAAA,EAAO,EAAA;AAAA,kCACP,MAAA,EAAQ,EAAA;AAAA,kCACR,OAAA,EAAS,MAAA;AAAA,kCACT,UAAA,EAAY,QAAA;AAAA,kCACZ,cAAA,EAAgB;AAAA,iCAClB;AAAA,gCAEA,8BAAC,YAAA,EAAA,EAAa;AAAA;AAAA,6BAChB;AAAA,4CACA,GAAA;AAAA,8BAAC,UAAA;AAAA,8BAAA;AAAA,gCACC,OAAA,EAAQ,OAAA;AAAA,gCACR,EAAA,EAAI,EAAE,QAAA,EAAU,MAAA,EAAQ,OAAO,cAAA,EAAe;AAAA,gCAE7C,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA;AACR;AAAA;AAAA,uBACF;AAAA,sCACA,IAAA;AAAA,wBAAC,UAAA;AAAA,wBAAA;AAAA,0BACC,OAAA,EAAQ,OAAA;AAAA,0BACR,EAAA,EAAI;AAAA,4BACF,QAAA,EAAU,MAAA;AAAA,4BACV,KAAA,EAAO,cAAA;AAAA,4BACP,UAAA,EAAY;AAAA,2BACd;AAAA,0BAEC,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAK,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,4BAAE;AAAA;AAAA;AAAA;AAC1B;AAAA;AAAA;AACF,eAAA;AAAA,cA5CK,IAAA,CAAK;AAAA,aA6CZ;AAAA,UAEJ,CAAC,CAAA;AAAA,8BACA,OAAA,EAAA,EAAQ,CAAA;AAAA,0BACT,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,OAAA;AAAA,cACR,IAAI,EAAE,EAAA,EAAI,GAAG,QAAA,EAAU,MAAA,EAAQ,OAAO,cAAA,EAAe;AAAA,cACtD,QAAA,EAAA;AAAA;AAAA;AAED,SAAA,EACF,CAAA;AAAA,QAEF,SAAA,EAAU,KAAA;AAAA,QAEV,+BAAC,UAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,KAAA,EAAO,aAAA,CAAc,EAAA,EAAI,OAAO,CAAA,EAAG,CAAA;AAAA,0BAChD,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,SAAA,EAAU,QAAA,EAAA,OAAA,EAAK;AAAA,SAAA,EACrC;AAAA;AAAA;AACF,GAAA,EAEJ,CAAA;AAIF,EAAA,IAAI,MAAA,CAAO,KAAK,IAAI,CAAA,CAAE,WAAW,CAAA,IAAK,aAAA,CAAc,WAAW,CAAA,EAAG;AAChE,IAAA,2BACG,QAAA,EAAA,EAAS,KAAA,EAAc,OAAc,YAAA,EACpC,QAAA,kBAAA,GAAA,CAAC,YAAS,CAAA,EACZ,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA,EAAQ,MAAA;AAAA,MACR,YAAA;AAAA,MAEA,QAAA,kBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO;AAAA,YACL,OAAA,EAAS,MAAA;AAAA,YACT,cAAA,EAAgB,QAAA;AAAA,YAChB,UAAA,EAAY,QAAA;AAAA,YACZ,KAAA,EAAO,MAAA;AAAA,YACP,IAAA,EAAM,CAAA;AAAA,YACN,SAAA,EAAW;AAAA,WACb;AAAA,UAEA,QAAA,kBAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAM,SAAA;AAAA,cACN,KAAA,EAAO,GAAA;AAAA,cACP,MAAA,EAAQ,GAAA;AAAA,cACR,aAAA;AAAA,cACA,eAAA,EAAiB;AAAA;AAAA;AACnB;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,208 @@
1
+ import { jsx, jsxs } 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 { useApi, fetchApiRef } from '@backstage/core-plugin-api';
6
+ import { ChartBox } from '../common/ChartBox.esm.js';
7
+ import { useTopRisksData } from '../../queries/top-risks.queries.esm.js';
8
+ import { apiiroApiRef } from '../../api/index.esm.js';
9
+ import { CustomTooltip } from '../common/CustomTooltip.esm.js';
10
+ import { NotFound } from '../common/NotFound.esm.js';
11
+ import { SomethingWentWrong } from '../common/SomethingWentWrong.esm.js';
12
+ import { LogoSpinner } from '../common/logoSpinner.esm.js';
13
+ import { RiskLevel } from '../RiskLevel.esm.js';
14
+ import '@mui/material/SvgIcon';
15
+ import { ApiiroSmall } from '../../assets/apiiroLogo/apiiroSmall.esm.js';
16
+
17
+ const RiskListContainer = styled(Box)(() => ({
18
+ display: "flex",
19
+ flexDirection: "column",
20
+ gap: "8px",
21
+ width: "100%",
22
+ padding: "0 8px"
23
+ }));
24
+ const RiskItem = styled(Box)(({ theme }) => ({
25
+ display: "flex",
26
+ alignItems: "center",
27
+ justifyContent: "space-between",
28
+ padding: "12px 16px",
29
+ borderRadius: "14px",
30
+ border: `1px solid ${theme.palette.divider}`,
31
+ minHeight: "48px",
32
+ gap: "12px",
33
+ cursor: "pointer",
34
+ transition: "box-shadow 200ms ease-in-out",
35
+ "&:hover": {
36
+ boxShadow: "0 4px 8px rgba(0, 0, 0, 0.15)"
37
+ }
38
+ }));
39
+ const RiskContent = styled(Box)(() => ({
40
+ display: "flex",
41
+ alignItems: "center",
42
+ gap: "12px",
43
+ flex: 1,
44
+ minWidth: 0,
45
+ // Allow text truncation
46
+ overflow: "hidden"
47
+ // Ensure container doesn't overflow
48
+ }));
49
+ const TooltipWrapper = styled(Box)(() => ({
50
+ flex: 1,
51
+ minWidth: 0,
52
+ overflow: "hidden",
53
+ display: "flex"
54
+ }));
55
+ const RiskName = styled(Typography)(({ theme }) => ({
56
+ fontSize: "14px",
57
+ fontWeight: 400,
58
+ color: theme.palette.text.primary,
59
+ overflow: "hidden",
60
+ textOverflow: "ellipsis",
61
+ whiteSpace: "nowrap",
62
+ flex: 1,
63
+ minWidth: 0
64
+ }));
65
+ const RiskCount = styled(Typography)(({ theme }) => ({
66
+ fontSize: "16px",
67
+ fontWeight: 500,
68
+ color: theme.palette.text.primary,
69
+ minWidth: "fit-content"
70
+ }));
71
+ const CustomHeader = styled(Box)(() => ({
72
+ display: "flex",
73
+ alignItems: "center",
74
+ justifyContent: "space-between",
75
+ marginBottom: "12px"
76
+ }));
77
+ const TitleContainer = styled(Box)(() => ({
78
+ display: "flex",
79
+ alignItems: "center",
80
+ gap: "8px"
81
+ }));
82
+ const StyledTitle = styled(Typography)(({ theme }) => ({
83
+ fontWeight: 400,
84
+ fontSize: "16px",
85
+ lineHeight: "24px",
86
+ color: theme.palette.text.primary
87
+ }));
88
+ const TopRiskTile = ({
89
+ title = "Top risks",
90
+ data = [],
91
+ width = "100%",
92
+ height = "366px",
93
+ repoId,
94
+ entityRef
95
+ }) => {
96
+ const customHeader = /* @__PURE__ */ jsx(CustomHeader, { children: /* @__PURE__ */ jsxs(TitleContainer, { children: [
97
+ /* @__PURE__ */ jsx(StyledTitle, { children: title }),
98
+ /* @__PURE__ */ jsx(ApiiroSmall, { sx: { width: 20, height: 20, color: "text.primary" } })
99
+ ] }) });
100
+ const connectBackendApi = useApi(apiiroApiRef);
101
+ const { fetch } = useApi(fetchApiRef);
102
+ const { topRisksData, topRisksDataError, topRisksDataLoading } = useTopRisksData({
103
+ connectApi: connectBackendApi,
104
+ fetchApi: fetch,
105
+ repoId,
106
+ entityRef
107
+ });
108
+ const finalData = topRisksData ? topRisksData.map((point) => ({
109
+ ruleName: point.ruleName,
110
+ count: point.count,
111
+ severity: point.severity,
112
+ devPhase: point.devPhase
113
+ })) : data;
114
+ if (topRisksDataLoading) {
115
+ return /* @__PURE__ */ jsx(
116
+ ChartBox,
117
+ {
118
+ title,
119
+ width,
120
+ height,
121
+ customHeader,
122
+ children: /* @__PURE__ */ jsx(
123
+ Box,
124
+ {
125
+ display: "flex",
126
+ justifyContent: "center",
127
+ alignItems: "center",
128
+ minHeight: "250px",
129
+ children: /* @__PURE__ */ jsx(LogoSpinner, {})
130
+ }
131
+ )
132
+ }
133
+ );
134
+ }
135
+ if (topRisksDataError) {
136
+ return /* @__PURE__ */ jsx(
137
+ ChartBox,
138
+ {
139
+ title,
140
+ width,
141
+ height,
142
+ customHeader,
143
+ children: /* @__PURE__ */ jsx(
144
+ Box,
145
+ {
146
+ display: "flex",
147
+ justifyContent: "center",
148
+ alignItems: "center",
149
+ minHeight: "300px",
150
+ children: /* @__PURE__ */ jsx(SomethingWentWrong, {})
151
+ }
152
+ )
153
+ }
154
+ );
155
+ }
156
+ if (!repoId) {
157
+ return /* @__PURE__ */ jsx(
158
+ ChartBox,
159
+ {
160
+ title,
161
+ width,
162
+ height,
163
+ customHeader,
164
+ children: /* @__PURE__ */ jsx(
165
+ Box,
166
+ {
167
+ display: "flex",
168
+ justifyContent: "center",
169
+ alignItems: "center",
170
+ minHeight: "300px",
171
+ children: /* @__PURE__ */ jsx(NotFound, { message: "Please provide the repository details to access the data." })
172
+ }
173
+ )
174
+ }
175
+ );
176
+ }
177
+ if (finalData.length === 0) {
178
+ return /* @__PURE__ */ jsx(
179
+ ChartBox,
180
+ {
181
+ title,
182
+ width,
183
+ height,
184
+ customHeader,
185
+ children: /* @__PURE__ */ jsx(NotFound, {})
186
+ }
187
+ );
188
+ }
189
+ return /* @__PURE__ */ jsx(
190
+ ChartBox,
191
+ {
192
+ title,
193
+ width,
194
+ height,
195
+ customHeader,
196
+ children: /* @__PURE__ */ jsx(RiskListContainer, { children: finalData.map((risk, index) => /* @__PURE__ */ jsxs(RiskItem, { children: [
197
+ /* @__PURE__ */ jsxs(RiskContent, { children: [
198
+ /* @__PURE__ */ jsx(RiskLevel, { level: risk.severity, iconSize: "large" }),
199
+ /* @__PURE__ */ jsx(TooltipWrapper, { children: /* @__PURE__ */ jsx(CustomTooltip, { title: risk.ruleName, children: /* @__PURE__ */ jsx(RiskName, { children: risk.ruleName }) }) })
200
+ ] }),
201
+ /* @__PURE__ */ jsx(RiskCount, { children: risk.count })
202
+ ] }, `${risk.ruleName}-${index}`)) })
203
+ }
204
+ );
205
+ };
206
+
207
+ export { TopRiskTile, TopRiskTile as default };
208
+ //# sourceMappingURL=TopRiskTile.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopRiskTile.esm.js","sources":["../../../src/components/tiles/TopRiskTile.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 { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { ChartBox } from '../common/ChartBox';\nimport { useTopRisksData } from '../../queries/top-risks.queries';\nimport { apiiroApiRef } from '../../api';\nimport { TopRiskDataPoint } from '../../queries/queries.type';\nimport { CustomTooltip, NotFound, SomethingWentWrong } from '../common';\nimport { LogoSpinner } from '../common/logoSpinner';\nimport { RiskLevel } from '../RiskLevel';\nimport { ApiiroSmall } from '../../assets/apiiroLogo';\n\nexport interface TopRiskData {\n ruleName: string;\n count: number;\n severity: string;\n devPhase: string;\n}\n\nexport interface TopRiskTileProps {\n title?: string;\n tooltip?: string;\n data?: TopRiskData[];\n width?: string | number;\n height?: string | number;\n repoId?: string;\n entityRef?: string;\n}\n\nconst RiskListContainer = styled(Box)(() => ({\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n width: '100%',\n padding: '0 8px',\n}));\n\nconst RiskItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 16px',\n borderRadius: '14px',\n border: `1px solid ${theme.palette.divider}`,\n minHeight: '48px',\n gap: '12px',\n cursor: 'pointer',\n transition: 'box-shadow 200ms ease-in-out',\n\n '&:hover': {\n boxShadow: '0 4px 8px rgba(0, 0, 0, 0.15)',\n },\n}));\n\nconst RiskContent = styled(Box)(() => ({\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n flex: 1,\n minWidth: 0, // Allow text truncation\n overflow: 'hidden', // Ensure container doesn't overflow\n}));\n\nconst TooltipWrapper = styled(Box)(() => ({\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n display: 'flex',\n}));\n\nconst RiskName = styled(Typography)(({ theme }) => ({\n fontSize: '14px',\n fontWeight: 400,\n color: theme.palette.text.primary,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n flex: 1,\n minWidth: 0,\n}));\n\nconst RiskCount = styled(Typography)(({ theme }) => ({\n fontSize: '16px',\n fontWeight: 500,\n color: theme.palette.text.primary,\n minWidth: 'fit-content',\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}));\n\nconst StyledTitle = styled(Typography)(({ theme }) => ({\n fontWeight: 400,\n fontSize: '16px',\n lineHeight: '24px',\n color: theme.palette.text.primary,\n}));\n\nexport const TopRiskTile = ({\n title = 'Top risks',\n data = [],\n width = '100%',\n height = '366px',\n repoId,\n entityRef,\n}: TopRiskTileProps) => {\n const customHeader = (\n <CustomHeader>\n <TitleContainer>\n <StyledTitle>{title}</StyledTitle>\n <ApiiroSmall sx={{ width: 20, height: 20, color: 'text.primary' }} />\n </TitleContainer>\n </CustomHeader>\n );\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 { topRisksData, topRisksDataError, topRisksDataLoading } =\n useTopRisksData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n repoId,\n entityRef,\n });\n\n // Transform API data to component data format\n const finalData: TopRiskData[] = topRisksData\n ? topRisksData.map((point: TopRiskDataPoint) => ({\n ruleName: point.ruleName,\n count: point.count,\n severity: point.severity,\n devPhase: point.devPhase,\n }))\n : data;\n\n // Show loading state while data is loading\n if (topRisksDataLoading) {\n return (\n <ChartBox\n title={title}\n width={width}\n height={height}\n customHeader={customHeader}\n >\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\n if (topRisksDataError) {\n return (\n <ChartBox\n title={title}\n width={width}\n height={height}\n customHeader={customHeader}\n >\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"300px\"\n >\n <SomethingWentWrong />\n </Box>\n </ChartBox>\n );\n }\n\n // Show message when no repository key is provided\n if (!repoId) {\n return (\n <ChartBox\n title={title}\n width={width}\n height={height}\n customHeader={customHeader}\n >\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 // Show message when no data is available\n if (finalData.length === 0) {\n return (\n <ChartBox\n title={title}\n width={width}\n height={height}\n customHeader={customHeader}\n >\n <NotFound />\n </ChartBox>\n );\n }\n\n return (\n <ChartBox\n title={title}\n width={width}\n height={height}\n customHeader={customHeader}\n >\n <RiskListContainer>\n {finalData.map((risk, index) => (\n <RiskItem key={`${risk.ruleName}-${index}`}>\n <RiskContent>\n <RiskLevel level={risk.severity} iconSize=\"large\" />\n <TooltipWrapper>\n <CustomTooltip title={risk.ruleName}>\n <RiskName>{risk.ruleName}</RiskName>\n </CustomTooltip>\n </TooltipWrapper>\n </RiskContent>\n <RiskCount>{risk.count}</RiskCount>\n </RiskItem>\n ))}\n </RiskListContainer>\n </ChartBox>\n );\n};\n\nexport default TopRiskTile;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import { useState, useCallback } from 'react';
2
+
3
+ const useUrlFilters = () => {
4
+ const getInitialFilters = () => {
5
+ if (typeof window === "undefined") {
6
+ return {
7
+ riskCategory: [],
8
+ riskLevel: [],
9
+ findingCategory: [],
10
+ riskInsight: [],
11
+ discoveredOnRange: [],
12
+ selectedPreset: ""
13
+ };
14
+ }
15
+ const urlParams = new URLSearchParams(window.location.search);
16
+ const parseArrayParam = (param) => {
17
+ const value = urlParams.get(param);
18
+ return value ? value.split(",").filter(Boolean) : [];
19
+ };
20
+ const parseDateRange = () => {
21
+ const startDate = urlParams.get("discoveredStart");
22
+ const endDate = urlParams.get("discoveredEnd");
23
+ if (startDate && endDate) {
24
+ try {
25
+ const parseLocalDate = (dateStr) => {
26
+ const [year, month, day] = dateStr.split("-").map(Number);
27
+ return new Date(year, month - 1, day);
28
+ };
29
+ return [parseLocalDate(startDate), parseLocalDate(endDate)];
30
+ } catch {
31
+ return [];
32
+ }
33
+ }
34
+ return [];
35
+ };
36
+ return {
37
+ riskCategory: parseArrayParam("riskCategory"),
38
+ riskLevel: parseArrayParam("riskLevel"),
39
+ findingCategory: parseArrayParam("findingCategory"),
40
+ riskInsight: parseArrayParam("riskInsight"),
41
+ discoveredOnRange: parseDateRange(),
42
+ selectedPreset: urlParams.get("preset") || ""
43
+ };
44
+ };
45
+ const [filters, setFilters] = useState(getInitialFilters);
46
+ const updateURL = useCallback((newFilters) => {
47
+ if (typeof window === "undefined") return;
48
+ setFilters((prevFilters) => {
49
+ const updatedFilters = { ...prevFilters, ...newFilters };
50
+ const url = new URL(window.location.href);
51
+ const setArrayParam = (key, values) => {
52
+ if (values.length > 0) {
53
+ url.searchParams.set(key, values.join(","));
54
+ } else {
55
+ url.searchParams.delete(key);
56
+ }
57
+ };
58
+ setArrayParam("riskCategory", updatedFilters.riskCategory);
59
+ setArrayParam("riskLevel", updatedFilters.riskLevel);
60
+ setArrayParam("findingCategory", updatedFilters.findingCategory);
61
+ setArrayParam("riskInsight", updatedFilters.riskInsight);
62
+ if (Array.isArray(updatedFilters.discoveredOnRange) && updatedFilters.discoveredOnRange[0] instanceof Date && updatedFilters.discoveredOnRange[1] instanceof Date) {
63
+ const formatLocalDate = (date) => {
64
+ const year = date.getFullYear();
65
+ const month = String(date.getMonth() + 1).padStart(2, "0");
66
+ const day = String(date.getDate()).padStart(2, "0");
67
+ return `${year}-${month}-${day}`;
68
+ };
69
+ url.searchParams.set(
70
+ "discoveredStart",
71
+ formatLocalDate(updatedFilters.discoveredOnRange[0])
72
+ );
73
+ url.searchParams.set(
74
+ "discoveredEnd",
75
+ formatLocalDate(updatedFilters.discoveredOnRange[1])
76
+ );
77
+ } else {
78
+ url.searchParams.delete("discoveredStart");
79
+ url.searchParams.delete("discoveredEnd");
80
+ }
81
+ if (updatedFilters.selectedPreset) {
82
+ url.searchParams.set("preset", updatedFilters.selectedPreset);
83
+ } else {
84
+ url.searchParams.delete("preset");
85
+ }
86
+ window.history.replaceState({}, "", url.toString());
87
+ return updatedFilters;
88
+ });
89
+ }, []);
90
+ return {
91
+ filters,
92
+ setRiskCategoryFilter: (value) => updateURL({ riskCategory: value }),
93
+ setRiskLevelFilter: (value) => updateURL({ riskLevel: value }),
94
+ setFindingCategoryFilter: (value) => updateURL({ findingCategory: value }),
95
+ setRiskInsightFilter: (value) => updateURL({ riskInsight: value }),
96
+ setDiscoveredOnRange: (value) => updateURL({ discoveredOnRange: value }),
97
+ setSelectedPreset: (value) => updateURL({ selectedPreset: value })
98
+ };
99
+ };
100
+
101
+ export { useUrlFilters };
102
+ //# sourceMappingURL=useUrlFilters.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUrlFilters.esm.js","sources":["../../src/hooks/useUrlFilters.ts"],"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 { useState, useCallback } from 'react';\nimport { CalendarDateValue } from '../components';\n\nexport interface UrlFilters {\n riskCategory: string[];\n riskLevel: string[];\n findingCategory: string[];\n riskInsight: string[];\n discoveredOnRange: CalendarDateValue;\n selectedPreset: string;\n}\n\nexport const useUrlFilters = () => {\n // Get initial values from URL parameters\n const getInitialFilters = (): UrlFilters => {\n if (typeof window === 'undefined') {\n return {\n riskCategory: [],\n riskLevel: [],\n findingCategory: [],\n riskInsight: [],\n discoveredOnRange: [],\n selectedPreset: '',\n };\n }\n\n const urlParams = new URLSearchParams(window.location.search);\n\n // Parse array parameters\n const parseArrayParam = (param: string): string[] => {\n const value = urlParams.get(param);\n return value ? value.split(',').filter(Boolean) : [];\n };\n\n // Parse date range\n const parseDateRange = (): CalendarDateValue => {\n const startDate = urlParams.get('discoveredStart');\n const endDate = urlParams.get('discoveredEnd');\n\n if (startDate && endDate) {\n try {\n // Parse dates in local timezone to avoid timezone conversion issues\n const parseLocalDate = (dateStr: string) => {\n const [year, month, day] = dateStr.split('-').map(Number);\n return new Date(year, month - 1, day);\n };\n\n return [parseLocalDate(startDate), parseLocalDate(endDate)];\n } catch {\n return [];\n }\n }\n return [];\n };\n\n return {\n riskCategory: parseArrayParam('riskCategory'),\n riskLevel: parseArrayParam('riskLevel'),\n findingCategory: parseArrayParam('findingCategory'),\n riskInsight: parseArrayParam('riskInsight'),\n discoveredOnRange: parseDateRange(),\n selectedPreset: urlParams.get('preset') || '',\n };\n };\n\n const [filters, setFilters] = useState<UrlFilters>(getInitialFilters);\n\n // Update URL parameters\n const updateURL = useCallback((newFilters: Partial<UrlFilters>) => {\n if (typeof window === 'undefined') return;\n\n setFilters(prevFilters => {\n const updatedFilters = { ...prevFilters, ...newFilters };\n const url = new URL(window.location.href);\n\n // Helper to set or delete array parameters\n const setArrayParam = (key: string, values: string[]) => {\n if (values.length > 0) {\n url.searchParams.set(key, values.join(','));\n } else {\n url.searchParams.delete(key);\n }\n };\n\n // Update URL parameters\n setArrayParam('riskCategory', updatedFilters.riskCategory);\n setArrayParam('riskLevel', updatedFilters.riskLevel);\n setArrayParam('findingCategory', updatedFilters.findingCategory);\n setArrayParam('riskInsight', updatedFilters.riskInsight);\n\n // Handle date range\n if (\n Array.isArray(updatedFilters.discoveredOnRange) &&\n updatedFilters.discoveredOnRange[0] instanceof Date &&\n updatedFilters.discoveredOnRange[1] instanceof Date\n ) {\n // Format dates in local timezone to avoid timezone conversion issues\n const formatLocalDate = (date: Date) => {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n return `${year}-${month}-${day}`;\n };\n\n url.searchParams.set(\n 'discoveredStart',\n formatLocalDate(updatedFilters.discoveredOnRange[0]),\n );\n url.searchParams.set(\n 'discoveredEnd',\n formatLocalDate(updatedFilters.discoveredOnRange[1]),\n );\n } else {\n url.searchParams.delete('discoveredStart');\n url.searchParams.delete('discoveredEnd');\n }\n\n // Handle preset\n if (updatedFilters.selectedPreset) {\n url.searchParams.set('preset', updatedFilters.selectedPreset);\n } else {\n url.searchParams.delete('preset');\n }\n\n window.history.replaceState({}, '', url.toString());\n return updatedFilters;\n });\n }, []);\n\n return {\n filters,\n setRiskCategoryFilter: (value: string[]) =>\n updateURL({ riskCategory: value }),\n setRiskLevelFilter: (value: string[]) => updateURL({ riskLevel: value }),\n setFindingCategoryFilter: (value: string[]) =>\n updateURL({ findingCategory: value }),\n setRiskInsightFilter: (value: string[]) =>\n updateURL({ riskInsight: value }),\n setDiscoveredOnRange: (value: CalendarDateValue) =>\n updateURL({ discoveredOnRange: value }),\n setSelectedPreset: (value: string) => updateURL({ selectedPreset: value }),\n };\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /// <reference types="react" />
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+ import { Entity } from '@backstage/catalog-model';
5
+
6
+ /** @public */
7
+ declare const apiiroPlugin: _backstage_core_plugin_api.BackstagePlugin<{
8
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
9
+ }, {}, {}>;
10
+ /** @public */
11
+ declare const ApiiroPage: () => react_jsx_runtime.JSX.Element;
12
+
13
+ /** @public */
14
+ declare const ApiiroSidebar: () => JSX.Element;
15
+
16
+ /** @public */
17
+ declare const ApiiroTab: () => react_jsx_runtime.JSX.Element;
18
+
19
+ /** @public */
20
+ declare const ApiiroWidget: () => react_jsx_runtime.JSX.Element;
21
+
22
+ /**
23
+ * @public
24
+ * Checks if the entity has the APIIRO project annotation.
25
+ */
26
+ declare const isApiiroRepoAvailable: (entity: Entity) => boolean;
27
+
28
+ export { ApiiroPage, ApiiroSidebar, ApiiroTab, ApiiroWidget, apiiroPlugin, isApiiroRepoAvailable };
@@ -0,0 +1,42 @@
1
+ export { ApiiroPage, apiiroPlugin } from './plugin.esm.js';
2
+ export { ApiiroSidebar } from './components/ApiiroSidebar.esm.js';
3
+ import 'react/jsx-runtime';
4
+ import 'react';
5
+ import '@mui/x-data-grid';
6
+ import '@mui/material/Box';
7
+ import '@mui/material/styles';
8
+ import '@mui/material/MenuItem';
9
+ import '@mui/material/ListItemIcon';
10
+ import '@mui/material/ListItemText';
11
+ import '@mui/icons-material';
12
+ import '@mui/material/Typography';
13
+ import '@mui/material/Select';
14
+ import '@mui/material/Pagination';
15
+ import '@mui/material/TextField';
16
+ import '@mui/material/InputAdornment';
17
+ import '@mui/icons-material/Search';
18
+ import '@mui/icons-material/Clear';
19
+ import '@mui/material/IconButton';
20
+ import './components/common/ChartBox.esm.js';
21
+ import 'react-dom';
22
+ import './components/common/logoSpinner.esm.js';
23
+ import '@backstage/core-components';
24
+ import '@mui/material/SvgIcon';
25
+ import '@mui/material/Chip';
26
+ import '@mui/material/Link';
27
+ import '@mui/icons-material/VisibilityOff';
28
+ import '@mui/material/Avatar';
29
+ export { isApiiroRepoAvailable } from './utils/utils.esm.js';
30
+ import './components/filters/FilterDropdown.esm.js';
31
+ import './components/filters/RiskInsightFilter.esm.js';
32
+ import './components/CalendarDatePicker.esm.js';
33
+ import '@mui/material/ButtonBase';
34
+ import '@mui/material/Popper';
35
+ import '@mui/material/ClickAwayListener';
36
+ import '@mui/material/Tooltip';
37
+ import '@mui/material/Skeleton';
38
+ import '@mui/icons-material/KeyboardArrowDown';
39
+ import '@mui/icons-material/Close';
40
+ export { ApiiroTab } from './pages/tab/TabProvider.esm.js';
41
+ export { ApiiroWidget } from './pages/widget/WidgetProvider.esm.js';
42
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,102 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { Page, Content } from '@backstage/core-components';
4
+ import { useApi, fetchApiRef } from '@backstage/core-plugin-api';
5
+ import Typography from '@mui/material/Typography';
6
+ import Box from '@mui/material/Box';
7
+ import { apiiroApiRef } from '../../api/index.esm.js';
8
+ import { DataGrid } from '../../components/DataGrid/DataGrid.esm.js';
9
+ import '@mui/material/Select';
10
+ import '@mui/material/MenuItem';
11
+ import '@mui/material/Pagination';
12
+ import '@mui/material/styles';
13
+ import '@mui/x-data-grid';
14
+ import '@mui/material/ListItemIcon';
15
+ import '@mui/material/ListItemText';
16
+ import '@mui/icons-material';
17
+ import '@mui/material/TextField';
18
+ import '@mui/material/InputAdornment';
19
+ import '@mui/icons-material/Search';
20
+ import '@mui/icons-material/Clear';
21
+ import '@mui/material/IconButton';
22
+ import { Header } from '../../components/Header.esm.js';
23
+ import { useRepositoriesData } from '../../queries/repository.queries.esm.js';
24
+ import '@tanstack/react-query';
25
+ import { columnVisibilityModal, repositoryColumns } from './tableConfig.esm.js';
26
+ import '../../components/common/ChartBox.esm.js';
27
+ import 'react-dom';
28
+ import { SomethingWentWrong } from '../../components/common/SomethingWentWrong.esm.js';
29
+
30
+ const SomethingWentWrongBox = ({ statusCode }) => {
31
+ return /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(
32
+ Box,
33
+ {
34
+ display: "flex",
35
+ justifyContent: "center",
36
+ alignItems: "center",
37
+ flexDirection: "column",
38
+ minHeight: "300px",
39
+ children: /* @__PURE__ */ jsx(SomethingWentWrong, { statusCode })
40
+ }
41
+ ) });
42
+ };
43
+ const INITIAL_SORTING = [
44
+ {
45
+ field: "riskScore",
46
+ sort: "desc"
47
+ }
48
+ ];
49
+ const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];
50
+ const DATA_GRID_FEATURES = {
51
+ quickSearch: true,
52
+ columnPinning: true,
53
+ columnReordering: true,
54
+ customPagination: true,
55
+ columnMenu: true,
56
+ persistLayout: true
57
+ };
58
+ const Repositories = () => {
59
+ const connectBackendApi = useApi(apiiroApiRef);
60
+ const { fetch } = useApi(fetchApiRef);
61
+ const { repositoriesData, repositoriesDataLoading, repositoriesDataError } = useRepositoriesData({
62
+ connectApi: connectBackendApi,
63
+ fetchApi: fetch
64
+ });
65
+ const rows = useMemo(
66
+ () => repositoriesData?.repositories || [],
67
+ [repositoriesData?.repositories]
68
+ );
69
+ const showDataGrid = !repositoriesDataError;
70
+ const errorStatusCode = repositoriesDataError?.details?.status;
71
+ return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
72
+ /* @__PURE__ */ jsx(Header, {}),
73
+ /* @__PURE__ */ jsxs(Content, { children: [
74
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", sx: { color: "text.primary", mb: 2 }, children: "Repositories" }),
75
+ repositoriesDataError && /* @__PURE__ */ jsx(SomethingWentWrongBox, { statusCode: errorStatusCode }),
76
+ showDataGrid && /* @__PURE__ */ jsx(
77
+ DataGrid,
78
+ {
79
+ getRowId: (row) => `${row.key}-${row.entityUrl}`,
80
+ loading: repositoriesDataLoading,
81
+ tableKey: "repositories",
82
+ columns: repositoryColumns,
83
+ rows,
84
+ dataLabel: "repositories",
85
+ searchBarPlaceHolder: "Search repository name...",
86
+ features: DATA_GRID_FEATURES,
87
+ initialState: {
88
+ sorting: {
89
+ sortModel: INITIAL_SORTING
90
+ }
91
+ },
92
+ initialPageSize: PAGE_SIZE_OPTIONS[0],
93
+ pageSizeOptions: PAGE_SIZE_OPTIONS,
94
+ columnVisibility: columnVisibilityModal
95
+ }
96
+ )
97
+ ] })
98
+ ] });
99
+ };
100
+
101
+ export { Repositories };
102
+ //# sourceMappingURL=Repositories.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Repositories.esm.js","sources":["../../../src/pages/Repositories/Repositories.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 { useMemo } from 'react';\nimport { Content, Page } from '@backstage/core-components';\nimport { fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport Typography from '@mui/material/Typography';\nimport Box from '@mui/material/Box';\nimport { apiiroApiRef } from '../../api';\nimport { DataGrid } from '../../components/DataGrid';\nimport { Header } from '../../components/Header';\nimport { RepositoryType, useRepositoriesData } from '../../queries';\nimport { columnVisibilityModal, repositoryColumns } from './tableConfig';\nimport { SomethingWentWrong } from '../../components/common';\n\ninterface SomethingWentWrongBoxProps {\n statusCode?: number;\n}\n\nconst SomethingWentWrongBox = ({ statusCode }: SomethingWentWrongBoxProps) => {\n return (\n <Content>\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n flexDirection=\"column\"\n minHeight=\"300px\"\n >\n <SomethingWentWrong statusCode={statusCode} />\n </Box>\n </Content>\n );\n};\n\nconst INITIAL_SORTING = [\n {\n field: 'riskScore',\n sort: 'desc' as const,\n },\n];\n\nconst PAGE_SIZE_OPTIONS = [10, 20, 50, 100];\n\nconst DATA_GRID_FEATURES = {\n quickSearch: true,\n columnPinning: true,\n columnReordering: true,\n customPagination: true,\n columnMenu: true,\n persistLayout: true,\n} as const;\n\nexport const Repositories = () => {\n const connectBackendApi = useApi(apiiroApiRef);\n const { fetch } = useApi(fetchApiRef);\n\n const { repositoriesData, repositoriesDataLoading, repositoriesDataError } =\n useRepositoriesData({\n connectApi: connectBackendApi,\n fetchApi: fetch,\n });\n\n const rows = useMemo(\n () => repositoriesData?.repositories || [],\n [repositoriesData?.repositories],\n );\n\n const showDataGrid = !repositoriesDataError;\n const errorStatusCode = repositoriesDataError?.details?.status;\n\n return (\n <Page themeId=\"tool\">\n <Header />\n <Content>\n <Typography variant=\"h4\" sx={{ color: 'text.primary', mb: 2 }}>\n Repositories\n </Typography>\n\n {repositoriesDataError && (\n <SomethingWentWrongBox statusCode={errorStatusCode} />\n )}\n\n {showDataGrid && (\n <DataGrid<RepositoryType>\n getRowId={row => `${row.key}-${row.entityUrl}`}\n loading={repositoriesDataLoading}\n tableKey=\"repositories\"\n columns={repositoryColumns}\n rows={rows}\n dataLabel=\"repositories\"\n searchBarPlaceHolder=\"Search repository name...\"\n features={DATA_GRID_FEATURES}\n initialState={{\n sorting: {\n sortModel: INITIAL_SORTING,\n },\n }}\n initialPageSize={PAGE_SIZE_OPTIONS[0]}\n pageSizeOptions={PAGE_SIZE_OPTIONS}\n columnVisibility={columnVisibilityModal}\n />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}