Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/src/components/public-content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function PublicContent({
aria-label={
headingMode === 'article' ? 'Article content' : 'Project documentation'
}
className="prose max-w-none min-w-0 wrap-anywhere prose-neutral dark:prose-invert prose-a:decoration-transparent prose-a:transition-all prose-a:duration-300 prose-a:ease-in-out prose-a:hover:decoration-current prose-a:motion-reduce:transition-none"
className="prose max-w-none min-w-0 wrap-anywhere prose-neutral dark:prose-invert prose-a:decoration-transparent prose-a:transition-[text-decoration-color] prose-a:duration-300 prose-a:ease-in-out prose-a:hover:decoration-current prose-a:motion-reduce:transition-none"
>
<Markdown
remarkPlugins={
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from '@tanstack/react-router'
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { lazy, Suspense } from 'react'

import type { ORPCRouterOutputs } from '@altstack/api/routers'

Expand All @@ -11,11 +11,6 @@ import {
CardHeader,
CardTitle,
} from '@altstack/ui/components/card'
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from '@altstack/ui/components/chart'

import { AdminEmpty } from '#/features/admin-dashboard/components/dashboard-state'

Expand All @@ -29,16 +24,89 @@ const labels = {
}
const number = new Intl.NumberFormat('en-US')

const StatusDistribution = lazy(async () => {
const [
{ Bar, BarChart, CartesianGrid, XAxis, YAxis },
{ ChartContainer, ChartTooltip, ChartTooltipContent },
] = await Promise.all([
import('recharts').then((module) => {
return {
Bar: module.Bar,
BarChart: module.BarChart,
CartesianGrid: module.CartesianGrid,
XAxis: module.XAxis,
YAxis: module.YAxis,
}
}),
import('@altstack/ui/components/chart').then((module) => {
return {
ChartContainer: module.ChartContainer,
ChartTooltip: module.ChartTooltip,
ChartTooltipContent: module.ChartTooltipContent,
}
}),
])
return {
default: function LoadedStatusDistribution({
statuses,
}: {
statuses: Overview['statuses']
}) {
const distribution = statuses.map((item) => {
return { ...item, label: labels[item.status] }
})
return (
<ChartContainer
config={config}
className="h-40 min-h-40 w-full"
aria-label="Project status distribution"
>
<BarChart
accessibilityLayer
data={distribution}
layout="vertical"
margin={{ left: 0, right: 8, top: 0, bottom: 0 }}
>
<CartesianGrid horizontal={false} />
<XAxis
type="number"
allowDecimals={false}
tickLine={false}
axisLine={false}
fontSize={11}
tick={{ fill: 'var(--muted-foreground)' }}
/>
<YAxis
type="category"
dataKey="label"
width={72}
tickLine={false}
axisLine={false}
fontSize={11}
tick={{ fill: 'var(--muted-foreground)' }}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<Bar
dataKey="count"
fill="var(--color-count)"
radius={[0, 4, 4, 0]}
maxBarSize={18}
isAnimationActive={false}
/>
</BarChart>
</ChartContainer>
)
},
}
})

export function ProjectStatusChart({
statuses,
counts,
}: {
statuses: Overview['statuses']
counts: Overview['counts']
}) {
const distribution = statuses.map((item) => {
return { ...item, label: labels[item.status] }
})
return (
<Card className="min-w-0">
<CardHeader>
Expand Down Expand Up @@ -90,45 +158,15 @@ export function ProjectStatusChart({
</div>
</dl>
{statuses.some((item) => item.count > 0) ? (
<ChartContainer
config={config}
className="h-40 min-h-40 w-full"
aria-label="Project status distribution"
<Suspense
fallback={
<output className="flex h-40 min-h-40 items-center justify-center text-xs text-muted-foreground">
Loading status chart…
</output>
}
>
<BarChart
accessibilityLayer
data={distribution}
layout="vertical"
margin={{ left: 0, right: 8, top: 0, bottom: 0 }}
>
<CartesianGrid horizontal={false} />
<XAxis
type="number"
allowDecimals={false}
tickLine={false}
axisLine={false}
fontSize={11}
tick={{ fill: 'var(--muted-foreground)' }}
/>
<YAxis
type="category"
dataKey="label"
width={72}
tickLine={false}
axisLine={false}
fontSize={11}
tick={{ fill: 'var(--muted-foreground)' }}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<Bar
dataKey="count"
fill="var(--color-count)"
radius={[0, 4, 4, 0]}
maxBarSize={18}
isAnimationActive={false}
/>
</BarChart>
</ChartContainer>
<StatusDistribution statuses={statuses} />
</Suspense>
) : (
<AdminEmpty
title="No projects yet"
Expand Down
1 change: 1 addition & 0 deletions apps/web/tests/admin-dashboard-route.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ describe('admin dashboard routes', () => {
expect(
screen.getByText('Current project distribution by status')
).toBeTruthy()
await screen.findByLabelText('Project status distribution')
})
it('keeps catalog filters across reload and history navigation', async () => {
const router = await routerAt(
Expand Down
5 changes: 5 additions & 0 deletions apps/web/tests/browser/admin-overview.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ describe('admin overview in Chromium', () => {
await page.viewport(width, 900)
for (const theme of ['light', 'dark']) {
await mount(theme)
await screen.findByLabelText(
'Project status distribution',
{},
{ timeout: 10_000 }
)
expect(document.documentElement.scrollWidth).toBeLessThanOrEqual(width)
expect(
screen
Expand Down
Loading