feat: web frontend; middleware; serde (WIP?)
This commit is contained in:
83
frontend/src/components/CommandQueue.tsx
Normal file
83
frontend/src/components/CommandQueue.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Component, createResource, For, Show } from 'solid-js';
|
||||
import { commandsApi } from '../api/client';
|
||||
|
||||
const CommandQueue: Component = () => {
|
||||
const [commands, { refetch }] = createResource(commandsApi.list);
|
||||
|
||||
const updateCommandStatus = async (id: number, status: string) => {
|
||||
try {
|
||||
await commandsApi.updateStatus(id, { status });
|
||||
refetch();
|
||||
} catch (err) {
|
||||
console.error('Failed to update command:', err);
|
||||
alert(`Error: ${err}`);
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateStr: string) => {
|
||||
return new Date(dateStr).toLocaleString();
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-2xl font-semibold">Command Queue</h2>
|
||||
|
||||
<div class="bg-white shadow rounded-lg overflow-hidden">
|
||||
<Show when={!commands.loading} fallback={<div class="p-4">Loading...</div>}>
|
||||
<For each={commands()} fallback={
|
||||
<div class="p-8 text-center text-gray-500">
|
||||
No commands in queue
|
||||
</div>
|
||||
}>
|
||||
{(cmd) => (
|
||||
<div class="border-b p-4 hover:bg-gray-50">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class={`px-2 py-1 rounded-full text-xs font-semibold ${
|
||||
cmd.status === 'verified' ? 'bg-green-100 text-green-800' :
|
||||
cmd.status === 'rejected' ? 'bg-red-100 text-red-800' :
|
||||
'bg-yellow-100 text-yellow-800'
|
||||
}`}>
|
||||
{cmd.status}
|
||||
</span>
|
||||
<span class="text-sm text-gray-500">
|
||||
{formatDate(cmd.received_at)}
|
||||
</span>
|
||||
</div>
|
||||
<pre class="text-sm bg-gray-100 p-3 rounded overflow-x-auto">
|
||||
{JSON.stringify(cmd.command, null, 2)}
|
||||
</pre>
|
||||
<Show when={cmd.notes}>
|
||||
<div class="mt-2 text-sm text-gray-600">
|
||||
<strong>Notes:</strong> {cmd.notes}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={cmd.status === 'unverified'}>
|
||||
<div class="ml-4 flex flex-col gap-2">
|
||||
<button
|
||||
onClick={() => updateCommandStatus(cmd.id, 'verified')}
|
||||
class="px-3 py-1 bg-green-600 text-white rounded text-sm hover:bg-green-700"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
<button
|
||||
onClick={() => updateCommandStatus(cmd.id, 'rejected')}
|
||||
class="px-3 py-1 bg-red-600 text-white rounded text-sm hover:bg-red-700"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommandQueue;
|
||||
Reference in New Issue
Block a user