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) <noreply@anthropic.com>
This commit is contained in:
hailin 2026-04-05 01:43:16 -07:00
parent 0c0592b511
commit 28ebbbfb82
2 changed files with 27 additions and 28 deletions

View File

@ -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);
}

View File

@ -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<string, any>[] = []): 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<string, any>[] = [];
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([]);
}