@asteby/metacore-runtime-react 18.28.2 → 18.28.3

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,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 18.28.3
4
+
5
+ ### Patch Changes
6
+
7
+ - e5e9fca: feat(action-modal): a field-action modal now renders the acted-on record's related-lists (model metadata.relations) below the form, as read-only context — e.g. the reception history of a transfer shown right inside the "Recibir" modal. Create actions (no record) render nothing; reuses the same DynamicRelations the detail view uses.
8
+
3
9
  ## 18.28.2
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"AA+CA,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAExB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;AA0FhD,wBAAgB,qBAAqB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,sCAiDlB"}
1
+ {"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"AAgDA,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAExB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;AA0FhD,wBAAgB,qBAAqB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,sCAiDlB"}
@@ -15,6 +15,7 @@ import { toast } from 'sonner';
15
15
  import { useApi } from './api-context';
16
16
  import { DynamicIcon } from './dynamic-icon';
17
17
  import { DynamicLineItems } from './dynamic-line-items';
18
+ import { DynamicRelations } from './dynamic-relations';
18
19
  import { DynamicSelectField } from './dynamic-select-field';
19
20
  import { DynamicDateField } from './dynamic-date-field';
20
21
  import { UploadField } from './upload-field';
@@ -137,6 +138,34 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
137
138
  const api = useApi();
138
139
  const [formData, setFormData] = useState({});
139
140
  const [executing, setExecuting] = useState(false);
141
+ // Related records to surface BELOW the form, as read-only context for the
142
+ // record being acted on — e.g. the reception history of a transfer while
143
+ // receiving against it. Sourced from the model's metadata.relations (the
144
+ // same declarative relations the detail view renders). Only row actions on a
145
+ // real record show them; create actions (no record.id) render nothing.
146
+ const [relations, setRelations] = useState([]);
147
+ const recordId = record?.id;
148
+ useEffect(() => {
149
+ let cancelled = false;
150
+ if (!open || recordId == null) {
151
+ setRelations([]);
152
+ return;
153
+ }
154
+ api.get(`/metadata/table/${model}`)
155
+ .then((res) => {
156
+ if (cancelled)
157
+ return;
158
+ const rels = res?.data?.relations ?? res?.data?.data?.relations ?? [];
159
+ setRelations(Array.isArray(rels) ? rels : []);
160
+ })
161
+ .catch(() => {
162
+ if (!cancelled)
163
+ setRelations([]);
164
+ });
165
+ return () => {
166
+ cancelled = true;
167
+ };
168
+ }, [open, model, recordId, api]);
140
169
  useEffect(() => {
141
170
  if (open && action.fields) {
142
171
  const defaults = {};
@@ -209,12 +238,12 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
209
238
  : hasLineItems
210
239
  ? '820px'
211
240
  : undefined;
212
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: 'flex max-h-[90vh] flex-col overflow-hidden ' + (widthPx ? '' : 'sm:max-w-lg'), style: { maxHeight: '90vh', ...(widthPx ? { maxWidth: widthPx, width: '95vw' } : {}) }, children: [_jsxs(DialogHeader, { className: "shrink-0", children: [_jsxs(DialogTitle, { className: "flex items-center gap-2", children: [_jsx(DynamicIcon, { name: action.icon, className: "h-5 w-5" }), action.label] }), action.confirmMessage && _jsx(DialogDescription, { children: action.confirmMessage })] }), _jsx("div", { className: "-mx-1 grid min-h-0 flex-1 gap-4 overflow-y-auto px-1 py-4 sm:grid-cols-2", children: action.fields?.map((field) => {
213
- const fullWidth = isLineItemsField(field) ||
214
- resolveWidget(field) === 'textarea' ||
215
- resolveWidget(field) === 'richtext';
216
- return (_jsxs("div", { className: 'grid gap-2 ' + (fullWidth ? 'sm:col-span-2' : ''), children: [_jsxs(Label, { htmlFor: field.key, children: [field.label, field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData)] }, field.key));
217
- }) }), _jsxs(DialogFooter, { className: "shrink-0", children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') }), _jsxs(Button, { onClick: execute, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), action.label] })] })] }) }));
241
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: 'flex max-h-[90vh] flex-col overflow-hidden ' + (widthPx ? '' : 'sm:max-w-lg'), style: { maxHeight: '90vh', ...(widthPx ? { maxWidth: widthPx, width: '95vw' } : {}) }, children: [_jsxs(DialogHeader, { className: "shrink-0", children: [_jsxs(DialogTitle, { className: "flex items-center gap-2", children: [_jsx(DynamicIcon, { name: action.icon, className: "h-5 w-5" }), action.label] }), action.confirmMessage && _jsx(DialogDescription, { children: action.confirmMessage })] }), _jsxs("div", { className: "-mx-1 grid min-h-0 flex-1 gap-4 overflow-y-auto px-1 py-4 sm:grid-cols-2", children: [action.fields?.map((field) => {
242
+ const fullWidth = isLineItemsField(field) ||
243
+ resolveWidget(field) === 'textarea' ||
244
+ resolveWidget(field) === 'richtext';
245
+ return (_jsxs("div", { className: 'grid gap-2 ' + (fullWidth ? 'sm:col-span-2' : ''), children: [_jsxs(Label, { htmlFor: field.key, children: [field.label, field.required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData)] }, field.key));
246
+ }), relations.length > 0 && (_jsx("div", { className: "sm:col-span-2", children: _jsx(DynamicRelations, { record: record, relations: relations }) }))] }), _jsxs(DialogFooter, { className: "shrink-0", children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') }), _jsxs(Button, { onClick: execute, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), action.label] })] })] }) }));
218
247
  }
219
248
  function renderField(field, value, onChange,
220
249
  // Full current form values — lets a line-items grid (and any cascading
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "18.28.2",
3
+ "version": "18.28.3",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,8 +34,8 @@
34
34
  "react-i18next": ">=13",
35
35
  "sonner": ">=1.7",
36
36
  "zustand": ">=5",
37
- "@asteby/metacore-sdk": "^3.2.0",
38
- "@asteby/metacore-ui": "^2.5.2"
37
+ "@asteby/metacore-ui": "^2.5.2",
38
+ "@asteby/metacore-sdk": "^3.2.0"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@tanstack/react-router": {
@@ -64,8 +64,8 @@
64
64
  "typescript": "^6.0.0",
65
65
  "vitest": "^4.0.0",
66
66
  "zustand": "^5.0.0",
67
- "@asteby/metacore-sdk": "3.2.0",
68
- "@asteby/metacore-ui": "2.5.2"
67
+ "@asteby/metacore-ui": "2.5.2",
68
+ "@asteby/metacore-sdk": "3.2.0"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "tsc -p tsconfig.json",
@@ -39,6 +39,7 @@ import { toast } from 'sonner'
39
39
  import { useApi } from './api-context'
40
40
  import { DynamicIcon } from './dynamic-icon'
41
41
  import { DynamicLineItems } from './dynamic-line-items'
42
+ import { DynamicRelations } from './dynamic-relations'
42
43
  import { DynamicSelectField } from './dynamic-select-field'
43
44
  import { DynamicDateField } from './dynamic-date-field'
44
45
  import { UploadField } from './upload-field'
@@ -270,6 +271,32 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
270
271
  const api = useApi()
271
272
  const [formData, setFormData] = useState<Record<string, any>>({})
272
273
  const [executing, setExecuting] = useState(false)
274
+ // Related records to surface BELOW the form, as read-only context for the
275
+ // record being acted on — e.g. the reception history of a transfer while
276
+ // receiving against it. Sourced from the model's metadata.relations (the
277
+ // same declarative relations the detail view renders). Only row actions on a
278
+ // real record show them; create actions (no record.id) render nothing.
279
+ const [relations, setRelations] = useState<any[]>([])
280
+ const recordId = record?.id
281
+ useEffect(() => {
282
+ let cancelled = false
283
+ if (!open || recordId == null) {
284
+ setRelations([])
285
+ return
286
+ }
287
+ api.get(`/metadata/table/${model}`)
288
+ .then((res) => {
289
+ if (cancelled) return
290
+ const rels = res?.data?.relations ?? res?.data?.data?.relations ?? []
291
+ setRelations(Array.isArray(rels) ? rels : [])
292
+ })
293
+ .catch(() => {
294
+ if (!cancelled) setRelations([])
295
+ })
296
+ return () => {
297
+ cancelled = true
298
+ }
299
+ }, [open, model, recordId, api])
273
300
 
274
301
  useEffect(() => {
275
302
  if (open && action.fields) {
@@ -389,6 +416,11 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
389
416
  </div>
390
417
  )
391
418
  })}
419
+ {relations.length > 0 && (
420
+ <div className="sm:col-span-2">
421
+ <DynamicRelations record={record} relations={relations} />
422
+ </div>
423
+ )}
392
424
  </div>
393
425
  <DialogFooter className="shrink-0">
394
426
  <Button variant="outline" onClick={() => onOpenChange(false)} disabled={executing}>