docs: add report draft and dashboard form refinements
This commit is contained in:
parent
4e0cf0140f
commit
441e709193
26 changed files with 1700 additions and 505 deletions
|
|
@ -2,10 +2,10 @@ import { Button } from "@minmon/ui/components/button";
|
|||
import { StatusBadge } from "@minmon/ui/components/status-badge";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
|
||||
import { useEffect } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { DetailCard, FormCard, PageSection, QueryStateCard, TextAreaField, TextField } from "@/components/dashboard-ui";
|
||||
import { DetailCard, FormCard, PageSection, QueryStateCard, ResourceListCard, SelectField, TextAreaField, TextField } from "@/components/dashboard-ui";
|
||||
import { queryClient, trpc, trpcClient } from "@/utils/trpc";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/servers_/$serverId")({
|
||||
|
|
@ -23,10 +23,17 @@ type ServerFormValues = {
|
|||
status: "active" | "maintenance" | "inactive";
|
||||
};
|
||||
|
||||
const serverStatusOptions = [
|
||||
{ value: "active", label: "Active" },
|
||||
{ value: "maintenance", label: "Maintenance" },
|
||||
{ value: "inactive", label: "Inactive" },
|
||||
] as const;
|
||||
|
||||
function RouteComponent() {
|
||||
const { serverId } = Route.useParams();
|
||||
const navigate = useNavigate();
|
||||
const server = useQuery(trpc.servers.byId.queryOptions({ id: serverId }));
|
||||
const notes = useQuery(trpc.notes.list.queryOptions({ serverId }));
|
||||
|
||||
const updateServer = useMutation({
|
||||
mutationFn: async (values: ServerFormValues) =>
|
||||
|
|
@ -108,6 +115,54 @@ function RouteComponent() {
|
|||
/>
|
||||
</PageSection>
|
||||
|
||||
{notes.isLoading ? (
|
||||
<QueryStateCard title="Loading server notes" description="Fetching notes attached to this server." />
|
||||
) : notes.isError || !notes.data ? (
|
||||
<QueryStateCard title="Server notes unavailable" description="The notes for this server could not be loaded." />
|
||||
) : (
|
||||
<PageSection
|
||||
title="Server notes"
|
||||
description="Notes and internal documentation attached to this server."
|
||||
action={
|
||||
<Link to="/dashboard/notes/new">
|
||||
<Button variant="outline">New note</Button>
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<ResourceListCard
|
||||
title="Attached notes"
|
||||
description="Review server-specific documentation without leaving this detail page."
|
||||
columns={[
|
||||
{
|
||||
key: "title",
|
||||
header: "Title",
|
||||
render: (item: (typeof notes.data)[number]) => (
|
||||
<div className="grid gap-1">
|
||||
<Link to="/dashboard/notes/$noteId" params={{ noteId: item.id }} className="font-medium hover:underline">
|
||||
{item.title}
|
||||
</Link>
|
||||
<span className="text-xs text-muted-foreground line-clamp-2">{item.content}</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "category",
|
||||
header: "Category",
|
||||
render: (item: (typeof notes.data)[number]) => item.category || "-",
|
||||
},
|
||||
{
|
||||
key: "updatedAt",
|
||||
header: "Updated",
|
||||
render: (item: (typeof notes.data)[number]) => new Date(item.updatedAt).toLocaleString(),
|
||||
},
|
||||
]}
|
||||
items={notes.data}
|
||||
emptyTitle="No notes for this server"
|
||||
emptyDescription="Add a note to document maintenance, incidents, or internal server context."
|
||||
/>
|
||||
</PageSection>
|
||||
)}
|
||||
|
||||
<form
|
||||
className="grid gap-4"
|
||||
onSubmit={(e) => {
|
||||
|
|
@ -137,7 +192,7 @@ function RouteComponent() {
|
|||
<form.Field name="operatingSystem">{(field) => <TextField label="Operating system" name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} />}</form.Field>
|
||||
<form.Field name="location">{(field) => <TextField label="Location" name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} />}</form.Field>
|
||||
<form.Field name="provider">{(field) => <TextField label="Provider" name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} />}</form.Field>
|
||||
<form.Field name="status">{(field) => <TextField label="Status" name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value as "active" | "maintenance" | "inactive")} />}</form.Field>
|
||||
<form.Field name="status">{(field) => <SelectField label="Status" name={field.name} value={field.state.value} onBlur={field.handleBlur} onValueChange={(value) => field.handleChange(value as ServerFormValues["status"])} placeholder="Select server status" options={[...serverStatusOptions]} />}</form.Field>
|
||||
</div>
|
||||
<form.Field name="description">{(field) => <TextAreaField label="Description" name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} />}</form.Field>
|
||||
</FormCard>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue