diff --git a/frontend/src/components/ReportEditor/ConfigPanel.jsx b/frontend/src/components/ReportEditor/ConfigPanel.jsx index 3a1b6b7..bf11273 100644 --- a/frontend/src/components/ReportEditor/ConfigPanel.jsx +++ b/frontend/src/components/ReportEditor/ConfigPanel.jsx @@ -1,9 +1,11 @@ import React, { useState } from 'react'; import { useReportData } from './DataContext'; +import { useNomenclatureData } from '../../contexts/NomenclatureDataContext'; import './ConfigPanel.css'; function ConfigPanel({ apiEndpoint, onApiEndpointChange, isOpen, onClose }) { const { reportData, isLoading, error, fetchData, setData, clearData } = useReportData(); + const { definitions, entries } = useNomenclatureData(); const [localEndpoint, setLocalEndpoint] = useState(apiEndpoint || ''); const [manualDataInput, setManualDataInput] = useState(''); const [showManualInput, setShowManualInput] = useState(false); @@ -84,153 +86,49 @@ function ConfigPanel({ apiEndpoint, onApiEndpointChange, isOpen, onClose }) { className="config-button" onClick={() => { if (!showManualInput && !manualDataInput) { - // Pre-fill with example data when opening for the first time - setManualDataInput(JSON.stringify({ - "reportTitle": "Weight Measurements Report", - "reportDate": "2026-01-26", - "owner": { - "name": "John Doe", - "contact": { - "phone": "555-1234", - "email": "john.doe@example.com" - } - }, - "vessel": { - "id": "ABC123", - "type": "Truck", - "capacity": 5000 - }, - "measurements": [ - { - "id": 1, - "weight": 1500, - "timestamp": "2026-01-26T08:00:00", - "operator": "Alice", - "items": [ - { "name": "Box A", "quantity": 10, "unitWeight": 50 }, - { "name": "Box B", "quantity": 20, "unitWeight": 25 } - ] - }, - { - "id": 2, - "weight": 1650, - "timestamp": "2026-01-26T09:30:00", - "operator": "Bob", - "items": [ - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Pallet D", "quantity": 15, "unitWeight": 30 } - ] - }, - { - "id": 3, - "weight": 1820, - "timestamp": "2026-01-26T11:15:00", - "operator": "Charlie", - "items": [ - { "name": "Container E", "quantity": 8, "unitWeight": 75 } - ] - }, - { - "id": 4, - "weight": 41820, - "timestamp": "2026-01-26T11:15:00", - "operator": "4Charlie", - "items": [ - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Crate C", "quantity": 5, "unitWeight": 100 }, - { "name": "Container E", "quantity": 8, "unitWeight": 75 } - ] + // Build extra sample from actual nomenclature definitions + // Lookup fields become nested objects with all their sub-fields + const extra = {}; + for (const def of Object.values(definitions)) { + if (def.kind === 'lookup') { + const activeEntries = (entries[def.code] || []).filter(e => e.is_active); + const firstEntry = activeEntries[0]; + if (firstEntry?.data && Object.keys(firstEntry.data).length > 0) { + // Use actual field values from the first active entry + extra[def.name] = { ...firstEntry.data }; + } else if (def.fields?.length > 0) { + // No entries yet — build placeholders from field definitions + const sample = {}; + for (const field of def.fields) { + if (field.field_type === 'number') sample[field.key] = 0; + else if (field.field_type === 'bool') sample[field.key] = false; + else sample[field.key] = 'Sample'; + } + extra[def.name] = sample; + } else { + extra[def.name] = {}; } - - ], - "summary": { - "totalMeasurements": 3, - "averageWeight": 1656.67, - "maxWeight": 1820, - "minWeight": 1500 + } else { + extra[def.name] = 'Sample Text'; + } + } + setManualDataInput(JSON.stringify({ + vehicle: { + vehicle_number: 'АА1234ВВ', + trailer1_number: 'ПВ5678ВВ', + trailer2_number: null, + driver_pid: '123456789', + tare: 8500, + tare_date: '2026-02-22T08:00:00Z', + tare_user_name: 'operator', + gross: 28500, + gross_date: '2026-02-22T10:30:00Z', + gross_user_name: 'operator', + net: 20000, + net_date: '2026-02-22T10:30:00Z', + net_user_name: 'operator', + doc_number: '2026-001', + extra, } }, null, 2)); } diff --git a/frontend/src/components/ReportEditor/utils/dataResolver.js b/frontend/src/components/ReportEditor/utils/dataResolver.js index 3431b08..f37d5be 100644 --- a/frontend/src/components/ReportEditor/utils/dataResolver.js +++ b/frontend/src/components/ReportEditor/utils/dataResolver.js @@ -91,12 +91,14 @@ export function getAvailableFields(obj, prefix = '') { const fields = []; for (const key of Object.keys(obj)) { + // Skip raw id/FK fields — only human-readable fields are useful for binding + if (key === 'id' || (key.endsWith('_user') && !key.endsWith('_user_name'))) continue; + const fullPath = prefix ? `${prefix}.${key}` : key; const value = obj[key]; if (typeof value === 'object' && value !== null && !Array.isArray(value)) { - // Nested object - add this key and recurse - fields.push(fullPath); + // Nested object - recurse into children only (don't add the object itself) fields.push(...getAvailableFields(value, fullPath)); } else { // Primitive or array - add this key