@flowerforce/flowerbase 1.7.5 → 1.7.6-beta.1

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.
Files changed (108) hide show
  1. package/README.md +125 -1
  2. package/dist/auth/controller.d.ts.map +1 -1
  3. package/dist/auth/controller.js +11 -10
  4. package/dist/auth/plugins/jwt.js +1 -1
  5. package/dist/auth/providers/anon-user/controller.js +1 -1
  6. package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
  7. package/dist/auth/providers/custom-function/controller.js +28 -7
  8. package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
  9. package/dist/auth/providers/local-userpass/controller.js +15 -14
  10. package/dist/auth/utils.d.ts +1 -0
  11. package/dist/auth/utils.d.ts.map +1 -1
  12. package/dist/constants.d.ts +11 -0
  13. package/dist/constants.d.ts.map +1 -1
  14. package/dist/constants.js +14 -3
  15. package/dist/features/encryption/interface.d.ts +36 -0
  16. package/dist/features/encryption/interface.d.ts.map +1 -0
  17. package/dist/features/encryption/interface.js +2 -0
  18. package/dist/features/encryption/utils.d.ts +9 -0
  19. package/dist/features/encryption/utils.d.ts.map +1 -0
  20. package/dist/features/encryption/utils.js +34 -0
  21. package/dist/features/rules/utils.d.ts.map +1 -1
  22. package/dist/features/rules/utils.js +1 -11
  23. package/dist/features/triggers/index.d.ts.map +1 -1
  24. package/dist/features/triggers/index.js +5 -1
  25. package/dist/features/triggers/utils.js +3 -3
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +9 -4
  29. package/dist/monitoring/plugin.d.ts.map +1 -1
  30. package/dist/monitoring/plugin.js +31 -0
  31. package/dist/monitoring/routes/users.d.ts.map +1 -1
  32. package/dist/monitoring/routes/users.js +7 -6
  33. package/dist/monitoring/utils.d.ts.map +1 -1
  34. package/dist/monitoring/utils.js +5 -4
  35. package/dist/services/api/index.d.ts +4 -0
  36. package/dist/services/api/index.d.ts.map +1 -1
  37. package/dist/services/api/utils.d.ts +1 -0
  38. package/dist/services/api/utils.d.ts.map +1 -1
  39. package/dist/services/index.d.ts +4 -0
  40. package/dist/services/index.d.ts.map +1 -1
  41. package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
  42. package/dist/services/mongodb-atlas/index.js +9 -7
  43. package/dist/services/mongodb-atlas/model.d.ts +2 -1
  44. package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
  45. package/dist/shared/handleUserDeletion.js +1 -1
  46. package/dist/shared/handleUserRegistration.js +2 -2
  47. package/dist/utils/context/helpers.d.ts +12 -0
  48. package/dist/utils/context/helpers.d.ts.map +1 -1
  49. package/dist/utils/index.d.ts +1 -0
  50. package/dist/utils/index.d.ts.map +1 -1
  51. package/dist/utils/index.js +14 -3
  52. package/dist/utils/initializer/exposeRoutes.js +1 -1
  53. package/dist/utils/initializer/mongodbCSFLE.d.ts +69 -0
  54. package/dist/utils/initializer/mongodbCSFLE.d.ts.map +1 -0
  55. package/dist/utils/initializer/mongodbCSFLE.js +131 -0
  56. package/dist/utils/initializer/registerPlugins.d.ts +5 -1
  57. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
  58. package/dist/utils/initializer/registerPlugins.js +27 -5
  59. package/dist/utils/rules-matcher/interface.d.ts +5 -1
  60. package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
  61. package/dist/utils/rules-matcher/interface.js +2 -0
  62. package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
  63. package/dist/utils/rules-matcher/utils.js +51 -16
  64. package/package.json +4 -2
  65. package/src/auth/__tests__/controller.test.ts +1 -0
  66. package/src/auth/controller.ts +12 -11
  67. package/src/auth/plugins/jwt.ts +2 -2
  68. package/src/auth/providers/anon-user/__tests__/controller.test.ts +1 -0
  69. package/src/auth/providers/anon-user/controller.ts +2 -2
  70. package/src/auth/providers/custom-function/controller.ts +29 -8
  71. package/src/auth/providers/local-userpass/controller.ts +16 -15
  72. package/src/auth/utils.ts +1 -0
  73. package/src/constants.ts +14 -4
  74. package/src/features/encryption/interface.ts +46 -0
  75. package/src/features/encryption/utils.ts +22 -0
  76. package/src/features/rules/utils.ts +1 -11
  77. package/src/features/triggers/__tests__/index.test.ts +1 -0
  78. package/src/features/triggers/index.ts +6 -2
  79. package/src/features/triggers/utils.ts +4 -4
  80. package/src/index.ts +10 -2
  81. package/src/monitoring/plugin.ts +33 -0
  82. package/src/monitoring/routes/users.ts +8 -7
  83. package/src/monitoring/ui.collections.js +7 -10
  84. package/src/monitoring/ui.css +383 -1
  85. package/src/monitoring/ui.endpoints.js +5 -10
  86. package/src/monitoring/ui.events.js +4 -6
  87. package/src/monitoring/ui.functions.js +64 -71
  88. package/src/monitoring/ui.html +8 -0
  89. package/src/monitoring/ui.js +189 -0
  90. package/src/monitoring/ui.shared.js +239 -3
  91. package/src/monitoring/ui.triggers.js +2 -3
  92. package/src/monitoring/ui.users.js +5 -9
  93. package/src/monitoring/utils.ts +6 -5
  94. package/src/services/mongodb-atlas/index.ts +10 -13
  95. package/src/services/mongodb-atlas/model.ts +3 -1
  96. package/src/shared/handleUserDeletion.ts +2 -2
  97. package/src/shared/handleUserRegistration.ts +3 -3
  98. package/src/types/fastify-raw-body.d.ts +0 -9
  99. package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
  100. package/src/utils/__tests__/operators.test.ts +24 -0
  101. package/src/utils/__tests__/rule.test.ts +39 -0
  102. package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +2 -0
  103. package/src/utils/index.ts +12 -1
  104. package/src/utils/initializer/exposeRoutes.ts +2 -2
  105. package/src/utils/initializer/mongodbCSFLE.ts +224 -0
  106. package/src/utils/initializer/registerPlugins.ts +45 -10
  107. package/src/utils/rules-matcher/interface.ts +5 -1
  108. package/src/utils/rules-matcher/utils.ts +78 -32
@@ -10,6 +10,10 @@
10
10
  --border: #1a2f22;
11
11
  --panel: #0b120d;
12
12
  --panel-2: #0d1711;
13
+ --scrollbar-track: rgba(12, 20, 14, 0.92);
14
+ --scrollbar-thumb: rgba(49, 233, 129, 0.32);
15
+ --scrollbar-thumb-hover: rgba(49, 233, 129, 0.52);
16
+ --scrollbar-border: rgba(26, 47, 34, 0.9);
13
17
  }
14
18
 
15
19
  * {
@@ -33,6 +37,36 @@ body {
33
37
  overflow: hidden;
34
38
  }
35
39
 
40
+ * {
41
+ scrollbar-width: thin;
42
+ scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
43
+ }
44
+
45
+ *::-webkit-scrollbar {
46
+ width: 10px;
47
+ height: 10px;
48
+ }
49
+
50
+ *::-webkit-scrollbar-track {
51
+ background: var(--scrollbar-track);
52
+ border: 1px solid var(--scrollbar-border);
53
+ border-radius: 999px;
54
+ }
55
+
56
+ *::-webkit-scrollbar-thumb {
57
+ background: linear-gradient(180deg, rgba(49, 233, 129, 0.52), rgba(49, 233, 129, 0.24));
58
+ border: 2px solid var(--scrollbar-track);
59
+ border-radius: 999px;
60
+ }
61
+
62
+ *::-webkit-scrollbar-thumb:hover {
63
+ background: linear-gradient(180deg, rgba(49, 233, 129, 0.72), var(--scrollbar-thumb-hover));
64
+ }
65
+
66
+ *::-webkit-scrollbar-corner {
67
+ background: var(--scrollbar-track);
68
+ }
69
+
36
70
  body::before {
37
71
  content: "";
38
72
  position: fixed;
@@ -169,6 +203,29 @@ main {
169
203
  min-height: 0;
170
204
  }
171
205
 
206
+ .split-grid.resizable-split-grid {
207
+ --split-left-size: 66%;
208
+ --split-handle-size: 10px;
209
+ grid-template-columns: minmax(220px, var(--split-left-size)) var(--split-handle-size) minmax(220px, 1fr);
210
+ gap: 0;
211
+ }
212
+
213
+ .split-grid.resizable-split-grid > .split-pane-left {
214
+ grid-column: 1;
215
+ min-width: 0;
216
+ margin-right: 3px;
217
+ }
218
+
219
+ .split-grid.resizable-split-grid > .split-resizer {
220
+ grid-column: 2;
221
+ }
222
+
223
+ .split-grid.resizable-split-grid > .split-pane-right {
224
+ grid-column: 3;
225
+ min-width: 0;
226
+ margin-left: 3px;
227
+ }
228
+
172
229
  .users-grid {
173
230
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
174
231
  }
@@ -193,6 +250,14 @@ main {
193
250
  height: 100%;
194
251
  }
195
252
 
253
+ .column-stack.resizable-stack {
254
+ gap: 0;
255
+ }
256
+
257
+ .column-stack.resizable-stack > .stack-pane {
258
+ min-height: 140px;
259
+ }
260
+
196
261
  .right-column {
197
262
  display: flex;
198
263
  flex-direction: column;
@@ -216,6 +281,62 @@ main {
216
281
  flex: 1;
217
282
  }
218
283
 
284
+ .split-resizer,
285
+ .stack-resizer {
286
+ position: relative;
287
+ background: transparent;
288
+ touch-action: none;
289
+ }
290
+
291
+ .split-resizer::before,
292
+ .stack-resizer::before {
293
+ content: '';
294
+ position: absolute;
295
+ border-radius: 999px;
296
+ background: transparent;
297
+ transition: background-color 0.12s ease;
298
+ }
299
+
300
+ .split-resizer {
301
+ cursor: col-resize;
302
+ }
303
+
304
+ .split-resizer::before {
305
+ top: 0;
306
+ bottom: 0;
307
+ left: 50%;
308
+ width: 2px;
309
+ transform: translateX(-50%);
310
+ }
311
+
312
+ .split-resizer:hover::before,
313
+ .split-resizer:focus-visible::before {
314
+ background: rgba(49, 233, 129, 0.56);
315
+ }
316
+
317
+ .stack-resizer {
318
+ height: 10px;
319
+ margin: 0;
320
+ cursor: row-resize;
321
+ }
322
+
323
+ .stack-resizer::before {
324
+ left: 0;
325
+ right: 0;
326
+ top: 50%;
327
+ height: 2px;
328
+ transform: translateY(-50%);
329
+ }
330
+
331
+ .stack-resizer:hover::before {
332
+ background: rgba(49, 233, 129, 0.56);
333
+ }
334
+
335
+ body.is-resizing,
336
+ body.is-resizing * {
337
+ user-select: none;
338
+ }
339
+
219
340
  /* Base: Panels + Controls */
220
341
  .panel {
221
342
  background: linear-gradient(180deg, rgba(12, 20, 14, 0.95), rgba(8, 14, 10, 0.95));
@@ -365,13 +486,17 @@ button.danger {
365
486
 
366
487
  .event-row {
367
488
  display: grid;
368
- grid-template-columns: 86px 90px 70px 160px 160px 1fr;
489
+ grid-template-columns: 170px 90px 70px 160px 160px 1fr;
369
490
  gap: 8px;
370
491
  padding: 4px 6px;
371
492
  border-bottom: 1px dashed rgba(26, 47, 34, 0.6);
372
493
  cursor: pointer;
373
494
  }
374
495
 
496
+ .event-row > div:first-child {
497
+ white-space: nowrap;
498
+ }
499
+
375
500
  .event-row.event-header {
376
501
  position: sticky;
377
502
  top: 0;
@@ -463,6 +588,69 @@ button.danger {
463
588
  white-space: pre-wrap;
464
589
  }
465
590
 
591
+ .event-detail.cm-json-host {
592
+ padding: 0;
593
+ overflow: hidden;
594
+ white-space: normal;
595
+ }
596
+
597
+ .event-detail.cm-json-host .CodeMirror {
598
+ height: 100%;
599
+ min-height: 140px;
600
+ width: 100%;
601
+ font-size: 11px;
602
+ line-height: 1.5;
603
+ color: #d4d4d4;
604
+ background: var(--panel);
605
+ }
606
+
607
+ .event-detail.cm-json-host .CodeMirror-gutters {
608
+ background: #141414;
609
+ border-right: 1px solid #2b2b2b;
610
+ }
611
+
612
+ .event-detail.cm-json-host .CodeMirror-linenumber,
613
+ .event-detail.cm-json-host .CodeMirror-foldgutter-open,
614
+ .event-detail.cm-json-host .CodeMirror-foldgutter-folded {
615
+ color: #8a8a8a;
616
+ }
617
+
618
+ .event-detail.cm-json-host .CodeMirror-cursor {
619
+ border-left-color: #ffffff;
620
+ }
621
+
622
+ .event-detail.cm-json-host .CodeMirror-selected {
623
+ background: rgba(88, 166, 255, 0.35);
624
+ }
625
+
626
+ .event-detail.cm-json-host .cm-comment {
627
+ color: #6a9955;
628
+ }
629
+
630
+ .event-detail.cm-json-host .cm-string,
631
+ .event-detail.cm-json-host .cm-string-2 {
632
+ color: #ce9178;
633
+ }
634
+
635
+ .event-detail.cm-json-host .cm-number {
636
+ color: #b5cea8;
637
+ }
638
+
639
+ .event-detail.cm-json-host .cm-keyword,
640
+ .event-detail.cm-json-host .cm-atom {
641
+ color: #569cd6;
642
+ }
643
+
644
+ .event-detail.cm-json-host .cm-property,
645
+ .event-detail.cm-json-host .cm-def,
646
+ .event-detail.cm-json-host .cm-variable,
647
+ .event-detail.cm-json-host .cm-variable-2,
648
+ .event-detail.cm-json-host .cm-variable-3,
649
+ .event-detail.cm-json-host .cm-operator,
650
+ .event-detail.cm-json-host .cm-bracket {
651
+ color: #d4d4d4;
652
+ }
653
+
466
654
  .subpanel {
467
655
  margin-top: 0;
468
656
  padding: 10px;
@@ -647,6 +835,7 @@ button.small {
647
835
  padding: 6px;
648
836
  border-bottom: 1px dashed rgba(26, 47, 34, 0.6);
649
837
  cursor: pointer;
838
+ min-width: 0;
650
839
  }
651
840
 
652
841
  /* Triggers Page */
@@ -658,6 +847,7 @@ button.small {
658
847
  padding: 6px;
659
848
  border-bottom: 1px dashed rgba(26, 47, 34, 0.6);
660
849
  cursor: pointer;
850
+ min-width: 0;
661
851
  }
662
852
 
663
853
  /* Endpoints Page */
@@ -669,6 +859,7 @@ button.small {
669
859
  padding: 6px;
670
860
  border-bottom: 1px dashed rgba(26, 47, 34, 0.6);
671
861
  cursor: pointer;
862
+ min-width: 0;
672
863
  }
673
864
 
674
865
  .endpoint-row.active {
@@ -688,6 +879,7 @@ button.small {
688
879
  display: flex;
689
880
  flex-direction: column;
690
881
  gap: 2px;
882
+ min-width: 0;
691
883
  }
692
884
 
693
885
  .endpoint-panel {
@@ -751,6 +943,24 @@ button.small {
751
943
  display: flex;
752
944
  flex-direction: column;
753
945
  gap: 2px;
946
+ min-width: 0;
947
+ }
948
+
949
+ .function-row .code,
950
+ .trigger-row .code,
951
+ .endpoint-row .code,
952
+ .user-row .code,
953
+ .collection-row .code {
954
+ overflow-wrap: anywhere;
955
+ }
956
+
957
+ .function-row .hint,
958
+ .trigger-row .hint,
959
+ .endpoint-row .hint,
960
+ .history-row .hint,
961
+ .user-row .hint,
962
+ .collection-row .hint {
963
+ overflow-wrap: anywhere;
754
964
  }
755
965
 
756
966
  .user-actions {
@@ -1070,6 +1280,71 @@ button.small {
1070
1280
  pointer-events: none;
1071
1281
  }
1072
1282
 
1283
+ .code-editor.cm-enabled .code-gutter,
1284
+ .code-editor.cm-enabled #functionHighlight {
1285
+ display: none;
1286
+ }
1287
+
1288
+ .code-editor.cm-enabled .code-surface {
1289
+ overflow: hidden;
1290
+ }
1291
+
1292
+ .code-editor.cm-enabled .CodeMirror {
1293
+ height: 100%;
1294
+ width: 100%;
1295
+ font-size: 12px;
1296
+ line-height: 1.5;
1297
+ color: #d4d4d4;
1298
+ background: #1e1e1e;
1299
+ }
1300
+
1301
+ .code-editor.cm-enabled .CodeMirror-gutters {
1302
+ background: #141414;
1303
+ border-right: 1px solid #2b2b2b;
1304
+ }
1305
+
1306
+ .code-editor.cm-enabled .CodeMirror-linenumber,
1307
+ .code-editor.cm-enabled .CodeMirror-foldgutter-open,
1308
+ .code-editor.cm-enabled .CodeMirror-foldgutter-folded {
1309
+ color: #8a8a8a;
1310
+ }
1311
+
1312
+ .code-editor.cm-enabled .CodeMirror-cursor {
1313
+ border-left-color: #ffffff;
1314
+ }
1315
+
1316
+ .code-editor.cm-enabled .CodeMirror-selected {
1317
+ background: rgba(88, 166, 255, 0.35);
1318
+ }
1319
+
1320
+ .code-editor.cm-enabled .cm-comment {
1321
+ color: #6a9955;
1322
+ }
1323
+
1324
+ .code-editor.cm-enabled .cm-string,
1325
+ .code-editor.cm-enabled .cm-string-2 {
1326
+ color: #ce9178;
1327
+ }
1328
+
1329
+ .code-editor.cm-enabled .cm-number {
1330
+ color: #b5cea8;
1331
+ }
1332
+
1333
+ .code-editor.cm-enabled .cm-keyword,
1334
+ .code-editor.cm-enabled .cm-atom {
1335
+ color: #569cd6;
1336
+ }
1337
+
1338
+ .code-editor.cm-enabled .cm-def,
1339
+ .code-editor.cm-enabled .cm-property,
1340
+ .code-editor.cm-enabled .cm-variable,
1341
+ .code-editor.cm-enabled .cm-variable-2,
1342
+ .code-editor.cm-enabled .cm-variable-3,
1343
+ .code-editor.cm-enabled .cm-operator,
1344
+ .code-editor.cm-enabled .cm-bracket {
1345
+ color: #d4d4d4;
1346
+ }
1347
+
1073
1348
  #functionCode {
1074
1349
  position: absolute;
1075
1350
  inset: 0;
@@ -1134,6 +1409,65 @@ button.small {
1134
1409
  color: #dcdcaa;
1135
1410
  }
1136
1411
 
1412
+ .json-highlight .json-tree,
1413
+ .json-highlight .json-node,
1414
+ .json-highlight .json-children {
1415
+ display: block;
1416
+ }
1417
+
1418
+ .json-highlight .json-line {
1419
+ display: block;
1420
+ padding-left: calc(var(--json-depth, 0) * 14px);
1421
+ white-space: pre;
1422
+ }
1423
+
1424
+ .json-highlight .json-toggle,
1425
+ .json-highlight .json-toggle-spacer {
1426
+ display: inline-flex;
1427
+ align-items: center;
1428
+ justify-content: center;
1429
+ width: 14px;
1430
+ height: 14px;
1431
+ margin-right: 4px;
1432
+ vertical-align: text-bottom;
1433
+ }
1434
+
1435
+ .json-highlight .json-toggle {
1436
+ padding: 0;
1437
+ border: 0;
1438
+ background: transparent;
1439
+ color: var(--muted);
1440
+ cursor: pointer;
1441
+ line-height: 1;
1442
+ }
1443
+
1444
+ .json-highlight .json-toggle:hover {
1445
+ color: var(--fg);
1446
+ }
1447
+
1448
+ .json-highlight .json-brace,
1449
+ .json-highlight .json-punct {
1450
+ color: #d4d4d4;
1451
+ }
1452
+
1453
+ .json-highlight .json-summary {
1454
+ display: none;
1455
+ color: var(--muted);
1456
+ }
1457
+
1458
+ .json-highlight .json-node.is-collapsed > .json-children,
1459
+ .json-highlight .json-node.is-collapsed > .json-close {
1460
+ display: none;
1461
+ }
1462
+
1463
+ .json-highlight .json-node.is-collapsed > .json-open .json-summary {
1464
+ display: inline;
1465
+ }
1466
+
1467
+ .json-highlight .json-node.is-collapsed > .json-open .json-toggle {
1468
+ transform: rotate(-90deg);
1469
+ }
1470
+
1137
1471
  .function-io {
1138
1472
  display: grid;
1139
1473
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
@@ -1321,6 +1655,20 @@ button.small {
1321
1655
  grid-template-columns: 1fr;
1322
1656
  }
1323
1657
 
1658
+ .split-grid.resizable-split-grid {
1659
+ grid-template-columns: 1fr;
1660
+ }
1661
+
1662
+ .split-grid.resizable-split-grid > .split-pane-left,
1663
+ .split-grid.resizable-split-grid > .split-pane-right {
1664
+ grid-column: 1;
1665
+ margin: 0;
1666
+ }
1667
+
1668
+ .split-grid.resizable-split-grid > .split-resizer {
1669
+ display: none;
1670
+ }
1671
+
1324
1672
  .users-grid {
1325
1673
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
1326
1674
  }
@@ -1329,3 +1677,37 @@ button.small {
1329
1677
  grid-template-columns: minmax(0, 1fr);
1330
1678
  }
1331
1679
  }
1680
+
1681
+ @media (max-width: 760px) {
1682
+ header,
1683
+ .panel-header,
1684
+ .detail-header,
1685
+ .status,
1686
+ .panel-actions,
1687
+ .editor-actions,
1688
+ .pager {
1689
+ flex-wrap: wrap;
1690
+ }
1691
+
1692
+ .status {
1693
+ justify-content: flex-end;
1694
+ }
1695
+
1696
+ .function-row,
1697
+ .trigger-row,
1698
+ .endpoint-row {
1699
+ flex-direction: column;
1700
+ align-items: flex-start;
1701
+ justify-content: flex-start;
1702
+ }
1703
+
1704
+ .history-row,
1705
+ .user-row,
1706
+ .collection-row {
1707
+ grid-template-columns: minmax(0, 1fr);
1708
+ }
1709
+
1710
+ .function-actions {
1711
+ justify-content: flex-start;
1712
+ }
1713
+ }
@@ -51,7 +51,7 @@
51
51
  endpointTabButtons,
52
52
  endpointTabPanels
53
53
  } = dom;
54
- const { api, parseOptionalJsonValue, highlightJson, escapeHtml, formatTime, safeStringify } = utils;
54
+ const { api, parseOptionalJsonValue, renderJsonViewer, clearJsonViewer, escapeHtml, formatTime, safeStringify } = utils;
55
55
  const { setActiveTab } = helpers;
56
56
 
57
57
  const ENDPOINT_RESULT_PLACEHOLDER = state.endpointResult;
@@ -76,11 +76,9 @@
76
76
  const setEndpointResultContent = (text, highlight = false) => {
77
77
  if (!endpointResult) return;
78
78
  if (highlight) {
79
- endpointResult.classList.add('json-highlight');
80
- endpointResult.innerHTML = highlightJson(text || '');
79
+ renderJsonViewer(endpointResult, text || '', { collapsible: true });
81
80
  } else {
82
- endpointResult.classList.remove('json-highlight');
83
- endpointResult.textContent = text || '';
81
+ clearJsonViewer(endpointResult, text || '');
84
82
  }
85
83
  };
86
84
 
@@ -104,8 +102,7 @@
104
102
  const setEndpointDetail = (endpoint) => {
105
103
  if (!endpointMeta) return;
106
104
  if (!endpoint) {
107
- endpointMeta.textContent = 'select an endpoint to inspect';
108
- endpointMeta.classList.remove('json-highlight');
105
+ clearJsonViewer(endpointMeta, 'select an endpoint to inspect');
109
106
  if (endpointHint) endpointHint.textContent = 'select an endpoint';
110
107
  if (endpointFunctionButton) {
111
108
  endpointFunctionButton.classList.add('is-hidden');
@@ -121,9 +118,7 @@
121
118
  const route = endpoint.route || '';
122
119
  const functionName = endpoint.function_name || 'unknown';
123
120
  const status = endpoint.disabled ? 'disabled' : 'active';
124
- const jsonPayload = JSON.stringify(endpoint, null, 2) || '';
125
- endpointMeta.classList.add('json-highlight');
126
- endpointMeta.innerHTML = highlightJson(jsonPayload);
121
+ renderJsonViewer(endpointMeta, endpoint, { collapsible: true });
127
122
  if (endpointHint) endpointHint.textContent = status;
128
123
  if (endpointMethod) endpointMethod.value = method;
129
124
  if (endpointFunctionButton) {
@@ -26,7 +26,7 @@
26
26
  wsStatus,
27
27
  clearEvents
28
28
  } = dom;
29
- const { formatTime, highlightJson } = utils;
29
+ const { formatDateTime, highlightJson } = utils;
30
30
  const { setActiveTab } = helpers;
31
31
 
32
32
  const isOptionsEvent = (event) => {
@@ -141,7 +141,7 @@
141
141
  row.className = 'event-row';
142
142
  row.dataset.id = event.id;
143
143
  const typeClass = event.type === 'error' ? 'error' : (event.type === 'warn' ? 'warn' : '');
144
- row.innerHTML = '<div>' + formatTime(event.ts) + '</div>' +
144
+ row.innerHTML = '<div>' + formatDateTime(event.ts) + '</div>' +
145
145
  '<div class="event-type ' + typeClass + '">' + (event.type || '-') + '</div>' +
146
146
  '<div class="event-run" title="' + (runMode || '-') + '">' + (runMode || '-') + '</div>' +
147
147
  '<div class="event-invoked" title="' + (invokedFrom || '-') + '">' + (invokedFrom || '-') + '</div>' +
@@ -183,8 +183,7 @@
183
183
  state.selectedId = event.id;
184
184
  state.selectedEvent = event;
185
185
  const text = JSON.stringify(event, null, 2) || '';
186
- eventDetail.classList.add('json-highlight');
187
- eventDetail.innerHTML = highlightJson(text);
186
+ renderJsonViewer(eventDetail, text, { collapsible: true });
188
187
  const functionData = getFunctionEventData(event);
189
188
  if (functionData && eventFunctionButton) {
190
189
  eventFunctionButton.classList.remove('is-hidden');
@@ -247,8 +246,7 @@
247
246
  typeFilter.value = '';
248
247
  state.events = [];
249
248
  state.selectedEvent = null;
250
- eventDetail.classList.remove('json-highlight');
251
- eventDetail.textContent = 'select an event to inspect payload';
249
+ clearJsonViewer(eventDetail, 'select an event to inspect payload');
252
250
  if (eventFunctionButton) {
253
251
  eventFunctionButton.classList.add('is-hidden');
254
252
  eventFunctionButton.textContent = 'use in invoke';