@@ -36,6 +36,14 @@ const colorPalette = {
36
36
gray: ' #4B5563' , // Gray
37
37
}
38
38
39
+ // Define relationship colors
40
+ const relationshipColors = {
41
+ belongsTo: ' #EF4444' , // Red
42
+ hasMany: ' #3B82F6' , // Blue
43
+ hasOne: ' #10B981' , // Green
44
+ belongsToMany: ' #8B5CF6' // Purple
45
+ }
46
+
39
47
// Model definitions based on actual Models directory
40
48
const models: ModelNode [] = [
41
49
{
@@ -60,6 +68,7 @@ const models: ModelNode[] = [
60
68
{ type: ' hasOne' , model: ' Subscriber' },
61
69
{ type: ' hasMany' , model: ' Deployment' },
62
70
{ type: ' hasMany' , model: ' Post' },
71
+ { type: ' hasMany' , model: ' AccessToken' },
63
72
{ type: ' belongsToMany' , model: ' Team' }
64
73
],
65
74
color: colorPalette .primary
@@ -113,6 +122,7 @@ const models: ModelNode[] = [
113
122
{ name: ' updated_at' , type: ' timestamp' , nullable: true }
114
123
],
115
124
relationships: [
125
+ { type: ' belongsTo' , model: ' User' },
116
126
{ type: ' hasMany' , model: ' SubscriberEmail' }
117
127
],
118
128
color: colorPalette .tertiary
@@ -143,7 +153,8 @@ const models: ModelNode[] = [
143
153
{ name: ' updated_at' , type: ' timestamp' , nullable: true }
144
154
],
145
155
relationships: [
146
- { type: ' belongsTo' , model: ' User' }
156
+ { type: ' belongsTo' , model: ' User' },
157
+ { type: ' belongsTo' , model: ' Team' }
147
158
],
148
159
color: colorPalette .primary
149
160
},
@@ -158,7 +169,8 @@ const models: ModelNode[] = [
158
169
{ name: ' updated_at' , type: ' timestamp' , nullable: true }
159
170
],
160
171
relationships: [
161
- { type: ' belongsTo' , model: ' Project' }
172
+ { type: ' belongsTo' , model: ' Project' },
173
+ { type: ' belongsTo' , model: ' User' }
162
174
],
163
175
color: colorPalette .secondary
164
176
},
@@ -194,7 +206,24 @@ const models: ModelNode[] = [
194
206
color: colorPalette .secondary
195
207
},
196
208
{
197
- id: ' order_items' ,
209
+ id: ' order' ,
210
+ name: ' Order' ,
211
+ properties: [
212
+ { name: ' id' , type: ' bigInteger' , nullable: false },
213
+ { name: ' status' , type: ' string' , nullable: false },
214
+ { name: ' total' , type: ' decimal' , nullable: false },
215
+ { name: ' user_id' , type: ' bigInteger' , nullable: false },
216
+ { name: ' created_at' , type: ' timestamp' , nullable: true },
217
+ { name: ' updated_at' , type: ' timestamp' , nullable: true }
218
+ ],
219
+ relationships: [
220
+ { type: ' belongsTo' , model: ' User' },
221
+ { type: ' hasMany' , model: ' OrderItem' }
222
+ ],
223
+ color: colorPalette .quaternary
224
+ },
225
+ {
226
+ id: ' orderItem' ,
198
227
name: ' OrderItem' ,
199
228
properties: [
200
229
{ name: ' id' , type: ' bigInteger' , nullable: false },
@@ -211,18 +240,49 @@ const models: ModelNode[] = [
211
240
212
241
// Define relationships between models
213
242
const relationships: RelationshipLink [] = [
243
+ // User relationships
214
244
{ source: ' user' , target: ' team' , type: ' belongsToMany' },
215
- { source: ' team' , target: ' user' , type: ' belongsToMany' },
216
245
{ source: ' user' , target: ' accessToken' , type: ' hasMany' },
217
246
{ source: ' user' , target: ' post' , type: ' hasMany' },
247
+ { source: ' user' , target: ' subscriber' , type: ' hasOne' },
248
+ { source: ' user' , target: ' deployment' , type: ' hasMany' },
249
+ { source: ' user' , target: ' order' , type: ' hasMany' },
250
+
251
+ // Team relationships
252
+ { source: ' team' , target: ' user' , type: ' belongsToMany' },
253
+ { source: ' team' , target: ' accessToken' , type: ' hasMany' },
254
+
255
+ // Post relationships
218
256
{ source: ' post' , target: ' user' , type: ' belongsTo' },
257
+
258
+ // Subscriber relationships
259
+ { source: ' subscriber' , target: ' user' , type: ' belongsTo' },
260
+ { source: ' subscriber' , target: ' subscriberEmail' , type: ' hasMany' },
261
+
262
+ // SubscriberEmail relationships
263
+ { source: ' subscriberEmail' , target: ' subscriber' , type: ' belongsTo' },
264
+
265
+ // AccessToken relationships
266
+ { source: ' accessToken' , target: ' user' , type: ' belongsTo' },
267
+ { source: ' accessToken' , target: ' team' , type: ' belongsTo' },
268
+
269
+ // Project relationships
219
270
{ source: ' project' , target: ' deployment' , type: ' hasMany' },
220
271
{ source: ' project' , target: ' release' , type: ' hasMany' },
272
+
273
+ // Deployment relationships
221
274
{ source: ' deployment' , target: ' project' , type: ' belongsTo' },
275
+ { source: ' deployment' , target: ' user' , type: ' belongsTo' },
276
+
277
+ // Release relationships
222
278
{ source: ' release' , target: ' project' , type: ' belongsTo' },
223
- { source: ' subscriber' , target: ' subscriberEmail' , type: ' hasMany' },
224
- { source: ' subscriberEmail' , target: ' subscriber' , type: ' belongsTo' },
225
- { source: ' order_items' , target: ' order' , type: ' belongsTo' }
279
+
280
+ // Order relationships
281
+ { source: ' order' , target: ' user' , type: ' belongsTo' },
282
+ { source: ' order' , target: ' orderItem' , type: ' hasMany' },
283
+
284
+ // OrderItem relationships
285
+ { source: ' orderItem' , target: ' order' , type: ' belongsTo' }
226
286
]
227
287
228
288
// Visualization state
@@ -340,10 +400,51 @@ const createDiagram = () => {
340
400
.attr (' height' , height )
341
401
.attr (' class' , ' dark:bg-blue-gray-800' )
342
402
343
- // Define arrow marker
344
- svg .append (' defs' )
345
- .append (' marker' )
346
- .attr (' id' , ' arrow' )
403
+ // Define arrow markers for different relationship types
404
+ const defs = svg .append (' defs' )
405
+
406
+ // Add arrow marker for belongsTo
407
+ defs .append (' marker' )
408
+ .attr (' id' , ' arrow-belongsTo' )
409
+ .attr (' viewBox' , ' 0 -5 10 10' )
410
+ .attr (' refX' , 20 )
411
+ .attr (' refY' , 0 )
412
+ .attr (' markerWidth' , 8 )
413
+ .attr (' markerHeight' , 8 )
414
+ .attr (' orient' , ' auto' )
415
+ .append (' path' )
416
+ .attr (' d' , ' M0,-5L10,0L0,5' )
417
+ .attr (' fill' , relationshipColors .belongsTo )
418
+
419
+ // Add arrow marker for hasMany
420
+ defs .append (' marker' )
421
+ .attr (' id' , ' arrow-hasMany' )
422
+ .attr (' viewBox' , ' 0 -5 10 10' )
423
+ .attr (' refX' , 20 )
424
+ .attr (' refY' , 0 )
425
+ .attr (' markerWidth' , 8 )
426
+ .attr (' markerHeight' , 8 )
427
+ .attr (' orient' , ' auto' )
428
+ .append (' path' )
429
+ .attr (' d' , ' M0,-5L10,0L0,5' )
430
+ .attr (' fill' , relationshipColors .hasMany )
431
+
432
+ // Add arrow marker for hasOne
433
+ defs .append (' marker' )
434
+ .attr (' id' , ' arrow-hasOne' )
435
+ .attr (' viewBox' , ' 0 -5 10 10' )
436
+ .attr (' refX' , 20 )
437
+ .attr (' refY' , 0 )
438
+ .attr (' markerWidth' , 8 )
439
+ .attr (' markerHeight' , 8 )
440
+ .attr (' orient' , ' auto' )
441
+ .append (' path' )
442
+ .attr (' d' , ' M0,-5L10,0L0,5' )
443
+ .attr (' fill' , relationshipColors .hasOne )
444
+
445
+ // Add arrow marker for belongsToMany
446
+ defs .append (' marker' )
447
+ .attr (' id' , ' arrow-belongsToMany' )
347
448
.attr (' viewBox' , ' 0 -5 10 10' )
348
449
.attr (' refX' , 20 )
349
450
.attr (' refY' , 0 )
@@ -352,7 +453,7 @@ const createDiagram = () => {
352
453
.attr (' orient' , ' auto' )
353
454
.append (' path' )
354
455
.attr (' d' , ' M0,-5L10,0L0,5' )
355
- .attr (' fill' , ' #9CA3AF ' )
456
+ .attr (' fill' , relationshipColors . belongsToMany )
356
457
357
458
// Add zoom behavior
358
459
const zoom = d3 .zoom <SVGSVGElement , unknown >()
@@ -492,14 +593,14 @@ const createDiagram = () => {
492
593
493
594
// Create colored background for relationship
494
595
const relationshipType = rel .type
495
- let bgColor = ' #EF4444 ' // Red for belongsTo
596
+ let bgColor = relationshipColors . belongsTo // Default red for belongsTo
496
597
497
598
if (relationshipType === ' hasMany' ) {
498
- bgColor = ' #3B82F6 ' // Blue for hasMany
599
+ bgColor = relationshipColors . hasMany
499
600
} else if (relationshipType === ' hasOne' ) {
500
- bgColor = ' #10B981 ' // Green for hasOne
601
+ bgColor = relationshipColors . hasOne
501
602
} else if (relationshipType === ' belongsToMany' ) {
502
- bgColor = ' #8B5CF6 ' // Purple for belongsToMany
603
+ bgColor = relationshipColors . belongsToMany
503
604
}
504
605
505
606
// Add relationship background
@@ -543,14 +644,14 @@ const createDiagram = () => {
543
644
.join (' line' )
544
645
.attr (' stroke' , d => {
545
646
// Color links based on relationship type
546
- if (d .type === ' hasMany' ) return ' #3B82F6 '
547
- if (d .type === ' hasOne' ) return ' #10B981 '
548
- if (d .type === ' belongsToMany' ) return ' #8B5CF6 '
549
- return ' #EF4444 ' // belongsTo
647
+ if (d .type === ' hasMany' ) return relationshipColors . hasMany
648
+ if (d .type === ' hasOne' ) return relationshipColors . hasOne
649
+ if (d .type === ' belongsToMany' ) return relationshipColors . belongsToMany
650
+ return relationshipColors . belongsTo // belongsTo
550
651
})
551
652
.attr (' stroke-width' , 2 )
552
653
.attr (' stroke-dasharray' , d => d .type === ' belongsToMany' ? ' 5,5' : ' none' )
553
- .attr (' marker-end' , ' url(#arrow) ' )
654
+ .attr (' marker-end' , d => ` url(#arrow-${ d . type }) ` )
554
655
555
656
// Create force simulation
556
657
simulation = d3 .forceSimulation <ModelNode >(models )
0 commit comments