feat(12.1-02): password and form-only fields, rules per operation and preset
- pact.FormVirtualFields lists form fields that are not model columns: never bound, filled or projected; their values reach the Form hooks through cabana.VirtualFieldsFromContext when the field's context allows the operation - type: password is a masked field that must be listed as virtual - pact.FormRules supplies the rule set per operation and replaces the model's Rules() for admin saves; a rule on a virtual field sees the submitted value - preset on a text field follows another text field on the create form - SPA: PasswordField, preset handling in FormView, empty password left out of an update - README, docs, OpenAPI document, TS types and dist updated
This commit is contained in:
@@ -43,14 +43,19 @@ export function contextAllows(field: FormField, mode: FormMode): boolean {
|
||||
/**
|
||||
* The save body: values keyed by field name for every editable field that
|
||||
* has a value. Read-only fields and types without a renderer are never sent.
|
||||
* An empty password on update means "unchanged" and is left out; on create it
|
||||
* is sent as entered and the server's rules decide (UI-SPEC S7).
|
||||
*/
|
||||
export function editablePayload(fields: FormField[], values: AdminRecord): AdminRecord {
|
||||
export function editablePayload(fields: FormField[], values: AdminRecord, mode: FormMode = 'create'): AdminRecord {
|
||||
const out: AdminRecord = {}
|
||||
for (const field of fields) {
|
||||
if (field.readOnly || !isRegistered(field.type)) {
|
||||
continue
|
||||
}
|
||||
const value = values[field.name]
|
||||
if (field.type === 'password' && mode === 'update' && (value === '' || value === null)) {
|
||||
continue
|
||||
}
|
||||
if (value !== undefined) {
|
||||
out[field.name] = value
|
||||
}
|
||||
@@ -58,6 +63,22 @@ export function editablePayload(fields: FormField[], values: AdminRecord): Admin
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* The value a preset field takes from its source (fields.yaml `preset`). Type
|
||||
* slug: lower-case ASCII letters and digits, every run of other characters
|
||||
* one hyphen, no hyphen at either end. Type exact: the same text.
|
||||
*/
|
||||
export function presetValue(type: string, source: unknown): string {
|
||||
const text = typeof source === 'string' || typeof source === 'number' ? String(source) : ''
|
||||
if (type !== 'slug') {
|
||||
return text
|
||||
}
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
}
|
||||
|
||||
/** Initial values of a new record: schema defaults, toggles off, no ids. */
|
||||
export function initialValues(fields: FormField[]): AdminRecord {
|
||||
const out: AdminRecord = {}
|
||||
|
||||
Reference in New Issue
Block a user