added docker-compose for linux
This commit is contained in:
@@ -8,6 +8,30 @@ import { useElementSelection } from './hooks/useElementSelection';
|
||||
import { getElementStyle, isTextMultiLine, getTextWhiteSpace } from './utils/elementUtils';
|
||||
import './elements.css';
|
||||
|
||||
function formatValue(raw, dataType) {
|
||||
if (raw === '' || raw === null || raw === undefined) return '';
|
||||
switch (dataType) {
|
||||
case 'number': {
|
||||
const n = Number(raw);
|
||||
return isNaN(n) ? '' : String(n);
|
||||
}
|
||||
case 'date': {
|
||||
const d = new Date(raw);
|
||||
return isNaN(d.getTime()) ? '' : d.toLocaleDateString();
|
||||
}
|
||||
case 'time': {
|
||||
const d = new Date(raw);
|
||||
return isNaN(d.getTime()) ? '' : d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
case 'datetime': {
|
||||
const d = new Date(raw);
|
||||
return isNaN(d.getTime()) ? '' : d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
default:
|
||||
return String(raw);
|
||||
}
|
||||
}
|
||||
|
||||
function DBTextField({
|
||||
element,
|
||||
isSelected,
|
||||
@@ -51,12 +75,16 @@ function DBTextField({
|
||||
};
|
||||
|
||||
// Resolve data value
|
||||
const displayContent = previewMode
|
||||
const rawValue = previewMode
|
||||
? resolveDBTextValue(reportData, element.objectKey, element.fieldPath, parentBandId, { currentBandData })
|
||||
: parentBandId
|
||||
? `{${element.fieldPath}}` // Inside band: show field only
|
||||
: `{${element.objectKey}.${element.fieldPath}}`; // Outside band: show object.field
|
||||
|
||||
const displayContent = previewMode
|
||||
? formatValue(rawValue, element.dataType || 'general')
|
||||
: rawValue;
|
||||
|
||||
// Check if data is resolved
|
||||
// If inside a band, only fieldPath is required; otherwise both objectKey and fieldPath are required
|
||||
const isUnresolved = parentBandId
|
||||
@@ -71,7 +99,8 @@ function DBTextField({
|
||||
...getElementStyle(element, charWidth, charHeight),
|
||||
minWidth: `${charWidth}px`,
|
||||
minHeight: `${charHeight}px`,
|
||||
whiteSpace
|
||||
whiteSpace,
|
||||
textAlign: element.alignment || 'left',
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -237,6 +237,32 @@ function ObjectInspector({ element, onUpdate, allElements = [] }) {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="property-row">
|
||||
<label>Data Type:</label>
|
||||
<select
|
||||
value={element.dataType || 'general'}
|
||||
onChange={(e) => handleChange('dataType', e.target.value)}
|
||||
>
|
||||
<option value="general">General</option>
|
||||
<option value="number">Number</option>
|
||||
<option value="date">Date</option>
|
||||
<option value="time">Time</option>
|
||||
<option value="datetime">Date & Time</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Alignment:</label>
|
||||
<select
|
||||
value={element.alignment || 'left'}
|
||||
onChange={(e) => handleChange('alignment', e.target.value)}
|
||||
>
|
||||
<option value="left">Left</option>
|
||||
<option value="center">Center</option>
|
||||
<option value="right">Right</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { DataProvider } from './DataContext';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { DataProvider, useReportData } from './DataContext';
|
||||
import { BandProvider } from './BandContext';
|
||||
import Toolbar from './Toolbar';
|
||||
import EditorCanvas from './EditorCanvas';
|
||||
@@ -33,6 +34,38 @@ function ReportEditorContent() {
|
||||
const [savedReports, setSavedReports] = useState([]);
|
||||
const [loadingReports, setLoadingReports] = useState(false);
|
||||
|
||||
// Auto-load report and vehicle data passed via router state
|
||||
const location = useLocation();
|
||||
const { setData } = useReportData();
|
||||
|
||||
useEffect(() => {
|
||||
const { reportName, vehicleData } = location.state || {};
|
||||
if (!reportName) return;
|
||||
|
||||
api.get('/api/reports/').then(res => {
|
||||
const reports = res.data.results || res.data;
|
||||
const found = reports.find(r => r.name === reportName);
|
||||
if (found) {
|
||||
setReport({
|
||||
name: found.name,
|
||||
pageWidth: found.page_width,
|
||||
pageHeight: found.page_height,
|
||||
apiEndpoint: found.api_endpoint || '',
|
||||
elements: found.elements || [],
|
||||
});
|
||||
setReportId(found.id);
|
||||
} else {
|
||||
// Report doesn't exist yet — pre-fill the name so Save creates it
|
||||
setReport(prev => ({ ...prev, name: reportName }));
|
||||
}
|
||||
if (vehicleData) {
|
||||
setData(vehicleData);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('Failed to auto-load report:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleAddElement = (element) => {
|
||||
setReport(prev => {
|
||||
// Check if the new element is positioned inside a band
|
||||
|
||||
@@ -113,12 +113,14 @@ export class Element {
|
||||
* Database-bound text field element
|
||||
*/
|
||||
export class DBTextElement extends Element {
|
||||
constructor({ id, x, y, width = 10, height = 1, objectKey = '', fieldPath = '' }) {
|
||||
constructor({ id, x, y, width = 10, height = 1, objectKey = '', fieldPath = '', dataType = 'general', alignment = 'left' }) {
|
||||
super({ id, type: 'dbtext', x, y });
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.objectKey = objectKey;
|
||||
this.fieldPath = fieldPath;
|
||||
this.dataType = dataType;
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
getBounds() {
|
||||
@@ -148,7 +150,9 @@ export class DBTextElement extends Element {
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
objectKey: this.objectKey,
|
||||
fieldPath: this.fieldPath
|
||||
fieldPath: this.fieldPath,
|
||||
dataType: this.dataType,
|
||||
alignment: this.alignment
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user