// Mobile-connector "Mobile devices" console (page_id `devices`). // // Lists every paired device with its state and bound user, and lets an admin // reassign a device to another user (`POST /devices/bind`) or revoke it // (`POST /devices/revoke`). The user directory for the reassign dropdown comes // from the host `/api/users` (the fragment runs with the admin's session). // Default-exports the element class; the host registers it. import { html, nothing } from 'lit'; import { MobileBase, jf, ago, deviceLabel, t } from './common.js'; const P = 'plugin.mobile-connector'; export default class MobileDevicesPage extends MobileBase { static get properties() { return { _devices: { state: true }, // [] | null (loading) _users: { state: true }, // [{id, username, display_name}] _error: { state: true }, _pick: { state: true }, // { [pubkey]: user_id } reassign selections }; } constructor() { super(); this._devices = null; this._users = []; this._error = null; this._pick = {}; this._poll = null; } connectedCallback() { super.connectedCallback(); this._load(); this._poll = setInterval(() => this._load(true), 5000); } disconnectedCallback() { super.disconnectedCallback(); if (this._poll) { clearInterval(this._poll); this._poll = null; } } async _load(quiet = false) { if (!quiet) this._error = null; try { const [d, u] = await Promise.all([ jf(`${this.api}/devices`), this._users.length ? Promise.resolve({ list: this._users }) : jf('/api/users').then(list => ({ list })), ]); this._devices = d.devices || []; if (u.list) this._users = u.list; } catch (e) { if (!quiet) this._error = e.message; } } _userName(id) { const u = this._users.find(x => x.id === id); return u ? (u.display_name || u.username) : id; } async _bind(pubkey) { const user_id = this._pick[pubkey]; if (!user_id) return; try { await jf(`${this.api}/devices/bind`, { method: 'POST', body: JSON.stringify({ pubkey, user_id }) }); await this._load(); } catch (e) { this._error = e.message; } } async _revoke(pubkey) { if (!confirm(t(`${P}.devices.revoke_confirm`))) return; try { await jf(`${this.api}/devices/revoke`, { method: 'POST', body: JSON.stringify({ pubkey }) }); await this._load(); } catch (e) { this._error = e.message; } } render() { const loading = this._devices === null && !this._error; return html`
${t(`${P}.devices.empty`)}
${t(`${P}.devices.empty_hint`)}
| ${t(`${P}.devices.col_device`)} | ${t(`${P}.devices.col_state`)} | ${t(`${P}.devices.col_bound`)} | ${t(`${P}.devices.col_last_seen`)} | ${t(`${P}.devices.col_actions`)} |
|---|