@saltcorn/server 0.9.4-beta.9 → 0.9.5-beta.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.
Files changed (183) hide show
  1. package/app.js +16 -1
  2. package/auth/admin.js +19 -3
  3. package/auth/routes.js +16 -4
  4. package/auth/testhelp.js +17 -1
  5. package/load_plugins.js +8 -2
  6. package/locales/en.json +24 -2
  7. package/markup/admin.js +22 -18
  8. package/package.json +10 -9
  9. package/public/dayjslocales/af.js +1 -0
  10. package/public/dayjslocales/am.js +1 -0
  11. package/public/dayjslocales/ar-dz.js +1 -0
  12. package/public/dayjslocales/ar-iq.js +1 -0
  13. package/public/dayjslocales/ar-kw.js +1 -0
  14. package/public/dayjslocales/ar-ly.js +1 -0
  15. package/public/dayjslocales/ar-ma.js +1 -0
  16. package/public/dayjslocales/ar-sa.js +1 -0
  17. package/public/dayjslocales/ar-tn.js +1 -0
  18. package/public/dayjslocales/ar.js +1 -0
  19. package/public/dayjslocales/az.js +1 -0
  20. package/public/dayjslocales/be.js +1 -0
  21. package/public/dayjslocales/bg.js +1 -0
  22. package/public/dayjslocales/bi.js +1 -0
  23. package/public/dayjslocales/bm.js +1 -0
  24. package/public/dayjslocales/bn-bd.js +1 -0
  25. package/public/dayjslocales/bn.js +1 -0
  26. package/public/dayjslocales/bo.js +1 -0
  27. package/public/dayjslocales/br.js +1 -0
  28. package/public/dayjslocales/bs.js +1 -0
  29. package/public/dayjslocales/ca.js +1 -0
  30. package/public/dayjslocales/cs.js +1 -0
  31. package/public/dayjslocales/cv.js +1 -0
  32. package/public/dayjslocales/cy.js +1 -0
  33. package/public/dayjslocales/da.js +1 -0
  34. package/public/dayjslocales/de-at.js +1 -0
  35. package/public/dayjslocales/de-ch.js +1 -0
  36. package/public/dayjslocales/de.js +1 -0
  37. package/public/dayjslocales/dv.js +1 -0
  38. package/public/dayjslocales/el.js +1 -0
  39. package/public/dayjslocales/en-au.js +1 -0
  40. package/public/dayjslocales/en-ca.js +1 -0
  41. package/public/dayjslocales/en-gb.js +1 -0
  42. package/public/dayjslocales/en-ie.js +1 -0
  43. package/public/dayjslocales/en-il.js +1 -0
  44. package/public/dayjslocales/en-in.js +1 -0
  45. package/public/dayjslocales/en-nz.js +1 -0
  46. package/public/dayjslocales/en-sg.js +1 -0
  47. package/public/dayjslocales/en-tt.js +1 -0
  48. package/public/dayjslocales/en.js +1 -0
  49. package/public/dayjslocales/eo.js +1 -0
  50. package/public/dayjslocales/es-do.js +1 -0
  51. package/public/dayjslocales/es-mx.js +1 -0
  52. package/public/dayjslocales/es-pr.js +1 -0
  53. package/public/dayjslocales/es-us.js +1 -0
  54. package/public/dayjslocales/es.js +1 -0
  55. package/public/dayjslocales/et.js +1 -0
  56. package/public/dayjslocales/eu.js +1 -0
  57. package/public/dayjslocales/fa.js +1 -0
  58. package/public/dayjslocales/fi.js +1 -0
  59. package/public/dayjslocales/fo.js +1 -0
  60. package/public/dayjslocales/fr-ca.js +1 -0
  61. package/public/dayjslocales/fr-ch.js +1 -0
  62. package/public/dayjslocales/fr.js +1 -0
  63. package/public/dayjslocales/fy.js +1 -0
  64. package/public/dayjslocales/ga.js +1 -0
  65. package/public/dayjslocales/gd.js +1 -0
  66. package/public/dayjslocales/gl.js +1 -0
  67. package/public/dayjslocales/gom-latn.js +1 -0
  68. package/public/dayjslocales/gu.js +1 -0
  69. package/public/dayjslocales/he.js +1 -0
  70. package/public/dayjslocales/hi.js +1 -0
  71. package/public/dayjslocales/hr.js +1 -0
  72. package/public/dayjslocales/ht.js +1 -0
  73. package/public/dayjslocales/hu.js +1 -0
  74. package/public/dayjslocales/hy-am.js +1 -0
  75. package/public/dayjslocales/id.js +1 -0
  76. package/public/dayjslocales/is.js +1 -0
  77. package/public/dayjslocales/it-ch.js +1 -0
  78. package/public/dayjslocales/it.js +1 -0
  79. package/public/dayjslocales/ja.js +1 -0
  80. package/public/dayjslocales/jv.js +1 -0
  81. package/public/dayjslocales/ka.js +1 -0
  82. package/public/dayjslocales/kk.js +1 -0
  83. package/public/dayjslocales/km.js +1 -0
  84. package/public/dayjslocales/kn.js +1 -0
  85. package/public/dayjslocales/ko.js +1 -0
  86. package/public/dayjslocales/ku.js +1 -0
  87. package/public/dayjslocales/ky.js +1 -0
  88. package/public/dayjslocales/lb.js +1 -0
  89. package/public/dayjslocales/lo.js +1 -0
  90. package/public/dayjslocales/lt.js +1 -0
  91. package/public/dayjslocales/lv.js +1 -0
  92. package/public/dayjslocales/me.js +1 -0
  93. package/public/dayjslocales/mi.js +1 -0
  94. package/public/dayjslocales/mk.js +1 -0
  95. package/public/dayjslocales/ml.js +1 -0
  96. package/public/dayjslocales/mn.js +1 -0
  97. package/public/dayjslocales/mr.js +1 -0
  98. package/public/dayjslocales/ms-my.js +1 -0
  99. package/public/dayjslocales/ms.js +1 -0
  100. package/public/dayjslocales/mt.js +1 -0
  101. package/public/dayjslocales/my.js +1 -0
  102. package/public/dayjslocales/nb.js +1 -0
  103. package/public/dayjslocales/ne.js +1 -0
  104. package/public/dayjslocales/nl-be.js +1 -0
  105. package/public/dayjslocales/nl.js +1 -0
  106. package/public/dayjslocales/nn.js +1 -0
  107. package/public/dayjslocales/oc-lnc.js +1 -0
  108. package/public/dayjslocales/pa-in.js +1 -0
  109. package/public/dayjslocales/pl.js +1 -0
  110. package/public/dayjslocales/pt-br.js +1 -0
  111. package/public/dayjslocales/pt.js +1 -0
  112. package/public/dayjslocales/rn.js +1 -0
  113. package/public/dayjslocales/ro.js +1 -0
  114. package/public/dayjslocales/ru.js +1 -0
  115. package/public/dayjslocales/rw.js +1 -0
  116. package/public/dayjslocales/sd.js +1 -0
  117. package/public/dayjslocales/se.js +1 -0
  118. package/public/dayjslocales/si.js +1 -0
  119. package/public/dayjslocales/sk.js +1 -0
  120. package/public/dayjslocales/sl.js +1 -0
  121. package/public/dayjslocales/sq.js +1 -0
  122. package/public/dayjslocales/sr-cyrl.js +1 -0
  123. package/public/dayjslocales/sr.js +1 -0
  124. package/public/dayjslocales/ss.js +1 -0
  125. package/public/dayjslocales/sv-fi.js +1 -0
  126. package/public/dayjslocales/sv.js +1 -0
  127. package/public/dayjslocales/sw.js +1 -0
  128. package/public/dayjslocales/ta.js +1 -0
  129. package/public/dayjslocales/te.js +1 -0
  130. package/public/dayjslocales/tet.js +1 -0
  131. package/public/dayjslocales/tg.js +1 -0
  132. package/public/dayjslocales/th.js +1 -0
  133. package/public/dayjslocales/tk.js +1 -0
  134. package/public/dayjslocales/tl-ph.js +1 -0
  135. package/public/dayjslocales/tlh.js +1 -0
  136. package/public/dayjslocales/tr.js +1 -0
  137. package/public/dayjslocales/tzl.js +1 -0
  138. package/public/dayjslocales/tzm-latn.js +1 -0
  139. package/public/dayjslocales/tzm.js +1 -0
  140. package/public/dayjslocales/ug-cn.js +1 -0
  141. package/public/dayjslocales/uk.js +1 -0
  142. package/public/dayjslocales/ur.js +1 -0
  143. package/public/dayjslocales/uz-latn.js +1 -0
  144. package/public/dayjslocales/uz.js +1 -0
  145. package/public/dayjslocales/vi.js +1 -0
  146. package/public/dayjslocales/x-pseudo.js +1 -0
  147. package/public/dayjslocales/yo.js +1 -0
  148. package/public/dayjslocales/zh-cn.js +1 -0
  149. package/public/dayjslocales/zh-hk.js +1 -0
  150. package/public/dayjslocales/zh-tw.js +1 -0
  151. package/public/dayjslocales/zh.js +1 -0
  152. package/public/gridedit.js +2 -2
  153. package/public/log_viewer_utils.js +156 -0
  154. package/public/saltcorn-builder.css +43 -2
  155. package/public/saltcorn-common.js +39 -29
  156. package/public/saltcorn.js +27 -17
  157. package/public/tabulator_bootstrap5.min.css +1 -0
  158. package/restart_watcher.js +1 -0
  159. package/routes/actions.js +158 -16
  160. package/routes/admin.js +83 -9
  161. package/routes/common_lists.js +40 -17
  162. package/routes/fields.js +18 -3
  163. package/routes/homepage.js +2 -1
  164. package/routes/page.js +30 -13
  165. package/routes/page_groupedit.js +104 -83
  166. package/routes/pageedit.js +4 -3
  167. package/routes/tables.js +34 -0
  168. package/routes/tag_entries.js +6 -1
  169. package/routes/tags.js +4 -0
  170. package/routes/utils.js +23 -2
  171. package/routes/view.js +5 -1
  172. package/routes/viewedit.js +9 -0
  173. package/serve.js +177 -10
  174. package/tests/admin.test.js +17 -11
  175. package/tests/api.test.js +27 -0
  176. package/tests/fields.test.js +132 -5
  177. package/tests/help.test.js +37 -0
  178. package/tests/page_group.test.js +1 -0
  179. package/tests/plugins.test.js +0 -12
  180. package/tests/table.test.js +1 -5
  181. package/tests/view.test.js +12 -0
  182. package/tests/viewedit.test.js +52 -8
  183. package/wrapper.js +9 -1
@@ -0,0 +1 @@
1
+ .tabulator{position:relative;border:1px solid #dee2e6;font-size:16px;text-align:left;overflow:hidden;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.tabulator[tabulator-layout=fitDataFill] .tabulator-tableholder .tabulator-table{min-width:100%}.tabulator[tabulator-layout=fitDataTable]{display:inline-block}.tabulator.tabulator-block-select{user-select:none}.tabulator .tabulator-header{position:relative;box-sizing:border-box;width:100%;border-bottom:1px solid #dee2e6;background-color:#fff;color:#555;font-weight:700;white-space:nowrap;overflow:hidden;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none}.tabulator .tabulator-header.tabulator-header-hidden{display:none}.tabulator .tabulator-header .tabulator-header-contents{position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers{display:inline-block}.tabulator .tabulator-header .tabulator-col{display:inline-flex;position:relative;box-sizing:border-box;flex-direction:column;justify-content:flex-start;border-right:1px solid #aaa;background:#fff;text-align:left;vertical-align:bottom;overflow:hidden}.tabulator .tabulator-header .tabulator-col.tabulator-moving{position:absolute;border:1px solid #dee2e6;background:#e6e6e6;pointer-events:none}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{box-sizing:border-box;position:relative;padding:4px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button{padding:0 8px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover{cursor:pointer;opacity:.6}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder{position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title{box-sizing:border-box;width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap{white-space:normal;text-overflow:clip}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor{box-sizing:border-box;width:100%;border:1px solid #999;padding:1px;background:#fff}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button+.tabulator-title-editor{width:calc(100% - 22px)}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{display:flex;align-items:center;position:absolute;top:0;bottom:0;right:4px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #bbb}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{position:relative;display:flex;border-top:1px solid #aaa;overflow:hidden;margin-right:-1px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter{position:relative;box-sizing:border-box;margin-top:2px;width:100%;text-align:center}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea{height:auto!important}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg{margin-top:3px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear{width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:25px}.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover{cursor:pointer;background-color:#e6e6e6}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter{color:#bbb}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #bbb}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter{color:#666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter{color:#666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-top:6px solid #555}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:none;border-top:6px solid #666;color:#666}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title{writing-mode:vertical-rl;text-orientation:mixed;display:flex;align-items:center;justify-content:center}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title{transform:rotate(180deg)}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title{padding-right:0;padding-top:20px}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title{padding-right:0;padding-bottom:20px}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter{justify-content:center;left:0;right:0;top:4px;bottom:auto}.tabulator .tabulator-header .tabulator-frozen{position:sticky;left:0;z-index:10}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left{border-right:2px solid #dee2e6}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right{border-left:2px solid #dee2e6}.tabulator .tabulator-header .tabulator-calcs-holder{box-sizing:border-box;min-width:600%;background:#fff!important;border-top:1px solid #dee2e6;border-bottom:1px solid #aaa}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row{background:#fff!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-header .tabulator-frozen-rows-holder{min-width:600%}.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty{display:none}.tabulator .tabulator-tableholder{position:relative;width:100%;white-space:nowrap;overflow:auto;-webkit-overflow-scrolling:touch}.tabulator .tabulator-tableholder:focus{outline:none}.tabulator .tabulator-tableholder .tabulator-placeholder{box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%}.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode=virtual]{min-height:100%;min-width:100%}.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents{display:inline-block;text-align:center;padding:10px;color:#ccc;font-weight:700;font-size:20px;white-space:normal}.tabulator .tabulator-tableholder .tabulator-table{position:relative;display:inline-block;background-color:#fff;white-space:nowrap;overflow:visible;color:#333}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{font-weight:700;background:#dadfe4!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top{border-bottom:2px solid #dee2e6}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom{border-top:2px solid #dee2e6}.tabulator .tabulator-footer{border-top:1px solid #dee2e6;background-color:#e6e6e6;color:#555;font-weight:700;white-space:nowrap;user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none}.tabulator .tabulator-footer .tabulator-footer-contents{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:5px 10px}.tabulator .tabulator-footer .tabulator-footer-contents:empty{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder{box-sizing:border-box;width:100%;text-align:left;background:#f3f3f3!important;border-bottom:1px solid #dee2e6;border-top:1px solid #dee2e6;overflow:hidden}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{display:inline-block;background:#f3f3f3!important}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{margin-bottom:-5px;border-bottom:none}.tabulator .tabulator-footer>*+.tabulator-page-counter{margin-left:10px}.tabulator .tabulator-footer .tabulator-page-counter{font-weight:400}.tabulator .tabulator-footer .tabulator-paginator{flex:1;text-align:right;color:#555;font-family:inherit;font-weight:inherit;font-size:inherit}.tabulator .tabulator-footer .tabulator-page-size{display:inline-block;margin:0 5px;padding:2px 5px;border:1px solid #dee2e6;border-radius:3px}.tabulator .tabulator-footer .tabulator-pages{margin:0 7px}.tabulator .tabulator-footer .tabulator-page{display:inline-block;margin:0 2px;padding:2px 5px;border:1px solid #dee2e6;border-radius:3px;background:hsla(0,0%,100%,.2)}.tabulator .tabulator-footer .tabulator-page:disabled{opacity:.5}.tabulator .tabulator-footer .tabulator-page:not(.disabled):hover{cursor:pointer;background:rgba(0,0,0,.2);color:#fff}.tabulator .tabulator-col-resize-handle{position:relative;display:inline-block;width:6px;margin-left:-3px;margin-right:-3px;z-index:10;vertical-align:middle}.tabulator .tabulator-col-resize-handle:hover{cursor:ew-resize}.tabulator .tabulator-col-resize-handle:last-of-type{width:3px;margin-right:0}.tabulator .tabulator-alert{position:absolute;display:flex;align-items:center;top:0;left:0;z-index:100;height:100%;width:100%;background:rgba(0,0,0,.4);text-align:center}.tabulator .tabulator-alert .tabulator-alert-msg{display:inline-block;margin:0 auto;padding:10px 20px;border-radius:10px;background:#fff;font-weight:700;font-size:16px}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg{border:4px solid #333;color:#000}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error{border:4px solid #d00;color:#590000}.tabulator-row{position:relative;box-sizing:border-box;min-height:24px;background-color:#fff}.tabulator-row.tabulator-row-even{background-color:#e9ecef}.tabulator-row.tabulator-selectable:hover{background-color:#ced4da;cursor:pointer}.tabulator-row.tabulator-selected{background-color:#9abcea}.tabulator-row.tabulator-selected:hover{background-color:#769bcc;cursor:pointer}.tabulator-row.tabulator-row-moving{border:1px solid #000;background:#fff}.tabulator-row.tabulator-moving{position:absolute;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6;pointer-events:none;z-index:15}.tabulator-row .tabulator-row-resize-handle{position:absolute;right:0;bottom:0;left:0;height:5px}.tabulator-row .tabulator-row-resize-handle.prev{top:0;bottom:auto}.tabulator-row .tabulator-row-resize-handle:hover{cursor:ns-resize}.tabulator-row .tabulator-responsive-collapse{box-sizing:border-box;padding:5px;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.tabulator-row .tabulator-responsive-collapse:empty{display:none}.tabulator-row .tabulator-responsive-collapse table{font-size:16px}.tabulator-row .tabulator-responsive-collapse table tr td{position:relative}.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type{padding-right:10px}.tabulator-row .tabulator-cell{display:inline-block;position:relative;box-sizing:border-box;padding:4px;border-right:1px solid #dee2e6;vertical-align:middle;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tabulator-row .tabulator-cell.tabulator-frozen{display:inline-block;position:sticky;left:0;background-color:inherit;z-index:10}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-right:2px solid #dee2e6}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-left:2px solid #dee2e6}.tabulator-row .tabulator-cell.tabulator-editing{border:1px solid #1d68cd;outline:none;padding:0}.tabulator-row .tabulator-cell.tabulator-editing input,.tabulator-row .tabulator-cell.tabulator-editing select{border:1px;background:transparent;outline:none}.tabulator-row .tabulator-cell.tabulator-validation-fail{border:1px solid #d00}.tabulator-row .tabulator-cell.tabulator-validation-fail input,.tabulator-row .tabulator-cell.tabulator-validation-fail select{border:1px;background:transparent;color:#d00}.tabulator-row .tabulator-cell.tabulator-row-handle{display:inline-flex;align-items:center;justify-content:center;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box{width:80%}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar{width:100%;height:3px;margin-top:2px;background:#666}.tabulator-row .tabulator-cell .tabulator-data-tree-branch{display:inline-block;vertical-align:middle;height:9px;width:7px;margin-top:-9px;margin-right:5px;border-bottom-left-radius:1px;border-left:2px solid #dee2e6;border-bottom:2px solid #dee2e6}.tabulator-row .tabulator-cell .tabulator-data-tree-control{display:inline-flex;justify-content:center;align-items:center;vertical-align:middle;height:11px;width:11px;margin-right:5px;border:1px solid #333;border-radius:2px;background:rgba(0,0,0,.1);overflow:hidden}.tabulator-row .tabulator-cell .tabulator-data-tree-control:hover{cursor:pointer;background:rgba(0,0,0,.2)}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse{display:inline-block;position:relative;height:7px;width:1px;background:transparent}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{position:absolute;content:"";left:-3px;top:3px;height:1px;width:7px;background:#333}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand{display:inline-block;position:relative;height:7px;width:1px;background:#333}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{position:absolute;content:"";left:-3px;top:3px;height:1px;width:7px;background:#333}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{display:inline-flex;align-items:center;justify-content:center;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;height:15px;width:15px;border-radius:20px;background:#666;color:#fff;font-weight:700;font-size:1.1em}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover{opacity:.7;cursor:pointer}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close{display:initial}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open{display:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg{stroke:#fff}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close{display:none}.tabulator-row .tabulator-cell .tabulator-traffic-light{display:inline-block;height:14px;width:14px;border-radius:14px}.tabulator-row.tabulator-group{box-sizing:border-box;border-bottom:1px solid #999;border-right:1px solid #dee2e6;border-top:1px solid #999;padding:5px 5px 5px 10px;background:#ccc;font-weight:700;min-width:100%}.tabulator-row.tabulator-group:hover{cursor:pointer;background-color:rgba(0,0,0,.1)}.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow{margin-right:10px;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #666;border-bottom:0}.tabulator-row.tabulator-group.tabulator-group-level-1{padding-left:30px}.tabulator-row.tabulator-group.tabulator-group-level-2{padding-left:50px}.tabulator-row.tabulator-group.tabulator-group-level-3{padding-left:70px}.tabulator-row.tabulator-group.tabulator-group-level-4{padding-left:90px}.tabulator-row.tabulator-group.tabulator-group-level-5{padding-left:110px}.tabulator-row.tabulator-group .tabulator-group-toggle{display:inline-block}.tabulator-row.tabulator-group .tabulator-arrow{display:inline-block;width:0;height:0;margin-right:16px;border-top:6px solid transparent;border-bottom:6px solid transparent;border-right:0;border-left:6px solid #666;vertical-align:middle}.tabulator-row.tabulator-group span{margin-left:10px;color:#d00}.tabulator-popup-container{position:absolute;display:inline-block;box-sizing:border-box;border:1px solid #dee2e6;box-shadow:0 0 5px 0 rgba(0,0,0,.2);font-size:16px;overflow-y:auto;-webkit-overflow-scrolling:touch;z-index:10000}.tabulator-popup{padding:5px;border-radius:3px}.tabulator-tooltip{max-width:Min(500px,100%);padding:3px 5px;border-radius:2px;box-shadow:none;font-size:12px;pointer-events:none}.tabulator-menu .tabulator-menu-item{position:relative;box-sizing:border-box;padding:5px 10px;user-select:none}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled{opacity:.5}.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{cursor:pointer;background:#e9ecef}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu{padding-right:25px}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after{display:inline-block;position:absolute;top:calc(5px + .4em);right:10px;height:7px;width:7px;content:"";border-color:#dee2e6;border-style:solid;border-width:1px 1px 0 0;vertical-align:top;transform:rotate(45deg)}.tabulator-menu .tabulator-menu-separator{border-top:1px solid #dee2e6}.tabulator-edit-list{max-height:200px;font-size:16px;overflow-y:auto;-webkit-overflow-scrolling:touch}.tabulator-edit-list .tabulator-edit-list-item{padding:4px;color:#333;outline:none}.tabulator-edit-list .tabulator-edit-list-item.active{background:#1d68cd}.tabulator-edit-list .tabulator-edit-list-item.focused{outline:1px solid #1d68cd}.tabulator-edit-list .tabulator-edit-list-item:hover{cursor:pointer;background:#1d68cd}.tabulator-edit-list .tabulator-edit-list-placeholder{padding:4px;color:#333;text-align:center}.tabulator-edit-list .tabulator-edit-list-group{border-bottom:1px solid #dee2e6;padding:6px 4px 4px;color:#333;font-weight:700}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2{padding-left:12px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3{padding-left:20px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4{padding-left:28px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5{padding-left:36px}.tabulator.tabulator-ltr{direction:ltr}.tabulator.tabulator-rtl{text-align:initial;direction:rtl}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{border-left:1px solid #aaa;border-right:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{margin-right:0;margin-left:-1px}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:0;padding-left:25px}.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{left:8px;right:auto}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell{border-right:initial;border-left:1px solid #dee2e6}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch{margin-right:0;margin-left:5px;border-bottom-left-radius:0;border-bottom-right-radius:1px;border-left:initial;border-right:2px solid #dee2e6}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control{margin-right:0;margin-left:5px}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-left:2px solid #dee2e6}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-right:2px solid #dee2e6}.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type{width:3px;margin-left:0;margin-right:-3px}.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder{text-align:initial}.tabulator-print-fullscreen{position:absolute;top:0;bottom:0;left:0;right:0;z-index:10000}body.tabulator-print-fullscreen-hide>:not(.tabulator-print-fullscreen){display:none!important}.tabulator-print-table{border-collapse:collapse}.tabulator-print-table .tabulator-data-tree-branch{display:inline-block;vertical-align:middle;height:9px;width:7px;margin-top:-9px;margin-right:5px;border-bottom-left-radius:1px;border-left:2px solid #dee2e6;border-bottom:2px solid #dee2e6}.tabulator-print-table .tabulator-print-table-group{box-sizing:border-box;border-bottom:1px solid #999;border-right:1px solid #dee2e6;border-top:1px solid #999;padding:5px 5px 5px 10px;background:#ccc;font-weight:700;min-width:100%}.tabulator-print-table .tabulator-print-table-group:hover{cursor:pointer;background-color:rgba(0,0,0,.1)}.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow{margin-right:10px;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #666;border-bottom:0}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td{padding-left:30px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td{padding-left:50px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td{padding-left:70px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td{padding-left:90px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td{padding-left:110px!important}.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle{display:inline-block}.tabulator-print-table .tabulator-print-table-group .tabulator-arrow{display:inline-block;width:0;height:0;margin-right:16px;border-top:6px solid transparent;border-bottom:6px solid transparent;border-right:0;border-left:6px solid #666;vertical-align:middle}.tabulator-print-table .tabulator-print-table-group span{margin-left:10px;color:#d00}.tabulator-print-table .tabulator-data-tree-control{display:inline-flex;justify-content:center;align-items:center;vertical-align:middle;height:11px;width:11px;margin-right:5px;border:1px solid #333;border-radius:2px;background:rgba(0,0,0,.1);overflow:hidden}.tabulator-print-table .tabulator-data-tree-control:hover{cursor:pointer;background:rgba(0,0,0,.2)}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse{display:inline-block;position:relative;height:7px;width:1px;background:transparent}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{position:absolute;content:"";left:-3px;top:3px;height:1px;width:7px;background:#333}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand{display:inline-block;position:relative;height:7px;width:1px;background:#333}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{position:absolute;content:"";left:-3px;top:3px;height:1px;width:7px;background:#333}.tabulator{background-color:#fff;border:none}.tabulator .tabulator-header{border-top:1px solid #dee2e6;border-bottom:2px solid #dee2e6;color:inherit}.tabulator .tabulator-header .tabulator-col{border-right:none;background-color:#fff}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{padding:12px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{border-top:1px solid #dee2e6}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input{padding:.375rem .75rem;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;font-size:1rem;line-height:1.5;color:#495057}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input:focus{color:#495057;background-color:#fff;border:1px solid #1d68cd;outline:0}.tabulator .tabulator-header .tabulator-calcs-holder{width:100%;border-bottom:1px solid #dee2e6}.tabulator .tabulator-tableholder .tabulator-placeholder span{color:#000}.tabulator .tabulator-footer,.tabulator .tabulator-footer .tabulator-paginator,.tabulator .tabulator-tableholder .tabulator-table{color:inherit}.tabulator .tabulator-footer .tabulator-pages{margin:0}.tabulator .tabulator-footer .tabulator-page{margin:5px 0 0;padding:8px 12px}.tabulator .tabulator-footer .tabulator-page[data-page=first]{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabulator .tabulator-footer .tabulator-page[data-page=last]{border:1px solid #dee2e6;border-top-right-radius:4px;border-bottom-right-radius:4px}.tabulator .tabulator-footer .tabulator-page.active{border-color:#0d6efd;background-color:#0d6efd;color:#fff}.tabulator .tabulator-footer .tabulator-page:disabled{border-color:#dee2e6;background:#fff;color:#6c757d}.tabulator .tabulator-footer .tabulator-page:not(.disabled):hover{border-color:#dee2e6;background:#e9ecef;color:#0a58ca}.tabulator.thead-dark .tabulator-header,.tabulator.thead-dark .tabulator-header .tabulator-col{border-color:#dee2e6;background-color:#fff;color:#212529}.tabulator.table{background-color:#fff}.tabulator.table:not(.thead-light) .tabulator-header,.tabulator.table:not(.thead-light) .tabulator-header .tabulator-col{border-color:#dee2e6;background-color:#fff;color:#212529}.tabulator.table .tabulator-tableholder{color:#212529}.tabulator.table .tabulator-row{border-color:#dee2e6;background-color:#fff;color:#212529}.tabulator.table .tabulator-row:hover{background-color:#dee2e6}.tabulator.table .tabulator-row:hover .tabulator-cell{background-color:#ced4da}.tabulator.table .tabulator-row.tabulator-selected{background-color:#9abcea}.tabulator.table .tabulator-footer{border-color:#dee2e6!important}.tabulator.table .tabulator-footer .tabulator-calcs-holder{border-color:#dee2e6!important;background:#fff!important}.tabulator.table .tabulator-footer .tabulator-calcs-holder .tabulator-row{border-color:#dee2e6!important;background-color:#fff!important;color:#212529!important}.tabulator.table-striped:not(.table) .tabulator-row.tabulator-row-even{background-color:#e9ecef}.tabulator.table-striped:not(.table) .tabulator-row.tabulator-row-even.tabulator-selected{background-color:#9abcea}.tabulator.table-striped:not(.table) .tabulator-row.tabulator-row-even.tabulator-selectable:hover{background-color:#ced4da;cursor:pointer}.tabulator.table-striped:not(.table) .tabulator-row.tabulator-row-even.tabulator-selected:hover{background-color:#769bcc;cursor:pointer}.tabulator.table-striped.table .tabulator-row:nth-child(2n) .tabulator-cell{background-color:transparent}.tabulator.table-bordered{border:1px solid #dee2e6}.tabulator.table-bordered .tabulator-header .tabulator-col,.tabulator.table-bordered .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{border-right:1px solid #dee2e6}.tabulator.table-borderless .tabulator-header,.tabulator.table-borderless .tabulator-row{border:none}.tabulator.table-sm .tabulator-header .tabulator-col .tabulator-col-content{padding:5px!important}.tabulator.table-sm .tabulator-tableholder .tabulator-table .tabulator-row{min-height:26px}.tabulator.table-sm .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell{padding:5px!important}.tabulator.table-sm .tabulator-row{padding-top:0;padding-bottom:0}.tabulator.table-sm .tabulator-col-resize-handle{padding:0}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-primary{background:#cfe2ff!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-secondary{background:#e2e3e5!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-success{background:#d1e7dd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-info{background:#cff4fc!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-warning{background:#fff3cd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-danger{background:#f8d7da!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-light{background:#f8f9fa!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table{background:#212529!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-active{background:#6c757d!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-primary{background:#cfe2ff!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-secondary{background:#e2e3e5!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-success{background:#d1e7dd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-info{background:#cff4fc!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-warning{background:#fff3cd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-danger{background:#f8d7da!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-light{background:#f8f9fa!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-dark{background:#212529!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.bg-active{background:#6c757d!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-primary{background:#cfe2ff!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-secondary{background:#e2e3e5!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-success{background:#d1e7dd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-info{background:#cff4fc!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-warning{background:#fff3cd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-danger{background:#f8d7da!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-light{background:#f8f9fa!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table{background:#212529!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.table-active{background:#6c757d!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-primary{background:#cfe2ff!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-secondary{background:#e2e3e5!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-success{background:#d1e7dd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-info{background:#cff4fc!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-warning{background:#fff3cd!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-danger{background:#f8d7da!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-light{background:#f8f9fa!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-dark{background:#212529!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell.bg-active{background:#6c757d!important}.tabulator-row{min-height:40px;border-bottom:1px solid #dee2e6}.tabulator-row .tabulator-cell{padding:12px;border-right:none}.tabulator-row .tabulator-cell:last-of-type{border-right:none}.tabulator-row .tabulator-cell .tabulator-data-tree-control{border:1px solid #ccc}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after,.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand,.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{background:#ccc}.tabulator-row.tabulator-group{background:#fafafa}.tabulator-row.tabulator-group span{color:#666}.tabulator-edit-select-list{background:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active{color:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-item.active.focused{outline:1px solid hsla(0,0%,100%,.5)}.tabulator-edit-select-list .tabulator-edit-select-list-item:hover{color:#fff}.tabulator-edit-select-list .tabulator-edit-select-list-group,.tabulator-edit-select-list .tabulator-edit-select-list-notice{color:inherit}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{text-align:initial;border-left:initial}.tabulator-print-table .tabulator-print-table-group{background:#fafafa}.tabulator-print-table .tabulator-print-table-group span{color:#666}.tabulator-print-table .tabulator-data-tree-control{color:inherit}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after,.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand,.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{background:#ccc}.tabulator-popup-container{background:#fff}.tabulator-edit-list .tabulator-edit-list-item.active{color:#fff}.tabulator-edit-list .tabulator-edit-list-item.active.focused{outline:1px solid hsla(0,0%,100%,.5)}.tabulator-edit-list .tabulator-edit-list-item:hover{color:#fff}
@@ -15,6 +15,7 @@ const { eachTenant } = require("@saltcorn/admin-models/models/tenant");
15
15
  */
16
16
  const relevantPackages = [
17
17
  "db-common",
18
+ "common-code",
18
19
  "postgres",
19
20
  "saltcorn-data",
20
21
  "saltcorn-builder",
package/routes/actions.js CHANGED
@@ -11,11 +11,14 @@ const {
11
11
  addOnDoneRedirect,
12
12
  is_relative_url,
13
13
  } = require("./utils.js");
14
+ const { ppVal } = require("@saltcorn/data/utils");
14
15
  const { getState } = require("@saltcorn/data/db/state");
15
16
  const Trigger = require("@saltcorn/data/models/trigger");
17
+ const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
16
18
  const { getTriggerList } = require("./common_lists");
17
19
  const TagEntry = require("@saltcorn/data/models/tag_entry");
18
20
  const Tag = require("@saltcorn/data/models/tag");
21
+ const db = require("@saltcorn/data/db");
19
22
 
20
23
  /**
21
24
  * @type {object}
@@ -105,7 +108,13 @@ router.get(
105
108
  title: req.__("Triggers"),
106
109
  contents: div(
107
110
  await getTriggerList(triggers, req, { filterOnTag }),
108
- link("/actions/new", req.__("Add trigger"))
111
+ a(
112
+ {
113
+ href: "/actions/new",
114
+ class: "btn btn-primary",
115
+ },
116
+ req.__("Create trigger")
117
+ )
109
118
  ),
110
119
  },
111
120
  {
@@ -160,11 +169,14 @@ const triggerForm = async (req, trigger) => {
160
169
  .filter(([k, v]) => v.hasChannel)
161
170
  .map(([k, v]) => k);
162
171
  const allActions = actions.map((t) => t.name);
172
+ allActions.push("Multi-step action");
163
173
  const table_triggers = ["Insert", "Update", "Delete", "Validate"];
164
174
  const action_options = {};
165
175
  const actionsNotRequiringRow = actions
166
176
  .filter((a) => !a.requireRow)
167
177
  .map((t) => t.name);
178
+ actionsNotRequiringRow.push("Multi-step action");
179
+
168
180
  Trigger.when_options.forEach((t) => {
169
181
  if (table_triggers.includes(t)) action_options[t] = allActions;
170
182
  else action_options[t] = actionsNotRequiringRow;
@@ -207,6 +219,17 @@ const triggerForm = async (req, trigger) => {
207
219
  "The table for which the trigger condition is checked."
208
220
  ),
209
221
  },
222
+ {
223
+ name: "table_id",
224
+ label: req.__("Table"),
225
+ input_type: "select",
226
+ options: [
227
+ { value: "", label: "Table not set" },
228
+ ...tables.map((t) => ({ value: t.id, label: t.name })),
229
+ ],
230
+ showIf: { when_trigger: "Never" },
231
+ sublabel: req.__("Optionally associate a table with this trigger"),
232
+ },
210
233
  {
211
234
  name: "channel",
212
235
  label: req.__("Time of day"),
@@ -230,9 +253,41 @@ const triggerForm = async (req, trigger) => {
230
253
  attributes: {
231
254
  calcOptions: ["when_trigger", action_options],
232
255
  },
256
+ showIf: {
257
+ when_trigger: Trigger.when_options.filter((t) => t !== "Never"),
258
+ },
259
+ sublabel: req.__("The action to be taken when the trigger fires"),
260
+ },
261
+ {
262
+ name: "action",
263
+ label: req.__("Action"),
264
+ type: "String",
265
+ required: true,
266
+ help: { topic: "Actions" },
267
+ attributes: {
268
+ options: actionsNotRequiringRow,
269
+ },
270
+ showIf: {
271
+ when_trigger: "Never",
272
+ table_id: "",
273
+ },
274
+ sublabel: req.__("The action to be taken when the trigger fires"),
275
+ },
276
+ {
277
+ name: "action",
278
+ label: req.__("Action"),
279
+ type: "String",
280
+ required: true,
281
+ help: { topic: "Actions" },
282
+ attributes: {
283
+ options: allActions,
284
+ },
285
+ showIf: {
286
+ when_trigger: "Never",
287
+ table_id: tables.map((t) => t.id),
288
+ },
233
289
  sublabel: req.__("The action to be taken when the trigger fires"),
234
290
  },
235
-
236
291
  {
237
292
  name: "description",
238
293
  label: req.__("Description"),
@@ -275,6 +330,17 @@ router.get(
275
330
  send_events_page({
276
331
  res,
277
332
  req,
333
+ headers: [
334
+ // date flat picker external component
335
+ {
336
+ script: `/static_assets/${db.connectObj.version_tag}/flatpickr.min.js`,
337
+ },
338
+
339
+ // css for date flat picker external component
340
+ {
341
+ css: `/static_assets/${db.connectObj.version_tag}/flatpickr.min.css`,
342
+ },
343
+ ],
278
344
  active_sub: "Triggers",
279
345
  sub2_page: "New",
280
346
  contents: {
@@ -391,6 +457,66 @@ router.post(
391
457
  })
392
458
  );
393
459
 
460
+ const getMultiStepForm = async (req, id, table) => {
461
+ let stateActions = getState().actions;
462
+ const stateActionKeys = Object.entries(stateActions)
463
+ .filter(([k, v]) => !v.disableInList && (table || !v.requireRow))
464
+ .map(([k, v]) => k);
465
+ const actions = [...stateActionKeys];
466
+ const triggers = Trigger.find({
467
+ when_trigger: { or: ["API call", "Never"] },
468
+ });
469
+ triggers.forEach((tr) => {
470
+ actions.push(tr.name);
471
+ });
472
+ const actionConfigFields = [];
473
+ for (const [name, action] of Object.entries(stateActions)) {
474
+ if (!stateActionKeys.includes(name)) continue;
475
+ const cfgFields = await getActionConfigFields(action, table);
476
+
477
+ for (const field of cfgFields) {
478
+ const cfgFld = {
479
+ ...field,
480
+ showIf: {
481
+ step_action_name: name,
482
+ ...(field.showIf || {}),
483
+ },
484
+ };
485
+ if (cfgFld.input_type === "code") cfgFld.input_type = "textarea";
486
+ actionConfigFields.push(cfgFld);
487
+ }
488
+ }
489
+ const form = new Form({
490
+ action: addOnDoneRedirect(`/actions/configure/${id}`, req),
491
+ onChange: "saveAndContinue(this)",
492
+ submitLabel: req.__("Done"),
493
+ fields: [
494
+ new FieldRepeat({
495
+ name: "steps",
496
+ fields: [
497
+ {
498
+ name: "step_action_name",
499
+ label: req.__("Action"),
500
+ type: "String",
501
+ required: true,
502
+ attributes: {
503
+ options: actions,
504
+ },
505
+ },
506
+ {
507
+ name: "step_only_if",
508
+ label: req.__("Only if..."),
509
+ type: "String",
510
+ class: "validate-expression",
511
+ },
512
+ ...actionConfigFields,
513
+ ],
514
+ }),
515
+ ],
516
+ });
517
+ return form;
518
+ };
519
+
394
520
  /**
395
521
  * Edit Trigger configuration (GET)
396
522
  *
@@ -433,7 +559,24 @@ router.get(
433
559
  { href: `/actions/testrun/${id}`, class: "ms-2" },
434
560
  req.__("Test run") + " »"
435
561
  );
436
- if (!action) {
562
+ if (trigger.action === "Multi-step action") {
563
+ const form = await getMultiStepForm(req, id, table);
564
+ form.values = trigger.configuration;
565
+ send_events_page({
566
+ res,
567
+ req,
568
+ active_sub: "Triggers",
569
+ sub2_page: "Configure",
570
+ page_title: req.__(`%s configuration`, trigger.name),
571
+ contents: {
572
+ type: "card",
573
+ titleAjaxIndicator: true,
574
+ title: req.__("Configure trigger %s", trigger.name),
575
+ subtitle,
576
+ contents: renderForm(form, req.csrfToken()),
577
+ },
578
+ });
579
+ } else if (!action) {
437
580
  req.flash("warning", req.__("Action not found"));
438
581
  res.redirect(`/actions/`);
439
582
  } else if (trigger.action === "blocks") {
@@ -557,13 +700,18 @@ router.post(
557
700
  const table = trigger.table_id
558
701
  ? Table.findOne({ id: trigger.table_id })
559
702
  : null;
560
- const cfgFields = await getActionConfigFields(action, table, {
561
- mode: "trigger",
562
- });
563
- const form = new Form({
564
- action: `/actions/configure/${id}`,
565
- fields: cfgFields,
566
- });
703
+ let form;
704
+ if (trigger.action === "Multi-step action") {
705
+ form = await getMultiStepForm(req, id, table);
706
+ } else {
707
+ const cfgFields = await getActionConfigFields(action, table, {
708
+ mode: "trigger",
709
+ });
710
+ form = new Form({
711
+ action: `/actions/configure/${id}`,
712
+ fields: cfgFields,
713
+ });
714
+ }
567
715
  form.validate(req.body);
568
716
  if (form.hasErrors) {
569
717
  if (req.xhr) {
@@ -625,12 +773,6 @@ router.get(
625
773
  const { id } = req.params;
626
774
  const trigger = await Trigger.findOne({ id });
627
775
  const output = [];
628
- const ppVal = (x) =>
629
- typeof x === "string"
630
- ? x
631
- : typeof x === "function"
632
- ? x.toString()
633
- : JSON.stringify(x, null, 2);
634
776
  const fakeConsole = {
635
777
  log(...s) {
636
778
  console.log(...s);
package/routes/admin.js CHANGED
@@ -186,6 +186,7 @@ admin_config_route({
186
186
  "smtp_password",
187
187
  "smtp_port",
188
188
  "smtp_secure",
189
+ "smtp_allow_self_signed",
189
190
  "email_from",
190
191
  ],
191
192
  response(form, req, res) {
@@ -599,7 +600,13 @@ router.post(
599
600
  snap.created
600
601
  ).fromNow()}`
601
602
  );
602
- res.redirect(/^[a-z]+$/g.test(type) ? `/${type}edit` : "/");
603
+ res.redirect(
604
+ type === "trigger"
605
+ ? `/actions`
606
+ : /^[a-z]+$/g.test(type)
607
+ ? `/${type}edit`
608
+ : "/"
609
+ );
603
610
  })
604
611
  );
605
612
 
@@ -2252,6 +2259,7 @@ router.post(
2252
2259
  "/build-mobile-app",
2253
2260
  isAdmin,
2254
2261
  error_catcher(async (req, res) => {
2262
+ getState().log(2, `starting mobile build: ${JSON.stringify(req.body)}`);
2255
2263
  let {
2256
2264
  entryPoint,
2257
2265
  entryPointType,
@@ -2427,6 +2435,7 @@ router.post(
2427
2435
  await PageGroup.delete({});
2428
2436
  }
2429
2437
  if (form.values.pages) {
2438
+ await db.deleteWhere("_sc_tag_entries", { not: { page_id: null } });
2430
2439
  await db.deleteWhere("_sc_pages");
2431
2440
  }
2432
2441
  if (form.values.views) {
@@ -2457,11 +2466,12 @@ router.post(
2457
2466
  });
2458
2467
  await table.update({ ownership_field_id: null });
2459
2468
  const fields = table.getFields();
2460
- for (const f of fields) {
2461
- if (f.is_fkey) {
2462
- await f.delete();
2469
+ if (!table.extername && !table.provider_name)
2470
+ for (const f of fields) {
2471
+ if (f.is_fkey) {
2472
+ await f.delete();
2473
+ }
2463
2474
  }
2464
- }
2465
2475
  }
2466
2476
  for (const table of tables) {
2467
2477
  if (table.name !== "users") await table.delete();
@@ -2540,6 +2550,52 @@ router.post(
2540
2550
  }
2541
2551
  })
2542
2552
  );
2553
+
2554
+ router.get(
2555
+ "/dev/logs_viewer",
2556
+ isAdmin,
2557
+ error_catcher(async (req, res) => {
2558
+ return send_admin_page({
2559
+ res,
2560
+ req,
2561
+ active_sub: "Development",
2562
+ contents: {
2563
+ above: [
2564
+ {
2565
+ type: "card",
2566
+ id: "server-logs-card-id",
2567
+ title: req.__("Server logs"),
2568
+ titleErrorInidicator: true,
2569
+ contents: mkTable(
2570
+ [
2571
+ {
2572
+ label: req.__("Timestamp"),
2573
+ width: "15%",
2574
+ },
2575
+ { label: req.__("Message") },
2576
+ ],
2577
+ [],
2578
+ {
2579
+ pagination: {
2580
+ current_page: 1,
2581
+ pages: 1,
2582
+ get_page_link: () => "logViewerHelpers.goToLogsPage(1)",
2583
+ },
2584
+ tableId: "_sc_logs_tbl_id_",
2585
+ }
2586
+ ),
2587
+ },
2588
+ script({
2589
+ src: `/static_assets/${db.connectObj.version_tag}/socket.io.min.js`,
2590
+ }),
2591
+ script({ src: "/log_viewer_utils.js" }),
2592
+ script(domReady(`logViewerHelpers.init_log_socket();`)),
2593
+ ],
2594
+ },
2595
+ });
2596
+ })
2597
+ );
2598
+
2543
2599
  /**
2544
2600
  * Dev / Admin
2545
2601
  */
@@ -2573,10 +2629,28 @@ admin_config_route({
2573
2629
  req,
2574
2630
  active_sub: "Development",
2575
2631
  contents: {
2576
- type: "card",
2577
- title: req.__("Development settings"),
2578
- titleAjaxIndicator: true,
2579
- contents: [renderForm(form, req.csrfToken())],
2632
+ above: [
2633
+ {
2634
+ type: "card",
2635
+ title: req.__("Development settings"),
2636
+ titleAjaxIndicator: true,
2637
+ contents: [renderForm(form, req.csrfToken())],
2638
+ },
2639
+ {
2640
+ type: "card",
2641
+ title: req.__("Runtime informations"),
2642
+ contents: [
2643
+ div(
2644
+ { class: "row form-group" },
2645
+ a(
2646
+ { class: "d-block", href: "dev/logs_viewer" },
2647
+ req.__("open logs viewer")
2648
+ ),
2649
+ i("Open a log viewer for the current server messages")
2650
+ ),
2651
+ ],
2652
+ },
2653
+ ],
2580
2654
  },
2581
2655
  });
2582
2656
  },
@@ -505,7 +505,7 @@ const getPageList = async (
505
505
  [
506
506
  {
507
507
  label: req.__("Name"),
508
- key: (r) => link(`/page/${r.name}`, r.name),
508
+ key: (r) => link(`/page/${encodeURIComponent(r.name)}`, r.name),
509
509
  },
510
510
  ...(tagId
511
511
  ? []
@@ -524,7 +524,8 @@ const getPageList = async (
524
524
  },
525
525
  {
526
526
  label: req.__("Edit"),
527
- key: (r) => link(`/pageedit/edit/${r.name}`, req.__("Edit")),
527
+ key: (r) =>
528
+ link(`/pageedit/edit/${encodeURIComponent(r.name)}`, req.__("Edit")),
528
529
  },
529
530
  !tagId
530
531
  ? {
@@ -582,6 +583,34 @@ const getPageGroupList = (rows, roles, req) => {
582
583
  );
583
584
  };
584
585
 
586
+ const trigger_dropdown = (trigger, req, on_done_redirect_str = "") =>
587
+ settingsDropdown(`dropdownMenuButton${trigger.id}`, [
588
+ a(
589
+ {
590
+ class: "dropdown-item",
591
+ href: `/actions/edit/${trigger.id}${on_done_redirect_str}`,
592
+ },
593
+ '<i class="fas fa-edit"></i>&nbsp;' + req.__("Edit")
594
+ ),
595
+
596
+ a(
597
+ {
598
+ class: "dropdown-item",
599
+ href: `javascript:ajax_modal('/admin/snapshot-restore/trigger/${trigger.name}')`,
600
+ },
601
+ '<i class="fas fa-undo-alt"></i>&nbsp;' + req.__("Restore")
602
+ ),
603
+ div({ class: "dropdown-divider" }),
604
+
605
+ post_dropdown_item(
606
+ `/actions/delete/${trigger.id}${on_done_redirect_str}`,
607
+ '<i class="far fa-trash-alt"></i>&nbsp;' + req.__("Delete"),
608
+ req,
609
+ true,
610
+ trigger.name
611
+ ),
612
+ ]);
613
+
585
614
  const getTriggerList = async (
586
615
  triggers,
587
616
  req,
@@ -617,13 +646,7 @@ const getTriggerList = async (
617
646
  },
618
647
  ]),
619
648
  { label: req.__("Action"), key: "action" },
620
- {
621
- label: req.__("Table or Channel"),
622
- key: (r) =>
623
- r.table_name
624
- ? a({ href: `/table/${r.table_name}` }, r.table_name)
625
- : r.channel,
626
- },
649
+
627
650
  {
628
651
  label: req.__("When"),
629
652
  key: (act) =>
@@ -638,15 +661,15 @@ const getTriggerList = async (
638
661
  : ""),
639
662
  },
640
663
  {
641
- label: req.__("Test run"),
664
+ label: req.__("Table or Channel"),
642
665
  key: (r) =>
643
- r.table_id
644
- ? ""
645
- : link(`/actions/testrun/${r.id}`, req.__("Test run")),
666
+ r.table_name
667
+ ? a({ href: `/table/${r.table_name}` }, r.table_name)
668
+ : r.channel,
646
669
  },
647
670
  {
648
- label: req.__("Edit"),
649
- key: (r) => link(`/actions/edit/${r.id}`, req.__("Edit")),
671
+ label: req.__("Test run"),
672
+ key: (r) => link(`/actions/testrun/${r.id}`, req.__("Test run")),
650
673
  },
651
674
  {
652
675
  label: req.__("Configure"),
@@ -654,8 +677,8 @@ const getTriggerList = async (
654
677
  },
655
678
  !tagId
656
679
  ? {
657
- label: req.__("Delete"),
658
- key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
680
+ label: "",
681
+ key: (r) => trigger_dropdown(r, req),
659
682
  }
660
683
  : {
661
684
  label: req.__("Remove From Tag"),
package/routes/fields.js CHANGED
@@ -1180,9 +1180,24 @@ router.post(
1180
1180
  type,
1181
1181
  join_field,
1182
1182
  join_fieldview,
1183
+ agg_outcome_type,
1184
+ agg_fieldview,
1185
+ agg_field,
1183
1186
  _columndef,
1184
1187
  } = req.body;
1185
1188
  const table = Table.findOne({ name: tableName });
1189
+ if (agg_outcome_type && agg_fieldview) {
1190
+ const type = getState().types[agg_outcome_type];
1191
+ const fv = type?.fieldviews?.[agg_fieldview];
1192
+ if (!fv?.configFields) {
1193
+ res.send(req.query?.accept == "json" ? "[]" : "");
1194
+ return;
1195
+ }
1196
+ const field = table.getField(agg_field);
1197
+ const cfgfields = await applyAsync(fv.configFields, field || { table });
1198
+ res.json(cfgfields);
1199
+ return;
1200
+ }
1186
1201
  if (typeof type !== "string") {
1187
1202
  try {
1188
1203
  type = JSON.parse(_columndef).type;
@@ -1193,19 +1208,19 @@ router.post(
1193
1208
  const fieldName = type == "Field" ? field_name : join_field;
1194
1209
  const fv_name = type == "Field" ? fieldview : join_fieldview;
1195
1210
  if (!fieldName) {
1196
- res.send("");
1211
+ res.send(req.query?.accept == "json" ? "[]" : "");
1197
1212
  return;
1198
1213
  }
1199
1214
 
1200
1215
  const field = table.getField(fieldName);
1201
1216
  if (!field) {
1202
- res.send("");
1217
+ res.send(req.query?.accept == "json" ? "[]" : "");
1203
1218
  return;
1204
1219
  }
1205
1220
  const fieldViewConfigForms = await calcfldViewConfig([field], false, 0);
1206
1221
  const formFields = fieldViewConfigForms[field.name][fv_name];
1207
1222
  if (!formFields) {
1208
- res.send("");
1223
+ res.send(req.query?.accept == "json" ? "[]" : "");
1209
1224
  return;
1210
1225
  }
1211
1226
  formFields.forEach((ff) => {
@@ -24,6 +24,7 @@ const packagejson = require("../package.json");
24
24
  const Trigger = require("@saltcorn/data/models/trigger");
25
25
  const { fileUploadForm } = require("../markup/forms");
26
26
  const { get_base_url, sendHtmlFile, getEligiblePage } = require("./utils.js");
27
+ const semver = require("semver");
27
28
 
28
29
  /**
29
30
  * Tables List
@@ -519,8 +520,8 @@ const no_views_logged_in = async (req, res) => {
519
520
  const latest =
520
521
  isRoot && (await get_latest_npm_version("@saltcorn/cli", 500));
521
522
  const can_update =
522
- packagejson.version !== latest &&
523
523
  latest &&
524
+ semver.gt(latest, packagejson.version) &&
524
525
  !process.env.SALTCORN_DISABLE_UPGRADE;
525
526
  if (latest && can_update && isRoot)
526
527
  req.flash(