diff --git a/src/Utils/Download.jsx b/src/Utils/Download.jsx index 1ef8501d..e9b77d4d 100644 --- a/src/Utils/Download.jsx +++ b/src/Utils/Download.jsx @@ -79,6 +79,8 @@ function Download(props) { provider_metadata, url_source, core_metadata, + chartData, + reactChartEditorLib, ); zip.file(`${title}.csv`, completeCSVData); @@ -96,6 +98,8 @@ function Download(props) { provider_metadata, url_source, core_metadata, + chartData, + reactChartEditorLib, ); exportCSVFile(csvData, title); }; diff --git a/src/Utils/utils.js b/src/Utils/utils.js index 82d11d34..d8ec4a46 100644 --- a/src/Utils/utils.js +++ b/src/Utils/utils.js @@ -51,16 +51,63 @@ export const generateOriginalCSV = ( provider_metadata, url_source, core_metadata, + chartData, + reactChartEditorLib, ) => { let array = []; let readme = provider_metadata?.readme ? [provider_metadata?.readme] : []; + const hasDataSources = + dataSources && + Object.keys(dataSources).some( + (key) => Array.isArray(dataSources[key]) && dataSources[key].length > 0, + ); - Object.entries(dataSources).forEach(([key, items]) => { - items.forEach((item, index) => { - if (!array[index]) array[index] = {}; - array[index][key] = item; + if (hasDataSources) { + Object.entries(dataSources).forEach(([key, items]) => { + items.forEach((item, index) => { + if (!array[index]) array[index] = {}; + array[index][key] = item; + }); }); - }); + } else if (chartData?.data && Array.isArray(chartData.data)) { + // Extract data from traces when dataSources is empty + const allTraceData = []; + for (const trace of chartData.data) { + const traceData = processTraceData( + trace, + dataSources || {}, + reactChartEditorLib, + ); + allTraceData.push(traceData); + } + // Process all trace data + if ( + allTraceData.length > 0 && + !allTraceData.every((data) => data.length === 0) + ) { + const maxLength = + allTraceData.length > 0 + ? Math.max(...allTraceData.map((data) => data.length)) + : 0; + + for (let i = 0; i < maxLength; i++) { + if (!array[i]) array[i] = {}; + + allTraceData.forEach((traceData) => { + if (traceData[i]) { + Object.keys(traceData[i]).forEach((key) => { + if ( + traceData[i][key] !== null && + traceData[i][key] !== undefined + ) { + array[i][key] = traceData[i][key]; + } + }); + } + }); + } + } + } const metadataFlags = getMetadataFlags(core_metadata); const metadataArrays = processMetadataArrays(core_metadata, metadataFlags); diff --git a/src/helpers/csvString.js b/src/helpers/csvString.js index 8da36880..46287a5f 100644 --- a/src/helpers/csvString.js +++ b/src/helpers/csvString.js @@ -240,67 +240,105 @@ function processTraceData(trace, dataSources, reactChartEditorLib) { const usedColumns = new Set(); const { getAttrsPath, constants, getSrcAttr } = reactChartEditorLib; + const hasDataSources = + dataSources && + Object.keys(dataSources).some( + (key) => Array.isArray(dataSources[key]) && dataSources[key].length > 0, + ); + if (hasDataSources) { + // Get all data attributes from constants.TRACE_SRC_ATTRIBUTES + const traceDataAttrs = getAttrsPath(trace, constants.TRACE_SRC_ATTRIBUTES); + + // For each data attribute, get the corresponding src attribute using getSrcAttr + Object.entries(traceDataAttrs).forEach(([dataAttrPath, dataValue]) => { + const srcAttr = getSrcAttr(trace, dataAttrPath); + + if (srcAttr && srcAttr.value && dataSources[srcAttr.value]) { + usedColumns.add(srcAttr.value); + } + }); - // Get all data attributes from constants.TRACE_SRC_ATTRIBUTES - const traceDataAttrs = getAttrsPath(trace, constants.TRACE_SRC_ATTRIBUTES); - - // For each data attribute, get the corresponding src attribute using getSrcAttr - Object.entries(traceDataAttrs).forEach(([dataAttrPath, dataValue]) => { - const srcAttr = getSrcAttr(trace, dataAttrPath); + // Add columns from transforms + if (trace.transforms && Array.isArray(trace.transforms)) { + trace.transforms.forEach((transform) => { + if (transform.targetsrc && dataSources[transform.targetsrc]) { + usedColumns.add(transform.targetsrc); + } + }); + } - if (srcAttr && srcAttr.value && dataSources[srcAttr.value]) { - usedColumns.add(srcAttr.value); + // If no specific columns found, use all available data sources + if (usedColumns.size === 0) { + Object.keys(dataSources).forEach((key) => { + if (Array.isArray(dataSources[key])) { + usedColumns.add(key); + } + }); } - }); - // Add columns from transforms - if (trace.transforms && Array.isArray(trace.transforms)) { - trace.transforms.forEach((transform) => { - if (transform.targetsrc && dataSources[transform.targetsrc]) { - usedColumns.add(transform.targetsrc); - } - }); - } + const maxLength = Math.max( + ...Array.from(usedColumns).map((col) => + dataSources[col] ? dataSources[col].length : 0, + ), + ); + + for (let i = 0; i < maxLength; i++) { + const row = {}; + usedColumns.forEach((col) => { + if (dataSources[col] && dataSources[col][i] !== undefined) { + row[col] = dataSources[col][i]; + } + }); + processedData.push(row); + } - // If no specific columns found, use all available data sources - if (usedColumns.size === 0) { - Object.keys(dataSources).forEach((key) => { - if (Array.isArray(dataSources[key])) { - usedColumns.add(key); - } + // Ensure all rows have the same columns (fill missing columns with empty values) + const allColumns = new Set(); + processedData.forEach((row) => { + Object.keys(row).forEach((col) => allColumns.add(col)); }); - } - const maxLength = Math.max( - ...Array.from(usedColumns).map((col) => - dataSources[col] ? dataSources[col].length : 0, - ), - ); - - for (let i = 0; i < maxLength; i++) { - const row = {}; - usedColumns.forEach((col) => { - if (dataSources[col] && dataSources[col][i] !== undefined) { - row[col] = dataSources[col][i]; - } + processedData.forEach((row) => { + allColumns.forEach((col) => { + if (!(col in row)) { + row[col] = ''; + } + }); }); - processedData.push(row); - } + } else { + const traceDataAttrs = getAttrsPath(trace, constants.TRACE_SRC_ATTRIBUTES); - // Ensure all rows have the same columns (fill missing columns with empty values) - const allColumns = new Set(); - processedData.forEach((row) => { - Object.keys(row).forEach((col) => allColumns.add(col)); - }); + // Extract data directly from trace properties + const dataColumns = new Set(); + const traceDataValues = {}; - processedData.forEach((row) => { - allColumns.forEach((col) => { - if (!(col in row)) { - row[col] = ''; + Object.entries(traceDataAttrs).forEach(([dataAttrPath, dataValue]) => { + if (dataValue && Array.isArray(dataValue)) { + const columnName = dataAttrPath.replace(/\./g, '_'); + dataColumns.add(columnName); + traceDataValues[columnName] = dataValue; } }); - }); - + if (dataColumns.size > 0) { + const maxLength = Math.max( + ...Array.from(dataColumns).map((col) => + traceDataValues[col] ? traceDataValues[col].length : 0, + ), + ); + + for (let i = 0; i < maxLength; i++) { + const row = {}; + dataColumns.forEach((col) => { + if (traceDataValues[col] && traceDataValues[col][i] !== undefined) { + row[col] = traceDataValues[col][i]; + } + }); + if (Object.keys(row).length > 0) { + processedData.push(row); + } + } + } + } // Apply transforms if they exist if (trace.transforms && Array.isArray(trace.transforms)) { trace.transforms.forEach((transform) => {