diff --git a/Dockerfile b/Dockerfile index afed01c..9f04d9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:12-slim AS build +FROM debian:13.2-slim AS build ENV DEBIAN_FRONTEND=noninteractive # Install dependencies @@ -59,7 +59,7 @@ RUN yarn tsc COPY app-config.yaml ./ RUN yarn build:backend -FROM debian:12-slim AS run +FROM debian:13.2-slim AS run # Install dependencies RUN apt-get update && \ diff --git a/packages/app/.eslintrc.js b/packages/app/.eslintrc.js index 5073122..e4beedc 100644 --- a/packages/app/.eslintrc.js +++ b/packages/app/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { rules: { - 'no-unused-vars': ['error', { varsIgnorePattern: '^_' }], + 'no-unused-vars': ['error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }], }, }); diff --git a/packages/app/src/App.test.tsx b/packages/app/src/App.test.tsx index 87676ab..871ebfb 100644 --- a/packages/app/src/App.test.tsx +++ b/packages/app/src/App.test.tsx @@ -4,7 +4,7 @@ import App from './App'; describe('App', () => { // Skip this test as app.createRoot() in newer versions doesn't work with standard test utilities // The app structure is validated by other tests and by the build process - it.skip('should render', async () => { + it('should render', async () => { process.env = { NODE_ENV: 'test', APP_CONFIG: [ diff --git a/packages/app/src/components/explore/CategoryFilter.tsx b/packages/app/src/components/explore/CategoryFilter.tsx index 632216c..7c3691d 100644 --- a/packages/app/src/components/explore/CategoryFilter.tsx +++ b/packages/app/src/components/explore/CategoryFilter.tsx @@ -6,7 +6,7 @@ import { ToolCategory, categoryLabels, categoryColors } from './toolsConfig'; interface CategoryFilterProps { categories: ToolCategory[]; selectedCategory: ToolCategory | 'all'; - onCategoryChange: (category: ToolCategory | 'all') => void; + onCategoryChange: (_selection: ToolCategory | 'all') => void; categoryCounts?: Record; } diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx index 8d7433a..a77bc70 100644 --- a/packages/app/src/components/home/HomePage.tsx +++ b/packages/app/src/components/home/HomePage.tsx @@ -268,7 +268,7 @@ export const HomePage = () => { setTemplates(templateList); setLoadingTemplates(false); } catch (err) { - console.error('Failed to fetch catalog data:', err); + // Failed to fetch catalog data setStats(prev => ({ ...prev, loading: false })); setLoadingRecent(false); setLoadingTemplates(false); @@ -578,92 +578,102 @@ export const HomePage = () => { } /> - {loadingTemplates ? ( - - {[1, 2, 3, 4].map(i => ( - - + {(() => { + if (loadingTemplates) { + return ( + + {[1, 2, 3, 4].map(i => ( + + + + ))} - ))} - - ) : templates.length > 0 ? ( - - {templates.map(template => ( - - - navigate( - `/self-service/templates/default/${template.name}`, - ) - } - > - - - {template.title} - - 0) { + return ( + + {templates.map(template => ( + + + navigate( + `/self-service/templates/default/${template.name}`, + ) + } > - {template.description} - - - {template.tags.slice(0, 3).map(tag => ( - - ))} - - - + + + {template.title} + + + {template.description} + + + {template.tags.slice(0, 3).map(tag => ( + + ))} + + + + + ))} - ))} - - ) : ( - - - - No templates available yet.{' '} - navigate('/self-service')} - > - Create your first template - - - - )} + ); + } + + return ( + + + + No templates available yet.{' '} + navigate('/self-service')} + > + Create your first template + + + + ); + })()} @@ -684,62 +694,72 @@ export const HomePage = () => { } /> - {loadingRecent ? ( - - {[1, 2, 3, 4, 5].map(i => ( - - ))} - - ) : recentEntities.length > 0 ? ( - - {recentEntities.map((entity, index) => ( - - - - navigate( - `/catalog/${ - entity.namespace - }/${entity.kind.toLowerCase()}/${entity.name}`, - ) - } - > - - - {entity.kind.charAt(0)} - - - - - - - {index < recentEntities.length - 1 && } + {(() => { + if (loadingRecent) { + return ( + + {[1, 2, 3, 4, 5].map(i => ( + + ))} - ))} - - ) : ( - - - No entities in the catalog yet. - - - )} + ); + } + + if (recentEntities.length > 0) { + return ( + + {recentEntities.map((entity, index) => ( + + + + navigate( + `/catalog/${ + entity.namespace + }/${entity.kind.toLowerCase()}/${entity.name}`, + ) + } + > + + + {entity.kind.charAt(0)} + + + + + + + {index < recentEntities.length - 1 && } + + ))} + + ); + } + + return ( + + + No entities in the catalog yet. + + + ); + })()} @@ -783,12 +803,15 @@ export const HomePage = () => { borderRadius: 4, bgcolor: theme.palette.grey[200], '& .MuiLinearProgress-bar': { - bgcolor: - healthPercentage >= 80 - ? theme.palette.success.main - : healthPercentage >= 50 - ? theme.palette.warning.main - : theme.palette.error.main, + bgcolor: (() => { + if (healthPercentage >= 80) { + return theme.palette.success.main; + } + if (healthPercentage >= 50) { + return theme.palette.warning.main; + } + return theme.palette.error.main; + })(), }, }} /> diff --git a/packages/app/src/components/icons/Aws.tsx b/packages/app/src/components/icons/Aws.tsx index 8a4a621..930633c 100644 --- a/packages/app/src/components/icons/Aws.tsx +++ b/packages/app/src/components/icons/Aws.tsx @@ -1,11 +1,9 @@ -import * as React from 'react'; - interface IconProps { width: number; height: number; } -const icon: React.FC = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( = ({ width, height }) => { +const icon = ({ width, height }: IconProps) => { return ( { const theme = useTheme(); const isPositive = trend === 'up'; - const isNegative = trend === 'down'; return ( diff --git a/packages/app/src/components/pulse-check/PulseCheckPage.tsx b/packages/app/src/components/pulse-check/PulseCheckPage.tsx index de5e424..8418069 100644 --- a/packages/app/src/components/pulse-check/PulseCheckPage.tsx +++ b/packages/app/src/components/pulse-check/PulseCheckPage.tsx @@ -44,12 +44,15 @@ const generateMockHealth = (entity: Entity): SystemHealth => { status: randomStatus, uptime: uptimes[randomStatus], lastChecked: new Date(Date.now() - Math.random() * 3600000), - message: - randomStatus === 'degraded' - ? 'Elevated error rates detected' - : randomStatus === 'down' - ? 'Service unreachable' - : undefined, + message: (() => { + if (randomStatus === 'degraded') { + return 'Elevated error rates detected'; + } + if (randomStatus === 'down') { + return 'Service unreachable'; + } + return undefined; + })(), }; }; diff --git a/packages/app/src/components/scorecard/ScorecardPage.tsx b/packages/app/src/components/scorecard/ScorecardPage.tsx index 134b764..b800c4e 100644 --- a/packages/app/src/components/scorecard/ScorecardPage.tsx +++ b/packages/app/src/components/scorecard/ScorecardPage.tsx @@ -9,7 +9,7 @@ import InputLabel from '@mui/material/InputLabel'; import Select from '@mui/material/Select'; import MenuItem from '@mui/material/MenuItem'; import CircularProgress from '@mui/material/CircularProgress'; -import { styled, useTheme } from '@mui/material/styles'; +import { styled } from '@mui/material/styles'; import { Page, Header, Content } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; @@ -76,7 +76,6 @@ const calculateEntityScore = (entity: Entity): EntityScore => { }; export const ScorecardPage = () => { - const theme = useTheme(); const catalogApi = useApi(catalogApiRef); const [entities, setEntities] = useState([]); const [loading, setLoading] = useState(true);