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
+108
View File
@@ -0,0 +1,108 @@
// A page above any project, on the shell's F10 contract: `/<org>/<workspace>/modules/notes`. It lists the
// workspace's projects, each linked to its notes, and `?q=` filters them on the server, so the first byte
// already holds the result and a filter is a link anyone can copy.
//
// The shell answers 403 for `permission` before `load` runs; the rest is a `ProjectPage` with two slugs. This is
// the worked example for a catalogue, a list or a setting that belongs to a workspace, not to a project, and for
// a page's strings as one record, with a count only the browser knows formatted there (project-picker.tsx).
import type { Container, TransportCaller } from "@conusai-kit/core"
import type { I18n } from "@conusai-kit/i18n"
import { projectList } from "@conusai-kit/tenancy"
import { type WorkspacePage, workspacePage } from "@conusai-kit/ui"
import { FilterBar, Page, PageHeader, PageState, TextField } from "@conusai-kit/ui/patterns"
import { Button } from "@conusai-kit/ui/primitives"
import { ProjectPicker } from "./project-picker.js"
/** Every string of the page, as one record. `selected` keeps its placeholder: only the browser knows the count. */
export const WORKSPACE_LABEL_KEYS = [
"title",
"intro",
"filter",
"apply",
"clear",
"empty",
"noProjects",
"selected",
] as const
export interface NotesWorkspaceData {
readonly labels: Readonly<Record<(typeof WORKSPACE_LABEL_KEYS)[number], string>>
readonly query: string
readonly projects: readonly { readonly slug: string; readonly name: string }[]
}
export type NotesWorkspacePage = WorkspacePage<TransportCaller, I18n, Container, NotesWorkspaceData>
export const notesWorkspacePage: NotesWorkspacePage = workspacePage({
permission: "notes.note.read",
async load({ slugs, search, caller, i18n }): Promise<NotesWorkspaceData> {
const query = search.q ?? ""
const wanted = query.trim().toLowerCase()
const { projects } = await caller.call(projectList, slugs)
return {
labels: Object.fromEntries(
WORKSPACE_LABEL_KEYS.map((key) => [key, i18n.message(`notes.workspace.${key}`)]),
) as NotesWorkspaceData["labels"],
query,
projects: projects
.filter((project) => project.name.toLowerCase().includes(wanted))
.map(({ slug, name }) => ({ slug, name })),
}
},
View({ slugs, locale, data }) {
const { labels } = data
return (
<Page>
<PageHeader title={labels.title} description={labels.intro} />
<FilterBar
method="get"
actions={
<>
<Button type="submit" variant="secondary">
{labels.apply}
</Button>
{data.query.trim() && data.projects.length > 0 && (
<Button asChild variant="link">
<a href={`/${slugs.org}/${slugs.workspace}/modules/notes`}>{labels.clear}</a>
</Button>
)}
</>
}
>
<TextField
name="q"
label={labels.filter}
placeholder={labels.filter}
type="search"
defaultValue={data.query}
/>
</FilterBar>
{data.projects.length === 0 ? (
<PageState
title={data.query.trim() ? labels.empty : labels.noProjects}
action={
data.query.trim() ? (
<Button asChild variant="outline">
<a href={`/${slugs.org}/${slugs.workspace}/modules/notes`}>{labels.clear}</a>
</Button>
) : undefined
}
/>
) : (
<ProjectPicker
label={labels.title}
column={labels.filter}
empty={labels.noProjects}
projects={data.projects.map((project) => ({
...project,
href: `/${slugs.org}/${slugs.workspace}/${project.slug}/notes`,
}))}
selected={labels.selected}
locale={locale}
/>
)}
</Page>
)
},
})