@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 @@
|
|
|
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":"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"}
|
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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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"}
|