feat(10-03): open, edit and save a record with toast and 422 feedback
- The SPA loads the backend::lang bundle before /auth/me, sets the document language from meta.locale and renders plural messages with Intl.PluralRules; interpolate mirrors phrasebook for :name/:Name/:NAME - Create and record routes; mapWinterUrl maps recordUrl and redirects onto the controller's list, create and record routes only - List rows open their record; FormView loads the form schema and the record, shows context-allowed fields in the span grid, saves values keyed by field name and toasts the resolved saved message - A 422 puts each message under its field (aria-invalid, aria-describedby), shows the plural banner, focuses the first invalid field in schema order and clears a field's error on change - The D-05 registry maps text, textarea, number and dropdown; any other type renders the unsupported-field box with the type in DM Mono - The admin OpenAPI document declares the write request bodies (AdminRecord, AdminIDsRequest) and the list filter query as a deepObject, so the typed client can send them - New backend::lang form.load_failed key; boardwalk/dist rebuilt
This commit is contained in:
49
admin/src/api/schema.d.ts
vendored
49
admin/src/api/schema.d.ts
vendored
@@ -474,7 +474,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Setting values keyed by field name */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminRecord"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -617,6 +622,10 @@ export interface paths {
|
||||
page?: number;
|
||||
/** @description Records per page */
|
||||
per_page?: number;
|
||||
/** @description Filter values keyed by filter name, sent as filter[<name>]=<value> */
|
||||
filter?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
header?: never;
|
||||
path: {
|
||||
@@ -697,7 +706,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Field values keyed by field name; relation fields carry ids */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminRecord"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Created */
|
||||
201: {
|
||||
@@ -776,7 +790,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Record ids */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminIDsRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -1299,7 +1318,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Field values keyed by field name; relation fields carry ids */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminRecord"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -1614,7 +1638,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Related record ids */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminIDsRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -1697,7 +1726,12 @@ export interface paths {
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
/** @description Related record ids */
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.AdminIDsRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -1756,6 +1790,9 @@ export interface paths {
|
||||
export type webhooks = Record<string, never>;
|
||||
export interface components {
|
||||
schemas: {
|
||||
"cabana.AdminIDsRequest": {
|
||||
ids: number[];
|
||||
};
|
||||
"cabana.AdminLoginData": {
|
||||
access_token?: string;
|
||||
expires_in?: number;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Aliases onto the generated OpenAPI schema (D-15, D-16). No API shape is
|
||||
// written by hand: every type here points at components['schemas'].
|
||||
import type { components } from './schema'
|
||||
import type { components, paths } from './schema'
|
||||
|
||||
type Schemas = components['schemas']
|
||||
type ControllerPath = paths['/{vendor}/{plugin}/{controller}']
|
||||
type FieldOptionsPath = paths['/{vendor}/{plugin}/{controller}/fields/{field}/options']
|
||||
|
||||
export type AdminLoginData = Schemas['cabana.AdminLoginData']
|
||||
export type AdminLoginRequest = Schemas['cabana.AdminLoginRequest']
|
||||
@@ -36,3 +38,13 @@ export type LangBundle = Schemas['cabana.LangBundle']
|
||||
export type ErrorEnvelope = Schemas['cabana.ErrorEnvelope']
|
||||
/** One record: a string-keyed map read through its list or form schema. */
|
||||
export type AdminRecord = Schemas['cabana.AdminRecord']
|
||||
export type ErrorBody = Schemas['cabana.ErrorBody']
|
||||
export type SuccessMeta = Schemas['cabana.SuccessMeta']
|
||||
/** Body of bulk delete and relation link/unlink. */
|
||||
export type IDsRequest = Schemas['cabana.AdminIDsRequest']
|
||||
/** Path parameters naming one controller: vendor, plugin, controller (D-10). */
|
||||
export type ControllerParams = ControllerPath['get']['parameters']['path']
|
||||
/** The list query: search, sort, dir, page, per_page and filter[<name>]. */
|
||||
export type ListQuery = NonNullable<ControllerPath['get']['parameters']['query']>
|
||||
/** Relation field options query: search, page, per_page. */
|
||||
export type FieldOptionsQuery = NonNullable<FieldOptionsPath['get']['parameters']['query']>
|
||||
|
||||
Reference in New Issue
Block a user