@saltcorn/server 1.3.0-beta.3 → 1.3.0-beta.5

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 (396) hide show
  1. package/app.js +8 -8
  2. package/docs/assets/search.js +1 -1
  3. package/docs/classes/_saltcorn_common_code.Relation.html +10 -10
  4. package/docs/classes/_saltcorn_common_code.RelationsFinder.html +5 -5
  5. package/docs/classes/_saltcorn_data.models.Crash.html +17 -17
  6. package/docs/classes/_saltcorn_data.models.EventLog-1.html +19 -19
  7. package/docs/classes/_saltcorn_data.models.Field.html +73 -73
  8. package/docs/classes/_saltcorn_data.models.FieldRepeat.html +16 -16
  9. package/docs/classes/_saltcorn_data.models.File-1.html +48 -48
  10. package/docs/classes/_saltcorn_data.models.Form-1.html +38 -38
  11. package/docs/classes/_saltcorn_data.models.Library.html +13 -13
  12. package/docs/classes/_saltcorn_data.models.Page.html +24 -24
  13. package/docs/classes/_saltcorn_data.models.PageGroup-1.html +25 -25
  14. package/docs/classes/_saltcorn_data.models.Plugin.html +25 -25
  15. package/docs/classes/_saltcorn_data.models.Role.html +9 -9
  16. package/docs/classes/_saltcorn_data.models.Table-1.html +92 -92
  17. package/docs/classes/_saltcorn_data.models.TableConstraint.html +14 -14
  18. package/docs/classes/_saltcorn_data.models.Trigger.html +36 -36
  19. package/docs/classes/_saltcorn_data.models.User.html +48 -48
  20. package/docs/classes/_saltcorn_data.models.View-1.html +105 -53
  21. package/docs/classes/_saltcorn_data.models.Workflow.html +17 -17
  22. package/docs/classes/_saltcorn_data.models.WorkflowRun.html +35 -35
  23. package/docs/classes/_saltcorn_data.models.WorkflowStep.html +25 -25
  24. package/docs/classes/_saltcorn_data.models.WorkflowTrace.html +18 -18
  25. package/docs/classes/_saltcorn_mobile_builder.MobileBuilder.html +36 -36
  26. package/docs/enums/_saltcorn_common_code.RelationType.html +7 -7
  27. package/docs/enums/_saltcorn_common_code.ViewDisplayType.html +4 -4
  28. package/docs/functions/_saltcorn_admin_models.backup.create_backup.html +1 -1
  29. package/docs/functions/_saltcorn_admin_models.backup.create_csv_from_rows.html +1 -1
  30. package/docs/functions/_saltcorn_admin_models.backup.restore.html +1 -1
  31. package/docs/functions/_saltcorn_admin_models.pack.add_to_menu.html +1 -1
  32. package/docs/functions/_saltcorn_admin_models.pack.can_install_pack.html +1 -1
  33. package/docs/functions/_saltcorn_admin_models.pack.fetch_available_packs.html +1 -1
  34. package/docs/functions/_saltcorn_admin_models.pack.fetch_pack_by_name.html +1 -1
  35. package/docs/functions/_saltcorn_admin_models.pack.install_pack.html +1 -1
  36. package/docs/functions/_saltcorn_admin_models.pack.library_pack.html +1 -1
  37. package/docs/functions/_saltcorn_admin_models.pack.model_instance_pack.html +1 -1
  38. package/docs/functions/_saltcorn_admin_models.pack.model_pack.html +1 -1
  39. package/docs/functions/_saltcorn_admin_models.pack.page_group_pack.html +1 -1
  40. package/docs/functions/_saltcorn_admin_models.pack.page_pack.html +1 -1
  41. package/docs/functions/_saltcorn_admin_models.pack.plugin_pack.html +1 -1
  42. package/docs/functions/_saltcorn_admin_models.pack.role_pack.html +1 -1
  43. package/docs/functions/_saltcorn_admin_models.pack.table_pack.html +1 -1
  44. package/docs/functions/_saltcorn_admin_models.pack.trigger_pack.html +1 -1
  45. package/docs/functions/_saltcorn_admin_models.pack.uninstall_pack.html +1 -1
  46. package/docs/functions/_saltcorn_admin_models.pack.view_pack.html +1 -1
  47. package/docs/functions/_saltcorn_admin_models.tenant.copy_tenant_template.html +1 -1
  48. package/docs/functions/_saltcorn_admin_models.tenant.create_tenant.html +1 -1
  49. package/docs/functions/_saltcorn_admin_models.tenant.deleteTenant.html +1 -1
  50. package/docs/functions/_saltcorn_admin_models.tenant.domain_sanitize.html +1 -1
  51. package/docs/functions/_saltcorn_admin_models.tenant.eachTenant.html +1 -1
  52. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenantRows.html +1 -1
  53. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenants.html +1 -1
  54. package/docs/functions/_saltcorn_admin_models.tenant.insertTenant.html +1 -1
  55. package/docs/functions/_saltcorn_admin_models.tenant.switchToTenant.html +1 -1
  56. package/docs/functions/_saltcorn_common_code.buildTableCaches.html +1 -1
  57. package/docs/functions/_saltcorn_common_code.parseLegacyRelation.html +1 -1
  58. package/docs/functions/_saltcorn_common_code.parseRelationPath.html +1 -1
  59. package/docs/functions/_saltcorn_data.models.config.check_email_mask.html +1 -1
  60. package/docs/functions/_saltcorn_data.models.config.deleteConfig.html +1 -1
  61. package/docs/functions/_saltcorn_data.models.config.getAllConfig.html +1 -1
  62. package/docs/functions/_saltcorn_data.models.config.getConfig.html +1 -1
  63. package/docs/functions/_saltcorn_data.models.config.get_base_url.html +1 -1
  64. package/docs/functions/_saltcorn_data.models.config.get_latest_npm_version.html +1 -1
  65. package/docs/functions/_saltcorn_data.models.config.remove_from_menu.html +1 -1
  66. package/docs/functions/_saltcorn_data.models.config.save_menu_items.html +1 -1
  67. package/docs/functions/_saltcorn_data.models.config.setConfig.html +1 -1
  68. package/docs/functions/_saltcorn_data.models.discovery.discover_tables.html +1 -1
  69. package/docs/functions/_saltcorn_data.models.discovery.discoverable_tables.html +1 -1
  70. package/docs/functions/_saltcorn_data.models.discovery.findType.html +1 -1
  71. package/docs/functions/_saltcorn_data.models.discovery.get_existing_views.html +1 -1
  72. package/docs/functions/_saltcorn_data.models.discovery.implement_discovery.html +1 -1
  73. package/docs/functions/_saltcorn_data.models.email.getMailTransport.html +1 -1
  74. package/docs/functions/_saltcorn_data.models.email.send_verification_email.html +1 -1
  75. package/docs/functions/_saltcorn_data.models.email.viewToEmailHtml.html +1 -1
  76. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields.html +1 -1
  77. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields_stored.html +1 -1
  78. package/docs/functions/_saltcorn_data.models.expression.eval_expression.html +1 -1
  79. package/docs/functions/_saltcorn_data.models.expression.expressionValidator.html +1 -1
  80. package/docs/functions/_saltcorn_data.models.expression.get_async_expression_function.html +1 -1
  81. package/docs/functions/_saltcorn_data.models.expression.get_expression_function.html +1 -1
  82. package/docs/functions/_saltcorn_data.models.expression.jsexprToWhere.html +1 -1
  83. package/docs/functions/_saltcorn_data.models.expression.recalculate_for_stored.html +1 -1
  84. package/docs/functions/_saltcorn_data.models.expression.transform_for_async.html +1 -1
  85. package/docs/functions/_saltcorn_data.models.layout.eachView.html +1 -1
  86. package/docs/functions/_saltcorn_data.models.layout.getStringsForI18n.html +1 -1
  87. package/docs/functions/_saltcorn_data.models.layout.getViews.html +1 -1
  88. package/docs/functions/_saltcorn_data.models.layout.translateLayout.html +1 -1
  89. package/docs/functions/_saltcorn_data.models.layout.traverse.html +1 -1
  90. package/docs/functions/_saltcorn_data.models.layout.traverseSync.html +1 -1
  91. package/docs/functions/_saltcorn_data.models.random.all_views.html +1 -1
  92. package/docs/functions/_saltcorn_data.models.random.fill_table_row.html +1 -1
  93. package/docs/functions/_saltcorn_data.models.random.initial_view.html +1 -1
  94. package/docs/functions/_saltcorn_data.models.random.random_table.html +1 -1
  95. package/docs/functions/_saltcorn_db_common.buildInsertBulkSql.html +1 -1
  96. package/docs/functions/_saltcorn_db_common.buildInsertSql.html +1 -1
  97. package/docs/functions/_saltcorn_db_common.doCount.html +1 -1
  98. package/docs/functions/_saltcorn_db_common.doDeleteWhere.html +1 -1
  99. package/docs/functions/_saltcorn_db_common.doListScTables.html +1 -1
  100. package/docs/functions/_saltcorn_db_common.doListTables.html +1 -1
  101. package/docs/functions/_saltcorn_db_common.doListUserDefinedTables.html +1 -1
  102. package/docs/functions/_saltcorn_db_common.do_add_index.html +1 -1
  103. package/docs/functions/_saltcorn_db_common.do_drop_index.html +1 -1
  104. package/docs/functions/_saltcorn_db_common.ftsFieldsSqlExpr.html +1 -1
  105. package/docs/functions/_saltcorn_db_common.mkSelectOptions.html +1 -1
  106. package/docs/functions/_saltcorn_db_common.mkVal.html +1 -1
  107. package/docs/functions/_saltcorn_db_common.mkWhere.html +1 -1
  108. package/docs/functions/_saltcorn_db_common.multi_tenant.enable_multi_tenant.html +1 -1
  109. package/docs/functions/_saltcorn_db_common.multi_tenant.getRequestContext.html +1 -1
  110. package/docs/functions/_saltcorn_db_common.multi_tenant.getTenantSchema.html +1 -1
  111. package/docs/functions/_saltcorn_db_common.multi_tenant.init.html +1 -1
  112. package/docs/functions/_saltcorn_db_common.multi_tenant.is_it_multi_tenant.html +1 -1
  113. package/docs/functions/_saltcorn_db_common.multi_tenant.runWithTenant.html +1 -1
  114. package/docs/functions/_saltcorn_db_common.orderByIsObject.html +1 -1
  115. package/docs/functions/_saltcorn_db_common.orderByIsOperator.html +1 -1
  116. package/docs/functions/_saltcorn_db_common.prefixFieldsInWhere.html +1 -1
  117. package/docs/functions/_saltcorn_db_common.reprAsJson.html +1 -1
  118. package/docs/functions/_saltcorn_db_common.slugify.html +1 -1
  119. package/docs/functions/_saltcorn_db_common.sqlBinOp.html +1 -1
  120. package/docs/functions/_saltcorn_db_common.sqlFun.html +1 -1
  121. package/docs/functions/_saltcorn_db_common.sqlsanitize.html +1 -1
  122. package/docs/functions/_saltcorn_db_common.sqlsanitizeAllowDots.html +1 -1
  123. package/docs/functions/_saltcorn_db_common.subSelectWhere.html +1 -1
  124. package/docs/functions/_saltcorn_db_common.tryCatchInTransaction.html +1 -1
  125. package/docs/functions/_saltcorn_db_common.withTransaction.html +1 -1
  126. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidFeatures.html +1 -1
  127. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidPermissions.html +1 -1
  128. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.buildTablesFile.html +1 -1
  129. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyPrepopulatedDb.html +1 -1
  130. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyServerFiles.html +1 -1
  131. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyShareExtFiles.html +1 -1
  132. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copySiteLogo.html +1 -1
  133. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyTranslationFiles.html +1 -1
  134. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.createSqliteDb.html +1 -1
  135. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.decodeProvisioningProfile.html +1 -1
  136. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.extractDomain.html +1 -1
  137. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.generateAndroidVersionCode.html +1 -1
  138. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyAndroidManifest.html +1 -1
  139. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyConfigXml.html +1 -1
  140. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyGradleConfig.html +1 -1
  141. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyInfoPlist.html +1 -1
  142. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyXcodeProjectFile.html +1 -1
  143. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepAppIcon.html +1 -1
  144. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareAppIcon.html +1 -1
  145. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareBuildDir.html +1 -1
  146. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareExportOptionsPlist.html +1 -1
  147. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashIcon.html +1 -1
  148. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashPage.html +1 -1
  149. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCapacitorConfig.html +1 -1
  150. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCfgFile.html +1 -1
  151. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeDataExtractionRules.html +1 -1
  152. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeNetworkSecurityConfig.html +1 -1
  153. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePodfile.html +1 -1
  154. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePrivacyInfo.html +1 -1
  155. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundleMobileAppCode.html +1 -1
  156. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundlePackagesAndPlugins.html +1 -1
  157. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyMobileAppDirs.html +1 -1
  158. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyPublicDirs.html +1 -1
  159. package/docs/functions/_saltcorn_sqlite.add_index.html +1 -1
  160. package/docs/functions/_saltcorn_sqlite.add_unique_constraint.html +1 -1
  161. package/docs/functions/_saltcorn_sqlite.begin.html +1 -1
  162. package/docs/functions/_saltcorn_sqlite.changeConnection.html +1 -1
  163. package/docs/functions/_saltcorn_sqlite.close.html +1 -1
  164. package/docs/functions/_saltcorn_sqlite.commit.html +1 -1
  165. package/docs/functions/_saltcorn_sqlite.count.html +1 -1
  166. package/docs/functions/_saltcorn_sqlite.deleteWhere.html +1 -1
  167. package/docs/functions/_saltcorn_sqlite.dropTable.html +1 -1
  168. package/docs/functions/_saltcorn_sqlite.dropTables.html +1 -1
  169. package/docs/functions/_saltcorn_sqlite.drop_index.html +1 -1
  170. package/docs/functions/_saltcorn_sqlite.drop_reset_schema.html +1 -1
  171. package/docs/functions/_saltcorn_sqlite.drop_unique_constraint.html +1 -1
  172. package/docs/functions/_saltcorn_sqlite.getVersion.html +1 -1
  173. package/docs/functions/_saltcorn_sqlite.get_db_filepath.html +1 -1
  174. package/docs/functions/_saltcorn_sqlite.get_sql_logging.html +1 -1
  175. package/docs/functions/_saltcorn_sqlite.init.html +1 -1
  176. package/docs/functions/_saltcorn_sqlite.insert.html +1 -1
  177. package/docs/functions/_saltcorn_sqlite.listScTables.html +1 -1
  178. package/docs/functions/_saltcorn_sqlite.listTables.html +1 -1
  179. package/docs/functions/_saltcorn_sqlite.listUserDefinedTables.html +1 -1
  180. package/docs/functions/_saltcorn_sqlite.query.html +1 -1
  181. package/docs/functions/_saltcorn_sqlite.rollback.html +1 -1
  182. package/docs/functions/_saltcorn_sqlite.select.html +1 -1
  183. package/docs/functions/_saltcorn_sqlite.selectMaybeOne.html +1 -1
  184. package/docs/functions/_saltcorn_sqlite.selectOne.html +1 -1
  185. package/docs/functions/_saltcorn_sqlite.set_sql_logging.html +1 -1
  186. package/docs/functions/_saltcorn_sqlite.sql_log.html +1 -1
  187. package/docs/functions/_saltcorn_sqlite.update.html +1 -1
  188. package/docs/functions/_saltcorn_sqlite.updateWhere.html +1 -1
  189. package/docs/functions/_saltcorn_sqlite_mobile.add_index.html +1 -1
  190. package/docs/functions/_saltcorn_sqlite_mobile.add_unique_constraint.html +1 -1
  191. package/docs/functions/_saltcorn_sqlite_mobile.count.html +1 -1
  192. package/docs/functions/_saltcorn_sqlite_mobile.deleteWhere.html +1 -1
  193. package/docs/functions/_saltcorn_sqlite_mobile.drop_index.html +1 -1
  194. package/docs/functions/_saltcorn_sqlite_mobile.drop_reset_schema.html +1 -1
  195. package/docs/functions/_saltcorn_sqlite_mobile.drop_unique_constraint.html +1 -1
  196. package/docs/functions/_saltcorn_sqlite_mobile.init.html +1 -1
  197. package/docs/functions/_saltcorn_sqlite_mobile.insert.html +1 -1
  198. package/docs/functions/_saltcorn_sqlite_mobile.insertRows.html +1 -1
  199. package/docs/functions/_saltcorn_sqlite_mobile.listScTables.html +1 -1
  200. package/docs/functions/_saltcorn_sqlite_mobile.listTables.html +1 -1
  201. package/docs/functions/_saltcorn_sqlite_mobile.listUserDefinedTables.html +1 -1
  202. package/docs/functions/_saltcorn_sqlite_mobile.query.html +1 -1
  203. package/docs/functions/_saltcorn_sqlite_mobile.select.html +1 -1
  204. package/docs/functions/_saltcorn_sqlite_mobile.selectMaybeOne.html +1 -1
  205. package/docs/functions/_saltcorn_sqlite_mobile.selectOne.html +1 -1
  206. package/docs/functions/_saltcorn_sqlite_mobile.setConnectionObject.html +1 -1
  207. package/docs/functions/_saltcorn_sqlite_mobile.tableExists.html +1 -1
  208. package/docs/functions/_saltcorn_sqlite_mobile.time.html +1 -1
  209. package/docs/functions/_saltcorn_sqlite_mobile.update.html +1 -1
  210. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_field.instanceOfField.html +1 -1
  211. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_page.instanceOfPage.html +1 -1
  212. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_view.instanceOfView.html +1 -1
  213. package/docs/functions/_saltcorn_types.Types.base_types.instanceOWithHtmlFile.html +1 -1
  214. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfErrorMsg.html +1 -1
  215. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfSuccessMsg.html +1 -1
  216. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfType.html +1 -1
  217. package/docs/functions/_saltcorn_types.generators.generateBool.html +1 -1
  218. package/docs/functions/_saltcorn_types.generators.generateString.html +1 -1
  219. package/docs/functions/_saltcorn_types.generators.num_between.html +1 -1
  220. package/docs/functions/_saltcorn_types.generators.oneOf.html +1 -1
  221. package/docs/interfaces/_saltcorn_mobile_builder.common_build_utils.ScCapacitorConfig.html +10 -10
  222. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractField.html +15 -15
  223. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractFieldRepeat.html +3 -3
  224. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_form.AbstractForm.html +26 -26
  225. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_page.AbstractPage.html +7 -7
  226. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_role.AbstractRole.html +3 -3
  227. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_table.AbstractTable.html +11 -11
  228. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_trigger.AbstractTrigger.html +16 -16
  229. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_view.AbstractView.html +10 -10
  230. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_workflow.AbstractWorkflow.html +13 -13
  231. package/docs/modules/_saltcorn_admin_models.backup.html +1 -1
  232. package/docs/modules/_saltcorn_admin_models.html +1 -1
  233. package/docs/modules/_saltcorn_admin_models.pack.html +1 -1
  234. package/docs/modules/_saltcorn_admin_models.tenant.html +1 -1
  235. package/docs/modules/_saltcorn_common_code.html +1 -1
  236. package/docs/modules/_saltcorn_data.html +3 -3
  237. package/docs/modules/_saltcorn_data.models.EventLog.html +2 -2
  238. package/docs/modules/_saltcorn_data.models.File.html +2 -2
  239. package/docs/modules/_saltcorn_data.models.Form.html +2 -2
  240. package/docs/modules/_saltcorn_data.models.PageGroup.html +2 -2
  241. package/docs/modules/_saltcorn_data.models.Table.html +2 -2
  242. package/docs/modules/_saltcorn_data.models.View.html +2 -2
  243. package/docs/modules/_saltcorn_data.models.config.html +1 -1
  244. package/docs/modules/_saltcorn_data.models.discovery.html +1 -1
  245. package/docs/modules/_saltcorn_data.models.email.html +1 -1
  246. package/docs/modules/_saltcorn_data.models.expression.html +1 -1
  247. package/docs/modules/_saltcorn_data.models.html +1 -1
  248. package/docs/modules/_saltcorn_data.models.layout.html +1 -1
  249. package/docs/modules/_saltcorn_data.models.random.html +1 -1
  250. package/docs/modules/_saltcorn_data.models.scheduler.html +1 -1
  251. package/docs/modules/_saltcorn_data.plugin_helper.html +1 -1
  252. package/docs/modules/_saltcorn_data.utils.html +1 -1
  253. package/docs/modules/_saltcorn_db_common.html +2 -2
  254. package/docs/modules/_saltcorn_db_common.multi_tenant.html +1 -1
  255. package/docs/modules/_saltcorn_markup.html +2 -2
  256. package/docs/modules/_saltcorn_mobile_builder.common_build_utils.html +1 -1
  257. package/docs/modules/_saltcorn_mobile_builder.html +1 -1
  258. package/docs/modules/_saltcorn_mobile_builder.package_bundle_utils.html +1 -1
  259. package/docs/modules/_saltcorn_sqlite.html +1 -1
  260. package/docs/modules/_saltcorn_sqlite_mobile.html +1 -1
  261. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_field.html +1 -1
  262. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_form.html +1 -1
  263. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_library.html +1 -1
  264. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_page.html +1 -1
  265. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_plugin.html +1 -1
  266. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_role.html +1 -1
  267. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_table.html +1 -1
  268. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_trigger.html +1 -1
  269. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_view.html +1 -1
  270. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_workflow.html +1 -1
  271. package/docs/modules/_saltcorn_types.ModelAbstracts.html +1 -1
  272. package/docs/modules/_saltcorn_types.Types.base_types.html +1 -1
  273. package/docs/modules/_saltcorn_types.Types.common_types.html +1 -1
  274. package/docs/modules/_saltcorn_types.Types.html +1 -1
  275. package/docs/modules/_saltcorn_types.generators.html +1 -1
  276. package/docs/modules/_saltcorn_types.html +1 -1
  277. package/docs/types/_saltcorn_data.models.EventLog.EventLogCfg.html +1 -1
  278. package/docs/types/_saltcorn_data.models.File.FileCfg.html +1 -1
  279. package/docs/types/_saltcorn_data.models.Form.AdditionalButton.html +1 -1
  280. package/docs/types/_saltcorn_data.models.Form.FormCfg.html +1 -1
  281. package/docs/types/_saltcorn_data.models.PageGroup.ScreenInfoParams.html +1 -1
  282. package/docs/types/_saltcorn_data.models.Table.ChildRelations.html +1 -1
  283. package/docs/types/_saltcorn_data.models.Table.ParentRelations.html +1 -1
  284. package/docs/types/_saltcorn_data.models.Table.RelationData.html +1 -1
  285. package/docs/types/_saltcorn_data.models.View.FindViewsPred.html +1 -1
  286. package/docs/types/_saltcorn_db_common.AggregationOptions.html +1 -1
  287. package/docs/types/_saltcorn_db_common.CoordOpts.html +1 -1
  288. package/docs/types/_saltcorn_db_common.DatabaseClient.html +1 -1
  289. package/docs/types/_saltcorn_db_common.JoinField.html +1 -1
  290. package/docs/types/_saltcorn_db_common.JoinFields.html +1 -1
  291. package/docs/types/_saltcorn_db_common.JoinOptions.html +1 -1
  292. package/docs/types/_saltcorn_db_common.JsonPath.html +1 -1
  293. package/docs/types/_saltcorn_db_common.JsonPathElem.html +1 -1
  294. package/docs/types/_saltcorn_db_common.Operator.html +1 -1
  295. package/docs/types/_saltcorn_db_common.PartialSome.html +1 -1
  296. package/docs/types/_saltcorn_db_common.PrimaryKeyValue.html +1 -1
  297. package/docs/types/_saltcorn_db_common.Row.html +1 -1
  298. package/docs/types/_saltcorn_db_common.SelectOptions.html +1 -1
  299. package/docs/types/_saltcorn_db_common.SqlAndValues.html +1 -1
  300. package/docs/types/_saltcorn_db_common.StrongRow.html +1 -1
  301. package/docs/types/_saltcorn_db_common.SubselectOptions.html +1 -1
  302. package/docs/types/_saltcorn_db_common.Value.html +1 -1
  303. package/docs/types/_saltcorn_db_common.Where.html +1 -1
  304. package/docs/types/_saltcorn_mobile_builder.IosCfg.html +1 -1
  305. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.FieldCfg.html +1 -1
  306. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.InputType.html +1 -1
  307. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_form.AdditionalButton.html +1 -1
  308. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryCfg.html +1 -1
  309. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryPack.html +1 -1
  310. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PageCfg.html +1 -1
  311. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PagePack.html +1 -1
  312. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginCfg.html +1 -1
  313. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginPack.html +1 -1
  314. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RoleCfg.html +1 -1
  315. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RolePack.html +1 -1
  316. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TableCfg.html +1 -1
  317. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TablePack.html +1 -1
  318. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerCfg.html +1 -1
  319. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerPack.html +1 -1
  320. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewCfg.html +1 -1
  321. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewPack.html +1 -1
  322. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.ConfigWorkflowStep.html +1 -1
  323. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.RunResult.html +1 -1
  324. package/docs/types/_saltcorn_types.Types.base_types.Action.html +1 -1
  325. package/docs/types/_saltcorn_types.Types.base_types.AuthenticationMethod.html +1 -1
  326. package/docs/types/_saltcorn_types.Types.base_types.CalcJoinfield.html +1 -1
  327. package/docs/types/_saltcorn_types.Types.base_types.CapacitorPlugin.html +1 -1
  328. package/docs/types/_saltcorn_types.Types.base_types.CodePagePack.html +1 -1
  329. package/docs/types/_saltcorn_types.Types.base_types.Column.html +1 -1
  330. package/docs/types/_saltcorn_types.Types.base_types.ConnectObjType.html +1 -1
  331. package/docs/types/_saltcorn_types.Types.base_types.ConnectedObjects.html +1 -1
  332. package/docs/types/_saltcorn_types.Types.base_types.CopilotSkill.html +1 -1
  333. package/docs/types/_saltcorn_types.Types.base_types.ErrorObj.html +1 -1
  334. package/docs/types/_saltcorn_types.Types.base_types.FieldLike.html +1 -1
  335. package/docs/types/_saltcorn_types.Types.base_types.FieldView.html +1 -1
  336. package/docs/types/_saltcorn_types.Types.base_types.Header.html +1 -1
  337. package/docs/types/_saltcorn_types.Types.base_types.JoinFieldOption.html +1 -1
  338. package/docs/types/_saltcorn_types.Types.base_types.Layout.html +1 -1
  339. package/docs/types/_saltcorn_types.Types.base_types.MobileConfig.html +1 -1
  340. package/docs/types/_saltcorn_types.Types.base_types.ModelPattern.html +1 -1
  341. package/docs/types/_saltcorn_types.Types.base_types.Pack.html +1 -1
  342. package/docs/types/_saltcorn_types.Types.base_types.Plugin.html +1 -1
  343. package/docs/types/_saltcorn_types.Types.base_types.PluginFunction.html +1 -1
  344. package/docs/types/_saltcorn_types.Types.base_types.PluginLayout.html +1 -1
  345. package/docs/types/_saltcorn_types.Types.base_types.PluginRoute.html +1 -1
  346. package/docs/types/_saltcorn_types.Types.base_types.PluginSourceType.html +1 -1
  347. package/docs/types/_saltcorn_types.Types.base_types.PluginType.html +1 -1
  348. package/docs/types/_saltcorn_types.Types.base_types.PluginWrap.html +1 -1
  349. package/docs/types/_saltcorn_types.Types.base_types.PluginWrapArg.html +1 -1
  350. package/docs/types/_saltcorn_types.Types.base_types.RelationOption.html +1 -1
  351. package/docs/types/_saltcorn_types.Types.base_types.Req.html +1 -1
  352. package/docs/types/_saltcorn_types.Types.base_types.Res.html +1 -1
  353. package/docs/types/_saltcorn_types.Types.base_types.ResultType.html +1 -1
  354. package/docs/types/_saltcorn_types.Types.base_types.RouteAction.html +1 -1
  355. package/docs/types/_saltcorn_types.Types.base_types.RunExtra.html +1 -1
  356. package/docs/types/_saltcorn_types.Types.base_types.SlugStepType.html +1 -1
  357. package/docs/types/_saltcorn_types.Types.base_types.StepResType.html +1 -1
  358. package/docs/types/_saltcorn_types.Types.base_types.SubField.html +1 -1
  359. package/docs/types/_saltcorn_types.Types.base_types.TableProvider.html +1 -1
  360. package/docs/types/_saltcorn_types.Types.base_types.TableQuery.html +1 -1
  361. package/docs/types/_saltcorn_types.Types.base_types.Tablely.html +1 -1
  362. package/docs/types/_saltcorn_types.Types.base_types.ViewTemplate.html +1 -1
  363. package/docs/types/_saltcorn_types.Types.common_types.ErrorMessage.html +1 -1
  364. package/docs/types/_saltcorn_types.Types.common_types.GenObj.html +1 -1
  365. package/docs/types/_saltcorn_types.Types.common_types.ReqRes.html +1 -1
  366. package/docs/types/_saltcorn_types.Types.common_types.ResultMessage.html +1 -1
  367. package/docs/types/_saltcorn_types.Types.common_types.SuccessMessage.html +1 -1
  368. package/docs/types/_saltcorn_types.Types.common_types.Type.html +1 -1
  369. package/docs/variables/_saltcorn_data.db.html +1 -1
  370. package/docs/variables/_saltcorn_data.migrations.html +1 -1
  371. package/docs/variables/_saltcorn_data.models.config.available_languages.html +1 -1
  372. package/docs/variables/_saltcorn_data.models.config.configTypes.html +1 -1
  373. package/docs/variables/_saltcorn_data.models.scheduler.runScheduler.html +1 -1
  374. package/docs/variables/_saltcorn_data.plugin_helper.run_action_column.html +1 -1
  375. package/docs/variables/_saltcorn_data.utils.NotAuthorized.html +1 -1
  376. package/docs/variables/_saltcorn_data.utils.sleep.html +1 -1
  377. package/docs/variables/_saltcorn_db_common.multi_tenant.tenantNamespace.html +1 -1
  378. package/locales/en.json +5 -1
  379. package/markup/admin.js +11 -2
  380. package/package.json +9 -9
  381. package/public/saltcorn-common.js +19 -0
  382. package/public/saltcorn.css +8 -0
  383. package/public/saltcorn.js +8 -0
  384. package/routes/admin.js +2 -0
  385. package/routes/api.js +53 -0
  386. package/routes/files.js +12 -0
  387. package/routes/homepage.js +23 -1
  388. package/routes/menu.js +14 -0
  389. package/routes/notifications.js +12 -0
  390. package/routes/page.js +30 -1
  391. package/routes/registry.js +64 -4
  392. package/routes/search.js +10 -0
  393. package/routes/view.js +37 -1
  394. package/serve.js +41 -1
  395. package/systemd.js +1 -1
  396. package/tests/api.test.js +51 -0
package/routes/api.js CHANGED
@@ -135,6 +135,21 @@ const getFlashes = (req) =>
135
135
  })
136
136
  .filter((a) => a.msg && a.msg.length && a.msg.length > 0);
137
137
 
138
+ router.use(
139
+ error_catcher(async (req, res, next) => {
140
+ const state = getState();
141
+ const maintenanceModeEnabled = state.getConfig(
142
+ "maintenance_mode_enabled",
143
+ false
144
+ );
145
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
146
+ res.status(503).json({ error: "in maintenance mode" });
147
+ return;
148
+ }
149
+ next();
150
+ })
151
+ );
152
+
138
153
  router.post(
139
154
  "/viewQuery/:viewName/:queryName",
140
155
  error_catcher(async (req, res, next) => {
@@ -446,6 +461,44 @@ router.get(
446
461
  })
447
462
  );
448
463
 
464
+ router.get("/:tableName/count", async (req, res, next) => {
465
+ const { tableName } = req.params;
466
+ const { approximate, ...req_query } = req.query;
467
+
468
+ const table = Table.findOne(
469
+ strictParseInt(tableName)
470
+ ? { id: strictParseInt(tableName) }
471
+ : { name: tableName }
472
+ );
473
+ if (!table) {
474
+ getState().log(3, `API get ${tableName} table not found`);
475
+ res.status(404).json({ error: req.__("Not found") });
476
+ return;
477
+ }
478
+ await passport.authenticate(
479
+ ["api-bearer", "jwt"],
480
+ { session: false },
481
+ async function (err, user, info) {
482
+ if (accessAllowedRead(req, user, table)) {
483
+ const tbl_fields = table.getFields();
484
+ readState(req_query, tbl_fields, req);
485
+ const qstate = stateFieldsToWhere({
486
+ fields: tbl_fields,
487
+ approximate: !!approximate,
488
+ state: req_query,
489
+ table,
490
+ prefix: "a.",
491
+ });
492
+ const count = await table.countRows(qstate);
493
+ res.json({ success: count });
494
+ } else {
495
+ getState().log(3, `API get ${table.name} not authorized`);
496
+ res.status(401).json({ error: req.__("Not authorized") });
497
+ }
498
+ }
499
+ )(req, res, next);
500
+ });
501
+
449
502
  /**
450
503
  * Emit Event using POST
451
504
  * This is used from the mobile app to send an event to the server.
package/routes/files.js CHANGED
@@ -52,6 +52,18 @@ const { extract } = require("@saltcorn/admin-models/models/backup");
52
52
  const router = new Router();
53
53
  module.exports = router;
54
54
 
55
+ router.use(
56
+ error_catcher(async (req, res, next) => {
57
+ const state = getState();
58
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
59
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
60
+ res.status(503).send("Page Unavailable: in maintenance mode");
61
+ return;
62
+ }
63
+ next();
64
+ })
65
+ )
66
+
55
67
  const send_files_picker = async (folder, noSubdirs, inputId, req, res) => {
56
68
  res.set("SaltcornModalWidth", "1200px");
57
69
  res.sendWrap(req.__("Please select a file"), {
@@ -15,7 +15,7 @@ const Page = require("@saltcorn/data/models/page");
15
15
  const PageGroup = require("@saltcorn/data/models/page_group");
16
16
  const Plugin = require("@saltcorn/data/models/plugin");
17
17
  const { link, mkTable } = require("@saltcorn/markup");
18
- const { div, a, p, i, h5, span } = require("@saltcorn/markup/tags");
18
+ const { div, a, p, i, h5, span, title } = require("@saltcorn/markup/tags");
19
19
  const Table = require("@saltcorn/data/models/table");
20
20
  const { get_cached_packs } = require("@saltcorn/admin-models/models/pack");
21
21
  // const { restore_backup } = require("../markup/admin");
@@ -553,6 +553,28 @@ const no_views_logged_in = async (req, res) => {
553
553
  * @returns {Promise<boolean>}
554
554
  */
555
555
  const get_config_response = async (role_id, res, req) => {
556
+ const state = getState();
557
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
558
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
559
+
560
+ if(maintenanceModeEnabled && (!req.user || req.user.role_id > 1) && maintenanceModePage) {
561
+ const db_page = await Page.findOne({ name: maintenanceModePage });
562
+ if (db_page) {
563
+ res.sendWrap(
564
+ {
565
+ title: db_page.title,
566
+ description: db_page.description,
567
+ bodyClass: "page_" + db.sqlsanitize(maintenanceModePage),
568
+ },
569
+ await db_page.run(req.query, { res, req })
570
+ );
571
+ return true;
572
+ } else {
573
+ res.status(503).send("Page Unavailable: in maintenance mode");
574
+ return true;
575
+ }
576
+ }
577
+
556
578
  const wrap = async (
557
579
  contents,
558
580
  homeCfg,
package/routes/menu.js CHANGED
@@ -624,6 +624,20 @@ router.post(
624
624
  })
625
625
  );
626
626
 
627
+ router.post(
628
+ "/action/:rndid",
629
+ error_catcher(async (req, res, next) => {
630
+ const state = getState();
631
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
632
+
633
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
634
+ res.status(503).json({ error: "in maintenance mode" });
635
+ return;
636
+ }
637
+ next();
638
+ }),
639
+ );
640
+
627
641
  const getIcons = () => {
628
642
  return getState().icons;
629
643
  };
@@ -20,6 +20,18 @@ const db = require("@saltcorn/data/db");
20
20
  const router = new Router();
21
21
  module.exports = router;
22
22
 
23
+ router.use(
24
+ error_catcher(async (req, res, next) => {
25
+ const state = getState();
26
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
27
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
28
+ res.status(503).send("Page Unavailable: in maintenance mode");
29
+ return;
30
+ }
31
+ next();
32
+ })
33
+ );
34
+
23
35
  const notificationSettingsForm = () =>
24
36
  new Form({
25
37
  action: `/notifications/settings`,
package/routes/page.js CHANGED
@@ -145,8 +145,23 @@ const runPageGroup = async (pageGroup, req, res, tic) => {
145
145
  router.get(
146
146
  "/:pagename",
147
147
  error_catcher(async (req, res) => {
148
- const { pagename } = req.params;
149
148
  const state = getState();
149
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
150
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
151
+
152
+ if (
153
+ maintenanceModeEnabled &&
154
+ (!req.user || req.user.role_id > 1) &&
155
+ maintenanceModePage
156
+ ) {
157
+ const maintenancePage = await Page.findOne({ name: maintenanceModePage });
158
+ if (maintenancePage) {
159
+ await runPage(maintenancePage, req, res, new Date());
160
+ return;
161
+ }
162
+ }
163
+
164
+ const { pagename } = req.params;
150
165
  state.log(
151
166
  3,
152
167
  `Route /page/${pagename} user=${req.user?.id}${
@@ -177,6 +192,13 @@ router.post(
177
192
  "/:pagename/preview",
178
193
  isAdmin,
179
194
  error_catcher(async (req, res) => {
195
+ const state = getState();
196
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
197
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
198
+ res.status(503).json({ error: "in maintenance mode" });
199
+ return;
200
+ }
201
+
180
202
  const { pagename } = req.params;
181
203
  const page = await Page.findOne({ name: pagename });
182
204
  if (!page) {
@@ -191,6 +213,13 @@ router.post(
191
213
  router.post(
192
214
  "/:pagename/action/:rndid",
193
215
  error_catcher(async (req, res) => {
216
+ const state = getState();
217
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
218
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
219
+ res.status(503).json({ error: "in maintenance mode" });
220
+ return;
221
+ }
222
+
194
223
  const { pagename, rndid } = req.params;
195
224
  const role = req.user && req.user.id ? req.user.role_id : 100;
196
225
  const db_page = await Page.findOne({ name: pagename });
@@ -19,12 +19,14 @@ const {
19
19
  details,
20
20
  summary,
21
21
  } = require("@saltcorn/markup/tags");
22
- const Table = require("@saltcorn/data/models/table");
23
22
  const { isAdmin, error_catcher } = require("./utils");
24
23
  const { send_infoarch_page } = require("../markup/admin.js");
24
+ const Table = require("@saltcorn/data/models/table");
25
25
  const View = require("@saltcorn/data/models/view");
26
26
  const Page = require("@saltcorn/data/models/page");
27
27
  const Form = require("@saltcorn/data/models/form");
28
+ const Trigger = require("@saltcorn/data/models/trigger");
29
+ const Plugin = require("@saltcorn/data/models/plugin");
28
30
  const {
29
31
  table_pack,
30
32
  view_pack,
@@ -40,8 +42,8 @@ const {
40
42
  event_log_pack,
41
43
  install_pack,
42
44
  } = require("@saltcorn/admin-models/models/pack");
43
- const Trigger = require("@saltcorn/data/models/trigger");
44
45
  const { getState } = require("@saltcorn/data/db/state");
46
+ const { sleep } = require("@saltcorn/data/utils");
45
47
  /**
46
48
  * @type {object}
47
49
  * @const
@@ -81,6 +83,10 @@ router.get(
81
83
  {},
82
84
  { orderBy: "name", nocase: true }
83
85
  );
86
+ const all_plugins = await Plugin.find(
87
+ { name: { not: { in: ["base", "sbadmin2"] } } },
88
+ { orderBy: "name", nocase: true }
89
+ );
84
90
  const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
85
91
 
86
92
  const all_configs_obj = await getState().getAllConfigOrDefaults();
@@ -91,7 +97,7 @@ router.get(
91
97
  }))
92
98
  .filter((c) => isRoot || !c.root_only);
93
99
 
94
- let tables, views, pages, triggers, configs;
100
+ let tables, views, pages, triggers, configs, plugins;
95
101
  if (q) {
96
102
  const qlower = q.toLowerCase();
97
103
  const includesQ = (s) => s.toLowerCase().includes(qlower);
@@ -113,12 +119,17 @@ router.get(
113
119
  return includesQ(JSON.stringify(pack));
114
120
  });
115
121
  configs = all_configs.filter((c) => includesQ(JSON.stringify(c)));
122
+ plugins = all_plugins.filter(
123
+ (p) =>
124
+ includesQ(p.name) || includesQ(JSON.stringify(p.configuration || {}))
125
+ );
116
126
  } else {
117
127
  tables = all_tables;
118
128
  views = all_views;
119
129
  pages = all_pages;
120
130
  triggers = all_triggers;
121
131
  configs = all_configs;
132
+ plugins = all_plugins;
122
133
  }
123
134
  const li_link = (etype1, ename1) =>
124
135
  li(
@@ -224,6 +235,20 @@ router.get(
224
235
 
225
236
  edContents = renderForm(mkForm(trpack), req.csrfToken());
226
237
  break;
238
+ case "module":
239
+ const plugin = all_plugins.find((p) => p.name === ename);
240
+ cfg_link =
241
+ `${ename} ${etype}` +
242
+ a(
243
+ {
244
+ class: "ms-1 me-3",
245
+ href: `/plugins/configure/${encodeURIComponent(ename)}`,
246
+ },
247
+ "Configure&nbsp;",
248
+ i({ class: "fas fa-cog" })
249
+ );
250
+ edContents = renderForm(mkForm(plugin.configuration), req.csrfToken());
251
+ break;
227
252
  }
228
253
  send_infoarch_page({
229
254
  res,
@@ -315,6 +340,16 @@ router.get(
315
340
  configs.map((t) => li_link("config", t.name))
316
341
  )
317
342
  )
343
+ ),
344
+ li(
345
+ details(
346
+ { open: q || etype === "module" },
347
+ summary("Modules"),
348
+ ul(
349
+ { class: "ps-3" },
350
+ plugins.map((m) => li_link("module", m.name))
351
+ )
352
+ )
318
353
  )
319
354
  )
320
355
  ),
@@ -372,7 +407,25 @@ router.post(
372
407
  break;
373
408
  }
374
409
  await db.withTransaction(async () => {
375
- await install_pack(pack);
410
+ if (etype === "module") {
411
+ const plugin = await Plugin.findOne({ name: ename });
412
+ if (!plugin) throw new Error(`Module ${ename} not found`);
413
+ let module = getState().plugins[plugin.name];
414
+ if (!module) {
415
+ module =
416
+ getState().plugins[getState().plugin_module_names[plugin.name]];
417
+ }
418
+ if (module.configuration_workflow) {
419
+ const flow = module.configuration_workflow();
420
+ if (flow?.onStepSave) await flow.onStepSave({}, {}, entVal);
421
+ if (flow?.onDone) {
422
+ const doneRes = await flow.onDone(entVal);
423
+ if (doneRes?.cleanup) await doneRes.cleanup();
424
+ }
425
+ }
426
+ plugin.configuration = entVal;
427
+ await plugin.upsert();
428
+ } else await install_pack(pack);
376
429
  });
377
430
  switch (etype) {
378
431
  case "table":
@@ -390,6 +443,13 @@ router.post(
390
443
  case "config":
391
444
  await getState().refresh_config();
392
445
  break;
446
+ case "module":
447
+ getState().processSend({
448
+ refresh_plugin_cfg: ename,
449
+ tenant: db.getTenantSchema(),
450
+ });
451
+ await sleep(500);
452
+ break;
393
453
  }
394
454
  res.redirect(
395
455
  `/registry-editor?etype=${etype}&ename=${encodeURIComponent(
package/routes/search.js CHANGED
@@ -365,6 +365,16 @@ const syntax_help_link = (req) => {
365
365
  */
366
366
  router.get(
367
367
  "/",
368
+ error_catcher(async (req, res, next) => {
369
+ const state = getState();
370
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
371
+
372
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
373
+ res.status(503).send("Page Unavailable: in maintenance mode");
374
+ return;
375
+ }
376
+ next();
377
+ }),
368
378
  error_catcher(async (req, res) => {
369
379
  const min_role = getState().getConfig("min_role_search");
370
380
  const role = (req.user || {}).role_id || 100;
package/routes/view.js CHANGED
@@ -9,6 +9,7 @@ const Router = require("express-promise-router");
9
9
  const View = require("@saltcorn/data/models/view");
10
10
  const Table = require("@saltcorn/data/models/table");
11
11
  const Trigger = require("@saltcorn/data/models/trigger");
12
+ const Page = require("@saltcorn/data/models/page");
12
13
 
13
14
  const { text, style, div } = require("@saltcorn/markup/tags");
14
15
  const {
@@ -41,11 +42,27 @@ module.exports = router;
41
42
  router.get(
42
43
  ["/:viewname", "/:viewname/*slug"],
43
44
  error_catcher(async (req, res) => {
45
+ const state = getState();
46
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
47
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
48
+
49
+ if (
50
+ maintenanceModeEnabled &&
51
+ (!req.user || req.user.role_id > 1) &&
52
+ maintenanceModePage
53
+ ) {
54
+ const maintenancePage = await Page.findOne({ name: maintenanceModePage });
55
+ if (maintenancePage) {
56
+ const tic = new Date();
57
+ await maintenancePage.run(req.query, { res, req });
58
+ return;
59
+ }
60
+ }
61
+
44
62
  const { viewname } = req.params;
45
63
  const query = { ...req.query };
46
64
  const view = await View.findOne({ name: viewname });
47
65
  const role = req.user && req.user.id ? req.user.role_id : 100;
48
- const state = getState();
49
66
  state.log(
50
67
  3,
51
68
  `Route /view/${viewname} user=${req.user?.id}${
@@ -223,6 +240,16 @@ router.post(
223
240
  */
224
241
  router.post(
225
242
  "/:viewname/:route",
243
+ error_catcher(async (req, res, next) => {
244
+ const state = getState();
245
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
246
+
247
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
248
+ res.status(503).json({ error: "in maintenance mode" });
249
+ return;
250
+ }
251
+ next();
252
+ }),
226
253
  error_catcher(async (req, res) => {
227
254
  const { viewname, route } = req.params;
228
255
  const role = req.user && req.user.id ? req.user.role_id : 100;
@@ -258,6 +285,15 @@ router.post(
258
285
  */
259
286
  router.post(
260
287
  ["/:viewname", "/:viewname/*slug"],
288
+ error_catcher(async (req, res, next) => {
289
+ const state = getState();
290
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
291
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
292
+ res.status(503).send("Page Unavailable: in maintenance mode");
293
+ return;
294
+ }
295
+ next();
296
+ }),
261
297
  setTenant,
262
298
  error_catcher(async (req, res) => {
263
299
  const { viewname } = req.params;
package/serve.js CHANGED
@@ -183,7 +183,10 @@ const initMaster = async ({ disableMigrate }, useClusterAdaptor = true) => {
183
183
  }
184
184
  eachTenant(async () => {
185
185
  const state = getState();
186
- if (state) await state.setConfig("joined_log_socket_ids", []);
186
+ if (state) {
187
+ await state.setConfig("joined_log_socket_ids", []);
188
+ await state.setConfig("joined_real_time_socket_ids", []);
189
+ }
187
190
  });
188
191
  if (useClusterAdaptor) setupPrimary();
189
192
  };
@@ -518,6 +521,11 @@ const setupSocket = (subdomainOffset, pruneSessionInterval, ...servers) => {
518
521
  .emit("log_msg", { text: msg, time, level });
519
522
  });
520
523
 
524
+ // Real-time collaboration emitter
525
+ getState().setCollabEmitter((tenant, type, data) => {
526
+ io.of("/").to(`_${tenant}_collab_room_`).emit(type, data);
527
+ });
528
+
521
529
  io.of("/").on("connection", (socket) => {
522
530
  socket.on("join_room", ([viewname, room_id]) => {
523
531
  const ten = get_tenant_from_req(socket.request) || "public";
@@ -569,6 +577,38 @@ const setupSocket = (subdomainOffset, pruneSessionInterval, ...servers) => {
569
577
  else await f();
570
578
  });
571
579
 
580
+ // or join the room more generally and later register views ??
581
+ socket.on("join_collab_room", async (viewname, callback) => {
582
+ const tenant =
583
+ get_tenant_from_req(socket.request, subdomainOffset) || "public";
584
+ const f = async () => {
585
+ try {
586
+ const view = View.findOne({ name: viewname });
587
+ if (!view) throw new Error(`View ${viewname} not found`);
588
+ const user = socket.request.user;
589
+ const role_id = user ? user.role_id : 100;
590
+ if (view.min_role < role_id)
591
+ throw new Error("Not authorized to join collaboration room");
592
+ socket.join(`_${tenant}_collab_room_`);
593
+ const socketIds = await getState().getConfig(
594
+ "joined_real_time_socket_ids"
595
+ );
596
+ socketIds.push(socket.id);
597
+ await getState().setConfig(
598
+ "joined_real_time_socket_ids",
599
+ [...socketIds]
600
+ );
601
+ if (typeof callback === "function") callback({ status: "ok" });
602
+ } catch (err) {
603
+ getState().log(1, `Socket join_collab_room: ${err.stack}`);
604
+ if (typeof callback === "function")
605
+ callback({ status: "error", msg: err.message || "unknown error" });
606
+ }
607
+ };
608
+ if (tenant && tenant !== "public") db.runWithTenant(tenant, f);
609
+ else await f();
610
+ });
611
+
572
612
  socket.on("disconnect", async () => {
573
613
  const tenant =
574
614
  get_tenant_from_req(socket.request, subdomainOffset) || "public";
package/systemd.js CHANGED
@@ -66,7 +66,7 @@ module.exports =
66
66
  notify.ready();
67
67
  const watchdogInterval = notify.watchdogInterval();
68
68
  if (watchdogInterval && watchdogInterval > 0) {
69
- const interval = Math.floor(watchdogInterval / 2);
69
+ const interval = Math.floor(watchdogInterval / 3);
70
70
  setInterval(() => {
71
71
  watchDog(interval, notify, opts);
72
72
  }, interval);
package/tests/api.test.js CHANGED
@@ -223,6 +223,57 @@ describe("API read", () => {
223
223
  );
224
224
  });
225
225
  });
226
+ describe("API count", () => {
227
+ it("should count books for public simple", async () => {
228
+ const app = await getApp({ disableCsrf: true });
229
+ await request(app)
230
+ .get("/api/books/count")
231
+ .expect(succeedJsonWith((count) => count === 2));
232
+ });
233
+
234
+ // it("should count books for public fts", async () => {
235
+
236
+ it("should count books for public with search", async () => {
237
+ const app = await getApp({ disableCsrf: true });
238
+ await request(app)
239
+ .get("/api/books/count?pages=967")
240
+ .expect(succeedJsonWith((count) => count === 1));
241
+ });
242
+ it("should count with fkey args ", async () => {
243
+ const loginCookie = await getAdminLoginCookie();
244
+ const app = await getApp({ disableCsrf: true });
245
+ await request(app)
246
+ .get("/api/patients/count/?favbook=1")
247
+ .set("Cookie", loginCookie)
248
+ .expect(succeedJsonWith((count) => count === 1));
249
+ });
250
+ it("should count with fkey args with no value", async () => {
251
+ const loginCookie = await getAdminLoginCookie();
252
+ const app = await getApp({ disableCsrf: true });
253
+ await request(app)
254
+ .get("/api/patients/count/?favbook=")
255
+ .set("Cookie", loginCookie)
256
+ .expect(succeedJsonWith((count) => count === 0));
257
+ });
258
+ it("should count books for public with search and one field", async () => {
259
+ const app = await getApp({ disableCsrf: true });
260
+ await request(app)
261
+ .get("/api/books/count/?fields=author&pages=967")
262
+ .expect(succeedJsonWith((count) => count === 1));
263
+ });
264
+ it("should not allow public count access to patients", async () => {
265
+ const app = await getApp({ disableCsrf: true });
266
+ await request(app).get("/api/patients/count").expect(notAuthorized);
267
+ });
268
+ it("should allow staff count access to patients", async () => {
269
+ const loginCookie = await getStaffLoginCookie();
270
+ const app = await getApp({ disableCsrf: true });
271
+ await request(app)
272
+ .get("/api/patients/count")
273
+ .set("Cookie", loginCookie)
274
+ .expect(succeedJsonWith((count) => count === 2));
275
+ });
276
+ });
226
277
  describe("API post", () => {
227
278
  it("should post books", async () => {
228
279
  const loginCookie = await getAdminLoginCookie();