000d97fdeb
Add the static HTTP dashboard example and wire in the recent daemon/API polish: CORS-aware API routing, service-install behavior cleanup, safer systemd unit ExecStart quoting, and friendly-name validation for path-safe targeting. Also refresh README/API/roadmap docs, remove the temporary claude observations file, and include the related tests for API/status and daemon validation.
136 lines
4.5 KiB
HTML
136 lines
4.5 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>tvctl HTTP API Dashboard</title>
|
|
<link rel="stylesheet" href="./styles.css">
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>tvctl HTTP API Dashboard</h1>
|
|
<p>Local manual test dashboard for every <code>/v1</code> endpoint.</p>
|
|
</header>
|
|
|
|
<main>
|
|
<section class="panel">
|
|
<h2>Connection</h2>
|
|
<label>
|
|
API Base URL
|
|
<input id="baseUrl" value="http://127.0.0.1:7272/v1" />
|
|
</label>
|
|
<div class="row">
|
|
<button id="pingBtn" type="button">GET /daemon/status</button>
|
|
<button id="listDevicesBtn" type="button">GET /devices</button>
|
|
<button id="discoverBtn" type="button">POST /devices/discover</button>
|
|
</div>
|
|
<p class="hint">Tip: if browser requests fail, enable CORS in tvctl config first.</p>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Device Target</h2>
|
|
<label>
|
|
Known Devices
|
|
<select id="deviceSelect">
|
|
<option value="">(none loaded)</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Manual device UUID or name override
|
|
<input id="targetOverride" placeholder="optional" />
|
|
</label>
|
|
<p class="hint">Device endpoint actions use override when set, otherwise selected device.</p>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Device Endpoints</h2>
|
|
<div class="row">
|
|
<button id="getDeviceBtn" type="button">GET /devices/{id}</button>
|
|
<button id="deleteDeviceBtn" class="danger" type="button">DELETE /devices/{id}</button>
|
|
<button id="getStateBtn" type="button">GET /devices/{id}/state</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Apps Endpoints</h2>
|
|
<label>
|
|
Launch app name or id
|
|
<input id="appLaunchValue" placeholder="jellyfin" />
|
|
</label>
|
|
<label>
|
|
Refresh clear cache first
|
|
<input id="refreshClear" type="checkbox" />
|
|
</label>
|
|
<div class="row">
|
|
<button id="listAppsBtn" type="button">GET /devices/{id}/apps</button>
|
|
<button id="launchAppBtn" class="warn" type="button">POST /devices/{id}/apps/launch</button>
|
|
<button id="stopAppBtn" class="warn" type="button">POST /devices/{id}/apps/stop</button>
|
|
<button id="refreshAppsBtn" type="button">POST /devices/{id}/apps/refresh</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Remote Endpoints</h2>
|
|
<label>
|
|
Single key
|
|
<input id="singleKey" placeholder="home" />
|
|
</label>
|
|
<label>
|
|
Sequence keys (comma separated)
|
|
<input id="sequenceKeys" placeholder="home,down,select" />
|
|
</label>
|
|
<label>
|
|
Sequence delay_ms
|
|
<input id="sequenceDelay" type="number" value="200" min="0" />
|
|
</label>
|
|
<div class="row">
|
|
<button id="sendKeyBtn" type="button">POST /devices/{id}/remote/key</button>
|
|
<button id="sendSequenceBtn" type="button">POST /devices/{id}/remote/sequence</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Dev Endpoints</h2>
|
|
<label>
|
|
Zip file for sideload
|
|
<input id="devZip" type="file" accept=".zip,application/zip" />
|
|
</label>
|
|
<div class="row">
|
|
<button id="devInstallBtn" class="warn" type="button">POST /devices/{id}/dev/install</button>
|
|
<button id="devReloadBtn" type="button">POST /devices/{id}/dev/reload</button>
|
|
<button id="devLogsBtn" type="button">GET /devices/{id}/dev/logs</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Config Endpoints</h2>
|
|
<label>
|
|
Config patch key
|
|
<input id="configKey" placeholder="daemon.http_port" />
|
|
</label>
|
|
<label>
|
|
Config patch value (JSON literal, e.g. 7272, true, "text")
|
|
<input id="configValue" placeholder="7272" />
|
|
</label>
|
|
<div class="row">
|
|
<button id="getConfigBtn" type="button">GET /config</button>
|
|
<button id="patchConfigBtn" class="danger" type="button">PATCH /config</button>
|
|
<button id="reloadConfigBtn" class="warn" type="button">POST /config/reload</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel panel-wide">
|
|
<h2>Request Log</h2>
|
|
<textarea id="requestLog" readonly></textarea>
|
|
</section>
|
|
|
|
<section class="panel panel-wide">
|
|
<h2>Response</h2>
|
|
<textarea id="responseView" readonly></textarea>
|
|
</section>
|
|
</main>
|
|
|
|
<script src="./app.js"></script>
|
|
</body>
|
|
</html>
|