fix: add topic selection checkbox that auto-creates datapoints
When a user checks a topic checkbox, a datapoint is automatically created and the broker subscribes to that topic for live updates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
086b470860
commit
73179f3040
@ -8,6 +8,7 @@ interface Topic {
|
|||||||
topic: string;
|
topic: string;
|
||||||
last_payload: string | null;
|
last_payload: string | null;
|
||||||
json_path: string | null;
|
json_path: string | null;
|
||||||
|
selected: number;
|
||||||
ignored: number;
|
ignored: number;
|
||||||
discovered_at: string;
|
discovered_at: string;
|
||||||
}
|
}
|
||||||
@ -46,6 +47,15 @@ export default function MqttTopics() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleSelect(id: number, selected: boolean) {
|
||||||
|
try {
|
||||||
|
await api.put(`/api/mqtt/brokers/${brokerId}/topics/${id}`, { selected: selected ? 1 : 0 });
|
||||||
|
load();
|
||||||
|
} catch (e) {
|
||||||
|
setError((e as Error).message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleIgnore(id: number, ignored: number) {
|
async function handleIgnore(id: number, ignored: number) {
|
||||||
try {
|
try {
|
||||||
await api.put(`/api/mqtt/brokers/${brokerId}/topics/${id}`, { ignored: ignored ? 0 : 1 });
|
await api.put(`/api/mqtt/brokers/${brokerId}/topics/${id}`, { ignored: ignored ? 0 : 1 });
|
||||||
@ -100,6 +110,7 @@ export default function MqttTopics() {
|
|||||||
<table className="w-full text-sm">
|
<table className="w-full text-sm">
|
||||||
<thead className="bg-gray-50">
|
<thead className="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase w-10">Aktiv</th>
|
||||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Topic</th>
|
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Topic</th>
|
||||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Letzter Wert</th>
|
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Letzter Wert</th>
|
||||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">JSON-Pfad</th>
|
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">JSON-Pfad</th>
|
||||||
@ -108,10 +119,18 @@ export default function MqttTopics() {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-100">
|
<tbody className="divide-y divide-gray-100">
|
||||||
{filtered.length === 0 && (
|
{filtered.length === 0 && (
|
||||||
<tr><td colSpan={4} className="px-4 py-6 text-center text-gray-400">Keine Topics gefunden</td></tr>
|
<tr><td colSpan={5} className="px-4 py-6 text-center text-gray-400">Keine Topics gefunden</td></tr>
|
||||||
)}
|
)}
|
||||||
{filtered.map((t) => (
|
{filtered.map((t) => (
|
||||||
<tr key={t.id} className="hover:bg-gray-50">
|
<tr key={t.id} className={`hover:bg-gray-50 ${t.selected ? 'bg-green-50' : ''}`}>
|
||||||
|
<td className="px-4 py-2 text-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={!!t.selected}
|
||||||
|
onChange={(e) => handleSelect(t.id, e.target.checked)}
|
||||||
|
className="w-4 h-4 accent-green-500"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
<td className="px-4 py-2 font-mono text-xs text-gray-700">{t.topic}</td>
|
<td className="px-4 py-2 font-mono text-xs text-gray-700">{t.topic}</td>
|
||||||
<td className="px-4 py-2 text-xs text-gray-500 max-w-xs truncate">{t.last_payload ?? '-'}</td>
|
<td className="px-4 py-2 text-xs text-gray-500 max-w-xs truncate">{t.last_payload ?? '-'}</td>
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
|
|||||||
@ -5,6 +5,9 @@ import {
|
|||||||
startDiscovery,
|
startDiscovery,
|
||||||
addManualTopic,
|
addManualTopic,
|
||||||
} from '../../modules/mqtt/topic-discovery';
|
} from '../../modules/mqtt/topic-discovery';
|
||||||
|
import { createDatapointFromMqtt, getDatapointByTopicId } from '../../modules/datapoints/datapoint-manager';
|
||||||
|
import { getConnection } from './../../modules/mqtt/broker-manager';
|
||||||
|
import { getDb } from '../../db/index';
|
||||||
|
|
||||||
const router = Router({ mergeParams: true });
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
@ -21,8 +24,23 @@ router.get('/', (req, res): void => {
|
|||||||
// PUT /api/mqtt/brokers/:brokerId/topics/:id
|
// PUT /api/mqtt/brokers/:brokerId/topics/:id
|
||||||
router.put('/:id', (req, res): void => {
|
router.put('/:id', (req, res): void => {
|
||||||
try {
|
try {
|
||||||
const topic = updateTopic(parseInt(req.params.id), req.body);
|
const topicId = parseInt(req.params.id);
|
||||||
if (!topic) { res.status(404).json({ error: 'Topic not found' }); return; }
|
const topicRow = getDb().prepare('SELECT * FROM mqtt_topics WHERE id = ?').get(topicId) as any;
|
||||||
|
if (!topicRow) { res.status(404).json({ error: 'Topic not found' }); return; }
|
||||||
|
|
||||||
|
const topic = updateTopic(topicId, req.body);
|
||||||
|
|
||||||
|
// If selecting a topic, auto-create a datapoint
|
||||||
|
if (req.body.selected === 1 || req.body.selected === true) {
|
||||||
|
const existing = getDatapointByTopicId(topicId);
|
||||||
|
if (!existing) {
|
||||||
|
createDatapointFromMqtt(topicRow.broker_id, topicId, topicRow.topic);
|
||||||
|
}
|
||||||
|
// Subscribe to the topic on the broker connection
|
||||||
|
const client = getConnection(topicRow.broker_id);
|
||||||
|
if (client?.connected) client.subscribe(topicRow.topic);
|
||||||
|
}
|
||||||
|
|
||||||
res.json(topic);
|
res.json(topic);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ error: (err as Error).message });
|
res.status(500).json({ error: (err as Error).message });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user