HeatTransPlan / frontend /src /utils /csvExport.ts
drzg15's picture
Initial code commit with LFS for binaries
c993983
/**
* Utility to export the current project state to a CSV file.
* Synchronized with the StreamDataTable and ActionBar.
*/
import type { ProjectState } from '../types/project';
import { extractStreamInfo } from './streamInfo';
export function exportProjectToCsv(state: ProjectState) {
const rows: string[][] = [];
const header = [
'Process',
'Subprocess',
'Stream Name',
'Type',
'Tin',
'Tout',
'ṁ',
'cp',
'CP',
'Q (kW)',
'Lat',
'Lon',
'Hours',
'Water In',
'Water Out',
'Density',
'Pressure',
'Notes',
];
rows.push(header);
(state.proc_groups || []).forEach((subIdxs, gIdx) => {
const gName = state.proc_group_names?.[gIdx] || `Process ${gIdx + 1}`;
const gCoord = state.proc_group_coordinates?.[gIdx] || {};
subIdxs.forEach((si) => {
const sub = state.processes[si];
if (!sub) return;
const notes = sub.extra_info?.notes || '';
const lat = String(sub.lat || gCoord.lat || '');
const lon = String(sub.lon || gCoord.lon || '');
const hours = sub.hours || gCoord.hours || '';
const water_in = sub.extra_info?.water_content_in || '';
const water_out = sub.extra_info?.water_content_out || '';
const density = sub.extra_info?.density || '';
const pressure = sub.extra_info?.pressure || '';
// Add streams for this subprocess
if (!sub.streams?.length && !sub.children?.length) {
rows.push([gName, sub.name, '', '', '', '', '', '', '', '', lat, lon, hours, water_in, water_out, density, pressure, notes]);
} else {
(sub.streams || []).forEach((s) => {
const si = extractStreamInfo(s as any);
rows.push([
gName,
sub.name,
s.name,
si.type || '',
String(si.tin ?? ''),
String(si.tout ?? ''),
String(si.mdot ?? ''),
String(si.cp ?? ''),
String(si.CP ?? ''),
si.Q ? si.Q.toFixed(1) : '',
lat,
lon,
hours,
String(si.water_in || water_in),
String(si.water_out || water_out),
String(si.density || density),
String(si.pressure || pressure),
notes,
]);
});
// Also add streams for sub-subprocesses (children)
(sub.children || []).forEach((child) => {
const c_notes = child.extra_info?.notes || notes || '';
const c_lat = String(child.lat || sub.lat || gCoord.lat || '');
const c_lon = String(child.lon || sub.lon || gCoord.lon || '');
const c_hours = child.hours || hours || '';
const c_water_in = child.extra_info?.water_content_in || water_in || '';
const c_water_out = child.extra_info?.water_content_out || water_out || '';
const c_density = child.extra_info?.density || density || '';
const c_pressure = child.extra_info?.pressure || pressure || '';
const c_name = `${sub.name}${child.name}`;
if (!(child.streams || []).length) {
rows.push([gName, c_name, '', '', '', '', '', '', '', '', c_lat, c_lon, c_hours, c_water_in, c_water_out, c_density, c_pressure, c_notes]);
} else {
(child.streams || []).forEach((s) => {
const si = extractStreamInfo(s as any);
rows.push([
gName,
c_name,
s.name,
si.type || '',
String(si.tin ?? ''),
String(si.tout ?? ''),
String(si.mdot ?? ''),
String(si.cp ?? ''),
String(si.CP ?? ''),
si.Q ? si.Q.toFixed(1) : '',
c_lat,
c_lon,
c_hours,
String(si.water_in || c_water_in),
String(si.water_out || c_water_out),
String(si.density || c_density),
String(si.pressure || c_pressure),
c_notes,
]);
});
}
});
}
});
});
const csv = rows.map((r) => r.map((c) => `"${c}"`).join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `heattransplan_export_${new Date().toISOString().slice(0, 10)}.csv`;
a.click();
URL.revokeObjectURL(url);
}