Adds .d.ts declarations beside the untyped JS modules imported from TS (api.js, navConfig.js, adminSchema.js, adminNav.js, src/data/*), with shapes taken from the server routes and migrations. get/post/ patch/del now return unknown unless the caller names the response. Fixes found along the way: - website/email/instagram are bare strings from splitLinks, not Link objects; OrganizationDetail's website and email pills rendered with no href or label and now link correctly. - The chapter map falls back to FALLBACK_COLOR for a region with no colour instead of painting its tiles black. Adds defineSection() so each page manifest entry's props are checked against its own Component. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
3.1 KiB
TypeScript
118 lines
3.1 KiB
TypeScript
/* Types for adminSchema.js: the client half of the descriptor-driven
|
|
admin CRUD engine. Rows are whatever columns the server-side
|
|
descriptor in server/src/admin-schema.js declares, so they stay a
|
|
string-keyed record; the descriptors are what's fixed. */
|
|
|
|
/** A row from /api/admin/:entity or /:entity/:id. Nested paths
|
|
* ('region.scope') are side-table objects under their key, and
|
|
* child collections are arrays of rows under theirs. */
|
|
export type AdminRow = Record<string, unknown>;
|
|
|
|
/** One row of an OPTION_QUERIES result. `kind` and `org_id` ride
|
|
* along on the lists that filterBy narrows. */
|
|
export type AdminOption = {
|
|
id: string;
|
|
label: string;
|
|
kind?: string;
|
|
org_id?: string | null;
|
|
};
|
|
|
|
/** GET /api/admin/options, keyed by OPTION_QUERIES name. */
|
|
export type AdminOptions = Record<string, AdminOption[]>;
|
|
|
|
export type FieldWidget =
|
|
| "text"
|
|
| "textarea"
|
|
| "select"
|
|
| "checkbox"
|
|
| "color"
|
|
| "number"
|
|
| "date";
|
|
|
|
/** A bare value, or [value, label]. */
|
|
export type SelectOption = string | readonly [string, string];
|
|
|
|
/** Show a group or collection only when another field has this value. */
|
|
export type FieldCondition = { path: string; value: unknown };
|
|
|
|
export type AdminFieldSpec = {
|
|
path: string;
|
|
label: string;
|
|
widget?: FieldWidget;
|
|
required?: boolean;
|
|
full?: boolean;
|
|
help?: string;
|
|
options?: readonly SelectOption[];
|
|
optionsFrom?: string;
|
|
blankLabel?: string;
|
|
filterBy?: (option: AdminOption, row: AdminRow) => boolean;
|
|
/* Set by EntityEdit on the id field rather than in a manifest. */
|
|
readOnly?: boolean;
|
|
prefix?: string;
|
|
prefixPending?: boolean;
|
|
placeholder?: string;
|
|
};
|
|
|
|
export type FieldGroupSpec = {
|
|
legend: string;
|
|
note?: string;
|
|
when?: FieldCondition;
|
|
fields: AdminFieldSpec[];
|
|
};
|
|
|
|
export type CollectionSpec = {
|
|
key: string;
|
|
label: string;
|
|
addLabel?: string;
|
|
note?: string;
|
|
when?: FieldCondition;
|
|
title?: (row: AdminRow, options: AdminOptions | null | undefined) => string;
|
|
blank: AdminRow;
|
|
fields: AdminFieldSpec[];
|
|
children?: CollectionSpec[];
|
|
};
|
|
|
|
export type ListColumn = {
|
|
key: string;
|
|
label: string;
|
|
primary?: boolean;
|
|
widget?: "bool";
|
|
};
|
|
|
|
export type ListFilter = {
|
|
key: string;
|
|
label: string;
|
|
options?: readonly SelectOption[];
|
|
optionsFrom?: string;
|
|
};
|
|
|
|
export type EntitySpec = {
|
|
key: string;
|
|
label: string;
|
|
singular: string;
|
|
idLabel: string;
|
|
/** "auto": the table assigns the id, so the form shows it rather than asking. */
|
|
idKind?: "auto";
|
|
/** Field(s) the slug is composed from. Absent when idKind is "auto". */
|
|
slugFrom?: string | string[];
|
|
titleFrom?: string;
|
|
list: { columns: ListColumn[]; filters: ListFilter[] };
|
|
groups: FieldGroupSpec[];
|
|
children?: CollectionSpec[];
|
|
};
|
|
|
|
export type AdminEntityKey =
|
|
| "organizations"
|
|
| "events"
|
|
| "people"
|
|
| "teams"
|
|
| "awards"
|
|
| "timeline";
|
|
|
|
/* Indexed by route param as often as by name, so any other string
|
|
reads as possibly missing. */
|
|
export declare const ADMIN_ENTITIES: { readonly [K in AdminEntityKey]: EntitySpec } & {
|
|
readonly [key: string]: EntitySpec | undefined;
|
|
};
|
|
|
|
export declare function slugify(value: unknown): string;
|