From 7fce0a12d9435816cbba184edeb11de93cf1f47b Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Wed, 16 Sep 2026 09:18:40 +0100 Subject: [PATCH] feat(design-system): first pass at db report chart colours (#46787) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? This is a first draft at introducing semantic colours to our Observability charts. This moves away from just random colours being assigned to prop after prop. They're only scoped to the Database reports right now, but if it flows nice, we can open it up to the other reports too. This also aims to tone down some of the harsher colours in our charts, such as the orange which sometimes can look like a warning metric/prop. | Before | After | |--------|--------| | Screenshot 2026-06-10 at 09 14 56 | Screenshot 2026-09-14 at 18 14
47 | cc @supabase/design for additional thoughts. ## Summary by CodeRabbit * **New Features** * Added semantic chart color roles with light and dark theme variants for consistent visualizations. * Standardized colors and fills across database, networking, storage, and connection charts. * Maximum-value lines now use configured chart colors when available. * Added chart palette reference and stress-test examples. * Added stacked bar charts, customizable margins, and gradient-filled line charts. * Improved multi-series bar chart focus and date-range footer alignment. * **Documentation** * Documented the chart palette, theme variants, accessibility guidance, and usage recommendations. --------- Co-authored-by: Claude Opus 4.8 (1M context) Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> --- .../content/docs/components/chart.mdx | 74 +++------- .../content/docs/ui-patterns/charts.mdx | 23 +++ apps/design-system/registry/charts.ts | 16 +++ .../default/block/chart-bar-interactive.tsx | 4 +- .../default/block/chart-composed-basic.tsx | 4 +- .../default/block/chart-palette-stress.tsx | 72 ++++++++++ .../registry/default/block/chart-palette.tsx | 135 ++++++++++++++++++ .../default/example/chart-tooltip-demo.tsx | 12 +- apps/design-system/styles/globals.css | 16 --- apps/learn/styles/globals.css | 15 -- .../Explorer/QueryEditor/QueryResultChart.tsx | 6 +- .../EdgeFunctionOverview.utils.ts | 2 +- .../QueryInsightsChart.constants.ts | 4 +- .../Reports/ReportBlock/ChartBlock.tsx | 8 +- .../interfaces/UnifiedLogs/UnifiedLogs.tsx | 4 +- .../components/ui/Charts/ComposedChart.tsx | 25 ++-- .../ui/Charts/ComposedChart.utils.tsx | 23 +-- .../ui/DataTable/DataTable.utils.ts | 4 +- apps/studio/data/reports/database-charts.ts | 91 ++++++++++-- apps/studio/styles/globals.css | 20 --- apps/ui-library/styles/globals.css | 15 -- packages/config/css/charts.css | 48 +++++++ packages/config/tailwind.config.css | 1 + .../src/Chart/charts/chart-bar.tsx | 49 ++++++- .../src/Chart/charts/chart-line.tsx | 84 ++++++----- .../ui-patterns/src/LogsBarChart/index.tsx | 4 +- 26 files changed, 540 insertions(+), 219 deletions(-) create mode 100644 apps/design-system/registry/default/block/chart-palette-stress.tsx create mode 100644 apps/design-system/registry/default/block/chart-palette.tsx create mode 100644 packages/config/css/charts.css diff --git a/apps/design-system/content/docs/components/chart.mdx b/apps/design-system/content/docs/components/chart.mdx index 671491da8e8..68e336bdcf2 100644 --- a/apps/design-system/content/docs/components/chart.mdx +++ b/apps/design-system/content/docs/components/chart.mdx @@ -49,27 +49,7 @@ We do not wrap Recharts. This means you're not locked into an abstraction. When -Add the following colors to your CSS file in your app. - -```css -@layer base { - :root { - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - } - - .dark { - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - } -} -``` +Chart colors are already defined for every app in `packages/config/css/charts.css`, which ships through the shared Tailwind config. It provides eight categorical slots, `--chart-1` through `--chart-8`, each with a matching `-fill` token, resolved per theme. See the [Charts](/docs/ui-patterns/charts) pattern page for the palette and the rules for assigning slots. ## Your First Chart @@ -327,25 +307,19 @@ Charts has built-in support for theming. You can use css variables (recommended) -Define your colors in your css file +Pick a slot from the shared palette -```css {6-7,14-15} title="globals.css" -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 240 10% 3.9%; - // ... - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - } +```css title="packages/config/css/charts.css" +:root { + --chart-1: var(--color-brand-800); + --chart-2: var(--color-blue-900); + /* ... */ +} - .dark: { - --background: 240 10% 3.9%; - --foreground: 0 0% 100%; - // ... - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - } +[data-theme*='dark'] { + --chart-1: var(--color-brand-900); + --chart-2: var(--color-blue-1100); + /* ... */ } ``` @@ -355,28 +329,18 @@ Charts has built-in support for theming. You can use css variables (recommended) const chartConfig = { desktop: { label: 'Desktop', - color: 'hsl(var(--chart-1))', + color: 'var(--chart-1)', }, mobile: { label: 'Mobile', - color: 'hsl(var(--chart-2))', + color: 'var(--chart-2)', }, } satisfies ChartConfig ``` -We're wrapping the value in `hsl()` here because we define the colors without color space function. - -This is not required. You can use full color values, such as hex, hsl or oklch. - -```css ---chart-1: oklch(70% 0.227 154.59); -``` - -```tsx -color: "var(--chart-1)", -``` +The slots are full color values, so pass them as `var(--chart-1)`. Do not wrap them in `hsl()`; that form is for bare HSL triplets and produces an invalid color here. @@ -472,11 +436,11 @@ const chartConfig = { }, chrome: { label: 'Chrome', - color: 'hsl(var(--chart-1))', + color: 'var(--chart-1)', }, safari: { label: 'Safari', - color: 'hsl(var(--chart-2))', + color: 'var(--chart-2)', }, } satisfies ChartConfig ``` @@ -516,11 +480,11 @@ const chartData = [ const chartConfig = { chrome: { label: 'Chrome', - color: 'hsl(var(--chart-1))', + color: 'var(--chart-1)', }, safari: { label: 'Safari', - color: 'hsl(var(--chart-2))', + color: 'var(--chart-2)', }, } satisfies ChartConfig ``` diff --git a/apps/design-system/content/docs/ui-patterns/charts.mdx b/apps/design-system/content/docs/ui-patterns/charts.mdx index ef2b6cf8ad9..db889d46815 100644 --- a/apps/design-system/content/docs/ui-patterns/charts.mdx +++ b/apps/design-system/content/docs/ui-patterns/charts.mdx @@ -23,6 +23,29 @@ Our charts use a combination of our own presentational components and [Recharts] 3. **Keep it simple**: Try to avoid abstracting the chart content too much. These components should cover most of your presentational needs. +## Color + +Series colors come from eight categorical slots, `--chart-1` through `--chart-8`, defined in +`packages/config/css/charts.css`. Assign them in order and never cycle: a ninth series folds +into "Other" or becomes small multiples. Each slot has a matching `-fill` token. Slots resolve +per theme, so pass `var(--chart-n)` and never branch on light/dark in code. Adjacent slots +alternate hue families and clear colorblind separation in both themes. + +Reference lines use `--chart-reference`. Headroom, idle and unused capacity use `--chart-muted`. +Directional pairs use `--chart-in` / `--chart-out` so read and write keep the same hue across +charts. + +Status colors (`--chart-status-success`, `-warning`, `-destructive`, each with a `-muted` tier) +are reserved for state and always ship with an icon or label. Never use one as a series color: +amber on a neutral metric reads as a problem. Warm hues are otherwise limited to tomato, slot 5, +because no amber or yellow step is legible on the dark surface. + + + +Every slot stacked together, to check adjacent segments stay separable in both themes. + + + ## Examples ### Basic Chart Types diff --git a/apps/design-system/registry/charts.ts b/apps/design-system/registry/charts.ts index 9a42e5095a0..a272b16eede 100644 --- a/apps/design-system/registry/charts.ts +++ b/apps/design-system/registry/charts.ts @@ -57,4 +57,20 @@ export const charts: Registry = [ category: 'Charts', subcategory: 'Composed', }, + { + name: 'chart-palette', + type: 'components:block', + registryDependencies: ['chart'], + files: ['block/chart-palette.tsx'], + category: 'Charts', + subcategory: 'Palette', + }, + { + name: 'chart-palette-stress', + type: 'components:block', + registryDependencies: ['chart'], + files: ['block/chart-palette-stress.tsx'], + category: 'Charts', + subcategory: 'Palette', + }, ] diff --git a/apps/design-system/registry/default/block/chart-bar-interactive.tsx b/apps/design-system/registry/default/block/chart-bar-interactive.tsx index 128664bb431..c235862f1a0 100644 --- a/apps/design-system/registry/default/block/chart-bar-interactive.tsx +++ b/apps/design-system/registry/default/block/chart-bar-interactive.tsx @@ -116,11 +116,11 @@ const chartConfig = { }, desktop: { label: 'Desktop', - color: 'hsl(var(--chart-1))', + color: 'var(--chart-1)', }, mobile: { label: 'Mobile', - color: 'hsl(var(--chart-2))', + color: 'var(--chart-2)', }, } satisfies ChartConfig diff --git a/apps/design-system/registry/default/block/chart-composed-basic.tsx b/apps/design-system/registry/default/block/chart-composed-basic.tsx index 99be1076b08..d185c5e79bb 100644 --- a/apps/design-system/registry/default/block/chart-composed-basic.tsx +++ b/apps/design-system/registry/default/block/chart-composed-basic.tsx @@ -52,11 +52,11 @@ export default function ComposedChartBasic() { }, performance: { label: 'Performance', - color: 'hsl(var(--chart-2))', + color: 'var(--chart-2)', }, efficiency: { label: 'Efficiency', - color: 'hsl(var(--chart-5))', + color: 'var(--chart-5)', }, } diff --git a/apps/design-system/registry/default/block/chart-palette-stress.tsx b/apps/design-system/registry/default/block/chart-palette-stress.tsx new file mode 100644 index 00000000000..740e5c882e6 --- /dev/null +++ b/apps/design-system/registry/default/block/chart-palette-stress.tsx @@ -0,0 +1,72 @@ +'use client' + +import { + Chart, + ChartBar, + ChartCard, + ChartContent, + ChartHeader, + ChartTitle, + type ChartBarTick, + type ChartConfig, +} from 'ui-patterns/Chart' + +const SERIES = [ + { key: 'postgres', label: 'Postgres' }, + { key: 'postgrest', label: 'PostgREST' }, + { key: 'reserved', label: 'Reserved' }, + { key: 'auth', label: 'Auth' }, + { key: 'storage', label: 'Storage' }, + { key: 'realtime', label: 'Realtime' }, + { key: 'cron', label: 'Cron' }, + { key: 'other', label: 'Other roles' }, +] + +const config: ChartConfig = Object.fromEntries( + SERIES.map((s, i) => [s.key, { label: s.label, color: `var(--chart-${i + 1})` }]) +) + +export default function ChartPaletteStress() { + const data: ChartBarTick[] = Array.from({ length: 40 }, (_, i) => { + const date = new Date() + date.setMinutes(date.getMinutes() - (40 - i) * 3) + const row: ChartBarTick = { timestamp: date.toISOString() } + + const trend = Math.sin((i / 40) * Math.PI * 2) + SERIES.forEach((s, idx) => { + const phase = Math.sin(i / 3.5 + idx * 1.7) + const jitter = Math.sin(i * 2.3 + idx * 0.9) * 1.5 + row[s.key] = Math.max(1, Math.round(5 + idx * 1.8 + phase * 3 + trend * 2 + jitter)) + }) + return row + }) + + return ( +
+ + + + + Client connections by role + + + +
+ s.key)} + config={config} + isStacked + isFullHeight + showGrid + showYAxis + YAxisProps={{ width: 36 }} + /> +
+
+
+
+
+ ) +} diff --git a/apps/design-system/registry/default/block/chart-palette.tsx b/apps/design-system/registry/default/block/chart-palette.tsx new file mode 100644 index 00000000000..8d44644e59d --- /dev/null +++ b/apps/design-system/registry/default/block/chart-palette.tsx @@ -0,0 +1,135 @@ +import { ReactNode } from 'react' + +const SLOTS = [1, 2, 3, 4, 5, 6, 7, 8] + +const STATUS = [ + { name: '--chart-status-success', muted: '--chart-status-success-muted', note: 'Healthy, ok' }, + { + name: '--chart-status-warning', + muted: '--chart-status-warning-muted', + note: 'Threshold breach', + }, + { + name: '--chart-status-destructive', + muted: '--chart-status-destructive-muted', + note: 'Error, failure', + }, +] + +const DEFAULTS = [ + { name: '--chart-in', note: 'Pinned: network in, disk read' }, + { name: '--chart-out', note: 'Pinned: network out, disk write' }, + { name: '--chart-reference', note: 'Reference lines, max values' }, + { name: '--chart-muted', note: 'Headroom, idle, unused capacity' }, +] + +function Swatch({ token, label }: { token: string; label: string }) { + return ( +
+
+ {label} +
+ ) +} + +function TokenCard({ + title, + token, + note, + children, +}: { + title: ReactNode + token: string + note?: string + children: ReactNode +}) { + return ( +
+
+
{title}
+ {token} +
+
{children}
+ {note &&

{note}

} +
+ ) +} + +function Section({ + title, + description, + children, + className, +}: { + title: string + description: string + children: ReactNode + className: string +}) { + return ( +
+
+

{title}

+

{description}

+
+
{children}
+
+ ) +} + +export default function ChartPalette() { + return ( +
+
+ {SLOTS.map((n) => ( + + + + + ))} +
+ +
+ {STATUS.map((d) => ( + + + + + ))} +
+ +
+ {DEFAULTS.map((d) => ( + + + + ))} +
+
+ ) +} diff --git a/apps/design-system/registry/default/example/chart-tooltip-demo.tsx b/apps/design-system/registry/default/example/chart-tooltip-demo.tsx index 5fffac2424a..af4c7735696 100644 --- a/apps/design-system/registry/default/example/chart-tooltip-demo.tsx +++ b/apps/design-system/registry/default/example/chart-tooltip-demo.tsx @@ -32,8 +32,8 @@ export default function Component() { @@ -64,8 +64,8 @@ export default function Component() { label="Browser" hideLabel payload={[ - { name: 'Chrome', value: 1286, fill: 'hsl(var(--chart-3))' }, - { name: 'Firefox', value: 1000, fill: 'hsl(var(--chart-4))' }, + { name: 'Chrome', value: 1286, fill: 'var(--chart-3)' }, + { name: 'Firefox', value: 1000, fill: 'var(--chart-4)' }, ]} indicator="dashed" className="w-32" @@ -74,7 +74,7 @@ export default function Component() {
@@ -84,7 +84,7 @@ export default function Component() { diff --git a/apps/design-system/styles/globals.css b/apps/design-system/styles/globals.css index 32c9d5d396b..0a55d08da3e 100644 --- a/apps/design-system/styles/globals.css +++ b/apps/design-system/styles/globals.css @@ -36,22 +36,6 @@ } @layer base { - :root { - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - } - - .dark { - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - } - * { @apply border-border; } diff --git a/apps/learn/styles/globals.css b/apps/learn/styles/globals.css index 1478d871f62..a0fc87d4f3f 100644 --- a/apps/learn/styles/globals.css +++ b/apps/learn/styles/globals.css @@ -30,11 +30,6 @@ --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); - --color-chart-1: hsl(var(--chart-1)); - --color-chart-2: hsl(var(--chart-2)); - --color-chart-3: hsl(var(--chart-3)); - --color-chart-4: hsl(var(--chart-4)); - --color-chart-5: hsl(var(--chart-5)); } @layer base { @@ -58,11 +53,6 @@ --border: hsl(220 13% 91%); --input: hsl(220 13% 91%); --ring: hsl(220 13% 70.8%); - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; --radius: 0.625rem; --sidebar: hsl(210 20% 98.5%); --sidebar-foreground: hsl(224 71.4% 4.1%); @@ -94,11 +84,6 @@ --border: hsl(215 27.9% 16.9%); --input: hsl(215 27.9% 16.9%); --ring: hsl(217.9 10.6% 55.6%); - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; --sidebar: hsl(220.9 39.3% 11%); --sidebar-foreground: hsl(210 20% 98%); --sidebar-primary: hsl(220 70% 50%); diff --git a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultChart.tsx b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultChart.tsx index 32e018133a6..25412b9ea91 100644 --- a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultChart.tsx +++ b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultChart.tsx @@ -17,11 +17,7 @@ interface QueryResultChartProps { result?: QueryResult } -const Y_SERIES_COLORS = [ - 'hsl(var(--brand-default))', - 'hsl(var(--chart-blue))', - 'hsl(var(--chart-3))', -] +const Y_SERIES_COLORS = ['hsl(var(--brand-default))', 'var(--chart-2)', 'var(--chart-3)'] const toChartValue = (value: unknown): string | number => { if (typeof value === 'number' || typeof value === 'string') return value diff --git a/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionOverview.utils.ts b/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionOverview.utils.ts index dbb91f1aed2..a0d90f31fd9 100644 --- a/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionOverview.utils.ts +++ b/apps/studio/components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionOverview.utils.ts @@ -88,7 +88,7 @@ export const INVOCATION_CHART_CONFIG = { }, warning_count: { label: 'Warnings', - color: 'var(--chart-warning)', + color: 'var(--chart-status-warning)', }, error_count: { label: 'Errors', diff --git a/apps/studio/components/interfaces/QueryInsights/QueryInsightsChart/QueryInsightsChart.constants.ts b/apps/studio/components/interfaces/QueryInsights/QueryInsightsChart/QueryInsightsChart.constants.ts index 35ec04d9a08..ebcad57322f 100644 --- a/apps/studio/components/interfaces/QueryInsights/QueryInsightsChart/QueryInsightsChart.constants.ts +++ b/apps/studio/components/interfaces/QueryInsights/QueryInsightsChart/QueryInsightsChart.constants.ts @@ -9,7 +9,7 @@ export const CHART_TABS = [ export const LEGEND_ITEMS: Record = { query_latency: [ - { label: 'P50', color: 'hsl(var(--chart-4))', dataKey: 'p50' }, + { label: 'P50', color: 'var(--chart-4)', dataKey: 'p50' }, { label: 'P95', color: CHART_COLORS.GREEN_1, dataKey: 'p95' }, ], rows_read: [{ label: 'Rows Read', color: CHART_COLORS.GREEN_1, dataKey: 'rows_read' }], @@ -19,4 +19,4 @@ export const LEGEND_ITEMS: Record= threshold.danger - ? 'var(--chart-destructive)' + ? 'var(--chart-status-destructive)' : value >= threshold.warning - ? 'var(--chart-warning)' + ? 'var(--chart-status-warning)' : 'var(--chart-1)' } else { return value <= threshold.danger - ? 'var(--chart-destructive)' + ? 'var(--chart-status-destructive)' : value <= threshold.warning - ? 'var(--chart-warning)' + ? 'var(--chart-status-warning)' : 'var(--chart-1)' } } diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx index f67b3f1040a..b5099542a44 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx @@ -77,11 +77,11 @@ import { useShortcut } from '@/state/shortcuts/useShortcut' export const CHART_CONFIG = { success: { label: , - color: 'var(--chart-success)', + color: 'var(--chart-muted)', }, warning: { label: , - color: 'var(--chart-warning)', + color: 'var(--chart-status-warning)', }, error: { label: , diff --git a/apps/studio/components/ui/Charts/ComposedChart.tsx b/apps/studio/components/ui/Charts/ComposedChart.tsx index 90b1babe16e..757556976d4 100644 --- a/apps/studio/components/ui/Charts/ComposedChart.tsx +++ b/apps/studio/components/ui/Charts/ComposedChart.tsx @@ -40,6 +40,7 @@ import { CustomTooltip, getStackId, MultiAttribute, + resolveChartColor, } from './ComposedChart.utils' import NoDataPlaceholder from './NoDataPlaceholder' import { ChartHighlight } from './useChartHighlight' @@ -307,7 +308,7 @@ export function ComposedChart({ const maxAttribute = attributes.find((a) => a.isMaxValue) const maxAttributeData = { name: maxAttribute?.attribute, - color: CHART_COLORS.REFERENCE_LINE, + color: resolveChartColor(maxAttribute?.color, isDarkMode) ?? CHART_COLORS.REFERENCE_LINE, } const referenceLines = attributes.filter((attribute) => { @@ -342,16 +343,12 @@ export function ComposedChart({ const attribute = attributes.find((attr) => attr.attribute === att.name) return { ...att, - color: attribute?.color - ? isDarkMode - ? attribute.color.dark - : attribute.color.light - : STACKED_CHART_COLORS[index % STACKED_CHART_COLORS.length], - fill: attribute?.fill - ? isDarkMode - ? attribute.fill.dark - : attribute.fill.light - : STACKED_CHART_FILLS[index % STACKED_CHART_FILLS.length], + color: + resolveChartColor(attribute?.color, isDarkMode) ?? + STACKED_CHART_COLORS[index % STACKED_CHART_COLORS.length], + fill: + resolveChartColor(attribute?.fill, isDarkMode) ?? + STACKED_CHART_FILLS[index % STACKED_CHART_FILLS.length], } }) : [] @@ -600,7 +597,9 @@ export function ComposedChart({ key={maxAttribute.attribute} type="linear" dataKey={maxAttribute.attribute} - stroke={CHART_COLORS.REFERENCE_LINE} + stroke={ + resolveChartColor(maxAttribute.color, isDarkMode) ?? CHART_COLORS.REFERENCE_LINE + } strokeWidth={2} strokeDasharray={maxAttribute.strokeDasharray ?? '3 3'} dot={false} @@ -616,7 +615,7 @@ export function ComposedChart({ key={line.attribute} y={line.value} strokeWidth={1} - stroke={isDarkMode ? line.color?.dark : line.color?.light} + stroke={resolveChartColor(line.color, isDarkMode)} strokeDasharray={line.strokeDasharray ?? '3 3'} label={undefined} > diff --git a/apps/studio/components/ui/Charts/ComposedChart.utils.tsx b/apps/studio/components/ui/Charts/ComposedChart.utils.tsx index 3aa6b215d15..60690c6bdb2 100644 --- a/apps/studio/components/ui/Charts/ComposedChart.utils.tsx +++ b/apps/studio/components/ui/Charts/ComposedChart.utils.tsx @@ -40,18 +40,25 @@ export interface ReportAttributes { export type Provider = 'infra-monitoring' | 'daily-stats' | 'mock' | 'reference-line' | 'logs' +export type ThemedColor = { + light?: string + dark?: string +} + +export const resolveChartColor = ( + color: string | ThemedColor | undefined, + isDarkMode: boolean | undefined +) => { + if (typeof color === 'string') return color + return isDarkMode ? color?.dark : color?.light +} + export type MultiAttribute = { attribute: string provider?: Provider label?: string - color?: { - light: string - dark: string - } - fill?: { - light?: string - dark?: string - } + color?: string | { light: string; dark: string } + fill?: string | ThemedColor statusCode?: string grantType?: string providerType?: string diff --git a/apps/studio/components/ui/DataTable/DataTable.utils.ts b/apps/studio/components/ui/DataTable/DataTable.utils.ts index 54366ba78c7..b26e17c4d38 100644 --- a/apps/studio/components/ui/DataTable/DataTable.utils.ts +++ b/apps/studio/components/ui/DataTable/DataTable.utils.ts @@ -63,9 +63,9 @@ export function getLevelColor( case 'success': return { text: 'text-muted', - bg: 'bg-[var(--chart-success)] group-data-[state=selected]/row:bg-foreground-lighter', + bg: 'bg-[var(--chart-muted)] group-data-[state=selected]/row:bg-foreground-lighter', border: - 'border-[var(--chart-success)] group-data-[state=selected]/row:border-foreground-lighter', + 'border-[var(--chart-muted)] group-data-[state=selected]/row:border-foreground-lighter', } case 'warning': return { diff --git a/apps/studio/data/reports/database-charts.ts b/apps/studio/data/reports/database-charts.ts index 65e300266e0..45682dbdc16 100644 --- a/apps/studio/data/reports/database-charts.ts +++ b/apps/studio/data/reports/database-charts.ts @@ -75,6 +75,8 @@ export const getReportAttributesV2: ( attribute: 'ram_usage_used', provider: 'infra-monitoring', label: 'Used', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'RAM in use by Postgres and the operating system. Sustained high usage may indicate memory pressure', }, @@ -82,6 +84,8 @@ export const getReportAttributesV2: ( attribute: 'ram_usage_cache_and_buffers', provider: 'infra-monitoring', label: 'Cache + Buffers', + color: 'var(--chart-2)', + fill: 'var(--chart-2-fill)', tooltip: 'RAM used by the operating system page cache and PostgreSQL buffers to accelerate disk reads/writes', }, @@ -89,6 +93,8 @@ export const getReportAttributesV2: ( attribute: 'ram_usage_free', provider: 'infra-monitoring', label: 'Free', + color: 'var(--chart-muted)', + fill: 'var(--chart-muted-fill)', tooltip: 'Unallocated memory available for use. A small portion is always reserved by the operating system', }, @@ -105,6 +111,7 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'Swap', omitFromTotal: true, + color: 'var(--chart-3)', tooltip: 'Swap space in use by the operating system. Sustained swap usage indicates memory pressure and may degrade database performance', }, @@ -132,6 +139,8 @@ export const getReportAttributesV2: ( attribute: 'ram_commit_used', provider: 'infra-monitoring', label: 'Committed', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'Total memory the kernel has promised to processes (RAM plus swap). Sustained values near or above the commit limit indicate overcommitment and a high risk of out-of-memory failures', }, @@ -139,6 +148,7 @@ export const getReportAttributesV2: ( attribute: 'ram_commit_limit', provider: 'infra-monitoring', label: 'Commit limit', + color: 'var(--chart-reference)', isMaxValue: true, omitFromTotal: true, tooltip: @@ -201,8 +211,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'System', format: '%', - color: { light: '#EDC35E', dark: '#EDD35E' }, - fill: { light: '#F6D99F', dark: '#5C5230' }, + color: 'var(--chart-2)', + fill: 'var(--chart-2-fill)', tooltip: 'CPU time spent on kernel operations (e.g., process scheduling, memory management). High values may indicate system overhead', }, @@ -211,8 +221,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'User', format: '%', - color: { light: '#0063E8', dark: '#65BCD9' }, - fill: { light: '#80B1F4', dark: '#2A3D45' }, + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'CPU time used by database queries and user-space processes. High values may suggest CPU-intensive queries', }, @@ -221,8 +231,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'IOwait', format: '%', - color: { light: '#DB3A34', dark: '#FF6B6B' }, - fill: { light: '#F2A7A3', dark: '#5C2A2A' }, + color: 'var(--chart-3)', + fill: 'var(--chart-3-fill)', tooltip: 'CPU time waiting for disk or network I/O. High values may indicate disk bottlenecks', }, @@ -231,8 +241,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'IRQs', format: '%', - color: { light: '#DA760B', dark: '#DA760B' }, - fill: { light: '#FFB885', dark: '#5C3D0A' }, + color: 'var(--chart-4)', + fill: 'var(--chart-4-fill)', tooltip: 'CPU time handling hardware interrupt requests (IRQ)', }, { @@ -240,11 +250,30 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', label: 'Other', format: '%', - color: { light: '#B616A6', dark: '#DB8DF9' }, - fill: { light: '#DB8BD3', dark: '#4A3D5C' }, + color: 'var(--chart-5)', + fill: 'var(--chart-5-fill)', tooltip: 'CPU time spent on other tasks (e.g., background processes, software interrupts)', }, + { + attribute: 'cpu_usage_busy_idle', + provider: 'infra-monitoring', + label: 'Idle', + format: '%', + omitFromTotal: true, + color: 'var(--chart-muted)', + fill: 'var(--chart-muted-fill)', + tooltip: 'CPU time spent idle and available for new work', + }, + { + attribute: 'cpu_usage_max', + provider: 'reference-line', + label: 'Max', + value: 100, + color: 'var(--chart-reference)', + tooltip: 'Max CPU usage', + isMaxValue: true, + }, ], }, { @@ -269,12 +298,16 @@ export const getReportAttributesV2: ( attribute: 'network_receive_bytes', provider: 'infra-monitoring', label: 'Network in', + color: 'var(--chart-in)', + fill: 'var(--chart-in-fill)', tooltip: 'Inbound network throughput (bytes per second)', }, { attribute: 'network_transmit_bytes', provider: 'infra-monitoring', label: 'Network out', + color: 'var(--chart-out)', + fill: 'var(--chart-out-fill)', tooltip: 'Outbound network throughput (bytes per second)', }, ], @@ -301,6 +334,8 @@ export const getReportAttributesV2: ( attribute: 'disk_iops_write', provider: 'infra-monitoring', label: 'Write IOPS', + color: 'var(--chart-out)', + fill: 'var(--chart-out-fill)', tooltip: 'Number of write operations per second. High values indicate frequent data writes, logging, or transaction activity', }, @@ -308,6 +343,8 @@ export const getReportAttributesV2: ( attribute: 'disk_iops_read', provider: 'infra-monitoring', label: 'Read IOPS', + color: 'var(--chart-in)', + fill: 'var(--chart-in-fill)', tooltip: 'Number of read operations per second. High values suggest frequent disk reads due to queries or poor caching', }, @@ -315,6 +352,7 @@ export const getReportAttributesV2: ( attribute: 'disk_iops_max', provider: 'reference-line', label: 'Max IOPS', + color: 'var(--chart-reference)', value: effectiveMaxIops, tooltip: 'Effective maximum IOPS for your current compute and disk configuration. Equal to the lower of the compute IOPS limit and the provisioned disk IOPS', @@ -345,18 +383,23 @@ export const getReportAttributesV2: ( attribute: 'disk_bytes_read', provider: 'infra-monitoring', label: 'Read throughput', + color: 'var(--chart-in)', + fill: 'var(--chart-in-fill)', tooltip: 'Disk read throughput (bytes per second)', }, { attribute: 'disk_bytes_written', provider: 'infra-monitoring', label: 'Write throughput', + color: 'var(--chart-out)', + fill: 'var(--chart-out-fill)', tooltip: 'Disk write throughput (bytes per second)', }, { attribute: 'disk_throughput_max', provider: 'reference-line', label: 'Max throughput', + color: 'var(--chart-reference)', value: diskConfig?.attributes?.type === 'gp3' && typeof diskConfig.attributes.throughput_mbps === 'number' @@ -418,12 +461,15 @@ export const getReportAttributesV2: ( attribute: 'pg_stat_database_num_backends', provider: 'infra-monitoring', label: 'Total connections', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'Total number of active database connections', }, { attribute: 'max_db_connections', provider: 'reference-line', label: 'Max connections', + color: 'var(--chart-reference)', value: maxConnections?.maxConnections, tooltip: 'Max available connections for your current compute size', isMaxValue: true, @@ -452,6 +498,8 @@ export const getReportAttributesV2: ( attribute: 'client_connections_postgres', provider: 'infra-monitoring', label: 'Postgres', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'Direct connections to the Postgres database from your application and external clients', }, @@ -459,12 +507,16 @@ export const getReportAttributesV2: ( attribute: 'client_connections_authenticator', provider: 'infra-monitoring', label: 'PostgREST', + color: 'var(--chart-2)', + fill: 'var(--chart-2-fill)', tooltip: 'Connection pool managed by PostgREST', }, { attribute: 'client_connections_supabase_admin', provider: 'infra-monitoring', label: 'Reserved', + color: 'var(--chart-3)', + fill: 'var(--chart-3-fill)', tooltip: 'Administrative connections used by various Supabase services for internal operations and maintenance tasks', }, @@ -472,24 +524,31 @@ export const getReportAttributesV2: ( attribute: 'client_connections_supabase_auth_admin', provider: 'infra-monitoring', label: 'Auth', + color: 'var(--chart-4)', + fill: 'var(--chart-4-fill)', tooltip: 'Connection pool managed by Supabase Auth', }, { attribute: 'client_connections_supabase_storage_admin', provider: 'infra-monitoring', label: 'Storage', + color: 'var(--chart-5)', + fill: 'var(--chart-5-fill)', tooltip: 'Connection pool managed by Supabase Storage', }, { attribute: 'client_connections_other', provider: 'infra-monitoring', label: 'Other roles', + color: 'var(--chart-6)', + fill: 'var(--chart-6-fill)', tooltip: "Miscellaneous database connections that don't fall into other categories.", }, { attribute: 'max_db_connections', provider: 'reference-line', label: 'Max connections', + color: 'var(--chart-reference)', value: maxConnections?.maxConnections, tooltip: 'Max available connections for your current compute size', isMaxValue: true, @@ -522,12 +581,15 @@ export const getReportAttributesV2: ( attribute: 'client_connections_pgbouncer', provider: 'infra-monitoring', label: isHighAvailability ? 'multipooler' : 'pgbouncer', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: isHighAvailability ? 'Multipooler connections' : 'PgBouncer connections', }, { attribute: 'pg_pooler_max_connections', provider: 'reference-line', label: 'Max pooler connections', + color: 'var(--chart-reference)', value: pgBouncerMaxConnections, tooltip: 'Maximum allowed pooler connections for your current compute size', isMaxValue: true, @@ -555,6 +617,8 @@ export const getReportAttributesV2: ( attribute: 'supavisor_connections_active', provider: 'infra-monitoring', label: 'supavisor', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'Supavisor connections', }, ], @@ -582,6 +646,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', format: 'bytes', label: 'System', + color: 'var(--chart-3)', + fill: 'var(--chart-3-fill)', tooltip: 'Reserved space for the system to ensure your database runs smoothly', }, { @@ -589,6 +655,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', format: 'bytes', label: 'WAL', + color: 'var(--chart-2)', + fill: 'var(--chart-2-fill)', tooltip: 'Disk usage by the write-ahead log. The usage depends on your WAL settings and the amount of data being written to the database', }, @@ -597,6 +665,8 @@ export const getReportAttributesV2: ( provider: 'infra-monitoring', format: 'bytes', label: 'Database', + color: 'var(--chart-1)', + fill: 'var(--chart-1-fill)', tooltip: 'Disk usage by your database (tables, indexes, data, ...)', }, { @@ -605,6 +675,7 @@ export const getReportAttributesV2: ( isMaxValue: true, format: 'bytes', label: 'Disk Size', + color: 'var(--chart-reference)', tooltip: 'Disk Size refers to the total space your project occupies on disk', }, entitledFeatures.includes('database') && diff --git a/apps/studio/styles/globals.css b/apps/studio/styles/globals.css index 44e8f55b3c1..d75d9ca72f4 100644 --- a/apps/studio/styles/globals.css +++ b/apps/studio/styles/globals.css @@ -138,16 +138,6 @@ } :root { - --chart-1: hsl(var(--brand-default)); - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - --chart-blue: 217 91% 60%; - --chart-warning: hsl(var(--warning-500)); - --chart-warning-muted: hsl(var(--warning-400)); - --chart-destructive: hsl(var(--destructive-default)); - --chart-success: color-mix(in oklch, var(--foreground-muted) 50%, white); --sidebar-background: var(--background-dash-sidebar); --sidebar-foreground: var(--foreground-default); --sidebar-primary: var(--foreground-default); @@ -161,16 +151,6 @@ [data-theme='dark'], .dark { - --chart-1: hsl(var(--brand-default)); - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - --chart-blue: 217 91% 65%; - --chart-warning: hsl(var(--warning-default)); - --chart-warning-muted: hsl(var(--warning-500)); - --chart-destructive: hsl(var(--destructive-default)); - --chart-success: color-mix(in oklch, var(--foreground-muted) 55%, var(--background)); --sidebar-background: var(--background-dash-sidebar); --sidebar-foreground: var(--foreground-default); --sidebar-primary: var(--foreground-default); diff --git a/apps/ui-library/styles/globals.css b/apps/ui-library/styles/globals.css index 6d89a7d3595..f1cb2bfd4d2 100644 --- a/apps/ui-library/styles/globals.css +++ b/apps/ui-library/styles/globals.css @@ -37,11 +37,6 @@ /* --color-border: var(--border); */ --color-input: var(--input); --color-ring: var(--ring); - --color-chart-1: hsl(var(--chart-1)); - --color-chart-2: hsl(var(--chart-2)); - --color-chart-3: hsl(var(--chart-3)); - --color-chart-4: hsl(var(--chart-4)); - --color-chart-5: hsl(var(--chart-5)); } @layer base { @@ -65,11 +60,6 @@ --border: hsl(0 0% 92.2%); --input: hsl(0 0% 92.2%); --ring: hsl(0 0% 70.8%); - --chart-1: 41.1 22.2% 64.6%; - --chart-2: 184.7 11.8% 60%; - --chart-3: 227.4 7% 39.8%; - --chart-4: 84.4 18.9% 82.8%; - --chart-5: 70.1 18.8% 76.9%; --radius: 0.625rem; --sidebar: hsl(0 0% 98.5%); --sidebar-foreground: hsl(0 0% 14.5%); @@ -102,11 +92,6 @@ --border: hsl(0 0% 26.9%); --input: hsl(0 0% 26.9%); --ring: hsl(0 0% 55.6%); - --chart-1: 264.4 24.3% 48.8%; - --chart-2: 162.5 17% 69.6%; - --chart-3: 70.1 18.8% 76.9%; - --chart-4: 303.9 26.5% 62.7%; - --chart-5: 16.4 24.6% 64.5%; --sidebar: hsl(0 0% 20.5%); --sidebar-foreground: hsl(0 0% 98.5%); --sidebar-primary: hsl(264.4 24.3% 48.8%); diff --git a/packages/config/css/charts.css b/packages/config/css/charts.css new file mode 100644 index 00000000000..806419ac650 --- /dev/null +++ b/packages/config/css/charts.css @@ -0,0 +1,48 @@ +:root { + --chart-1: var(--color-brand-800); + --chart-2: var(--color-blue-900); + --chart-3: var(--color-pink-1000); + --chart-4: var(--color-violet-900); + --chart-5: var(--color-tomato-1000); + --chart-6: var(--color-indigo-1000); + --chart-7: var(--color-green-1100); + --chart-8: var(--color-purple-1000); + + --chart-1-fill: var(--color-brand-500); + --chart-2-fill: var(--color-blue-500); + --chart-3-fill: var(--color-pink-500); + --chart-4-fill: var(--color-violet-500); + --chart-5-fill: var(--color-tomato-500); + --chart-6-fill: var(--color-indigo-500); + --chart-7-fill: var(--color-green-500); + --chart-8-fill: var(--color-purple-500); + + --chart-in: var(--chart-2); + --chart-out: var(--chart-5); + --chart-in-fill: var(--chart-2-fill); + --chart-out-fill: var(--chart-5-fill); + + --chart-reference: var(--color-scale-1000); + --chart-muted: var(--color-scale-700); + --chart-muted-fill: var(--color-scale-400); + + --chart-status-success: hsl(var(--brand-default)); + --chart-status-success-muted: hsl(var(--brand-500)); + --chart-status-warning: var(--warning); + --chart-status-warning-muted: hsl(var(--warning-500)); + --chart-status-destructive: var(--destructive); + --chart-status-destructive-muted: hsl(var(--destructive-500)); +} + +[data-theme*='dark'] { + --chart-1: var(--color-brand-900); + --chart-2: var(--color-blue-1100); + --chart-3: var(--color-pink-1100); + --chart-4: var(--color-violet-1100); + --chart-5: var(--color-tomato-1100); + --chart-6: var(--color-indigo-1100); + --chart-7: var(--color-green-1100); + --chart-8: var(--color-purple-1100); + + --chart-muted: var(--color-scale-800); +} diff --git a/packages/config/tailwind.config.css b/packages/config/tailwind.config.css index 329638a906a..28f167840a1 100644 --- a/packages/config/tailwind.config.css +++ b/packages/config/tailwind.config.css @@ -26,6 +26,7 @@ * consumes them from @theme inline so Tailwind generates the utilities. */ @import './css/colors.css'; @import './css/theme.css'; +@import './css/charts.css'; @import './css/animations.css'; @import './css/utilities.css'; @import './tailwind-plugins/hit-area.css'; diff --git a/packages/ui-patterns/src/Chart/charts/chart-bar.tsx b/packages/ui-patterns/src/Chart/charts/chart-bar.tsx index 49825a36265..1418ac7ab9a 100644 --- a/packages/ui-patterns/src/Chart/charts/chart-bar.tsx +++ b/packages/ui-patterns/src/Chart/charts/chart-bar.tsx @@ -15,6 +15,8 @@ import { import type { CategoricalChartState } from 'recharts/types/chart/types' import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, cn } from 'ui' +const DIMMED_FILL_OPACITY = 0.35 + const CHART_COLORS = { TICK: 'var(--background-overlay-hover)', AXIS: 'var(--background-overlay-hover)', @@ -66,6 +68,8 @@ export interface ChartBarProps { showGrid?: boolean showYAxis?: boolean showXAxis?: boolean + isStacked?: boolean + margin?: { top?: number; right?: number; bottom?: number; left?: number } XAxisProps?: { tick?: boolean tickFormatter?: (value: any) => string @@ -102,6 +106,8 @@ export const ChartBar = ({ showGrid = false, showYAxis = false, showXAxis = false, + isStacked = false, + margin: marginProp, XAxisProps, YAxisProps, }: ChartBarProps) => { @@ -146,23 +152,28 @@ export const ChartBar = ({ ...XAxisProps, } + const yAxisWidth = showYAxis ? (YAxisProps?.width ?? 60) : 0 + const yAxisConfig = { tick: showYAxis ? { fill: 'var(--color-foreground-lighter)', fontSize: 10, fontFamily: 'var(--font-mono)' } : false, hide: !showYAxis, tickMargin: showYAxis ? (YAxisProps?.tickMargin ?? 4) : 0, - width: showYAxis ? (YAxisProps?.width ?? 60) : 0, + width: yAxisWidth, axisLine: { stroke: CHART_COLORS.AXIS }, tickLine: { stroke: CHART_COLORS.AXIS }, ...YAxisProps, } + const hasDateRangeFooter = xKey === 'timestamp' && data.length > 0 + const margin = { top: 0, right: 0, left: 0, bottom: 0, + ...marginProp, } return ( @@ -170,7 +181,10 @@ export const ChartBar = ({ data-testid="chart-bar" className={cn('flex flex-col gap-y-3 w-full', isFullHeight ? 'h-full' : 'h-24', className)} > - + } /> - {/* Selection highlight area */} {showHighlightActions && ( + return ( + + {data.map((_entry: ChartBarTick, dataIndex: number) => ( + + ))} + + ) }) ) : ( @@ -267,8 +301,11 @@ export const ChartBar = ({ - {xKey === 'timestamp' && data && data.length > 0 && ( -
+ {hasDateRangeFooter && ( +
{dayjs(data[0][xKey]).format(DateTimeFormat)} {dayjs(data[data.length - 1]?.[xKey]).format(DateTimeFormat)}
diff --git a/packages/ui-patterns/src/Chart/charts/chart-line.tsx b/packages/ui-patterns/src/Chart/charts/chart-line.tsx index c100f8100fd..9ef6069064e 100644 --- a/packages/ui-patterns/src/Chart/charts/chart-line.tsx +++ b/packages/ui-patterns/src/Chart/charts/chart-line.tsx @@ -2,7 +2,7 @@ import dayjs from 'dayjs' import { useTheme } from 'next-themes' -import { ReactNode, useState } from 'react' +import { ReactNode, useId, useState } from 'react' import { Area, CartesianGrid, @@ -118,6 +118,7 @@ export const ChartLine = ({ referenceLines, }: ChartLineProps) => { const [focusDataIndex, setFocusDataIndex] = useState(null) + const gradientPrefix = `chart-line-fill-${useId().replace(/:/g, '')}` const { resolvedTheme } = useTheme() const isDarkMode = resolvedTheme?.includes('dark') @@ -157,18 +158,30 @@ export const ChartLine = ({ ...XAxisProps, } + const yAxisWidth = showYAxis ? (YAxisProps?.width ?? 60) : 0 + const yAxisConfig = { tick: showYAxis ? { fill: 'var(--color-foreground-lighter)', fontSize: 10, fontFamily: 'var(--font-mono)' } : false, hide: !showYAxis, tickMargin: showYAxis ? (YAxisProps?.tickMargin ?? 4) : 0, - width: showYAxis ? (YAxisProps?.width ?? 60) : 0, + width: yAxisWidth, axisLine: { stroke: CHART_COLORS.AXIS }, tickLine: { stroke: CHART_COLORS.AXIS }, ...YAxisProps, } + const hasDateRangeFooter = xKey === 'timestamp' && data.length > 0 + + const resolveSeriesColor = (key: string) => { + const keyConfig = chartConfig[key] + return ( + keyConfig?.color || + (keyConfig?.theme ? (isDarkMode ? keyConfig.theme.dark : keyConfig.theme.light) : color) + ) + } + const margin = { top: 0, right: 0, @@ -189,7 +202,10 @@ export const ChartLine = ({ data-testid="chart-line" className={cn('flex flex-col gap-y-3 w-full', isFullHeight ? 'h-full' : 'h-24', className)} > - + + + {keysToRender.map((key, index) => ( + + + + + ))} + {showGrid && } @@ -275,7 +306,6 @@ export const ChartLine = ({ /> } /> - {/* Selection highlight area */} {showHighlightActions && ( ))} - {keysToRender.map((key, index) => { - const keyConfig = chartConfig[key] - const lineColor = - keyConfig?.color || - (keyConfig?.theme - ? isDarkMode - ? keyConfig.theme.dark - : keyConfig.theme.light - : color) - const baseOpacity = 0.2 - const opacityIncrement = 0.1 - const maxOpacity = 0.6 - const fillOpacity = Math.min(baseOpacity + index * opacityIncrement, maxOpacity) - - return ( - 1 ? `stack-${key}` : undefined} - /> - ) - })} + {keysToRender.map((key, index) => ( + 1 ? `stack-${key}` : undefined} + /> + ))} - {xKey === 'timestamp' && data && data.length > 0 && ( -
+ {hasDateRangeFooter && ( +
{dayjs(data[0][xKey]).format(DateTimeFormat)} {dayjs(data[data.length - 1]?.[xKey]).format(DateTimeFormat)}
diff --git a/packages/ui-patterns/src/LogsBarChart/index.tsx b/packages/ui-patterns/src/LogsBarChart/index.tsx index c22c003eda2..3d05eaed38e 100644 --- a/packages/ui-patterns/src/LogsBarChart/index.tsx +++ b/packages/ui-patterns/src/LogsBarChart/index.tsx @@ -13,8 +13,8 @@ const CHART_COLORS = { GREEN_2: 'hsl(var(--brand-500))', RED_1: 'hsl(var(--destructive-default))', RED_2: 'hsl(var(--destructive-500))', - YELLOW_1: 'var(--chart-warning, hsl(var(--warning-default)))', - YELLOW_2: 'var(--chart-warning-muted, hsl(var(--warning-500)))', + YELLOW_1: 'var(--chart-status-warning)', + YELLOW_2: 'var(--chart-status-warning-muted)', } type LogsBarChartDatum = {