@object-ui/plugin-detail 0.5.0 → 2.0.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.
@@ -55,43 +55,58 @@ export const DetailView: React.FC<DetailViewProps> = ({
55
55
  });
56
56
  } else if (schema.api && schema.resourceId) {
57
57
  setLoading(true);
58
- // TODO: Fetch from API
59
- // This would integrate with the data provider
60
- setTimeout(() => {
61
- setLoading(false);
62
- }, 500);
58
+ fetch(`${schema.api}/${schema.resourceId}`)
59
+ .then(res => res.json())
60
+ .then(result => {
61
+ setData(result?.data || result);
62
+ })
63
+ .catch(err => {
64
+ console.error('Failed to fetch detail data:', err);
65
+ })
66
+ .finally(() => setLoading(false));
63
67
  }
64
68
  }, [schema.api, schema.resourceId]);
65
69
 
66
70
  const handleBack = React.useCallback(() => {
67
71
  if (onBack) {
68
72
  onBack();
73
+ } else if (schema.onNavigate) {
74
+ // SPA-aware navigation
75
+ const backUrl = schema.backUrl || (schema.objectName ? `/${schema.objectName}` : '/');
76
+ schema.onNavigate(backUrl, { replace: true });
69
77
  } else if (schema.backUrl) {
70
78
  window.location.href = schema.backUrl;
71
79
  } else {
72
80
  window.history.back();
73
81
  }
74
- }, [onBack, schema.backUrl]);
82
+ }, [onBack, schema]);
75
83
 
76
84
  const handleEdit = React.useCallback(() => {
77
85
  if (onEdit) {
78
86
  onEdit();
87
+ } else if (schema.onNavigate && schema.editUrl) {
88
+ // SPA-aware navigation
89
+ schema.onNavigate(schema.editUrl);
90
+ } else if (schema.onNavigate && schema.objectName && schema.resourceId) {
91
+ // Build edit URL from object + resource
92
+ schema.onNavigate(`/${schema.objectName}/${schema.resourceId}/edit`);
79
93
  } else if (schema.editUrl) {
80
94
  window.location.href = schema.editUrl;
81
95
  }
82
- // TODO: Implement inline edit mode
83
- // else {
84
- // setEditMode(true);
85
- // }
86
- }, [onEdit, schema.editUrl]);
96
+ }, [onEdit, schema]);
87
97
 
88
98
  const handleDelete = React.useCallback(() => {
89
- // TODO: Replace with proper confirmation dialog component
90
99
  const confirmMessage = schema.deleteConfirmation || 'Are you sure you want to delete this record?';
100
+ // Use window.confirm as fallback — the ActionProvider's onConfirm handler
101
+ // will intercept this if wired up via the action system.
91
102
  if (window.confirm(confirmMessage)) {
92
103
  onDelete?.();
104
+ // Navigate back after deletion if onNavigate available
105
+ if (schema.onNavigate && schema.objectName) {
106
+ schema.onNavigate(`/${schema.objectName}`, { replace: true });
107
+ }
93
108
  }
94
- }, [onDelete, schema.deleteConfirmation]);
109
+ }, [onDelete, schema]);
95
110
 
96
111
  if (loading || schema.loading) {
97
112
  return (
@@ -196,6 +211,7 @@ export const DetailView: React.FC<DetailViewProps> = ({
196
211
  api={related.api}
197
212
  data={related.data}
198
213
  columns={related.columns as any}
214
+ dataSource={dataSource}
199
215
  />
200
216
  ))}
201
217
  </div>
@@ -9,6 +9,7 @@
9
9
  import * as React from 'react';
10
10
  import { Card, CardHeader, CardTitle, CardContent } from '@object-ui/components';
11
11
  import { SchemaRenderer } from '@object-ui/react';
12
+ import type { DataSource } from '@object-ui/types';
12
13
 
13
14
  export interface RelatedListProps {
14
15
  title: string;
@@ -18,6 +19,7 @@ export interface RelatedListProps {
18
19
  schema?: any;
19
20
  columns?: any[];
20
21
  className?: string;
22
+ dataSource?: DataSource;
21
23
  }
22
24
 
23
25
  export const RelatedList: React.FC<RelatedListProps> = ({
@@ -28,18 +30,41 @@ export const RelatedList: React.FC<RelatedListProps> = ({
28
30
  schema,
29
31
  columns,
30
32
  className,
33
+ dataSource,
31
34
  }) => {
32
- const [relatedData] = React.useState(data);
35
+ const [relatedData, setRelatedData] = React.useState(data);
33
36
  const [loading, setLoading] = React.useState(false);
34
37
 
35
38
  React.useEffect(() => {
36
39
  if (api && !data.length) {
37
40
  setLoading(true);
38
- // TODO: Fetch data from API
39
- // This would integrate with the data provider
40
- setLoading(false);
41
+ if (dataSource) {
42
+ dataSource.find(api).then((result) => {
43
+ const items = Array.isArray(result)
44
+ ? result
45
+ : Array.isArray((result as any)?.data)
46
+ ? (result as any).data
47
+ : [];
48
+ setRelatedData(items);
49
+ setLoading(false);
50
+ }).catch((err) => {
51
+ console.error('Failed to fetch related data:', err);
52
+ setLoading(false);
53
+ });
54
+ } else {
55
+ fetch(api)
56
+ .then(res => res.json())
57
+ .then(result => {
58
+ const items = Array.isArray(result) ? result : (result?.data || []);
59
+ setRelatedData(items);
60
+ })
61
+ .catch(err => {
62
+ console.error('Failed to fetch related data:', err);
63
+ })
64
+ .finally(() => setLoading(false));
65
+ }
41
66
  }
42
- }, [api, data]);
67
+ }, [api, data, dataSource]);
43
68
 
44
69
  const viewSchema = React.useMemo(() => {
45
70
  if (schema) return schema;
package/src/index.tsx CHANGED
@@ -84,3 +84,16 @@ ComponentRegistry.register('related-list', RelatedList, {
84
84
  { name: 'columns', type: 'array', label: 'Columns' },
85
85
  ],
86
86
  });
87
+
88
+ // Alias for generic view
89
+ ComponentRegistry.register('detail', DetailView, {
90
+ namespace: 'view',
91
+ category: 'view',
92
+ label: 'Detail',
93
+ icon: 'FileText',
94
+ inputs: [
95
+ { name: 'objectName', type: 'string', label: 'Object Name', required: true },
96
+ { name: 'recordId', type: 'string', label: 'Record ID' },
97
+ { name: 'fields', type: 'array', label: 'Fields' },
98
+ ]
99
+ });