hvac: add gateway delete (retire the old Modbus gateway config)
There was no way to remove an mhi_gateways row either, alongside the already-fixed device-delete gap — exposed by the same Modbus->MQTT switchover. Adds DELETE /api/mhi-gateways/:id (manage_devices cap) and a 'Delete gateway' button. Devices referencing the gateway are NOT deleted (mhi_gateway_id just goes NULL per the existing ON DELETE SET NULL FK) — the confirm dialog says so and points at the separate device-delete flow for retiring the stale mhi_modbus rows too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7ce95a31da
commit
d7cbb0c452
3 changed files with 37 additions and 2 deletions
|
|
@ -54,6 +54,19 @@ export async function mhiGatewayRoutes(app) {
|
||||||
return rows[0]
|
return rows[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// DELETE /api/mhi-gateways/:id — remove a gateway config entirely. Main use:
|
||||||
|
// retiring a gateway after it's switched to native MQTT (see lib/mqtt.js) and
|
||||||
|
// its Modbus register-map config is no longer needed. Devices that reference
|
||||||
|
// this gateway (device_type='mhi_modbus') are NOT deleted — mhi_gateway_id
|
||||||
|
// just goes NULL (ON DELETE SET NULL) — delete those rows separately via
|
||||||
|
// DELETE /api/devices/:id if they're being retired too.
|
||||||
|
app.delete('/api/mhi-gateways/:id', { preHandler: requireCap('manage_devices') }, async (req, reply) => {
|
||||||
|
const { rows } = await pool.query('SELECT id FROM mhi_gateways WHERE id = $1', [req.params.id])
|
||||||
|
if (!rows.length) return reply.status(404).send({ error: 'Gateway not found' })
|
||||||
|
await pool.query('DELETE FROM mhi_gateways WHERE id = $1', [req.params.id])
|
||||||
|
return { ok: true }
|
||||||
|
})
|
||||||
|
|
||||||
// POST /api/mhi-gateways/:id/test-connection — live Modbus read of the
|
// POST /api/mhi-gateways/:id/test-connection — live Modbus read of the
|
||||||
// gateway comm status register (same check as scripts/test-modbus-connection.py)
|
// gateway comm status register (same check as scripts/test-modbus-connection.py)
|
||||||
app.post('/api/mhi-gateways/:id/test-connection', { preHandler: requireCap('manage_devices') }, async (req, reply) => {
|
app.post('/api/mhi-gateways/:id/test-connection', { preHandler: requireCap('manage_devices') }, async (req, reply) => {
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,9 @@ export function updateMhiGateway(id: number, body: Partial<{ name: string; host:
|
||||||
export function testMhiGatewayConnection(id: number): Promise<{ ok: boolean; note?: string; error?: string }> {
|
export function testMhiGatewayConnection(id: number): Promise<{ ok: boolean; note?: string; error?: string }> {
|
||||||
return request(`/mhi-gateways/${id}/test-connection`, { method: 'POST', body: JSON.stringify({}) })
|
return request(`/mhi-gateways/${id}/test-connection`, { method: 'POST', body: JSON.stringify({}) })
|
||||||
}
|
}
|
||||||
|
export function deleteMhiGateway(id: number): Promise<{ ok: boolean }> {
|
||||||
|
return request(`/mhi-gateways/${id}`, { method: 'DELETE' })
|
||||||
|
}
|
||||||
export async function importMhiRegisterMap(id: number, file: File): Promise<MhiGateway> {
|
export async function importMhiRegisterMap(id: number, file: File): Promise<MhiGateway> {
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
form.append('file', file)
|
form.append('file', file)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Plus, Wifi, WifiOff, Upload, Loader2 } from 'lucide-react'
|
import { Plus, Wifi, WifiOff, Upload, Loader2, Trash2 } from 'lucide-react'
|
||||||
import type { Zone, MhiGateway } from '../types'
|
import type { Zone, MhiGateway } from '../types'
|
||||||
import {
|
import {
|
||||||
fetchMhiGateways, createMhiGateway, testMhiGatewayConnection, importMhiRegisterMap, assignMhiUnit,
|
fetchMhiGateways, createMhiGateway, testMhiGatewayConnection, importMhiRegisterMap, assignMhiUnit, deleteMhiGateway,
|
||||||
} from '../api'
|
} from '../api'
|
||||||
|
|
||||||
// Gateway configuration + MAPS register-map import for MHI aircon units (manual
|
// Gateway configuration + MAPS register-map import for MHI aircon units (manual
|
||||||
|
|
@ -65,6 +65,22 @@ export default function GatewaysPanel({ zones, onAssigned }: { zones: Zone[]; on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleDelete(gw: MhiGateway) {
|
||||||
|
if (!confirm(
|
||||||
|
`Delete gateway "${gw.name}"? This removes its connection config and register-map import.` +
|
||||||
|
(gw.assigned_count > 0 ? ` ${gw.assigned_count} assigned device(s) will be unlinked from it (not deleted) — ` +
|
||||||
|
'if this gateway was switched to native MQTT, remove those Modbus device rows separately in Devices.' : '')
|
||||||
|
)) return
|
||||||
|
setError(''); setMsg('')
|
||||||
|
try {
|
||||||
|
await deleteMhiGateway(gw.id)
|
||||||
|
setMsg('Gateway deleted.')
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
setError(e instanceof Error ? e.message : 'Delete failed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleImport(id: number, file: File | undefined) {
|
async function handleImport(id: number, file: File | undefined) {
|
||||||
if (!file) return
|
if (!file) return
|
||||||
setImportingId(id); setError(''); setMsg('')
|
setImportingId(id); setError(''); setMsg('')
|
||||||
|
|
@ -170,6 +186,9 @@ export default function GatewaysPanel({ zones, onAssigned }: { zones: Zone[]; on
|
||||||
onChange={e => { handleImport(gw.id, e.target.files?.[0]); e.target.value = '' }}
|
onChange={e => { handleImport(gw.id, e.target.files?.[0]); e.target.value = '' }}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<button className="btn btn-sm btn-danger" onClick={() => handleDelete(gw)}>
|
||||||
|
<Trash2 size={13} strokeWidth={1.75} /> Delete gateway
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue