-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathparamToField.ts
More file actions
109 lines (101 loc) · 4.5 KB
/
Copy pathparamToField.ts
File metadata and controls
109 lines (101 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* paramToField — pure adapter from a resolved `ActionParamDef` to the
* `{ name, type, ...config }` field shape the shared form field widgets
* (`@object-ui/fields`) consume.
*
* `ActionParamDialog` renders every param through the same field-widget
* renderer the object form uses (`fieldWidgetMap` / `FORM_FIELD_TYPES`), so a
* declared action param of ANY form-supported field type — `file`, `image`,
* `richtext`, `color`, `address`, … — gets its real widget instead of
* collapsing to a text input (ADR-0059). This module is the whole translation
* layer: pure and exported so the mapping is unit-testable without the dialog
* render tree (mirrors `filterVisibleParams`' style), with a drift test
* asserting param support ⊇ form support.
*/
import type { ActionParamDef } from '@object-ui/core';
import { resolveFormWidgetType } from '@object-ui/fields';
/**
* Param-only type spellings the dialog historically accepted, folded onto the
* canonical form widget vocabulary. These are legacy dialect entries kept for
* params already authored with them — new params should use spec `FieldType`
* values directly.
*/
const PARAM_TYPE_ALIASES: Record<string, string> = {
checkbox: 'boolean',
reference: 'lookup',
'datetime-local': 'datetime',
// NOTE: spec's `autonumber` (vs the widget-map key `auto_number`) is folded
// in the shared `mapFieldTypeToFormType`, so `resolveFormWidgetType` already
// handles it — no param-only alias needed here.
};
/**
* Resolve a param `type` to the form widget key that renders it. Any type in
* `FORM_FIELD_TYPES` resolves to itself (identity — asserted by the drift
* test); aliases and unknown types resolve through the same fallback chain the
* form applies (unknown → `text`).
*/
export function resolveParamWidgetType(paramType: string): string {
return resolveFormWidgetType(PARAM_TYPE_ALIASES[paramType] ?? paramType);
}
/** Widget keys that render the record-picker family and need a reference target. */
const LOOKUP_WIDGET_TYPES = new Set(['lookup', 'master_detail']);
/**
* Map an `ActionParamDef` to the field-metadata shape `FieldWidgetProps.field`
* expects. Lossless for the widget-relevant config: options, `multiple`,
* upload `accept`/`maxSize`, and the full lookup picker config that
* `resolveActionParams()` copies from the underlying object field.
*
* Param-only fallback: a `lookup`/`reference` param with no known
* `referenceTo` target renders as a plain text input (the picker cannot query
* without a target object) — preserving the dialog's long-standing behavior
* for partially-resolved metadata.
*
* That fallback is now a last resort, not an expected path (#3405): inline
* params declare `reference` and field-backed ones inherit it, and the spec
* rejects a targetless inline picker at parse time. Reaching it means the
* metadata is broken or partial, so say so in dev instead of silently handing
* the user a box that wants a raw UUID.
*/
export function paramToField(param: ActionParamDef): Record<string, any> {
let type = resolveParamWidgetType(param.type);
if (LOOKUP_WIDGET_TYPES.has(type) && !param.referenceTo) {
if (process.env.NODE_ENV !== 'production') {
console.warn(
`[ActionParamDialog] Param "${param.name}" is type "${param.type}" but has no reference target, ` +
'so it degrades to a plain record-id text input. Declare `reference: \'<object>\'` on the param, ' +
'or make it field-backed (`{ field: \'<lookup_field>\' }`) to inherit the target.',
);
}
type = 'text';
}
const field: Record<string, any> = {
name: param.name,
label: param.label,
type,
required: param.required,
placeholder: param.placeholder,
options: param.options,
multiple: param.multiple,
accept: param.accept,
maxSize: param.maxSize,
};
// The dialog's boolean params render as an inline checkbox row (label beside
// the control), matching the pre-ADR-0059 dialog UX — not the form's switch.
if (type === 'boolean') {
field.widget = 'checkbox';
}
if (LOOKUP_WIDGET_TYPES.has(type) || type === 'user' || type === 'owner') {
Object.assign(field, {
reference_to: param.referenceTo,
display_field: param.displayField,
id_field: param.idField,
description_field: param.descriptionField,
title_format: param.titleFormat,
lookup_columns: param.lookupColumns,
lookup_filters: param.lookupFilters,
lookup_page_size: param.lookupPageSize,
depends_on: param.dependsOn,
});
}
return field;
}