@asteby/metacore-runtime-react 33.0.0 → 33.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 33.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9eab4e0: `EntitySelect` now accepts `createDefaults` and `lockedCreateFields` to seed
8
+ and lock fields in its inline "+" create dialog. Motivating case: the POS
9
+ vehicle picker creating a vehicle for an already-selected customer — the
10
+ customer field should come pre-filled and not be changeable from that
11
+ context, instead of the user having to search/select it again (and risking
12
+ attaching the vehicle to the wrong customer).
13
+
14
+ - `createDefaults?: Record<string, unknown>` — seeds the create dialog's
15
+ form (passed through as `CreateRecordDialog.defaults`).
16
+ - `lockedCreateFields?: string[]` — keys from `createDefaults` that render
17
+ visible-but-disabled on create instead of editable (passed through as the
18
+ new `CreateRecordDialog.lockedFields` / `DynamicRecordDialog.lockedFields`).
19
+
20
+ New `lockedFields` support in `DynamicRecordDialog`/`CreateRecordDialog`:
21
+ unlike a `readonly` field (excluded entirely on create), a locked field stays
22
+ visible so the user sees what value is being submitted, rendered through the
23
+ same `ReadonlyEditField` used for edit-mode readonly fields. Also fixes
24
+ `ReadonlyEditField` for relation/`Ref` fields (readonly-on-edit and now
25
+ locked-on-create): it previously rendered the raw foreign id, and now
26
+ resolves and shows the related record's label like `RelationViewValue`
27
+ already does in view mode.
28
+
3
29
  ## 33.0.0
4
30
 
5
31
  ### Patch Changes
@@ -1,3 +1,3 @@
1
1
  import type { CreateRecordDialogProps } from './types';
2
- export declare function CreateRecordDialog({ modelKey, open, onOpenChange, recordId, endpoint, schema, defaults, onCreate, onUpdate, onSaved, }: CreateRecordDialogProps): import("react").JSX.Element;
2
+ export declare function CreateRecordDialog({ modelKey, open, onOpenChange, recordId, endpoint, schema, defaults, lockedFields, onCreate, onUpdate, onSaved, }: CreateRecordDialogProps): import("react").JSX.Element;
3
3
  //# sourceMappingURL=create-record-dialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-record-dialog.d.ts","sourceRoot":"","sources":["../../src/dialogs/create-record-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAEtD,wBAAgB,kBAAkB,CAAC,EAC/B,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,OAAO,GACV,EAAE,uBAAuB,+BAiBzB"}
1
+ {"version":3,"file":"create-record-dialog.d.ts","sourceRoot":"","sources":["../../src/dialogs/create-record-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAEtD,wBAAgB,kBAAkB,CAAC,EAC/B,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,OAAO,GACV,EAAE,uBAAuB,+BAkBzB"}
@@ -14,7 +14,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
14
14
  * with the default `/dynamic/${modelKey}` endpoint convention.
15
15
  */
16
16
  import { DynamicRecordDialog } from './dynamic-record';
17
- export function CreateRecordDialog({ modelKey, open, onOpenChange, recordId, endpoint, schema, defaults, onCreate, onUpdate, onSaved, }) {
17
+ export function CreateRecordDialog({ modelKey, open, onOpenChange, recordId, endpoint, schema, defaults, lockedFields, onCreate, onUpdate, onSaved, }) {
18
18
  const mode = recordId ? 'edit' : 'create';
19
- return (_jsx(DynamicRecordDialog, { open: open, onOpenChange: onOpenChange, mode: mode, model: modelKey, recordId: recordId, endpoint: endpoint, schema: schema, defaults: defaults, onCreate: onCreate, onUpdate: onUpdate, onSaved: onSaved }));
19
+ return (_jsx(DynamicRecordDialog, { open: open, onOpenChange: onOpenChange, mode: mode, model: modelKey, recordId: recordId, endpoint: endpoint, schema: schema, defaults: defaults, lockedFields: lockedFields, onCreate: onCreate, onUpdate: onUpdate, onSaved: onSaved }));
20
20
  }
@@ -122,6 +122,12 @@ export interface DynamicRecordDialogProps {
122
122
  * `mode` is `'edit'` or `'view'` (those fetch from the record endpoint).
123
123
  */
124
124
  defaults?: Record<string, any>;
125
+ /**
126
+ * Field keys that render locked (visible, disabled, seeded from
127
+ * `defaults`) on create instead of editable. Ignored outside create mode.
128
+ * See `CreateRecordDialogProps.lockedFields` for the rationale.
129
+ */
130
+ lockedFields?: string[];
125
131
  /**
126
132
  * Optional pre-fetched metadata. When provided the dialog skips the
127
133
  * `/metadata/modal/:model` request and uses this shape directly.
@@ -185,7 +191,7 @@ export declare function fkSeedOption(field: FieldDef, value: any, record: any):
185
191
  export declare function isMoneyField(field: FieldDef, value: any): boolean;
186
192
  export declare function filterVisibleFields(fields: FieldDef[] | undefined, mode: 'view' | 'edit' | 'create', formValues?: Record<string, any>): FieldDef[];
187
193
  export declare function stripHiddenFieldValues(values: Record<string, any>, fields: FieldDef[] | undefined, mode: 'view' | 'edit' | 'create'): Record<string, any>;
188
- export declare function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl, timeZone, currency, onChange, }: DynamicRecordDialogProps): import("react").JSX.Element;
194
+ export declare function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, lockedFields, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl, timeZone, currency, onChange, }: DynamicRecordDialogProps): import("react").JSX.Element;
189
195
  export declare function ReadonlyEditField({ field, value }: {
190
196
  field: FieldDef;
191
197
  value: any;
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"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"}
@@ -284,7 +284,7 @@ export function stripHiddenFieldValues(values, fields, mode) {
284
284
  }
285
285
  return out;
286
286
  }
287
- export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl = identityImageUrl, timeZone, currency, onChange, }) {
287
+ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, lockedFields, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl = identityImageUrl, timeZone, currency, onChange, }) {
288
288
  const api = useApi();
289
289
  const { t, i18n } = useTranslation();
290
290
  const [modalMeta, setModalMeta] = useState(schema ? schema : null);
@@ -622,7 +622,7 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
622
622
  const isFullWidth = field.type === 'textarea' ||
623
623
  field.widget === 'textarea' ||
624
624
  field.widget === 'richtext';
625
- return (_jsx(FieldCell, { fullWidth: isFullWidth, children: _jsx(FieldRow, { field: field, record: record, value: formValues[field.key] ?? '', mode: mode, error: fieldErrors[field.key], onChange: val => {
625
+ return (_jsx(FieldCell, { fullWidth: isFullWidth, children: _jsx(FieldRow, { field: field, record: record, value: formValues[field.key] ?? '', mode: mode, locked: isCreate && !!lockedFields?.includes(field.key), error: fieldErrors[field.key], onChange: val => {
626
626
  setFormValues((prev) => ({ ...prev, [field.key]: val }));
627
627
  setFieldErrors(prev => {
628
628
  if (!prev[field.key])
@@ -655,14 +655,15 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
655
655
  function LoadingSkeleton() {
656
656
  return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-9 w-full" })] }, i))) }));
657
657
  }
658
- function FieldRow({ field, record, value, mode, onChange, error }) {
658
+ function FieldRow({ field, record, value, mode, onChange, error, locked }) {
659
659
  // A `readonly` field is server/system-generated (e.g. the GitHub addon's
660
660
  // `number`/`github_url`, filled by the API after the outbound create). On
661
661
  // CREATE it is excluded from the form entirely (see `visibleFields`); on EDIT
662
662
  // it stays visible but is NOT editable — rendered as a disabled, muted input
663
663
  // so the user sees its value without being able to change it. View mode keeps
664
- // the rich read-only renderer.
665
- const isEditReadonly = mode === 'edit' && !!field.readonly;
664
+ // the rich read-only renderer. `locked` forces the same disabled rendering on
665
+ // CREATE for a caller-specified field (see `lockedFields`).
666
+ const isEditReadonly = (mode === 'edit' && !!field.readonly) || !!locked;
666
667
  return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs(Label, { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: [field.label, field.required && mode !== 'view' && !isEditReadonly && (_jsx("span", { className: "text-destructive ml-0.5", children: "*" }))] }), mode === 'view' ? (_jsx(ViewValue, { field: field, value: value, record: record })) : isEditReadonly ? (_jsx(ReadonlyEditField, { field: field, value: value })) : (_jsx(EditField, { field: field, value: value, onChange: onChange, record: record })), error && mode !== 'view' && (_jsx("p", { className: "text-destructive text-xs mt-1", children: error }))] }));
667
668
  }
668
669
  // ReadonlyEditField — the edit-mode rendering of a `readonly` (system-generated)
@@ -674,9 +675,35 @@ export function ReadonlyEditField({ field, value }) {
674
675
  if (field.type === 'boolean' || typeof value === 'boolean') {
675
676
  return (_jsxs("div", { className: "flex items-center gap-2 py-1", children: [_jsx(Switch, { checked: !!value, disabled: true }), _jsx("span", { className: "text-sm text-muted-foreground", children: value ? 'Sí' : 'No' })] }));
676
677
  }
678
+ const fieldRef = getFieldRef(field);
679
+ if (fieldRef || field.searchEndpoint) {
680
+ return _jsx(ReadonlyRelationField, { field: field, value: value, fieldRef: fieldRef });
681
+ }
677
682
  const display = formatDisplayValue(value, field);
678
683
  return _jsx(Input, { value: display === '—' ? '' : display, disabled: true, readOnly: true, className: "text-muted-foreground" });
679
684
  }
685
+ // ReadonlyRelationField — a locked/readonly FK field (customer_id, category_id…)
686
+ // resolves the record's label instead of showing the raw id, mirroring
687
+ // RelationViewValue's lookup but rendered as a disabled input to match the rest
688
+ // of ReadonlyEditField. Without this, a locked relation field (e.g. `lockedFields`
689
+ // seeding a POS-selected customer into a vehicle create modal) would show a bare
690
+ // UUID — the exact readability bug this dialog otherwise avoids elsewhere.
691
+ function ReadonlyRelationField({ field, value, fieldRef, }) {
692
+ const rawVal = value && typeof value === 'object' ? (value.value ?? value.id) : value;
693
+ const needResolve = fieldRef != null || !!field.searchEndpoint;
694
+ const { options } = useOptionsResolver({
695
+ modelKey: '',
696
+ fieldKey: 'id',
697
+ ref: fieldRef,
698
+ endpoint: fieldRef ? undefined : field.searchEndpoint,
699
+ query: '',
700
+ limit: 50,
701
+ enabled: needResolve && rawVal != null && rawVal !== '',
702
+ });
703
+ const resolved = options.find(o => String(o.id) === String(rawVal));
704
+ const display = resolved?.label ?? (rawVal != null && rawVal !== '' ? String(rawVal) : '');
705
+ return _jsx(Input, { value: display, disabled: true, readOnly: true, className: "text-muted-foreground" });
706
+ }
680
707
  // RelationViewValue — read-only FK lead. Resolves the relation's label + image
681
708
  // from (1) the sibling object the table served, then (2) the canonical options
682
709
  // endpoint, and renders an OptionLead (thumbnail / icon / color dot) + label.
@@ -95,6 +95,15 @@ export interface CreateRecordDialogProps extends RecordDialogProps {
95
95
  onUpdate?: (recordId: string, data: Record<string, unknown>) => Promise<CreateResult>;
96
96
  /** Default values seeded into the form on create. */
97
97
  defaults?: Record<string, unknown>;
98
+ /**
99
+ * Field keys that must render locked (visible, disabled, seeded from
100
+ * `defaults`) on create instead of editable — e.g. a parent id the caller
101
+ * already knows and does not want the user to change. Unlike a `readonly`
102
+ * field (which is excluded entirely on create, see `filterVisibleFields`),
103
+ * a locked field stays visible so the user sees what value is being sent.
104
+ * Ignored outside create mode.
105
+ */
106
+ lockedFields?: string[];
98
107
  /** Notification when a create or update succeeds. */
99
108
  onSaved?: () => void;
100
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dialogs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAA;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACX,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,MAAM,CAAC,EAAE,OAAO,CAAA;QAEhB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAC3B,CAAC,CAAA;CACL;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,uEAAuE;IACvE,QAAQ,EAAE,QAAQ,CAAA;IAClB,6BAA6B;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,6BAA6B;IAC7B,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAC9D,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACrF,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC5D,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACjC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dialogs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAA;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACX,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,MAAM,CAAC,EAAE,OAAO,CAAA;QAEhB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAC3B,CAAC,CAAA;CACL;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,uEAAuE;IACvE,QAAQ,EAAE,QAAQ,CAAA;IAClB,6BAA6B;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,6BAA6B;IAC7B,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAC9D,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACrF,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC5D,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACjC"}
@@ -38,6 +38,19 @@ export interface EntitySelectProps {
38
38
  labelField?: string;
39
39
  /** Disable the whole control. */
40
40
  disabled?: boolean;
41
+ /**
42
+ * Values seeded into the create dialog's form (e.g. a parent id the caller
43
+ * already knows — a POS sale's selected customer, when creating a vehicle
44
+ * from the vehicle picker). Passed through to `CreateRecordDialog.defaults`.
45
+ */
46
+ createDefaults?: Record<string, unknown>;
47
+ /**
48
+ * Field keys from `createDefaults` that must also render locked (visible,
49
+ * disabled) on create instead of editable — e.g. don't let the user swap
50
+ * the customer while creating their vehicle from this picker. Passed
51
+ * through to `CreateRecordDialog.lockedFields`.
52
+ */
53
+ lockedCreateFields?: string[];
41
54
  }
42
- export declare function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder, searchPlaceholder, emptyText, preload, canCreate, canEdit, endpoint, labelField, disabled, }: EntitySelectProps): import("react").JSX.Element;
55
+ export declare function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder, searchPlaceholder, emptyText, preload, canCreate, canEdit, endpoint, labelField, disabled, createDefaults, lockedCreateFields, }: EntitySelectProps): import("react").JSX.Element;
43
56
  //# sourceMappingURL=entity-select.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-select.d.ts","sourceRoot":"","sources":["../src/entity-select.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAiBvE,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAC9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,sDAAsD;IACtD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3D,sFAAsF;IACtF,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAE1E,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAOD,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAI,EAAE,IAAI,EACV,WAA4B,EAC5B,iBAA6B,EAC7B,SAA4B,EAC5B,OAAe,EACf,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,QAAgB,GACnB,EAAE,iBAAiB,+BAuNnB"}
1
+ {"version":3,"file":"entity-select.d.ts","sourceRoot":"","sources":["../src/entity-select.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAiBvE,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAC9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,sDAAsD;IACtD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3D,sFAAsF;IACtF,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAE1E,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC;AAOD,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAI,EAAE,IAAI,EACV,WAA4B,EAC5B,iBAA6B,EAC7B,SAA4B,EAC5B,OAAe,EACf,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,QAAgB,EAChB,cAAc,EACd,kBAAkB,GACrB,EAAE,iBAAiB,+BAyNnB"}
@@ -25,7 +25,7 @@ import { useApi } from './api-context';
25
25
  function capabilityNamespace(model) {
26
26
  return model.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
27
27
  }
28
- export function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder = 'Seleccionar…', searchPlaceholder = 'Buscar…', emptyText = 'Sin resultados', preload = false, canCreate, canEdit, endpoint, labelField = 'name', disabled = false, }) {
28
+ export function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder = 'Seleccionar…', searchPlaceholder = 'Buscar…', emptyText = 'Sin resultados', preload = false, canCreate, canEdit, endpoint, labelField = 'name', disabled = false, createDefaults, lockedCreateFields, }) {
29
29
  const can = useCan();
30
30
  const api = useApi();
31
31
  const ns = capabilityNamespace(model);
@@ -110,7 +110,7 @@ export function EntitySelect({ model, value, label, onSelect, fetcher, icon: Ico
110
110
  searchTerm.length >= minChars &&
111
111
  results.length === 0 && _jsx(CommandEmpty, { children: emptyText }), !isLoading && results.length > 0 && (_jsx(CommandGroup, { className: "max-h-64 overflow-auto", children: results.map((row) => (_jsxs(CommandItem, { value: row.value, onSelect: () => pick(row), className: "flex flex-col items-start gap-0.5", children: [_jsx("span", { className: "text-sm font-medium", children: row.label }), row.description && (_jsx("span", { className: "text-muted-foreground text-xs", children: row.description }))] }, row.value))) })), !isLoading && !preload && searchTerm.length < minChars && (_jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-1 py-6", children: [_jsx(Search, { className: "size-5" }), _jsx("span", { className: "text-xs", children: "Escribe al menos 2 caracteres" })] }))] })] }) })] }), value
112
112
  ? mayEdit && (_jsx(Button, { type: "button", variant: "outline", size: "icon", disabled: disabled, onClick: openEdit, "aria-label": "Editar", title: "Editar", className: "shrink-0", children: _jsx(Pencil, { className: "size-4" }) }))
113
- : mayCreate && (_jsx(Button, { type: "button", variant: "outline", size: "icon", disabled: disabled, onClick: openCreate, "aria-label": "Crear", title: "Crear", className: "shrink-0", children: _jsx(Plus, { className: "size-4" }) })), dialogOpen && (_jsx(CreateRecordDialog, { modelKey: model, open: dialogOpen, onOpenChange: setDialogOpen, recordId: dialogRecordId, endpoint: base, onCreate: async (data) => {
113
+ : mayCreate && (_jsx(Button, { type: "button", variant: "outline", size: "icon", disabled: disabled, onClick: openCreate, "aria-label": "Crear", title: "Crear", className: "shrink-0", children: _jsx(Plus, { className: "size-4" }) })), dialogOpen && (_jsx(CreateRecordDialog, { modelKey: model, open: dialogOpen, onOpenChange: setDialogOpen, recordId: dialogRecordId, endpoint: base, defaults: dialogRecordId ? undefined : createDefaults, lockedFields: dialogRecordId ? undefined : lockedCreateFields, onCreate: async (data) => {
114
114
  const res = await api.post(base, data);
115
115
  const rec = (res.data?.data ?? res.data);
116
116
  selectSaved(rec);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "33.0.0",
3
+ "version": "33.1.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,6 +23,7 @@ export function CreateRecordDialog({
23
23
  endpoint,
24
24
  schema,
25
25
  defaults,
26
+ lockedFields,
26
27
  onCreate,
27
28
  onUpdate,
28
29
  onSaved,
@@ -38,6 +39,7 @@ export function CreateRecordDialog({
38
39
  endpoint={endpoint}
39
40
  schema={schema}
40
41
  defaults={defaults}
42
+ lockedFields={lockedFields}
41
43
  onCreate={onCreate}
42
44
  onUpdate={onUpdate}
43
45
  onSaved={onSaved}
@@ -243,6 +243,12 @@ export interface DynamicRecordDialogProps {
243
243
  * `mode` is `'edit'` or `'view'` (those fetch from the record endpoint).
244
244
  */
245
245
  defaults?: Record<string, any>
246
+ /**
247
+ * Field keys that render locked (visible, disabled, seeded from
248
+ * `defaults`) on create instead of editable. Ignored outside create mode.
249
+ * See `CreateRecordDialogProps.lockedFields` for the rationale.
250
+ */
251
+ lockedFields?: string[]
246
252
  /**
247
253
  * Optional pre-fetched metadata. When provided the dialog skips the
248
254
  * `/metadata/modal/:model` request and uses this shape directly.
@@ -548,6 +554,7 @@ export function DynamicRecordDialog({
548
554
  onCreate,
549
555
  onUpdate,
550
556
  defaults,
557
+ lockedFields,
551
558
  schema,
552
559
  onDelete,
553
560
  onEdit,
@@ -919,6 +926,7 @@ export function DynamicRecordDialog({
919
926
  record={record}
920
927
  value={formValues[field.key] ?? ''}
921
928
  mode={mode}
929
+ locked={isCreate && !!lockedFields?.includes(field.key)}
922
930
  error={fieldErrors[field.key]}
923
931
  onChange={val => {
924
932
  setFormValues((prev: Record<string, any>) => ({ ...prev, [field.key]: val }))
@@ -1122,16 +1130,24 @@ interface FieldRowProps {
1122
1130
  onChange: (val: any) => void
1123
1131
  /** Localized validation error for this field, shown in red under the input. */
1124
1132
  error?: string
1133
+ /**
1134
+ * Caller-forced lock (via `lockedFields`), independent of `field.readonly`.
1135
+ * Renders the same disabled/muted input as an edit-mode readonly field, but
1136
+ * applies on CREATE — where a plain `readonly` field would be excluded
1137
+ * instead. The seeded `value` (from `defaults`) still submits.
1138
+ */
1139
+ locked?: boolean
1125
1140
  }
1126
1141
 
1127
- function FieldRow({ field, record, value, mode, onChange, error }: FieldRowProps) {
1142
+ function FieldRow({ field, record, value, mode, onChange, error, locked }: FieldRowProps) {
1128
1143
  // A `readonly` field is server/system-generated (e.g. the GitHub addon's
1129
1144
  // `number`/`github_url`, filled by the API after the outbound create). On
1130
1145
  // CREATE it is excluded from the form entirely (see `visibleFields`); on EDIT
1131
1146
  // it stays visible but is NOT editable — rendered as a disabled, muted input
1132
1147
  // so the user sees its value without being able to change it. View mode keeps
1133
- // the rich read-only renderer.
1134
- const isEditReadonly = mode === 'edit' && !!field.readonly
1148
+ // the rich read-only renderer. `locked` forces the same disabled rendering on
1149
+ // CREATE for a caller-specified field (see `lockedFields`).
1150
+ const isEditReadonly = (mode === 'edit' && !!field.readonly) || !!locked
1135
1151
 
1136
1152
  return (
1137
1153
  <div className="flex flex-col gap-1.5">
@@ -1171,10 +1187,45 @@ export function ReadonlyEditField({ field, value }: { field: FieldDef; value: an
1171
1187
  </div>
1172
1188
  )
1173
1189
  }
1190
+ const fieldRef = getFieldRef(field as ActionFieldDef)
1191
+ if (fieldRef || field.searchEndpoint) {
1192
+ return <ReadonlyRelationField field={field} value={value} fieldRef={fieldRef} />
1193
+ }
1174
1194
  const display = formatDisplayValue(value, field)
1175
1195
  return <Input value={display === '—' ? '' : display} disabled readOnly className="text-muted-foreground" />
1176
1196
  }
1177
1197
 
1198
+ // ReadonlyRelationField — a locked/readonly FK field (customer_id, category_id…)
1199
+ // resolves the record's label instead of showing the raw id, mirroring
1200
+ // RelationViewValue's lookup but rendered as a disabled input to match the rest
1201
+ // of ReadonlyEditField. Without this, a locked relation field (e.g. `lockedFields`
1202
+ // seeding a POS-selected customer into a vehicle create modal) would show a bare
1203
+ // UUID — the exact readability bug this dialog otherwise avoids elsewhere.
1204
+ function ReadonlyRelationField({
1205
+ field,
1206
+ value,
1207
+ fieldRef,
1208
+ }: {
1209
+ field: FieldDef
1210
+ value: any
1211
+ fieldRef?: string
1212
+ }) {
1213
+ const rawVal = value && typeof value === 'object' ? (value.value ?? value.id) : value
1214
+ const needResolve = fieldRef != null || !!field.searchEndpoint
1215
+ const { options } = useOptionsResolver({
1216
+ modelKey: '',
1217
+ fieldKey: 'id',
1218
+ ref: fieldRef,
1219
+ endpoint: fieldRef ? undefined : field.searchEndpoint,
1220
+ query: '',
1221
+ limit: 50,
1222
+ enabled: needResolve && rawVal != null && rawVal !== '',
1223
+ })
1224
+ const resolved = options.find(o => String(o.id) === String(rawVal))
1225
+ const display = resolved?.label ?? (rawVal != null && rawVal !== '' ? String(rawVal) : '')
1226
+ return <Input value={display} disabled readOnly className="text-muted-foreground" />
1227
+ }
1228
+
1178
1229
  // RelationViewValue — read-only FK lead. Resolves the relation's label + image
1179
1230
  // from (1) the sibling object the table served, then (2) the canonical options
1180
1231
  // endpoint, and renders an OptionLead (thumbnail / icon / color dot) + label.
@@ -99,6 +99,15 @@ export interface CreateRecordDialogProps extends RecordDialogProps {
99
99
  onUpdate?: (recordId: string, data: Record<string, unknown>) => Promise<CreateResult>
100
100
  /** Default values seeded into the form on create. */
101
101
  defaults?: Record<string, unknown>
102
+ /**
103
+ * Field keys that must render locked (visible, disabled, seeded from
104
+ * `defaults`) on create instead of editable — e.g. a parent id the caller
105
+ * already knows and does not want the user to change. Unlike a `readonly`
106
+ * field (which is excluded entirely on create, see `filterVisibleFields`),
107
+ * a locked field stays visible so the user sees what value is being sent.
108
+ * Ignored outside create mode.
109
+ */
110
+ lockedFields?: string[]
102
111
  /** Notification when a create or update succeeds. */
103
112
  onSaved?: () => void
104
113
  }
@@ -75,6 +75,20 @@ export interface EntitySelectProps {
75
75
  labelField?: string
76
76
  /** Disable the whole control. */
77
77
  disabled?: boolean
78
+
79
+ /**
80
+ * Values seeded into the create dialog's form (e.g. a parent id the caller
81
+ * already knows — a POS sale's selected customer, when creating a vehicle
82
+ * from the vehicle picker). Passed through to `CreateRecordDialog.defaults`.
83
+ */
84
+ createDefaults?: Record<string, unknown>
85
+ /**
86
+ * Field keys from `createDefaults` that must also render locked (visible,
87
+ * disabled) on create instead of editable — e.g. don't let the user swap
88
+ * the customer while creating their vehicle from this picker. Passed
89
+ * through to `CreateRecordDialog.lockedFields`.
90
+ */
91
+ lockedCreateFields?: string[]
78
92
  }
79
93
 
80
94
  /** Lowercase model → permission capability namespace (Supplier → supplier). */
@@ -98,6 +112,8 @@ export function EntitySelect({
98
112
  endpoint,
99
113
  labelField = 'name',
100
114
  disabled = false,
115
+ createDefaults,
116
+ lockedCreateFields,
101
117
  }: EntitySelectProps) {
102
118
  const can = useCan()
103
119
  const api = useApi()
@@ -297,6 +313,8 @@ export function EntitySelect({
297
313
  onOpenChange={setDialogOpen}
298
314
  recordId={dialogRecordId}
299
315
  endpoint={base}
316
+ defaults={dialogRecordId ? undefined : createDefaults}
317
+ lockedFields={dialogRecordId ? undefined : lockedCreateFields}
300
318
  onCreate={async (data) => {
301
319
  const res = await api.post(base, data)
302
320
  const rec = (res.data?.data ?? res.data) as Record<string, unknown>