ConusAI vendor v0.1.0-beta.114
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-beta.114
2026-11-14 09:56:45 +00:00
commit 1ce8d23c35
867 changed files with 122104 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
"use client"
// The project's notes as one record type: the list, a new note and an edit in the right panel, all from this
// declaration. Attachments need a page, so the panel offers it ("Open in full"). The rows are live (live-notes.ts);
// a write resolves once the stream has seen it, so the list shows it the moment the panel closes.
import { emitAppEvent, type ProjectSlugs } from "@conusai-kit/ui"
import { useDataClient, useWrite } from "@conusai-kit/ui/data"
import { defineResource, ResourcePage } from "@conusai-kit/ui/patterns"
import { type ReactElement, type ReactNode, useRef } from "react"
import { z } from "zod"
import type { NoteView } from "../contract/index.js"
import type { NotesResourceLabels } from "./labels.js"
import { useLiveNotes } from "./live-notes.js"
const schema = z.object({ title: z.string().min(1).max(200), body: z.string().max(20_000) })
export interface NotesProps {
readonly slugs: ProjectSlugs
/** The first page, rendered on the server. */
readonly seed: readonly NoteView[]
readonly labels: NotesResourceLabels
readonly intro: ReactNode
/** The locale the server formatted dates in, so the rows read as they were rendered. */
readonly locale: string
}
export function NotesResource({ slugs, seed, labels, intro, locale }: NotesProps): ReactElement {
const client = useDataClient()
const rows = useLiveNotes(slugs, seed)
const create = useWrite<Record<string, unknown>, NoteView>("notes.note.create", { org: slugs.org })
const update = useWrite<Record<string, unknown>, NoteView>("notes.note.update", { org: slugs.org })
const remove = useWrite<Record<string, unknown>, unknown>("notes.note.delete", { org: slugs.org })
// A save carries the version the panel read, so a second editor's is a 409 and never a silent overwrite.
const read = useRef(new Map<string, number>())
for (const { noteId, version } of rows) if (!read.current.has(noteId)) read.current.set(noteId, version)
const day = new Intl.DateTimeFormat(locale).format
const resource = defineResource<NoteView, z.output<typeof schema>>({
id: "notes",
label: labels.one,
newLabel: labels.new,
columns: [
{ id: "title", header: labels.note, wrap: true, minWidth: "10rem", allowsSorting: true },
{ id: "attachmentCount", header: labels.attachments, align: "end" },
{ id: "updatedAt", header: labels.updated, allowsSorting: true, cell: (n) => day(new Date(n.updatedAt)) },
],
rowId: (note) => note.noteId,
source: { rows },
async get(noteId) {
const { value } = await client.call<{ note: NoteView }>("notes.note.get", { ...slugs, noteId })
read.current.set(noteId, value.note.version)
return value.note
},
schema,
fields: [
{ name: "title", label: labels.titleField, kind: "text" },
{ name: "body", label: labels.body, kind: "textarea" },
],
async create(input) {
const note = await create.mutate({ ...slugs, ...input })
await emitAppEvent("note_created") // what an in-app guide's checklist task listens for
return note
},
update: (id, input) => update.mutate({ ...slugs, noteId: id, ...input, expectedVersion: read.current.get(id) }),
remove: (noteId) => remove.mutate({ ...slugs, noteId }).then(() => undefined),
href: (n) => `/${slugs.org}/${slugs.workspace}/${slugs.project}/notes/${n.noteId}`,
permissions: { write: "notes.note.write", remove: "notes.note.delete" },
})
return <ResourcePage resource={resource} title={labels.title} description={intro} empty={{ title: labels.empty }} />
}