Tests / Test apps.device-host-agent.tests.test_mcp_token.test_load_or_create_concurrent_calls_do_not_corrupt failed
96 lines
4.4 KiB
HTML
96 lines
4.4 KiB
HTML
{% extends "base.html" %}
|
|
{% block body %}
|
|
<h1>Devices</h1>
|
|
{% if error %}
|
|
<p class="error">{{ error }}</p>
|
|
{% endif %}
|
|
<table>
|
|
<thead><tr><th>ID</th><th>Name</th><th>Driver</th><th>Cloud ID</th><th>Screenshot</th><th></th></tr></thead>
|
|
<tbody>{% for device in devices %}
|
|
<tr>
|
|
<td>{{ device["device_id"] }}</td>
|
|
<td>{{ device["name"] or "" }}</td>
|
|
<td>{{ device["driver_type"] }}</td>
|
|
<td>{{ device["cloud_device_id"] or "" }}</td>
|
|
<td>
|
|
<button type="button" class="screenshot-button" data-device-id="{{ device["device_id"] }}">Get screenshot</button>
|
|
<div class="screenshot-preview" data-screenshot-preview hidden>
|
|
<p class="screenshot-status" data-screenshot-status></p>
|
|
<img alt="Current screen for {{ device["device_id"] }}" data-screenshot-image hidden>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<a href="/devices?edit={{ device["device_id"] }}">Edit</a>
|
|
<form class="inline" method="post" action="/devices/remove">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input type="hidden" name="device_id" value="{{ device["device_id"] }}">
|
|
<button type="submit">Remove</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}</tbody>
|
|
</table>
|
|
<h2>{{ "Edit device" if edit_record else "Add device" }}</h2>
|
|
<form method="post" action="/devices/save">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<label>Device ID <input type="text" name="device_id" value="{{ edit_record["device_id"] if edit_record else "" }}" required></label><br>
|
|
<label>Name <input type="text" name="name" value="{{ edit_record["name"] if edit_record else "" }}"></label><br>
|
|
<label>Driver type <input type="text" name="driver_type" value="{{ edit_record["driver_type"] if edit_record else "wda" }}" required></label><br>
|
|
<label>Connection info (JSON)<br>
|
|
<textarea name="connection_info" rows="3" cols="50">{{ connection_info_json }}</textarea>
|
|
</label><br>
|
|
<button type="submit">Save</button>
|
|
</form>
|
|
<style>
|
|
.screenshot-preview { margin-top: 0.5rem; max-width: 260px; }
|
|
.screenshot-preview img { display: block; width: 100%; height: auto; border: 1px solid #c8d0d6; }
|
|
.screenshot-status { margin: 0 0 0.35rem; color: #5e6b73; }
|
|
.screenshot-status.error { color: #b00020; }
|
|
</style>
|
|
<script>
|
|
(() => {
|
|
const csrfInput = document.querySelector('input[name="csrf_token"]');
|
|
const csrfToken = csrfInput ? csrfInput.value : "";
|
|
document.querySelectorAll(".screenshot-button").forEach((button) => {
|
|
button.addEventListener("click", async () => {
|
|
const deviceId = button.dataset.deviceId;
|
|
const preview = button.parentElement.querySelector("[data-screenshot-preview]");
|
|
const status = preview.querySelector("[data-screenshot-status]");
|
|
const image = preview.querySelector("[data-screenshot-image]");
|
|
const previousUrl = image.dataset.objectUrl;
|
|
if (previousUrl) URL.revokeObjectURL(previousUrl);
|
|
button.disabled = true;
|
|
preview.hidden = false;
|
|
image.hidden = true;
|
|
status.classList.remove("error");
|
|
status.textContent = "Capturing...";
|
|
try {
|
|
const response = await fetch(
|
|
"/api/devices/" + encodeURIComponent(deviceId) + "/screenshot",
|
|
{ method: "POST", headers: { "X-CSRF-Token": csrfToken } }
|
|
);
|
|
if (!response.ok) {
|
|
let detail = "Screenshot failed.";
|
|
try {
|
|
const payload = await response.json();
|
|
if (payload.detail) detail = payload.detail;
|
|
} catch (_) {}
|
|
throw new Error(detail);
|
|
}
|
|
const objectUrl = URL.createObjectURL(await response.blob());
|
|
image.src = objectUrl;
|
|
image.dataset.objectUrl = objectUrl;
|
|
image.hidden = false;
|
|
status.textContent = "Captured.";
|
|
} catch (error) {
|
|
status.classList.add("error");
|
|
status.textContent = error.message || "Screenshot failed.";
|
|
} finally {
|
|
button.disabled = false;
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|