feat: add datapoint delete, show emoji icons in preview
- DELETE /api/datapoints/:id endpoint + frontend button - Preview shows emoji symbols instead of [icon] text Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4964a2e8ab
commit
8a5031649a
@ -49,6 +49,21 @@ interface EpaperPreviewProps {
|
||||
|
||||
const SCALE = 0.6;
|
||||
|
||||
const ICON_SYMBOLS: Record<string, string> = {
|
||||
thermometer: '🌡',
|
||||
droplet: '💧',
|
||||
wind: '🌬',
|
||||
pressure: '⏱',
|
||||
sun: '☀',
|
||||
bolt: '⚡',
|
||||
gauge: '📊',
|
||||
wifi: '📶',
|
||||
battery: '🔋',
|
||||
check: '✅',
|
||||
warning: '⚠',
|
||||
clock: '🕐',
|
||||
};
|
||||
|
||||
export default function EpaperPreview({ layoutId, elements, layoutWidth = 800, layoutHeight = 480 }: EpaperPreviewProps) {
|
||||
const [liveElements, setLiveElements] = useState<DisplayApiElement[] | null>(null);
|
||||
const [displayId, setDisplayId] = useState<number | null>(null);
|
||||
@ -170,7 +185,7 @@ export default function EpaperPreview({ layoutId, elements, layoutWidth = 800, l
|
||||
display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
|
||||
}}>
|
||||
<div style={{ fontSize: fontSize * 0.45, color: '#555', textTransform: 'uppercase', letterSpacing: 0.5 }}>
|
||||
{el.icon ? `[${el.icon}] ` : ''}{el.label || ''}
|
||||
{el.icon ? (ICON_SYMBOLS[el.icon] || el.icon) + ' ' : ''}{el.label || ''}
|
||||
</div>
|
||||
<div style={{ fontSize, fontWeight: 'bold', textAlign: 'right' }}>
|
||||
{el.value ?? '—'} <span style={{ fontSize: fontSize * 0.5, color: '#555' }}>{el.unit || ''}</span>
|
||||
|
||||
@ -40,6 +40,16 @@ export default function Datapoints() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete(id: number) {
|
||||
if (!confirm('Datenpunkt wirklich loeschen?')) return;
|
||||
try {
|
||||
await api.del(`/api/datapoints/${id}`);
|
||||
load();
|
||||
} catch (e) {
|
||||
setError((e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-6">Datenpunkte</h2>
|
||||
@ -55,11 +65,12 @@ export default function Datapoints() {
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Einheit</th>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Quelle</th>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Status</th>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-100">
|
||||
{datapoints.length === 0 && (
|
||||
<tr><td colSpan={6} className="px-4 py-6 text-center text-gray-400">Keine Datenpunkte vorhanden</td></tr>
|
||||
<tr><td colSpan={7} className="px-4 py-6 text-center text-gray-400">Keine Datenpunkte vorhanden</td></tr>
|
||||
)}
|
||||
{datapoints.map((dp) => (
|
||||
<tr key={dp.id} className="hover:bg-gray-50">
|
||||
@ -83,6 +94,9 @@ export default function Datapoints() {
|
||||
</td>
|
||||
<td className="px-4 py-2 text-gray-500 text-xs">{dp.source_type}</td>
|
||||
<td className="px-4 py-2"><StatusBadge status={dp.status} /></td>
|
||||
<td className="px-4 py-2">
|
||||
<button onClick={() => handleDelete(dp.id)} className="text-red-400 hover:text-red-600 text-xs">Loeschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
getAllDatapoints,
|
||||
getDatapointById,
|
||||
updateDatapoint,
|
||||
deleteDatapoint,
|
||||
} from '../../modules/datapoints/datapoint-manager';
|
||||
|
||||
const router = Router();
|
||||
@ -38,4 +39,15 @@ router.put('/:id', (req, res): void => {
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/datapoints/:id
|
||||
router.delete('/:id', (req, res): void => {
|
||||
try {
|
||||
const deleted = deleteDatapoint(parseInt(req.params.id));
|
||||
if (!deleted) { res.status(404).json({ error: 'Datapoint not found' }); return; }
|
||||
res.status(204).send();
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: (err as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@ -118,6 +118,12 @@ export function createDatapointFromPg(
|
||||
return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint;
|
||||
}
|
||||
|
||||
export function deleteDatapoint(id: number): boolean {
|
||||
const db = getDb();
|
||||
const result = db.prepare('DELETE FROM datapoints WHERE id = ?').run(id);
|
||||
return (result.changes as number) > 0;
|
||||
}
|
||||
|
||||
export function getDatapointByTopicId(topicId: number): Datapoint | undefined {
|
||||
const db = getDb();
|
||||
return db
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user