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:
@@ -31,3 +31,37 @@ func TxFromContext(ctx context.Context) (*gorm.DB, bool) {
|
||||
tx, ok := ctx.Value(txContextKey{}).(*gorm.DB)
|
||||
return tx, ok && tx != nil
|
||||
}
|
||||
|
||||
type virtualFieldsKey struct{}
|
||||
|
||||
// withVirtualFields returns ctx carrying the virtual field values of a save.
|
||||
func withVirtualFields(ctx context.Context, values map[string]any) context.Context {
|
||||
if values == nil {
|
||||
values = map[string]any{}
|
||||
}
|
||||
return context.WithValue(ctx, virtualFieldsKey{}, values)
|
||||
}
|
||||
|
||||
// VirtualFieldsFromContext returns the values an administrator submitted for
|
||||
// the form's virtual fields (pact.FormVirtualFields), keyed by field name, for
|
||||
// the context handed to a Form hook (pact.FormBeforeCreate,
|
||||
// pact.FormAfterCreate, pact.FormBeforeUpdate, pact.FormAfterUpdate). Only
|
||||
// fields that were present in the request body and whose `context` allows the
|
||||
// operation are in the map, so a missing key means "not submitted". Values
|
||||
// are scalars as decoded from the JSON body: a string, a bool, a json.Number
|
||||
// or nil. The map is a copy. The second result is false outside a create or
|
||||
// update save.
|
||||
func VirtualFieldsFromContext(ctx context.Context) (map[string]any, bool) {
|
||||
if ctx == nil {
|
||||
return nil, false
|
||||
}
|
||||
values, ok := ctx.Value(virtualFieldsKey{}).(map[string]any)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
out := make(map[string]any, len(values))
|
||||
for name, value := range values {
|
||||
out[name] = value
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user