Profile per-column cardinality and extent; add data-aware chart warnings (M4, A3/A4)

This commit is contained in:
2026-06-07 23:03:17 +03:00
parent dcb7037a71
commit 39555322e4
13 changed files with 552 additions and 90 deletions
+7 -1
View File
@@ -358,8 +358,14 @@ export function ChartBuilderModal() {
// fresh array each render (which loops useSyncExternalStore — see SnippetStore note).
const config = useChartBuilderStore((s) => s.config);
const rowCount = useChartBuilderStore((s) => s.rowCount);
// `columns` is a stable reference set once at init (not rebuilt per render), so
// subscribing to it won't loop useSyncExternalStore.
const columns = useChartBuilderStore((s) => s.columns);
const valid = useMemo(() => isBuilderConfigValid(config), [config]);
const warnings = useMemo(() => builderWarnings(config, rowCount), [config, rowCount]);
const warnings = useMemo(
() => builderWarnings(config, rowCount, columns),
[config, rowCount, columns],
);
const canSort = useMemo(() => supportsSort(config), [config]);
const canStack = useMemo(() => supportsStack(config), [config]);
@@ -10,6 +10,7 @@
import { CURRENT_DATASET_VERSION, type DataSource, type Dataset } from '@core/dataset';
import type { DataFormat } from '@core/format-detection';
import type { ColumnStats } from '@core/profile';
import type { ColumnType } from '@core/type-inference';
const FORMATS: ReadonlyArray<DataFormat> = ['json', 'csv', 'tsv', 'topojson'];
@@ -44,6 +45,10 @@ export function migrateDataset(raw: unknown): Dataset {
columnTypes: Array.isArray(r.columnTypes)
? (r.columnTypes as Array<{ name: string; type: ColumnType }>)
: [],
// Records predating cardinality/extent profiling default to empty stats; the
// Chart Builder's data-aware hints simply stay quiet until the dataset is
// re-saved (which re-profiles it) — graceful, no forced re-profile on read.
columnStats: Array.isArray(r.columnStats) ? (r.columnStats as ColumnStats[]) : [],
size: typeof r.size === 'number' ? r.size : 0,
created: typeof r.created === 'string' ? r.created : new Date(0).toISOString(),
modified: typeof r.modified === 'string' ? r.modified : new Date(0).toISOString(),
Binary file not shown.