domma-cms 0.3.0 → 0.5.2

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 (150) hide show
  1. package/README.md +3 -3
  2. package/admin/css/admin.css +1 -1
  3. package/admin/dist/domma/domma-tools.css +2313 -0
  4. package/admin/dist/domma/domma-tools.min.js +10 -0
  5. package/admin/index.html +4 -0
  6. package/admin/js/api.js +1 -1
  7. package/admin/js/app.js +8 -4
  8. package/admin/js/config/sidebar-config.js +1 -1
  9. package/admin/js/lib/markdown-toolbar.js +18 -10
  10. package/admin/js/templates/action-editor.html +171 -0
  11. package/admin/js/templates/actions-list.html +19 -0
  12. package/admin/js/templates/api-reference.html +1411 -0
  13. package/admin/js/templates/block-editor.html +158 -0
  14. package/admin/js/templates/blocks.html +8 -0
  15. package/admin/js/templates/collection-editor.html +47 -0
  16. package/admin/js/templates/collection-entries.html +3 -0
  17. package/admin/js/templates/collections.html +51 -4
  18. package/admin/js/templates/documentation.html +258 -0
  19. package/{plugins/form-builder/admin → admin/js}/templates/form-editor.html +238 -199
  20. package/{plugins/form-builder/admin → admin/js}/templates/form-submissions.html +30 -30
  21. package/{plugins/form-builder/admin/templates/forms-list.html → admin/js/templates/forms.html} +17 -17
  22. package/admin/js/templates/login.html +29 -4
  23. package/admin/js/templates/my-profile.html +17 -0
  24. package/admin/js/templates/page-editor.html +39 -0
  25. package/admin/js/templates/pages.html +6 -1
  26. package/admin/js/templates/pro-docs.html +259 -0
  27. package/admin/js/templates/role-editor.html +59 -0
  28. package/admin/js/templates/roles.html +10 -0
  29. package/admin/js/templates/settings.html +167 -23
  30. package/admin/js/templates/tutorials.html +81 -0
  31. package/admin/js/templates/user-editor.html +7 -0
  32. package/admin/js/templates/users.html +3 -26
  33. package/admin/js/templates/view-editor.html +201 -0
  34. package/admin/js/templates/view-preview.html +51 -0
  35. package/admin/js/templates/views-list.html +19 -0
  36. package/admin/js/views/action-editor.js +1 -0
  37. package/admin/js/views/actions-list.js +1 -0
  38. package/admin/js/views/api-reference.js +1 -0
  39. package/admin/js/views/block-editor.js +8 -0
  40. package/admin/js/views/blocks.js +4 -0
  41. package/admin/js/views/collection-editor.js +3 -3
  42. package/admin/js/views/collection-entries.js +1 -1
  43. package/admin/js/views/collections.js +1 -1
  44. package/admin/js/views/dashboard.js +1 -1
  45. package/admin/js/views/form-editor.js +8 -0
  46. package/admin/js/views/form-submissions.js +1 -0
  47. package/admin/js/views/forms.js +1 -0
  48. package/admin/js/views/index.js +1 -1
  49. package/admin/js/views/login.js +2 -2
  50. package/admin/js/views/media.js +1 -1
  51. package/admin/js/views/my-profile.js +1 -0
  52. package/admin/js/views/page-editor.js +34 -15
  53. package/admin/js/views/pages.js +5 -5
  54. package/admin/js/views/plugins.js +10 -10
  55. package/admin/js/views/pro-docs.js +1 -0
  56. package/admin/js/views/role-editor.js +1 -0
  57. package/admin/js/views/roles.js +4 -0
  58. package/admin/js/views/settings.js +3 -1
  59. package/admin/js/views/user-editor.js +1 -1
  60. package/admin/js/views/users.js +4 -7
  61. package/admin/js/views/view-editor.js +1 -0
  62. package/admin/js/views/view-preview.js +1 -0
  63. package/admin/js/views/views-list.js +1 -0
  64. package/bin/cli.js +1 -1
  65. package/config/auth.json +1 -0
  66. package/config/connections.json.bak +9 -0
  67. package/config/connections.json.example +9 -0
  68. package/config/navigation.json +5 -15
  69. package/config/plugins.json +19 -29
  70. package/config/server.json +6 -6
  71. package/config/site.json +16 -6
  72. package/package.json +25 -10
  73. package/plugins/example-analytics/stats.json +17 -12
  74. package/plugins/form-builder/data/forms/contacts.json +62 -62
  75. package/plugins/form-builder/data/forms/enquiries.json +103 -0
  76. package/plugins/form-builder/data/forms/feedback.json +17 -16
  77. package/plugins/form-builder/data/forms/notes.json +79 -0
  78. package/plugins/form-builder/data/forms/to-do.json +100 -0
  79. package/plugins/form-builder/data/submissions/contacts.json +1 -26
  80. package/plugins/form-builder/data/submissions/notes.json +1 -0
  81. package/plugins/form-builder/data/submissions/to-do.json +1 -0
  82. package/plugins/theme-roller/admin/templates/theme-roller.html +71 -0
  83. package/plugins/theme-roller/admin/views/theme-roller-view.js +403 -0
  84. package/plugins/theme-roller/config.js +1 -0
  85. package/plugins/theme-roller/plugin.js +233 -0
  86. package/plugins/theme-roller/plugin.json +31 -0
  87. package/plugins/theme-roller/public/active-theme.css +0 -0
  88. package/plugins/theme-roller/public/inject-head-late.html +1 -0
  89. package/public/css/forms.css +1 -0
  90. package/public/css/site.css +1 -1
  91. package/public/js/forms.js +1 -0
  92. package/public/js/site.js +1 -1
  93. package/scripts/build.js +194 -129
  94. package/scripts/pro.js +254 -0
  95. package/scripts/reset.js +33 -8
  96. package/scripts/seed.js +677 -128
  97. package/scripts/setup.js +1 -0
  98. package/server/middleware/auth.js +136 -120
  99. package/server/routes/api/actions.js +200 -0
  100. package/server/routes/api/auth.js +292 -146
  101. package/server/routes/api/blocks.js +84 -0
  102. package/server/routes/api/collections.js +79 -27
  103. package/{plugins/form-builder/plugin.js → server/routes/api/forms.js} +491 -505
  104. package/server/routes/api/layouts.js +49 -39
  105. package/server/routes/api/media.js +118 -92
  106. package/server/routes/api/navigation.js +40 -36
  107. package/server/routes/api/pages.js +132 -118
  108. package/server/routes/api/plugins.js +6 -3
  109. package/server/routes/api/settings.js +104 -88
  110. package/server/routes/api/users.js +27 -19
  111. package/server/routes/api/views.js +148 -0
  112. package/server/routes/public.js +124 -108
  113. package/server/server.js +269 -181
  114. package/server/services/actions.js +387 -0
  115. package/server/services/adapterRegistry.js +98 -0
  116. package/server/services/adapters/FileAdapter.js +192 -0
  117. package/server/services/adapters/MongoAdapter.js +220 -0
  118. package/server/services/blocks.js +162 -0
  119. package/server/services/collections.js +74 -86
  120. package/server/services/connectionManager.js +102 -0
  121. package/server/services/content.js +312 -307
  122. package/server/services/email.js +126 -0
  123. package/server/services/forms.js +173 -0
  124. package/server/services/markdown.js +1378 -747
  125. package/server/services/permissionRegistry.js +173 -0
  126. package/server/services/presetCollections.js +251 -0
  127. package/server/services/renderer.js +98 -2
  128. package/server/services/roles.js +227 -0
  129. package/server/services/rowAccess.js +104 -0
  130. package/server/services/userProfiles.js +199 -0
  131. package/server/services/users.js +281 -212
  132. package/server/services/views.js +280 -0
  133. package/server/templates/page.html +124 -113
  134. package/plugins/form-builder/admin/templates/form-settings.html +0 -29
  135. package/plugins/form-builder/admin/views/form-editor.js +0 -1444
  136. package/plugins/form-builder/admin/views/form-settings.js +0 -38
  137. package/plugins/form-builder/admin/views/form-submissions.js +0 -295
  138. package/plugins/form-builder/admin/views/forms-list.js +0 -164
  139. package/plugins/form-builder/config.js +0 -9
  140. package/plugins/form-builder/data/forms/consent.json +0 -104
  141. package/plugins/form-builder/data/forms/contact-details.json +0 -99
  142. package/plugins/form-builder/data/submissions/consent.json +0 -13
  143. package/plugins/form-builder/plugin.json +0 -52
  144. package/plugins/form-builder/public/inject-body.html +0 -352
  145. package/plugins/form-builder/public/inject-head.html +0 -58
  146. package/plugins/form-builder/public/package.json +0 -1
  147. package/scripts/copy-domma.js +0 -48
  148. package/server/services/userTypes.js +0 -167
  149. /package/plugins/form-builder/data/submissions/{contact-details.json → enquiries.json} +0 -0
  150. /package/{plugins/form-builder/public → public/js}/form-logic-engine.js +0 -0
@@ -11,6 +11,7 @@
11
11
  <button class="tab-item">Email / SMTP</button>
12
12
  <button class="tab-item">Back to Top</button>
13
13
  <button class="tab-item">Cookie Consent</button>
14
+ <button class="tab-item">Breadcrumbs</button>
14
15
  <button class="tab-item">Custom CSS</button>
15
16
  </div>
16
17
  <div class="tab-content">
@@ -104,9 +105,17 @@
104
105
  <option value="grayve-dark">Grayve Dark</option>
105
106
  <option value="grayve-light">Grayve Light</option>
106
107
  </optgroup>
107
- <optgroup label="Other">
108
+ <optgroup label="Mint">
109
+ <option value="mint-dark">Mint Dark</option>
110
+ <option value="mint-light">Mint Light</option>
111
+ </optgroup>
112
+ <optgroup label="Christmas">
108
113
  <option value="christmas-dark">Christmas Dark</option>
109
114
  <option value="christmas-light">Christmas Light</option>
115
+ </optgroup>
116
+ <optgroup label="Wedding">
117
+ <option value="wedding-dark">Wedding Dark</option>
118
+ <option value="wedding-light">Wedding Light</option>
110
119
  </optgroup>
111
120
  </select>
112
121
  <p class="form-hint text-muted" style="margin-top:0.4rem;font-size:0.8rem;">Applied to the public-facing
@@ -155,13 +164,55 @@
155
164
  <option value="grayve-dark">Grayve Dark</option>
156
165
  <option value="grayve-light">Grayve Light</option>
157
166
  </optgroup>
158
- <optgroup label="Other">
167
+ <optgroup label="Mint">
168
+ <option value="mint-dark">Mint Dark</option>
169
+ <option value="mint-light">Mint Light</option>
170
+ </optgroup>
171
+ <optgroup label="Christmas">
159
172
  <option value="christmas-dark">Christmas Dark</option>
160
173
  <option value="christmas-light">Christmas Light</option>
161
174
  </optgroup>
175
+ <optgroup label="Wedding">
176
+ <option value="wedding-dark">Wedding Dark</option>
177
+ <option value="wedding-light">Wedding Light</option>
178
+ </optgroup>
162
179
  </select>
163
180
  <p class="form-hint text-muted" style="margin-top:0.4rem;font-size:0.8rem;">Applied to the admin panel.</p>
164
181
  </div>
182
+ </div>
183
+ <!-- Auto day/night theme -->
184
+ <div class="row mt-3">
185
+ <div class="col">
186
+ <label class="form-check-label" style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
187
+ <input id="field-auto-theme-enabled" type="checkbox" class="form-check"> Enable automatic day/night
188
+ theme switching
189
+ </label>
190
+ <p id="auto-theme-roller-hint" class="form-hint text-muted"
191
+ style="display:none;margin-top:.35rem;font-size:.8rem;">Custom themes (Theme Roller) do not support
192
+ auto-switching.</p>
193
+ </div>
194
+ </div>
195
+ <div id="auto-theme-fields" class="row mt-3" style="display:none;">
196
+ <div class="col-6">
197
+ <label class="form-label">Day Theme</label>
198
+ <select id="field-day-theme" class="form-select"></select>
199
+ </div>
200
+ <div class="col-6">
201
+ <label class="form-label">Night Theme</label>
202
+ <select id="field-night-theme" class="form-select"></select>
203
+ </div>
204
+ <div class="col-3 mt-3">
205
+ <label class="form-label">Day Starts At</label>
206
+ <input id="field-day-start" type="time" class="form-input" value="07:00">
207
+ </div>
208
+ <div class="col-3 mt-3">
209
+ <label class="form-label">Night Starts At</label>
210
+ <input id="field-night-start" type="time" class="form-input" value="19:00">
211
+ </div>
212
+ <div class="col-12 mt-2">
213
+ <p class="form-hint text-muted" style="font-size:.8rem;">Themes switch based on each visitor's local
214
+ time. Any theme can be used — they need not be light/dark pairs.</p>
215
+ </div>
165
216
  </div>
166
217
  <div class="row mt-3">
167
218
  <div class="col-3">
@@ -296,52 +347,48 @@
296
347
 
297
348
  <!-- Back to Top -->
298
349
  <div class="tab-panel">
299
- <div class="row mb-3">
300
- <div class="col">
350
+ <div class="mb-3">
351
+ <label class="form-label">Label <span class="text-muted" style="font-weight:400;">(optional)</span></label>
352
+ <input id="field-btt-label" type="text" class="form-input" placeholder="Back to top">
353
+ <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">Leave blank for icon-only button.</p>
354
+ </div>
355
+ <div class="grid grid-cols-2 gap-3 mb-4">
356
+ <div>
301
357
  <label class="form-check-label" style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
302
358
  <input id="field-btt-enabled" type="checkbox" class="form-check"> Enable Back to Top button
303
359
  </label>
304
360
  </div>
361
+ <div>
362
+ <label class="form-check-label" style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
363
+ <input id="field-btt-smooth" type="checkbox" class="form-check"> Smooth scroll
364
+ </label>
365
+ </div>
305
366
  </div>
306
- <div class="row mb-3">
307
- <div class="col-4">
367
+ <div class="grid grid-cols-2 gap-3">
368
+ <div>
308
369
  <label class="form-label">Scroll Threshold (px)</label>
309
370
  <input id="field-btt-threshold" type="number" class="form-input" placeholder="300">
310
371
  <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">Show button after scrolling this many pixels.</p>
311
372
  </div>
312
- <div class="col-4">
373
+ <div>
313
374
  <label class="form-label">Position</label>
314
375
  <select id="field-btt-position" class="form-select">
315
376
  <option value="bottom-right">Bottom Right</option>
316
377
  <option value="bottom-left">Bottom Left</option>
317
378
  </select>
318
379
  </div>
319
- <div class="col-4">
380
+ <div>
320
381
  <label class="form-label">Side Offset (px)</label>
321
382
  <input id="field-btt-offset" type="number" class="form-input" placeholder="32">
322
383
  <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">Distance from the left or right
323
384
  edge.</p>
324
385
  </div>
325
- </div>
326
- <div class="row mb-3">
327
- <div class="col-4">
386
+ <div>
328
387
  <label class="form-label">Bottom Offset (px)</label>
329
388
  <input id="field-btt-bottom-offset" type="number" class="form-input" placeholder="32">
330
389
  <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">Distance from the bottom edge.</p>
331
390
  </div>
332
391
  </div>
333
- <div class="row mb-3">
334
- <div class="col-6">
335
- <label class="form-label">Label <span class="text-muted" style="font-weight:400;">(optional)</span></label>
336
- <input id="field-btt-label" type="text" class="form-input" placeholder="Back to top">
337
- <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">Leave blank for icon-only button.</p>
338
- </div>
339
- <div class="col-6" style="padding-top:2rem;">
340
- <label class="form-check-label" style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
341
- <input id="field-btt-smooth" type="checkbox" class="form-check"> Smooth scroll
342
- </label>
343
- </div>
344
- </div>
345
392
  </div>
346
393
 
347
394
  <!-- Cookie Consent -->
@@ -446,6 +493,103 @@
446
493
  </div>
447
494
  </div>
448
495
 
496
+ <!-- Custom CSS -->
497
+ <!-- Breadcrumbs -->
498
+ <div class="tab-panel">
499
+ <div class="row mb-3">
500
+ <div class="col">
501
+ <div class="card">
502
+ <div class="card-header"><strong>Breadcrumb Navigation</strong></div>
503
+ <div class="card-body">
504
+ <p class="text-muted mb-3" style="font-size:.875rem;">
505
+ When enabled, a frosted pill breadcrumb trail is fixed to your chosen viewport corner on all public
506
+ pages.
507
+ Individual pages can opt-out via "Show Breadcrumbs" in the page editor.
508
+ </p>
509
+ <div class="row mb-4">
510
+ <div class="col-auto" style="display:flex;align-items:center;gap:.75rem;">
511
+ <input id="field-breadcrumbs-enabled" type="checkbox" class="form-check">
512
+ <label for="field-breadcrumbs-enabled">Enable breadcrumbs on all pages</label>
513
+ </div>
514
+ </div>
515
+
516
+ <div class="row mb-4" style="align-items:flex-end;gap:0;">
517
+ <div class="col-sm-4">
518
+ <label class="form-label">Home label</label>
519
+ <input id="field-breadcrumbs-home-label" type="text" class="form-input" placeholder="Home">
520
+ </div>
521
+ </div>
522
+
523
+ <label class="form-label" style="margin-bottom:.6rem;">Pill Position &amp; Offsets</label>
524
+ <div class="row" style="align-items:flex-start;gap:0;">
525
+
526
+ <!-- Corner picker -->
527
+ <div class="col-auto" style="margin-right:1.5rem;margin-bottom:1rem;">
528
+ <div id="bc-pos-grid"
529
+ style="display:grid;grid-template-columns:1fr 1fr;gap:2px;border:1px solid var(--border-color,rgba(255,255,255,.1));border-radius:10px;overflow:hidden;background:var(--border-color,rgba(255,255,255,.07));width:fit-content;">
530
+ <button type="button" class="bc-pos-btn" data-pos="TL"
531
+ style="display:flex;flex-direction:column;align-items:flex-start;padding:.55rem .8rem;background:none;border:none;cursor:pointer;font-size:.78rem;color:var(--text-muted,#888);border-right:1px solid var(--border-color,rgba(255,255,255,.08));border-bottom:1px solid var(--border-color,rgba(255,255,255,.08));border-radius:0;gap:.05rem;user-select:none;transition:background .15s,color .15s;min-width:72px;">
532
+ <span
533
+ style="font-size:.6rem;opacity:.55;letter-spacing:.06em;text-transform:uppercase;line-height:1.2;">Top</span>
534
+ <span style="font-weight:600;">↖ Left</span>
535
+ </button>
536
+ <button type="button" class="bc-pos-btn" data-pos="TR"
537
+ style="display:flex;flex-direction:column;align-items:flex-end;padding:.55rem .8rem;background:none;border:none;cursor:pointer;font-size:.78rem;color:var(--text-muted,#888);border-bottom:1px solid var(--border-color,rgba(255,255,255,.08));border-radius:0;gap:.05rem;user-select:none;transition:background .15s,color .15s;min-width:72px;">
538
+ <span
539
+ style="font-size:.6rem;opacity:.55;letter-spacing:.06em;text-transform:uppercase;line-height:1.2;">Top</span>
540
+ <span style="font-weight:600;">Right ↗</span>
541
+ </button>
542
+ <button type="button" class="bc-pos-btn" data-pos="BL"
543
+ style="display:flex;flex-direction:column;align-items:flex-start;padding:.55rem .8rem;background:none;border:none;cursor:pointer;font-size:.78rem;color:var(--text-muted,#888);border-right:1px solid var(--border-color,rgba(255,255,255,.08));border-radius:0;gap:.05rem;user-select:none;transition:background .15s,color .15s;min-width:72px;">
544
+ <span style="font-weight:600;">↙ Left</span>
545
+ <span
546
+ style="font-size:.6rem;opacity:.55;letter-spacing:.06em;text-transform:uppercase;line-height:1.2;">Bottom</span>
547
+ </button>
548
+ <button type="button" class="bc-pos-btn" data-pos="BR"
549
+ style="display:flex;flex-direction:column;align-items:flex-end;padding:.55rem .8rem;background:none;border:none;cursor:pointer;font-size:.78rem;color:var(--text-muted,#888);border-radius:0;gap:.05rem;user-select:none;transition:background .15s,color .15s;min-width:72px;">
550
+ <span style="font-weight:600;">Right ↘</span>
551
+ <span
552
+ style="font-size:.6rem;opacity:.55;letter-spacing:.06em;text-transform:uppercase;line-height:1.2;">Bottom</span>
553
+ </button>
554
+ </div>
555
+ <input type="hidden" id="field-breadcrumbs-position" value="TL">
556
+ </div>
557
+
558
+ <!-- Offsets -->
559
+ <div class="col-sm-3" style="margin-right:1rem;">
560
+ <label class="form-label" for="field-bc-offset-x">Horizontal offset</label>
561
+ <div style="display:flex;align-items:center;gap:.4rem;">
562
+ <input id="field-bc-offset-x" type="number" class="form-input" min="0" max="500" placeholder="8"
563
+ style="max-width:90px;">
564
+ <span class="text-muted" style="font-size:.8rem;">px</span>
565
+ </div>
566
+ <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.75rem;">Distance from left or
567
+ right edge.</p>
568
+ </div>
569
+
570
+ <div class="col-sm-3">
571
+ <label class="form-label" for="field-bc-offset-y">Vertical offset</label>
572
+ <div style="display:flex;align-items:center;gap:.4rem;">
573
+ <input id="field-bc-offset-y" type="number" class="form-input" min="0" max="500" placeholder="60"
574
+ style="max-width:90px;">
575
+ <span class="text-muted" style="font-size:.8rem;">px</span>
576
+ </div>
577
+ <p class="form-hint text-muted" style="margin-top:.35rem;font-size:.75rem;">Distance from top or
578
+ bottom edge.</p>
579
+ </div>
580
+ </div>
581
+
582
+ </div>
583
+ </div>
584
+ </div>
585
+ </div>
586
+ <div class="row">
587
+ <div class="col">
588
+ <button id="save-breadcrumbs-btn" class="btn btn-primary"><span data-icon="save"></span> Save Breadcrumbs Settings</button>
589
+ </div>
590
+ </div>
591
+ </div>
592
+
449
593
  <!-- Custom CSS -->
450
594
  <div class="tab-panel">
451
595
  <div class="row mb-3">
@@ -229,5 +229,86 @@ export const myPluginView = {
229
229
  </div>
230
230
  </div>
231
231
 
232
+ <!-- Tutorial: Form Follow-Up -->
233
+ <div class="card card-collapsible mb-4">
234
+ <div class="card-header">
235
+ <h2>Form Follow-Up: Notifications &amp; Actions</h2>
236
+ </div>
237
+ <div class="card-body">
238
+
239
+ <p>Every form in Domma CMS can trigger up to four things after a submission is stored:</p>
240
+ <ol>
241
+ <li>Send an <strong>email notification</strong> to one or more recipients</li>
242
+ <li>POST to a <strong>webhook URL</strong></li>
243
+ <li>Execute a <strong>CMS Action</strong> (Pro)</li>
244
+ <li>Redirect the visitor to a <strong>success page</strong> (or show an inline message)</li>
245
+ </ol>
246
+ <p>These are configured per-form in the admin. Open any form in <a href="#/forms">Forms</a> and go to the
247
+ <strong>Settings</strong> and <strong>Actions</strong> tabs.</p>
248
+
249
+ <hr>
250
+
251
+ <h3>1. Email notification</h3>
252
+ <p>Go to the <strong>Actions</strong> tab of your form and enable <em>Send email on submit</em>. Enter one or
253
+ more comma-separated recipient addresses. This uses the SMTP settings configured in
254
+ <a href="#/settings">Site Settings → Email / SMTP</a>.</p>
255
+
256
+ <pre class="code-block"><code>Recipients: admin@example.com, team@example.com
257
+ Subject Prefix: [Contact Form]</code></pre>
258
+
259
+ <h3>2. Webhook</h3>
260
+ <p>Enable <em>POST to webhook on submit</em> and enter a URL. Domma will POST the following JSON body:</p>
261
+ <pre class="code-block"><code>{
262
+ "form": "enquiries",
263
+ "data": {
264
+ "full_name": "Jane Smith",
265
+ "email": "jane@example.com",
266
+ "message": "Hello!"
267
+ }
268
+ }</code></pre>
269
+ <p>Use this to integrate with Zapier, Make, Slack, or any HTTP endpoint.</p>
270
+
271
+ <h3>3. CMS Action (Pro)</h3>
272
+ <p>Actions are reusable workflow steps defined in <a href="#/actions">Actions</a>. A single action can chain
273
+ multiple steps: update a field, move an entry to another collection, send an email, call a webhook, or
274
+ delete an entry.</p>
275
+ <p>To wire an Action to a form:</p>
276
+ <ol>
277
+ <li>Create an Action in <a href="#/actions">Actions</a> targeting the same collection as your form.</li>
278
+ <li>Open the form in <a href="#/forms">Forms</a> → <strong>Actions</strong> tab → <strong>CMS Action</strong>
279
+ card.</li>
280
+ <li>Select the Action from the dropdown and save.</li>
281
+ </ol>
282
+ <p>The Action runs server-side, after the entry is saved. If it fails (e.g. MongoDB is not configured),
283
+ the submission is still stored — the action failure is non-fatal and logged as a warning.</p>
284
+
285
+ <h3>4. Success message vs. redirect</h3>
286
+ <p>After a successful submission the visitor sees one of two things:</p>
287
+ <ul>
288
+ <li><strong>Inline success message</strong> — the form is replaced by the text set in
289
+ <em>Settings → Success Message</em>. Good for simple acknowledgements.</li>
290
+ <li><strong>Page redirect</strong> — the visitor is sent to the URL set in
291
+ <em>Settings → Success Redirect URL</em>. Good for registration flows, checkouts, or when you want
292
+ a full thank-you page with additional content. <strong>Takes priority</strong> if both are set.</li>
293
+ </ul>
294
+ <p>Example: set <em>Success Redirect URL</em> to <code>/thank-you</code> and create a <code>thank-you.md</code>
295
+ page in the CMS with any content you like.</p>
296
+
297
+ <h3>Execution order</h3>
298
+ <p>On every submission, the pipeline runs in this fixed order:</p>
299
+ <ol>
300
+ <li>Validate fields + honeypot + rate limit</li>
301
+ <li>Store entry to collection</li>
302
+ <li>Send email (if enabled)</li>
303
+ <li>Call webhook (if enabled)</li>
304
+ <li>Execute CMS Action (if set)</li>
305
+ <li>Return success response → client redirects or shows message</li>
306
+ </ol>
307
+ <p>Steps 3–5 are non-fatal: a failure in any of them is logged as a warning but does not prevent the
308
+ submission from being stored or the success response from being returned.</p>
309
+
310
+ </div>
311
+ </div>
312
+
232
313
  </div>
233
314
  </div>
@@ -10,3 +10,10 @@
10
10
  <div id="user-form-container"></div>
11
11
  </div>
12
12
  </div>
13
+
14
+ <div class="card mt-4" id="profile-card" style="display:none;">
15
+ <div class="card-header"><h2><span data-icon="user"></span> Profile</h2></div>
16
+ <div class="card-body">
17
+ <div id="profile-form-container"></div>
18
+ </div>
19
+ </div>
@@ -5,31 +5,8 @@
5
5
  </div>
6
6
  </div>
7
7
 
8
- <div class="tabs" id="users-tabs">
9
- <div class="tab-list">
10
- <button class="tab-item active" data-tab="users">Users</button>
11
- <button class="tab-item" data-tab="user-types">User Types</button>
12
- </div>
13
- <div class="tab-content">
14
- <div class="tab-panel active" id="panel-users">
15
- <div class="card">
16
- <div class="card-body">
17
- <div id="users-table"></div>
18
- </div>
19
- </div>
20
- </div>
21
- <div class="tab-panel" id="panel-user-types">
22
- <div class="card">
23
- <div class="card-header" style="display:flex;align-items:center;justify-content:space-between;">
24
- <strong>User Types</strong>
25
- <button class="btn btn-primary btn-sm" id="btn-add-user-type">
26
- <span data-icon="plus"></span> Add User Type
27
- </button>
28
- </div>
29
- <div class="card-body">
30
- <div id="user-types-table"></div>
31
- </div>
32
- </div>
33
- </div>
8
+ <div class="card">
9
+ <div class="card-body">
10
+ <div id="users-table"></div>
34
11
  </div>
35
12
  </div>
@@ -0,0 +1,201 @@
1
+ <div class="view-header">
2
+ <h1><span data-icon="eye"></span> <span id="view-editor-title">New View</span></h1>
3
+ <div style="display:flex;gap:.5rem;">
4
+ <a href="#/views" class="btn btn-ghost btn-sm">
5
+ <span data-icon="arrow-left"></span> All Views
6
+ </a>
7
+ <button id="save-view-btn" class="btn btn-primary">
8
+ <span data-icon="save"></span> Save View
9
+ </button>
10
+ </div>
11
+ </div>
12
+
13
+ <div class="tabs" id="view-editor-tabs">
14
+ <div class="tab-list">
15
+ <button class="tab-item active">Source</button>
16
+ <button class="tab-item">Pipeline</button>
17
+ <button class="tab-item">Display</button>
18
+ <button class="tab-item">Access</button>
19
+ </div>
20
+ <div class="tab-content">
21
+
22
+ <!-- Source tab -->
23
+ <div class="tab-panel active">
24
+ <div class="card">
25
+ <div class="card-body" style="display:flex;flex-direction:column;gap:1rem;max-width:600px;">
26
+ <div>
27
+ <label class="form-label">Title <span style="color:var(--dm-danger,#f87171);">*</span></label>
28
+ <input id="view-title" type="text" class="form-input" placeholder="e.g. Active Premium Users">
29
+ </div>
30
+ <div>
31
+ <label class="form-label">Slug</label>
32
+ <input id="view-slug" type="text" class="form-input" placeholder="Auto-generated from title">
33
+ <small class="text-muted">URL-safe identifier. Leave blank to auto-generate.</small>
34
+ </div>
35
+ <div>
36
+ <label class="form-label">Description</label>
37
+ <textarea id="view-description" class="form-input" rows="2" placeholder="Describe what this view shows…"></textarea>
38
+ </div>
39
+ <div>
40
+ <label class="form-label">Source Collection <span style="color:var(--dm-danger,#f87171);">*</span></label>
41
+ <select id="view-source" class="form-input">
42
+ <option value="">— select collection —</option>
43
+ </select>
44
+ <small class="text-muted">Changing the collection will refresh field lists in Pipeline and
45
+ Display tabs.</small>
46
+ </div>
47
+ <div>
48
+ <label class="form-label">Connection</label>
49
+ <select id="view-connection" class="form-input">
50
+ <option value="default">default</option>
51
+ </select>
52
+ <small class="text-muted">MongoDB connection to use for execution.</small>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <!-- Pipeline tab -->
59
+ <div class="tab-panel">
60
+ <div class="card mb-3">
61
+ <div class="card-header" style="display:flex;justify-content:space-between;align-items:center;">
62
+ <h2>Aggregation Stages</h2>
63
+ <div style="display:flex;gap:.5rem;">
64
+ <select id="add-stage-type" class="form-input form-input--sm">
65
+ <option value="$match">$match — filter rows</option>
66
+ <option value="$sort">$sort — order rows</option>
67
+ <option value="$lookup">$lookup — join collection</option>
68
+ <option value="$project">$project — reshape fields</option>
69
+ <option value="$unwind">$unwind — flatten array</option>
70
+ <option value="$addFields">$addFields — compute fields</option>
71
+ <option value="$group">$group — aggregate</option>
72
+ </select>
73
+ <button id="add-stage-btn" class="btn btn-ghost btn-sm">
74
+ <span data-icon="plus"></span> Add Stage
75
+ </button>
76
+ </div>
77
+ </div>
78
+ <div class="card-body">
79
+ <div id="pipeline-stages-list">
80
+ <p class="text-muted stage-empty-placeholder" style="text-align:center;padding:2rem 0;">
81
+ No stages yet. Add a stage to filter, join, or transform your data.
82
+ </p>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <div class="card">
87
+ <div class="card-body" style="font-size:.8rem;color:var(--dm-text-muted,#888);">
88
+ <strong>Guided stages</strong> ($match, $sort) show a visual condition builder.
89
+ Other stages use a raw JSON textarea — enter only the <em>inner</em> config (e.g. for $lookup, enter
90
+ <code>{ from, localField, foreignField, as }</code> — do not wrap in <code>{ "$lookup": ... }</code>).
91
+ Field dropdowns are populated from the source collection — select a collection on the Source tab
92
+ first.
93
+ </div>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Display tab -->
98
+ <div class="tab-panel">
99
+ <div class="card">
100
+ <div class="card-body" style="display:flex;flex-direction:column;gap:1.25rem;max-width:640px;">
101
+ <div>
102
+ <label class="form-label">Display Mode</label>
103
+ <select id="view-display-mode" class="form-input">
104
+ <option value="table">Table</option>
105
+ <option value="list">List</option>
106
+ <option value="block">Block</option>
107
+ </select>
108
+ </div>
109
+ <div id="view-block-section" style="display:none;">
110
+ <label class="form-label">Block Template</label>
111
+ <select id="view-block-name" class="form-input">
112
+ <option value="">— select block —</option>
113
+ </select>
114
+ <small class="text-muted">
115
+ Choose a reusable HTML block template.
116
+ <a href="#/blocks" style="margin-left:.35rem;">Manage blocks</a>
117
+ </small>
118
+ </div>
119
+ <div>
120
+ <label class="form-label">Page Size</label>
121
+ <input id="view-page-size" type="number" class="form-input" value="25" min="1" max="200">
122
+ </div>
123
+ <div id="view-columns-section">
124
+ <label class="form-label">Columns</label>
125
+ <small class="text-muted" style="display:block;margin-bottom:.75rem;">
126
+ Choose which fields to display and their labels.
127
+ Field dropdowns are auto-populated from the source collection.
128
+ </small>
129
+ <div id="view-columns-builder" style="min-height:2rem;"></div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+
135
+ <!-- Access tab -->
136
+ <div class="tab-panel">
137
+ <div class="card mb-3">
138
+ <div class="card-body" style="max-width:500px;">
139
+ <div style="margin-bottom:1.25rem;">
140
+ <label class="form-label">Allowed Roles</label>
141
+ <small class="text-muted" style="display:block;margin-bottom:.75rem;">
142
+ Select which roles can access this view.
143
+ </small>
144
+ <div id="view-roles-checkboxes" style="display:flex;flex-direction:column;gap:.5rem;"></div>
145
+ </div>
146
+ <div>
147
+ <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
148
+ <input type="checkbox" id="view-public">
149
+ <span>Public (no authentication required)</span>
150
+ </label>
151
+ <small class="text-muted" style="display:block;margin-top:.4rem;">
152
+ When enabled, the <code>/views/:slug/public</code> endpoint requires no login.
153
+ </small>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ <div class="card">
158
+ <div class="card-header"><h2>Row-Level Access</h2></div>
159
+ <div class="card-body" style="max-width:500px;display:flex;flex-direction:column;gap:1rem;">
160
+ <div>
161
+ <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
162
+ <input type="checkbox" id="view-rowlevel-enabled">
163
+ <span>Filter results to current user's entries</span>
164
+ </label>
165
+ <small class="text-muted" style="display:block;margin-top:.4rem;">
166
+ When enabled, each user sees only their own matching entries.
167
+ Admins always see all results.
168
+ </small>
169
+ </div>
170
+ <div id="view-rowlevel-config" style="display:none;flex-direction:column;gap:1rem;">
171
+ <div>
172
+ <label class="form-label">Mode</label>
173
+ <select id="view-rowlevel-mode" class="form-input">
174
+ <option value="owner">Owner — entry was created by the current user</option>
175
+ <option value="field">Field Match — a field on the entry matches the user</option>
176
+ </select>
177
+ </div>
178
+ <div id="view-rowlevel-field-group" style="display:none;">
179
+ <label class="form-label">Field Name</label>
180
+ <input id="view-rowlevel-field" type="text" class="form-input"
181
+ placeholder="e.g. assigned_to">
182
+ <small class="text-muted">The entry field whose value must match the user property
183
+ below.</small>
184
+ </div>
185
+ <div>
186
+ <label class="form-label">User Property</label>
187
+ <select id="view-rowlevel-userkey" class="form-input">
188
+ <option value="id">id (UUID)</option>
189
+ <option value="email">email</option>
190
+ <option value="name">name</option>
191
+ <option value="role">role</option>
192
+ </select>
193
+ <small class="text-muted">Which property of the logged-in user to compare against.</small>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ </div>
199
+
200
+ </div>
201
+ </div>
@@ -0,0 +1,51 @@
1
+ <div class="view-header">
2
+ <h1><span data-icon="eye"></span> <span id="preview-title">View Preview</span></h1>
3
+ <div style="display:flex;gap:.5rem;align-items:center;">
4
+ <a id="preview-edit-btn" href="#/views" class="btn btn-ghost btn-sm">
5
+ <span data-icon="edit-3"></span> Edit View
6
+ </a>
7
+ <a href="#/views" class="btn btn-ghost btn-sm">
8
+ <span data-icon="arrow-left"></span> All Views
9
+ </a>
10
+ <button id="preview-run-btn" class="btn btn-primary">
11
+ <span data-icon="play"></span> Run
12
+ </button>
13
+ </div>
14
+ </div>
15
+
16
+ <div class="card mb-3" id="preview-meta-card" style="display:none;">
17
+ <div class="card-body" style="display:flex;gap:2rem;flex-wrap:wrap;font-size:.875rem;color:var(--dm-text-muted,#888);">
18
+ <span>Source: <strong id="preview-source"></strong></span>
19
+ <span>Connection: <strong id="preview-connection"></strong></span>
20
+ <span>Mode: <strong id="preview-mode"></strong></span>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="card mb-3" id="preview-pagination" style="display:none;">
25
+ <div class="card-body" style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap;">
26
+ <span id="preview-count" class="text-muted" style="font-size:.875rem;"></span>
27
+ <div style="display:flex;gap:.4rem;margin-left:auto;">
28
+ <button id="preview-prev" class="btn btn-ghost btn-sm" disabled>
29
+ <span data-icon="chevron-left"></span> Prev
30
+ </button>
31
+ <span id="preview-page-label" style="padding:.25rem .5rem;font-size:.875rem;align-self:center;"></span>
32
+ <button id="preview-next" class="btn btn-ghost btn-sm" disabled>
33
+ Next <span data-icon="chevron-right"></span>
34
+ </button>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="card">
40
+ <div class="card-body">
41
+ <div id="preview-placeholder" style="text-align:center;padding:3rem;color:var(--dm-text-muted,#888);">
42
+ <span data-icon="play" data-icon-size="48" style="opacity:.3;display:block;margin-bottom:1rem;"></span>
43
+ Click <strong>Run</strong> to execute this view and see results.
44
+ </div>
45
+ <div id="preview-table" style="display:none;"></div>
46
+ <div id="preview-list" style="display:none;"></div>
47
+ <div id="preview-empty" style="display:none;text-align:center;padding:2rem;color:var(--dm-text-muted,#888);">
48
+ No results returned.
49
+ </div>
50
+ </div>
51
+ </div>