1414import { useMemo } from 'react' ;
1515import { Badge } from '@object-ui/components' ;
1616import {
17- Settings2 ,
1817 Link2 ,
1918 KeyRound ,
2019 LayoutList ,
@@ -75,52 +74,63 @@ export function ObjectPropertiesWidget({ schema }: { schema: ObjectWidgetSchema
7574 if ( ! object ) return null ;
7675
7776 return (
78- < div className = "rounded-lg border bg-card p-4 sm:p-6 space-y-4" data-testid = "object-properties" >
79- < h2 className = "text-sm font-semibold flex items-center gap-2" >
80- < Settings2 className = "h-4 w-4" />
81- Object Properties
82- </ h2 >
83- < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-sm" >
84- < div >
85- < span className = "text-muted-foreground" > API Name</ span >
86- < p className = "font-mono text-xs mt-0.5" > { object . name } </ p >
87- </ div >
88- < div >
89- < span className = "text-muted-foreground" > Label</ span >
90- < p className = "mt-0.5" > { object . label } </ p >
91- </ div >
92- { object . pluralLabel && (
93- < div >
94- < span className = "text-muted-foreground" > Plural Label</ span >
95- < p className = "mt-0.5" > { object . pluralLabel } </ p >
77+ < div className = "space-y-6" data-testid = "object-properties" >
78+ { /* Basic Information Section */ }
79+ < div >
80+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
81+ Basic Information
82+ </ h3 >
83+ < div className = "grid grid-cols-1 sm:grid-cols-2 gap-4" >
84+ < div className = "space-y-1.5" >
85+ < label className = "text-xs font-medium text-muted-foreground" > Display Name</ label >
86+ < p className = "text-sm font-medium" > { object . label } </ p >
9687 </ div >
97- ) }
98- { object . group && (
99- < div >
100- < span className = "text-muted-foreground" > Group</ span >
101- < p className = "mt-0.5" > { object . group } </ p >
88+ < div className = "space-y-1.5" >
89+ < label className = "text-xs font-medium text-muted-foreground" > API Name</ label >
90+ < p className = "text-sm font-mono bg-muted/50 rounded px-2 py-1" > { object . name } </ p >
10291 </ div >
103- ) }
104- < div >
105- < span className = "text-muted-foreground" > Status </ span >
106- < p className = "mt-0.5" >
107- < Badge variant = { object . enabled !== false ? 'default' : 'secondary' } >
108- { object . enabled !== false ? 'Enabled' : 'Disabled' }
109- </ Badge >
110- </ p >
111- </ div >
112- < div className = "flex items-center gap-2" >
113- < span className = "text-muted-foreground" > Fields </ span >
114- < Badge variant = "outline" > { object . fieldCount ?? fields . length } </ Badge >
92+ { object . pluralLabel && (
93+ < div className = "space-y-1.5" >
94+ < label className = "text-xs font-medium text- muted-foreground" > Plural Label </ label >
95+ < p className = "text-sm font-medium" > { object . pluralLabel } </ p >
96+ </ div >
97+ ) }
98+ { object . group && (
99+ < div className = "space-y-1.5" >
100+ < label className = "text-xs font-medium text-muted-foreground" > Group </ label >
101+ < p className = "text-sm font-medium" > { object . group } </ p >
102+ </ div >
103+ ) }
115104 </ div >
116- { object . isSystem && (
117- < div >
118- < span className = "text-muted-foreground" > Type</ span >
119- < p className = "mt-0.5" >
120- < Badge variant = "secondary" > System Object</ Badge >
121- </ p >
105+ </ div >
106+
107+ { /* Configuration Section */ }
108+ < div >
109+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
110+ Configuration
111+ </ h3 >
112+ < div className = "grid grid-cols-1 sm:grid-cols-3 gap-4" >
113+ < div className = "space-y-1.5" >
114+ < label className = "text-xs font-medium text-muted-foreground" > Status</ label >
115+ < div >
116+ < Badge variant = { object . enabled !== false ? 'default' : 'secondary' } className = "font-normal" >
117+ { object . enabled !== false ? 'Enabled' : 'Disabled' }
118+ </ Badge >
119+ </ div >
122120 </ div >
123- ) }
121+ < div className = "space-y-1.5" >
122+ < label className = "text-xs font-medium text-muted-foreground" > Field Count</ label >
123+ < p className = "text-sm font-medium" > { object . fieldCount ?? fields . length } fields</ p >
124+ </ div >
125+ { object . isSystem && (
126+ < div className = "space-y-1.5" >
127+ < label className = "text-xs font-medium text-muted-foreground" > Type</ label >
128+ < div >
129+ < Badge variant = "secondary" className = "font-normal" > System Object</ Badge >
130+ </ div >
131+ </ div >
132+ ) }
133+ </ div >
124134 </ div >
125135 </ div >
126136 ) ;
@@ -137,34 +147,47 @@ export function ObjectRelationshipsWidget({ schema }: { schema: ObjectWidgetSche
137147
138148 if ( ! object ) return null ;
139149
150+ const hasRelationships = object . relationships && object . relationships . length > 0 ;
151+
140152 return (
141- < div className = "rounded-lg border bg-card p-4 sm:p-6 space-y-4" data-testid = "relationships-section" >
142- < h2 className = "text-sm font-semibold flex items-center gap-2" >
143- < Link2 className = "h-4 w-4" />
144- Relationships
145- </ h2 >
146- { object . relationships && object . relationships . length > 0 ? (
147- < div className = "space-y-2" >
148- { object . relationships . map ( ( rel , i ) => (
149- < div key = { i } className = "flex items-center gap-3 p-2 rounded-md bg-muted/40" >
150- < Badge variant = "outline" className = "text-xs shrink-0" >
151- { rel . type }
152- </ Badge >
153- < div className = "min-w-0 flex-1 text-sm" >
154- < span className = "font-medium" > { rel . label || rel . relatedObject } </ span >
155- { rel . label && rel . label !== rel . relatedObject && (
156- < span className = "text-muted-foreground ml-1" > → { rel . relatedObject } </ span >
157- ) }
158- { rel . foreignKey && (
159- < span className = "text-muted-foreground text-xs ml-2" > (FK: { rel . foreignKey } )</ span >
160- ) }
153+ < div className = "space-y-4" data-testid = "relationships-section" >
154+ < div >
155+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
156+ Relationships
157+ </ h3 >
158+ { hasRelationships ? (
159+ < div className = "space-y-3" >
160+ { object . relationships . map ( ( rel , i ) => (
161+ < div
162+ key = { i }
163+ className = "flex items-start gap-4 p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
164+ >
165+ < Badge variant = "outline" className = "text-xs shrink-0 mt-0.5" >
166+ { rel . type }
167+ </ Badge >
168+ < div className = "min-w-0 flex-1" >
169+ < p className = "font-medium text-sm" > { rel . label || rel . relatedObject } </ p >
170+ { rel . label && rel . label !== rel . relatedObject && (
171+ < p className = "text-sm text-muted-foreground mt-0.5" >
172+ Related Object: { rel . relatedObject }
173+ </ p >
174+ ) }
175+ { rel . foreignKey && (
176+ < p className = "text-xs text-muted-foreground mt-1" >
177+ Foreign Key: < span className = "font-mono" > { rel . foreignKey } </ span >
178+ </ p >
179+ ) }
180+ </ div >
161181 </ div >
162- </ div >
163- ) ) }
164- </ div >
165- ) : (
166- < p className = "text-sm text-muted-foreground" > No relationships defined for this object.</ p >
167- ) }
182+ ) ) }
183+ </ div >
184+ ) : (
185+ < div className = "text-center py-8 px-4 border border-dashed rounded-lg" >
186+ < Link2 className = "h-8 w-8 mx-auto mb-2 text-muted-foreground opacity-40" />
187+ < p className = "text-sm text-muted-foreground" > No relationships defined for this object.</ p >
188+ </ div >
189+ ) }
190+ </ div >
168191 </ div >
169192 ) ;
170193}
@@ -184,28 +207,40 @@ export function ObjectKeysWidget({ schema }: { schema: ObjectWidgetSchema }) {
184207 ) ;
185208
186209 return (
187- < div className = "rounded-lg border bg-card p-4 sm:p-6 space-y-4" data-testid = "keys-section" >
188- < h2 className = "text-sm font-semibold flex items-center gap-2" >
189- < KeyRound className = "h-4 w-4" />
190- Keys
191- </ h2 >
192- { keyFields . length > 0 ? (
193- < div className = "space-y-2" >
194- { keyFields . map ( ( kf ) => (
195- < div key = { kf . name } className = "flex items-center gap-3 p-2 rounded-md bg-muted/40" >
196- < Badge variant = { kf . name === 'id' ? 'default' : 'outline' } className = "text-xs shrink-0" >
197- { kf . name === 'id' ? 'Primary Key' : kf . externalId ? 'External ID' : 'Unique' }
198- </ Badge >
199- < div className = "min-w-0 flex-1 text-sm" >
200- < span className = "font-medium" > { kf . label || kf . name } </ span >
201- < span className = "text-muted-foreground text-xs ml-2" > ({ kf . type } )</ span >
210+ < div className = "space-y-4" data-testid = "keys-section" >
211+ < div >
212+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
213+ Unique Keys
214+ </ h3 >
215+ { keyFields . length > 0 ? (
216+ < div className = "space-y-3" >
217+ { keyFields . map ( ( kf ) => (
218+ < div
219+ key = { kf . name }
220+ className = "flex items-start gap-4 p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
221+ >
222+ < Badge
223+ variant = { kf . name === 'id' ? 'default' : 'outline' }
224+ className = "text-xs shrink-0 mt-0.5"
225+ >
226+ { kf . name === 'id' ? 'Primary Key' : kf . externalId ? 'External ID' : 'Unique' }
227+ </ Badge >
228+ < div className = "min-w-0 flex-1" >
229+ < p className = "font-medium text-sm" > { kf . label || kf . name } </ p >
230+ < p className = "text-xs text-muted-foreground mt-0.5" >
231+ Type: < span className = "font-mono" > { kf . type } </ span >
232+ </ p >
233+ </ div >
202234 </ div >
203- </ div >
204- ) ) }
205- </ div >
206- ) : (
207- < p className = "text-sm text-muted-foreground" > No unique keys or primary keys found.</ p >
208- ) }
235+ ) ) }
236+ </ div >
237+ ) : (
238+ < div className = "text-center py-8 px-4 border border-dashed rounded-lg" >
239+ < KeyRound className = "h-8 w-8 mx-auto mb-2 text-muted-foreground opacity-40" />
240+ < p className = "text-sm text-muted-foreground" > No unique keys or primary keys found.</ p >
241+ </ div >
242+ ) }
243+ </ div >
209244 </ div >
210245 ) ;
211246}
@@ -217,26 +252,30 @@ export function ObjectKeysWidget({ schema }: { schema: ObjectWidgetSchema }) {
217252
218253export function ObjectDataExperienceWidget ( _props : { schema : ObjectWidgetSchema } ) {
219254 return (
220- < div className = "rounded-lg border bg-card p-4 sm:p-6 space-y-4" data-testid = "data-experience-section" >
221- < h2 className = "text-sm font-semibold flex items-center gap-2" >
222- < LayoutList className = "h-4 w-4" />
223- Data Experience
224- </ h2 >
225- < div className = "grid grid-cols-1 sm:grid-cols-3 gap-3" >
226- < div className = "rounded-md border border-dashed p-4 text-center" data-testid = "data-experience-forms" >
227- < PanelTop className = "h-6 w-6 mx-auto mb-2 text-muted-foreground" />
228- < p className = "text-sm font-medium" > Forms</ p >
229- < p className = "text-xs text-muted-foreground mt-1" > Design forms for data entry</ p >
230- </ div >
231- < div className = "rounded-md border border-dashed p-4 text-center" data-testid = "data-experience-views" >
232- < LayoutList className = "h-6 w-6 mx-auto mb-2 text-muted-foreground" />
233- < p className = "text-sm font-medium" > Views</ p >
234- < p className = "text-xs text-muted-foreground mt-1" > Configure list and detail views</ p >
235- </ div >
236- < div className = "rounded-md border border-dashed p-4 text-center" data-testid = "data-experience-dashboards" >
237- < BarChart3 className = "h-6 w-6 mx-auto mb-2 text-muted-foreground" />
238- < p className = "text-sm font-medium" > Dashboards</ p >
239- < p className = "text-xs text-muted-foreground mt-1" > Build visual dashboards</ p >
255+ < div className = "space-y-4" data-testid = "data-experience-section" >
256+ < div >
257+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
258+ Data Experience
259+ </ h3 >
260+ < p className = "text-sm text-muted-foreground mb-4" >
261+ Configure how users interact with data in this object
262+ </ p >
263+ < div className = "grid grid-cols-1 sm:grid-cols-3 gap-4" >
264+ < div className = "rounded-lg border p-6 text-center hover:bg-accent/50 transition-colors cursor-pointer" data-testid = "data-experience-forms" >
265+ < PanelTop className = "h-8 w-8 mx-auto mb-3 text-muted-foreground" />
266+ < p className = "text-sm font-semibold mb-1" > Forms</ p >
267+ < p className = "text-xs text-muted-foreground" > Design forms for data entry</ p >
268+ </ div >
269+ < div className = "rounded-lg border p-6 text-center hover:bg-accent/50 transition-colors cursor-pointer" data-testid = "data-experience-views" >
270+ < LayoutList className = "h-8 w-8 mx-auto mb-3 text-muted-foreground" />
271+ < p className = "text-sm font-semibold mb-1" > Views</ p >
272+ < p className = "text-xs text-muted-foreground" > Configure list and detail views</ p >
273+ </ div >
274+ < div className = "rounded-lg border p-6 text-center hover:bg-accent/50 transition-colors cursor-pointer" data-testid = "data-experience-dashboards" >
275+ < BarChart3 className = "h-8 w-8 mx-auto mb-3 text-muted-foreground" />
276+ < p className = "text-sm font-semibold mb-1" > Dashboards</ p >
277+ < p className = "text-xs text-muted-foreground" > Build visual dashboards</ p >
278+ </ div >
240279 </ div >
241280 </ div >
242281 </ div >
@@ -253,17 +292,21 @@ export function ObjectDataPreviewWidget({ schema }: { schema: ObjectWidgetSchema
253292 const { object } = useObjectData ( objectName ) ;
254293
255294 return (
256- < div className = "rounded-lg border bg-card p-4 sm:p-6 space-y-4" data-testid = "data-preview-section" >
257- < h2 className = "text-sm font-semibold flex items-center gap-2" >
258- < Table className = "h-4 w-4" />
259- Data Preview
260- </ h2 >
261- < div className = "rounded-md border border-dashed p-8 text-center text-muted-foreground" >
262- < Table className = "h-8 w-8 mx-auto mb-3 opacity-40" />
263- < p className = "text-sm font-medium" > Sample Data</ p >
264- < p className = "text-xs mt-1" >
265- Live data preview for “{ object ?. label || objectName } ” will be available here
295+ < div className = "space-y-4" data-testid = "data-preview-section" >
296+ < div >
297+ < h3 className = "text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3" >
298+ Data Preview
299+ </ h3 >
300+ < p className = "text-sm text-muted-foreground mb-4" >
301+ View sample records from this object
266302 </ p >
303+ < div className = "rounded-lg border border-dashed p-12 text-center" >
304+ < Table className = "h-12 w-12 mx-auto mb-4 text-muted-foreground opacity-40" />
305+ < p className = "text-sm font-medium mb-1" > Sample Data</ p >
306+ < p className = "text-xs text-muted-foreground" >
307+ Live data preview for “{ object ?. label || objectName } ” will be available here
308+ </ p >
309+ </ div >
267310 </ div >
268311 </ div >
269312 ) ;
0 commit comments