portal: multi-line topic scope input + 'Add topic' on existing MQTT clients
Matches settings' new multi-topic-per-client support: the create form's Topic scope field is now a textarea (one pattern per line), the list shows all of a client's scopes, and a '+ Topic' button lets an admin grant an existing client more topic access without recreating it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
411911c4c8
commit
06690f0581
1 changed files with 29 additions and 4 deletions
|
|
@ -997,6 +997,19 @@ function MqttClientsTab() {
|
||||||
if (res.ok) load()
|
if (res.ok) load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addTopic(c: MqttClient) {
|
||||||
|
const topic = prompt(`Add a topic scope to "${c.name}" (e.g. hvac/mhi/#) — existing scopes are kept:`)
|
||||||
|
if (!topic || !topic.trim()) return
|
||||||
|
const res = await fetch(`/settings/api/mqtt-clients/${c.id}`, {
|
||||||
|
method: 'PATCH', credentials: 'include',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ add_topic_scope: topic.trim() }),
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (!res.ok) { alert(data.error || 'Failed to add topic'); return }
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
function copyPassword() {
|
function copyPassword() {
|
||||||
if (!created) return
|
if (!created) return
|
||||||
navigator.clipboard.writeText(created.password)
|
navigator.clipboard.writeText(created.password)
|
||||||
|
|
@ -1040,9 +1053,12 @@ function MqttClientsTab() {
|
||||||
placeholder="e.g. Kitchen Flash Reader" style={inputStyle} />
|
placeholder="e.g. Kitchen Flash Reader" style={inputStyle} />
|
||||||
</label>
|
</label>
|
||||||
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.3rem' }}>
|
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.3rem' }}>
|
||||||
<span style={{ fontSize: '0.78rem', fontWeight: 600, color: 'var(--text-mid)' }}>Topic scope</span>
|
<span style={{ fontSize: '0.78rem', fontWeight: 600, color: 'var(--text-mid)' }}>
|
||||||
<input value={topicScope} onChange={e => setTopicScope(e.target.value)}
|
Topic scope
|
||||||
placeholder="e.g. utilities/kitchen-meter/# or shellies/#" style={{ ...inputStyle, fontFamily: 'monospace' }} />
|
<span style={{ fontWeight: 400, color: 'var(--text-mid)' }}> — one per line if it needs more than one</span>
|
||||||
|
</span>
|
||||||
|
<textarea value={topicScope} onChange={e => setTopicScope(e.target.value)} rows={2}
|
||||||
|
placeholder={'e.g. shellies/#\nhvac/mhi/#'} style={{ ...inputStyle, fontFamily: 'monospace', resize: 'vertical' }} />
|
||||||
</label>
|
</label>
|
||||||
<div style={{ display: 'flex', gap: '1.5rem' }}>
|
<div style={{ display: 'flex', gap: '1.5rem' }}>
|
||||||
<label style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', fontSize: '0.85rem', color: 'var(--text-dark)' }}>
|
<label style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', fontSize: '0.85rem', color: 'var(--text-dark)' }}>
|
||||||
|
|
@ -1143,13 +1159,22 @@ function MqttClientsTab() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: '0.72rem', color: 'var(--text-mid)', fontFamily: 'monospace' }}>
|
<div style={{ fontSize: '0.72rem', color: 'var(--text-mid)', fontFamily: 'monospace' }}>
|
||||||
{c.topic_scope}
|
{c.topic_scope.split('\n').join(', ')}
|
||||||
<span style={{ marginLeft: '0.6rem', fontFamily: 'sans-serif' }}>
|
<span style={{ marginLeft: '0.6rem', fontFamily: 'sans-serif' }}>
|
||||||
{[c.can_publish && 'publish', c.can_subscribe && 'subscribe'].filter(Boolean).join(' + ')}
|
{[c.can_publish && 'publish', c.can_subscribe && 'subscribe'].filter(Boolean).join(' + ')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flexShrink: 0, display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
|
<div style={{ flexShrink: 0, display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
|
||||||
|
{c.active && (
|
||||||
|
<button onClick={() => addTopic(c)} title="Add another topic scope to this client" style={{
|
||||||
|
background: 'transparent', color: 'var(--text-mid)',
|
||||||
|
border: '1px solid var(--card-border)', borderRadius: '6px',
|
||||||
|
padding: '0.35rem 0.85rem', fontSize: '0.78rem', fontWeight: 600, cursor: 'pointer',
|
||||||
|
}}>
|
||||||
|
+ Topic
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{c.active ? (
|
{c.active ? (
|
||||||
<button onClick={() => revoke(c)} style={{
|
<button onClick={() => revoke(c)} style={{
|
||||||
background: 'transparent', color: 'var(--text-mid)',
|
background: 'transparent', color: 'var(--text-mid)',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue