From 28ebbbfb82567b9fc2880ebc1ac98c94d69edf1a Mon Sep 17 00:00:00 2001 From: hailin Date: Sun, 5 Apr 2026 01:43:16 -0700 Subject: [PATCH] fix: critical data mapping bugs in useImportData and useCreateChart - useImportData: use dataset_id instead of id from backend response, fetch rows after import, fix column type mapping - useCreateChart: fix bindings mapper to use axis instead of fieldRole, graceful error handling instead of throwing Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/frameworks/hooks/useCreateChart.ts | 11 ++--- .../src/frameworks/hooks/useImportData.ts | 44 ++++++++++--------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/frontend/src/frameworks/hooks/useCreateChart.ts b/frontend/src/frameworks/hooks/useCreateChart.ts index e6c2882..b134c47 100644 --- a/frontend/src/frameworks/hooks/useCreateChart.ts +++ b/frontend/src/frameworks/hooks/useCreateChart.ts @@ -8,17 +8,15 @@ import { addLayoutItem } from '@/adapters/state/redux/layoutSlice'; import { type ChartType } from '@/domain'; import { type ChartInstance } from '@/domain/entities/ChartInstance'; -/** - * Map a backend chart object (snake_case) to frontend ChartInstance (camelCase). - */ function mapBackendChart(raw: any): ChartInstance { return { id: raw.id, type: raw.chart_type ?? raw.type, dataSetId: raw.dataset_id ?? raw.dataSetId, bindings: (raw.bindings ?? []).map((b: any) => ({ - fieldRole: b.field_role ?? b.fieldRole, + axis: b.axis ?? b.field_role ?? b.fieldRole, columnName: b.column_name ?? b.columnName, + aggregation: b.aggregation, })), style: raw.style ?? {}, filters: (raw.filters ?? []).map((f: any) => ({ @@ -43,7 +41,8 @@ export function useCreateChart() { const handleCreate = useCallback( async (chartType?: ChartType) => { if (!activeDataSetId) { - throw new Error('No active dataset. Import data first.'); + setError('请先导入数据集'); + return; } setLoading(true); @@ -58,7 +57,6 @@ export function useCreateChart() { dispatch(addChart(chart)); dispatch(setActiveChart(chart.id)); - // Default position: stack items in a 2-column grid const col = layoutCount % 2; const row = Math.floor(layoutCount / 2); dispatch( @@ -74,7 +72,6 @@ export function useCreateChart() { return chart; } catch (e: any) { setError(e.message ?? 'Failed to create chart'); - throw e; } finally { setLoading(false); } diff --git a/frontend/src/frameworks/hooks/useImportData.ts b/frontend/src/frameworks/hooks/useImportData.ts index 8970d0b..d3a4cb8 100644 --- a/frontend/src/frameworks/hooks/useImportData.ts +++ b/frontend/src/frameworks/hooks/useImportData.ts @@ -8,40 +8,34 @@ import { type DataSet } from '@/domain/entities/DataSet'; import { type ChartSuggestion } from '@/application/dto/ChartSuggestion'; /** - * Map a backend dataset object (snake_case) to the frontend DataSet entity (camelCase). + * Map a backend import result (snake_case) to frontend DataSet entity. + * The import endpoint returns {dataset_id, file_name, columns, row_count, ...} + * We then fetch the full dataset (with rows) from GET /datasets/{id}. */ -function mapBackendDataSet(raw: any): DataSet { +function mapBackendDataSet(raw: any, rows: Record[] = []): DataSet { return { - id: raw.id, + id: raw.dataset_id ?? raw.id ?? '', fileName: raw.file_name ?? raw.fileName ?? '', sheetName: raw.sheet_name ?? raw.sheetName, columns: (raw.columns ?? []).map((col: any) => ({ name: col.name, - type: col.type ?? col.field_type ?? 'string', + type: col.field_type ?? col.type ?? 'text', sampleValues: col.sample_values ?? col.sampleValues ?? [], })), - rows: raw.rows ?? [], - rowCount: raw.row_count ?? raw.rowCount ?? (raw.rows?.length ?? 0), + rows, + rowCount: raw.row_count ?? raw.rowCount ?? rows.length, dataStructure: raw.data_structure ?? raw.dataStructure, createdAt: raw.created_at ?? raw.createdAt ?? new Date().toISOString(), updatedAt: raw.updated_at ?? raw.updatedAt ?? new Date().toISOString(), }; } -/** - * Map a backend chart recommendation (snake_case) to frontend ChartSuggestion. - */ function mapBackendSuggestion(raw: any): ChartSuggestion { return { chartType: raw.chart_type ?? raw.chartType, label: raw.label ?? raw.chart_type ?? '', - isPrimary: raw.is_primary ?? raw.isPrimary ?? false, - defaultBindings: (raw.default_bindings ?? raw.defaultBindings ?? []).map( - (b: any) => ({ - fieldRole: b.field_role ?? b.fieldRole, - columnName: b.column_name ?? b.columnName, - }), - ), + isPrimary: raw.primary ?? raw.is_primary ?? raw.isPrimary ?? false, + defaultBindings: [], }; } @@ -58,21 +52,29 @@ export function useImportData() { try { // Upload file to backend data-service const rawDatasets = await dataServiceClient.importFile(file); - - // The backend may return one or more datasets; take the first const rawDataSet = Array.isArray(rawDatasets) ? rawDatasets[0] : rawDatasets; - const dataSet = mapBackendDataSet(rawDataSet); + const dataSetId = rawDataSet.dataset_id ?? rawDataSet.id; + + // Fetch rows from backend + let rows: Record[] = []; + try { + const rowsResp = await dataServiceClient.getRows(dataSetId, 10000); + rows = rowsResp.rows ?? rowsResp ?? []; + } catch { + // rows fetch failed, continue without + } + + const dataSet = mapBackendDataSet(rawDataSet, rows); dispatch(addDataSet(dataSet)); dispatch(setActiveDataSet(dataSet.id)); - // Request chart suggestions from backend chart-service + // Request chart suggestions try { const rawSuggestions = await chartServiceClient.recommendCharts(dataSet.id); const mapped = (rawSuggestions ?? []).map(mapBackendSuggestion); setSuggestions(mapped); } catch { - // Non-critical: recommendations are optional setSuggestions([]); }