feat(frontend): implement step 1 - entity task detail and scheduler UX

This commit is contained in:
2026-03-26 20:32:06 -03:00
parent 381c6cbfcd
commit 888fb9f665
11 changed files with 470 additions and 45 deletions

View File

@@ -1,4 +1,5 @@
import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import {
getEntities,
@@ -8,6 +9,7 @@ import {
} from '../api/entitiesApi'
export default function EntitiesPage() {
const navigate = useNavigate()
const queryClient = useQueryClient()
const { data: entities = [] } = useQuery({ queryKey: ['entities'], queryFn: getEntities })
const [dialogOpen, setDialogOpen] = useState(false)
@@ -22,10 +24,11 @@ export default function EntitiesPage() {
const createMutation = useMutation({
mutationFn: createEntity,
onSuccess: () => {
onSuccess: (createdEntity) => {
queryClient.invalidateQueries({ queryKey: ['entities'] })
setDialogOpen(false)
setForm({ name: '', email: '', jobTitle: '', personality: '', scheduleCron: '', contextWindowDays: 3 })
navigate(`/entities/${createdEntity.id}`)
},
})
@@ -37,32 +40,40 @@ export default function EntitiesPage() {
return (
<div className="p-8">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-gray-900">Virtual Entities</h1>
<h1 className="text-2xl font-bold text-slate-100">Virtual Entities</h1>
<button
onClick={() => setDialogOpen(true)}
className="rounded bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
className="rounded bg-cyan-500 px-4 py-2 text-sm font-medium text-slate-950 hover:bg-cyan-400"
>
New Entity
</button>
</div>
<ul className="mt-6 divide-y divide-gray-100 rounded-lg border bg-white shadow-sm">
<ul className="mt-6 divide-y divide-slate-800 rounded-lg border border-slate-800 bg-slate-900/70 shadow-sm">
{entities.map((entity) => (
<li key={entity.id} className="flex items-center justify-between px-4 py-3">
<div>
<p className="font-medium">{entity.name}</p>
<p className="text-sm text-gray-500">{entity.jobTitle} {entity.email}</p>
<p className="font-medium text-slate-100">{entity.name}</p>
<p className="text-sm text-slate-300">{entity.jobTitle} - {entity.email}</p>
</div>
<div className="ml-4 flex items-center gap-2">
<Link
to={`/entities/${entity.id}`}
className="rounded border border-cyan-500 px-3 py-1 text-sm text-cyan-300 hover:bg-cyan-500/10"
>
Open details
</Link>
<button
onClick={() => deleteMutation.mutate(entity.id)}
className="rounded border border-red-400/60 px-3 py-1 text-sm text-red-300 hover:bg-red-400/10"
>
Delete
</button>
</div>
<button
onClick={() => deleteMutation.mutate(entity.id)}
className="ml-4 rounded border border-red-300 px-3 py-1 text-sm text-red-600 hover:bg-red-50"
>
Delete
</button>
</li>
))}
{entities.length === 0 && (
<li className="px-4 py-3 text-sm text-gray-400">No entities yet.</li>
<li className="px-4 py-3 text-sm text-slate-400">No entities yet.</li>
)}
</ul>
@@ -71,10 +82,10 @@ export default function EntitiesPage() {
role="dialog"
aria-modal="true"
aria-label="Create Entity"
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/70"
>
<div className="w-full max-w-md rounded-lg bg-white p-6 shadow-lg">
<h2 className="mb-4 text-lg font-semibold">New Entity</h2>
<div className="w-full max-w-md rounded-lg border border-slate-800 bg-slate-950 p-6 shadow-lg">
<h2 className="mb-4 text-lg font-semibold text-slate-100">New Entity</h2>
<form
onSubmit={(e) => {
e.preventDefault()
@@ -86,7 +97,7 @@ export default function EntitiesPage() {
placeholder="Name"
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
required
/>
<input
@@ -94,27 +105,27 @@ export default function EntitiesPage() {
type="email"
value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
required
/>
<input
placeholder="Job Title"
value={form.jobTitle}
onChange={(e) => setForm({ ...form, jobTitle: e.target.value })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
required
/>
<textarea
placeholder="Personality"
value={form.personality}
onChange={(e) => setForm({ ...form, personality: e.target.value })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
/>
<input
placeholder="Schedule Cron (e.g. 0 9 * * 1)"
value={form.scheduleCron}
onChange={(e) => setForm({ ...form, scheduleCron: e.target.value })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
required
/>
<input
@@ -122,7 +133,7 @@ export default function EntitiesPage() {
placeholder="Context Window Days"
value={form.contextWindowDays}
onChange={(e) => setForm({ ...form, contextWindowDays: Number(e.target.value) })}
className="block w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="block w-full rounded border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-100"
min={1}
required
/>
@@ -130,13 +141,13 @@ export default function EntitiesPage() {
<button
type="button"
onClick={() => setDialogOpen(false)}
className="rounded border border-gray-300 px-4 py-2 text-sm"
className="rounded border border-slate-700 px-4 py-2 text-sm text-slate-200"
>
Cancel
</button>
<button
type="submit"
className="rounded bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
className="rounded bg-cyan-500 px-4 py-2 text-sm font-medium text-slate-950 hover:bg-cyan-400"
>
Create
</button>