@saltcorn/server 1.3.0-beta.0 → 1.3.0-beta.10

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 (410) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/app.js +71 -48
  3. package/auth/routes.js +137 -12
  4. package/docs/assets/search.js +1 -1
  5. package/docs/classes/_saltcorn_common_code.Relation.html +10 -10
  6. package/docs/classes/_saltcorn_common_code.RelationsFinder.html +5 -5
  7. package/docs/classes/_saltcorn_data.models.Crash.html +17 -17
  8. package/docs/classes/_saltcorn_data.models.EventLog-1.html +19 -19
  9. package/docs/classes/_saltcorn_data.models.Field.html +90 -73
  10. package/docs/classes/_saltcorn_data.models.FieldRepeat.html +16 -16
  11. package/docs/classes/_saltcorn_data.models.File-1.html +48 -48
  12. package/docs/classes/_saltcorn_data.models.Form-1.html +38 -38
  13. package/docs/classes/_saltcorn_data.models.Library.html +13 -13
  14. package/docs/classes/_saltcorn_data.models.Page.html +24 -24
  15. package/docs/classes/_saltcorn_data.models.PageGroup-1.html +25 -25
  16. package/docs/classes/_saltcorn_data.models.Plugin.html +25 -25
  17. package/docs/classes/_saltcorn_data.models.Role.html +9 -9
  18. package/docs/classes/_saltcorn_data.models.Table-1.html +92 -92
  19. package/docs/classes/_saltcorn_data.models.TableConstraint.html +14 -14
  20. package/docs/classes/_saltcorn_data.models.Trigger.html +39 -39
  21. package/docs/classes/_saltcorn_data.models.User.html +48 -48
  22. package/docs/classes/_saltcorn_data.models.View-1.html +105 -53
  23. package/docs/classes/_saltcorn_data.models.Workflow.html +17 -17
  24. package/docs/classes/_saltcorn_data.models.WorkflowRun.html +35 -35
  25. package/docs/classes/_saltcorn_data.models.WorkflowStep.html +25 -25
  26. package/docs/classes/_saltcorn_data.models.WorkflowTrace.html +18 -18
  27. package/docs/classes/_saltcorn_mobile_builder.MobileBuilder.html +36 -36
  28. package/docs/enums/_saltcorn_common_code.RelationType.html +7 -7
  29. package/docs/enums/_saltcorn_common_code.ViewDisplayType.html +4 -4
  30. package/docs/functions/_saltcorn_admin_models.backup.create_backup.html +1 -1
  31. package/docs/functions/_saltcorn_admin_models.backup.create_csv_from_rows.html +1 -1
  32. package/docs/functions/_saltcorn_admin_models.backup.restore.html +5 -3
  33. package/docs/functions/_saltcorn_admin_models.pack.add_to_menu.html +1 -1
  34. package/docs/functions/_saltcorn_admin_models.pack.can_install_pack.html +1 -1
  35. package/docs/functions/_saltcorn_admin_models.pack.fetch_available_packs.html +1 -1
  36. package/docs/functions/_saltcorn_admin_models.pack.fetch_pack_by_name.html +1 -1
  37. package/docs/functions/_saltcorn_admin_models.pack.install_pack.html +1 -1
  38. package/docs/functions/_saltcorn_admin_models.pack.library_pack.html +1 -1
  39. package/docs/functions/_saltcorn_admin_models.pack.model_instance_pack.html +1 -1
  40. package/docs/functions/_saltcorn_admin_models.pack.model_pack.html +1 -1
  41. package/docs/functions/_saltcorn_admin_models.pack.page_group_pack.html +1 -1
  42. package/docs/functions/_saltcorn_admin_models.pack.page_pack.html +1 -1
  43. package/docs/functions/_saltcorn_admin_models.pack.plugin_pack.html +1 -1
  44. package/docs/functions/_saltcorn_admin_models.pack.role_pack.html +1 -1
  45. package/docs/functions/_saltcorn_admin_models.pack.table_pack.html +1 -1
  46. package/docs/functions/_saltcorn_admin_models.pack.trigger_pack.html +1 -1
  47. package/docs/functions/_saltcorn_admin_models.pack.uninstall_pack.html +1 -1
  48. package/docs/functions/_saltcorn_admin_models.pack.view_pack.html +1 -1
  49. package/docs/functions/_saltcorn_admin_models.tenant.copy_tenant_template.html +1 -1
  50. package/docs/functions/_saltcorn_admin_models.tenant.create_tenant.html +1 -1
  51. package/docs/functions/_saltcorn_admin_models.tenant.deleteTenant.html +1 -1
  52. package/docs/functions/_saltcorn_admin_models.tenant.domain_sanitize.html +1 -1
  53. package/docs/functions/_saltcorn_admin_models.tenant.eachTenant.html +1 -1
  54. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenantRows.html +1 -1
  55. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenants.html +1 -1
  56. package/docs/functions/_saltcorn_admin_models.tenant.insertTenant.html +1 -1
  57. package/docs/functions/_saltcorn_admin_models.tenant.switchToTenant.html +1 -1
  58. package/docs/functions/_saltcorn_common_code.buildTableCaches.html +1 -1
  59. package/docs/functions/_saltcorn_common_code.parseLegacyRelation.html +1 -1
  60. package/docs/functions/_saltcorn_common_code.parseRelationPath.html +1 -1
  61. package/docs/functions/_saltcorn_data.models.config.check_email_mask.html +1 -1
  62. package/docs/functions/_saltcorn_data.models.config.deleteConfig.html +1 -1
  63. package/docs/functions/_saltcorn_data.models.config.getAllConfig.html +1 -1
  64. package/docs/functions/_saltcorn_data.models.config.getConfig.html +1 -1
  65. package/docs/functions/_saltcorn_data.models.config.get_base_url.html +1 -1
  66. package/docs/functions/_saltcorn_data.models.config.get_latest_npm_version.html +1 -1
  67. package/docs/functions/_saltcorn_data.models.config.remove_from_menu.html +1 -1
  68. package/docs/functions/_saltcorn_data.models.config.save_menu_items.html +1 -1
  69. package/docs/functions/_saltcorn_data.models.config.setConfig.html +1 -1
  70. package/docs/functions/_saltcorn_data.models.discovery.discover_tables.html +1 -1
  71. package/docs/functions/_saltcorn_data.models.discovery.discoverable_tables.html +1 -1
  72. package/docs/functions/_saltcorn_data.models.discovery.findType.html +1 -1
  73. package/docs/functions/_saltcorn_data.models.discovery.get_existing_views.html +1 -1
  74. package/docs/functions/_saltcorn_data.models.discovery.implement_discovery.html +1 -1
  75. package/docs/functions/_saltcorn_data.models.email.getMailTransport.html +1 -1
  76. package/docs/functions/_saltcorn_data.models.email.send_verification_email.html +1 -1
  77. package/docs/functions/_saltcorn_data.models.email.viewToEmailHtml.html +1 -1
  78. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields.html +1 -1
  79. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields_stored.html +1 -1
  80. package/docs/functions/_saltcorn_data.models.expression.eval_expression.html +1 -1
  81. package/docs/functions/_saltcorn_data.models.expression.expressionValidator.html +1 -1
  82. package/docs/functions/_saltcorn_data.models.expression.get_async_expression_function.html +1 -1
  83. package/docs/functions/_saltcorn_data.models.expression.get_expression_function.html +1 -1
  84. package/docs/functions/_saltcorn_data.models.expression.jsexprToWhere.html +1 -1
  85. package/docs/functions/_saltcorn_data.models.expression.recalculate_for_stored.html +1 -1
  86. package/docs/functions/_saltcorn_data.models.expression.transform_for_async.html +1 -1
  87. package/docs/functions/_saltcorn_data.models.layout.eachView.html +1 -1
  88. package/docs/functions/_saltcorn_data.models.layout.getStringsForI18n.html +1 -1
  89. package/docs/functions/_saltcorn_data.models.layout.getViews.html +1 -1
  90. package/docs/functions/_saltcorn_data.models.layout.translateLayout.html +1 -1
  91. package/docs/functions/_saltcorn_data.models.layout.traverse.html +1 -1
  92. package/docs/functions/_saltcorn_data.models.layout.traverseSync.html +1 -1
  93. package/docs/functions/_saltcorn_data.models.random.all_views.html +1 -1
  94. package/docs/functions/_saltcorn_data.models.random.fill_table_row.html +1 -1
  95. package/docs/functions/_saltcorn_data.models.random.initial_view.html +1 -1
  96. package/docs/functions/_saltcorn_data.models.random.random_table.html +1 -1
  97. package/docs/functions/_saltcorn_db_common.buildInsertBulkSql.html +1 -1
  98. package/docs/functions/_saltcorn_db_common.buildInsertSql.html +1 -1
  99. package/docs/functions/_saltcorn_db_common.doCount.html +1 -1
  100. package/docs/functions/_saltcorn_db_common.doDeleteWhere.html +1 -1
  101. package/docs/functions/_saltcorn_db_common.doListScTables.html +1 -1
  102. package/docs/functions/_saltcorn_db_common.doListTables.html +1 -1
  103. package/docs/functions/_saltcorn_db_common.doListUserDefinedTables.html +1 -1
  104. package/docs/functions/_saltcorn_db_common.do_add_index.html +1 -1
  105. package/docs/functions/_saltcorn_db_common.do_drop_index.html +1 -1
  106. package/docs/functions/_saltcorn_db_common.ftsFieldsSqlExpr.html +1 -1
  107. package/docs/functions/_saltcorn_db_common.mkSelectOptions.html +1 -1
  108. package/docs/functions/_saltcorn_db_common.mkVal.html +1 -1
  109. package/docs/functions/_saltcorn_db_common.mkWhere.html +1 -1
  110. package/docs/functions/_saltcorn_db_common.multi_tenant.enable_multi_tenant.html +1 -1
  111. package/docs/functions/_saltcorn_db_common.multi_tenant.getRequestContext.html +1 -1
  112. package/docs/functions/_saltcorn_db_common.multi_tenant.getTenantSchema.html +1 -1
  113. package/docs/functions/_saltcorn_db_common.multi_tenant.init.html +1 -1
  114. package/docs/functions/_saltcorn_db_common.multi_tenant.is_it_multi_tenant.html +1 -1
  115. package/docs/functions/_saltcorn_db_common.multi_tenant.runWithTenant.html +1 -1
  116. package/docs/functions/_saltcorn_db_common.orderByIsObject.html +1 -1
  117. package/docs/functions/_saltcorn_db_common.orderByIsOperator.html +1 -1
  118. package/docs/functions/_saltcorn_db_common.prefixFieldsInWhere.html +1 -1
  119. package/docs/functions/_saltcorn_db_common.reprAsJson.html +1 -1
  120. package/docs/functions/_saltcorn_db_common.slugify.html +1 -1
  121. package/docs/functions/_saltcorn_db_common.sqlBinOp.html +1 -1
  122. package/docs/functions/_saltcorn_db_common.sqlFun.html +1 -1
  123. package/docs/functions/_saltcorn_db_common.sqlsanitize.html +1 -1
  124. package/docs/functions/_saltcorn_db_common.sqlsanitizeAllowDots.html +1 -1
  125. package/docs/functions/_saltcorn_db_common.subSelectWhere.html +1 -1
  126. package/docs/functions/_saltcorn_db_common.tryCatchInTransaction.html +1 -1
  127. package/docs/functions/_saltcorn_db_common.withTransaction.html +1 -1
  128. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidFeatures.html +1 -1
  129. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidPermissions.html +1 -1
  130. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.buildTablesFile.html +1 -1
  131. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyPrepopulatedDb.html +1 -1
  132. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyServerFiles.html +1 -1
  133. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyShareExtFiles.html +1 -1
  134. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copySiteLogo.html +1 -1
  135. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyTranslationFiles.html +1 -1
  136. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.createSqliteDb.html +1 -1
  137. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.decodeProvisioningProfile.html +1 -1
  138. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.extractDomain.html +1 -1
  139. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.generateAndroidVersionCode.html +1 -1
  140. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyAndroidManifest.html +1 -1
  141. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyConfigXml.html +1 -1
  142. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyGradleConfig.html +1 -1
  143. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyInfoPlist.html +1 -1
  144. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyXcodeProjectFile.html +1 -1
  145. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepAppIcon.html +1 -1
  146. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareAppIcon.html +1 -1
  147. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareBuildDir.html +1 -1
  148. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareExportOptionsPlist.html +1 -1
  149. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashIcon.html +1 -1
  150. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashPage.html +1 -1
  151. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCapacitorConfig.html +1 -1
  152. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCfgFile.html +1 -1
  153. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeDataExtractionRules.html +1 -1
  154. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeNetworkSecurityConfig.html +1 -1
  155. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePodfile.html +1 -1
  156. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePrivacyInfo.html +1 -1
  157. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundleMobileAppCode.html +1 -1
  158. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundlePackagesAndPlugins.html +1 -1
  159. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyMobileAppDirs.html +1 -1
  160. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyPublicDirs.html +1 -1
  161. package/docs/functions/_saltcorn_sqlite.add_index.html +1 -1
  162. package/docs/functions/_saltcorn_sqlite.add_unique_constraint.html +1 -1
  163. package/docs/functions/_saltcorn_sqlite.begin.html +1 -1
  164. package/docs/functions/_saltcorn_sqlite.changeConnection.html +1 -1
  165. package/docs/functions/_saltcorn_sqlite.close.html +1 -1
  166. package/docs/functions/_saltcorn_sqlite.commit.html +1 -1
  167. package/docs/functions/_saltcorn_sqlite.count.html +1 -1
  168. package/docs/functions/_saltcorn_sqlite.deleteWhere.html +1 -1
  169. package/docs/functions/_saltcorn_sqlite.dropTable.html +1 -1
  170. package/docs/functions/_saltcorn_sqlite.dropTables.html +1 -1
  171. package/docs/functions/_saltcorn_sqlite.drop_index.html +1 -1
  172. package/docs/functions/_saltcorn_sqlite.drop_reset_schema.html +1 -1
  173. package/docs/functions/_saltcorn_sqlite.drop_unique_constraint.html +1 -1
  174. package/docs/functions/_saltcorn_sqlite.getVersion.html +1 -1
  175. package/docs/functions/_saltcorn_sqlite.get_db_filepath.html +1 -1
  176. package/docs/functions/_saltcorn_sqlite.get_sql_logging.html +1 -1
  177. package/docs/functions/_saltcorn_sqlite.init.html +1 -1
  178. package/docs/functions/_saltcorn_sqlite.insert.html +1 -1
  179. package/docs/functions/_saltcorn_sqlite.listScTables.html +1 -1
  180. package/docs/functions/_saltcorn_sqlite.listTables.html +1 -1
  181. package/docs/functions/_saltcorn_sqlite.listUserDefinedTables.html +1 -1
  182. package/docs/functions/_saltcorn_sqlite.query.html +1 -1
  183. package/docs/functions/_saltcorn_sqlite.rollback.html +1 -1
  184. package/docs/functions/_saltcorn_sqlite.select.html +1 -1
  185. package/docs/functions/_saltcorn_sqlite.selectMaybeOne.html +1 -1
  186. package/docs/functions/_saltcorn_sqlite.selectOne.html +1 -1
  187. package/docs/functions/_saltcorn_sqlite.set_sql_logging.html +1 -1
  188. package/docs/functions/_saltcorn_sqlite.sql_log.html +1 -1
  189. package/docs/functions/_saltcorn_sqlite.update.html +1 -1
  190. package/docs/functions/_saltcorn_sqlite.updateWhere.html +1 -1
  191. package/docs/functions/_saltcorn_sqlite_mobile.add_index.html +1 -1
  192. package/docs/functions/_saltcorn_sqlite_mobile.add_unique_constraint.html +1 -1
  193. package/docs/functions/_saltcorn_sqlite_mobile.count.html +1 -1
  194. package/docs/functions/_saltcorn_sqlite_mobile.deleteWhere.html +1 -1
  195. package/docs/functions/_saltcorn_sqlite_mobile.drop_index.html +1 -1
  196. package/docs/functions/_saltcorn_sqlite_mobile.drop_reset_schema.html +1 -1
  197. package/docs/functions/_saltcorn_sqlite_mobile.drop_unique_constraint.html +1 -1
  198. package/docs/functions/_saltcorn_sqlite_mobile.init.html +1 -1
  199. package/docs/functions/_saltcorn_sqlite_mobile.insert.html +1 -1
  200. package/docs/functions/_saltcorn_sqlite_mobile.insertRows.html +1 -1
  201. package/docs/functions/_saltcorn_sqlite_mobile.listScTables.html +1 -1
  202. package/docs/functions/_saltcorn_sqlite_mobile.listTables.html +1 -1
  203. package/docs/functions/_saltcorn_sqlite_mobile.listUserDefinedTables.html +1 -1
  204. package/docs/functions/_saltcorn_sqlite_mobile.query.html +1 -1
  205. package/docs/functions/_saltcorn_sqlite_mobile.select.html +1 -1
  206. package/docs/functions/_saltcorn_sqlite_mobile.selectMaybeOne.html +1 -1
  207. package/docs/functions/_saltcorn_sqlite_mobile.selectOne.html +1 -1
  208. package/docs/functions/_saltcorn_sqlite_mobile.setConnectionObject.html +1 -1
  209. package/docs/functions/_saltcorn_sqlite_mobile.tableExists.html +1 -1
  210. package/docs/functions/_saltcorn_sqlite_mobile.time.html +1 -1
  211. package/docs/functions/_saltcorn_sqlite_mobile.update.html +1 -1
  212. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_field.instanceOfField.html +1 -1
  213. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_page.instanceOfPage.html +1 -1
  214. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_view.instanceOfView.html +1 -1
  215. package/docs/functions/_saltcorn_types.Types.base_types.instanceOWithHtmlFile.html +1 -1
  216. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfErrorMsg.html +1 -1
  217. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfSuccessMsg.html +1 -1
  218. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfType.html +1 -1
  219. package/docs/functions/_saltcorn_types.generators.generateBool.html +1 -1
  220. package/docs/functions/_saltcorn_types.generators.generateString.html +1 -1
  221. package/docs/functions/_saltcorn_types.generators.num_between.html +1 -1
  222. package/docs/functions/_saltcorn_types.generators.oneOf.html +1 -1
  223. package/docs/interfaces/_saltcorn_mobile_builder.common_build_utils.ScCapacitorConfig.html +10 -10
  224. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractField.html +15 -15
  225. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractFieldRepeat.html +3 -3
  226. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_form.AbstractForm.html +26 -26
  227. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_page.AbstractPage.html +7 -7
  228. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_role.AbstractRole.html +3 -3
  229. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_table.AbstractTable.html +11 -11
  230. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_trigger.AbstractTrigger.html +16 -16
  231. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_view.AbstractView.html +10 -10
  232. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_workflow.AbstractWorkflow.html +13 -13
  233. package/docs/modules/_saltcorn_admin_models.backup.html +1 -1
  234. package/docs/modules/_saltcorn_admin_models.html +1 -1
  235. package/docs/modules/_saltcorn_admin_models.pack.html +1 -1
  236. package/docs/modules/_saltcorn_admin_models.tenant.html +1 -1
  237. package/docs/modules/_saltcorn_common_code.html +1 -1
  238. package/docs/modules/_saltcorn_data.html +7 -5
  239. package/docs/modules/_saltcorn_data.models.EventLog.html +2 -2
  240. package/docs/modules/_saltcorn_data.models.File.html +2 -2
  241. package/docs/modules/_saltcorn_data.models.Form.html +2 -2
  242. package/docs/modules/_saltcorn_data.models.PageGroup.html +2 -2
  243. package/docs/modules/_saltcorn_data.models.Table.html +2 -2
  244. package/docs/modules/_saltcorn_data.models.View.html +2 -2
  245. package/docs/modules/_saltcorn_data.models.config.html +1 -1
  246. package/docs/modules/_saltcorn_data.models.discovery.html +1 -1
  247. package/docs/modules/_saltcorn_data.models.email.html +1 -1
  248. package/docs/modules/_saltcorn_data.models.expression.html +1 -1
  249. package/docs/modules/_saltcorn_data.models.html +1 -1
  250. package/docs/modules/_saltcorn_data.models.layout.html +1 -1
  251. package/docs/modules/_saltcorn_data.models.random.html +1 -1
  252. package/docs/modules/_saltcorn_data.models.scheduler.html +1 -1
  253. package/docs/modules/_saltcorn_data.plugin_helper.html +1 -1
  254. package/docs/modules/_saltcorn_data.utils.html +1 -1
  255. package/docs/modules/_saltcorn_db_common.html +2 -2
  256. package/docs/modules/_saltcorn_db_common.multi_tenant.html +1 -1
  257. package/docs/modules/_saltcorn_markup.html +2 -2
  258. package/docs/modules/_saltcorn_mobile_builder.common_build_utils.html +1 -1
  259. package/docs/modules/_saltcorn_mobile_builder.html +1 -1
  260. package/docs/modules/_saltcorn_mobile_builder.package_bundle_utils.html +1 -1
  261. package/docs/modules/_saltcorn_sqlite.html +1 -1
  262. package/docs/modules/_saltcorn_sqlite_mobile.html +1 -1
  263. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_field.html +1 -1
  264. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_form.html +1 -1
  265. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_library.html +1 -1
  266. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_page.html +1 -1
  267. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_plugin.html +1 -1
  268. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_role.html +1 -1
  269. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_table.html +1 -1
  270. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_trigger.html +1 -1
  271. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_view.html +1 -1
  272. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_workflow.html +1 -1
  273. package/docs/modules/_saltcorn_types.ModelAbstracts.html +1 -1
  274. package/docs/modules/_saltcorn_types.Types.base_types.html +1 -1
  275. package/docs/modules/_saltcorn_types.Types.common_types.html +1 -1
  276. package/docs/modules/_saltcorn_types.Types.html +1 -1
  277. package/docs/modules/_saltcorn_types.generators.html +1 -1
  278. package/docs/modules/_saltcorn_types.html +1 -1
  279. package/docs/types/_saltcorn_data.models.EventLog.EventLogCfg.html +1 -1
  280. package/docs/types/_saltcorn_data.models.File.FileCfg.html +1 -1
  281. package/docs/types/_saltcorn_data.models.Form.AdditionalButton.html +1 -1
  282. package/docs/types/_saltcorn_data.models.Form.FormCfg.html +1 -1
  283. package/docs/types/_saltcorn_data.models.PageGroup.ScreenInfoParams.html +1 -1
  284. package/docs/types/_saltcorn_data.models.Table.ChildRelations.html +1 -1
  285. package/docs/types/_saltcorn_data.models.Table.ParentRelations.html +1 -1
  286. package/docs/types/_saltcorn_data.models.Table.RelationData.html +1 -1
  287. package/docs/types/_saltcorn_data.models.View.FindViewsPred.html +1 -1
  288. package/docs/types/_saltcorn_db_common.AggregationOptions.html +4 -2
  289. package/docs/types/_saltcorn_db_common.CoordOpts.html +1 -1
  290. package/docs/types/_saltcorn_db_common.DatabaseClient.html +1 -1
  291. package/docs/types/_saltcorn_db_common.JoinField.html +1 -1
  292. package/docs/types/_saltcorn_db_common.JoinFields.html +1 -1
  293. package/docs/types/_saltcorn_db_common.JoinOptions.html +1 -1
  294. package/docs/types/_saltcorn_db_common.JsonPath.html +1 -1
  295. package/docs/types/_saltcorn_db_common.JsonPathElem.html +1 -1
  296. package/docs/types/_saltcorn_db_common.Operator.html +1 -1
  297. package/docs/types/_saltcorn_db_common.PartialSome.html +1 -1
  298. package/docs/types/_saltcorn_db_common.PrimaryKeyValue.html +1 -1
  299. package/docs/types/_saltcorn_db_common.Row.html +1 -1
  300. package/docs/types/_saltcorn_db_common.SelectOptions.html +3 -3
  301. package/docs/types/_saltcorn_db_common.SqlAndValues.html +1 -1
  302. package/docs/types/_saltcorn_db_common.StrongRow.html +1 -1
  303. package/docs/types/_saltcorn_db_common.SubselectOptions.html +1 -1
  304. package/docs/types/_saltcorn_db_common.Value.html +1 -1
  305. package/docs/types/_saltcorn_db_common.Where.html +1 -1
  306. package/docs/types/_saltcorn_mobile_builder.IosCfg.html +1 -1
  307. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.FieldCfg.html +1 -1
  308. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.InputType.html +1 -1
  309. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_form.AdditionalButton.html +1 -1
  310. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryCfg.html +1 -1
  311. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryPack.html +1 -1
  312. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PageCfg.html +1 -1
  313. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PagePack.html +1 -1
  314. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginCfg.html +1 -1
  315. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginPack.html +1 -1
  316. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RoleCfg.html +1 -1
  317. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RolePack.html +1 -1
  318. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TableCfg.html +1 -1
  319. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TablePack.html +1 -1
  320. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerCfg.html +1 -1
  321. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerPack.html +1 -1
  322. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewCfg.html +1 -1
  323. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewPack.html +1 -1
  324. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.ConfigWorkflowStep.html +1 -1
  325. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.RunResult.html +1 -1
  326. package/docs/types/_saltcorn_types.Types.base_types.Action.html +1 -1
  327. package/docs/types/_saltcorn_types.Types.base_types.AuthenticationMethod.html +1 -1
  328. package/docs/types/_saltcorn_types.Types.base_types.CalcJoinfield.html +1 -1
  329. package/docs/types/_saltcorn_types.Types.base_types.CapacitorPlugin.html +1 -1
  330. package/docs/types/_saltcorn_types.Types.base_types.CodePagePack.html +1 -1
  331. package/docs/types/_saltcorn_types.Types.base_types.Column.html +1 -1
  332. package/docs/types/_saltcorn_types.Types.base_types.ConnectObjType.html +1 -1
  333. package/docs/types/_saltcorn_types.Types.base_types.ConnectedObjects.html +1 -1
  334. package/docs/types/_saltcorn_types.Types.base_types.CopilotSkill.html +1 -1
  335. package/docs/types/_saltcorn_types.Types.base_types.ErrorObj.html +1 -1
  336. package/docs/types/_saltcorn_types.Types.base_types.FieldLike.html +1 -1
  337. package/docs/types/_saltcorn_types.Types.base_types.FieldView.html +1 -1
  338. package/docs/types/_saltcorn_types.Types.base_types.Header.html +1 -1
  339. package/docs/types/_saltcorn_types.Types.base_types.JoinFieldOption.html +1 -1
  340. package/docs/types/_saltcorn_types.Types.base_types.Layout.html +1 -1
  341. package/docs/types/_saltcorn_types.Types.base_types.MobileConfig.html +1 -1
  342. package/docs/types/_saltcorn_types.Types.base_types.ModelPattern.html +1 -1
  343. package/docs/types/_saltcorn_types.Types.base_types.Pack.html +1 -1
  344. package/docs/types/_saltcorn_types.Types.base_types.Plugin.html +1 -1
  345. package/docs/types/_saltcorn_types.Types.base_types.PluginFunction.html +1 -1
  346. package/docs/types/_saltcorn_types.Types.base_types.PluginLayout.html +1 -1
  347. package/docs/types/_saltcorn_types.Types.base_types.PluginRoute.html +4 -4
  348. package/docs/types/_saltcorn_types.Types.base_types.PluginSourceType.html +1 -1
  349. package/docs/types/_saltcorn_types.Types.base_types.PluginType.html +1 -1
  350. package/docs/types/_saltcorn_types.Types.base_types.PluginWrap.html +1 -1
  351. package/docs/types/_saltcorn_types.Types.base_types.PluginWrapArg.html +1 -1
  352. package/docs/types/_saltcorn_types.Types.base_types.RelationOption.html +1 -1
  353. package/docs/types/_saltcorn_types.Types.base_types.Req.html +1 -1
  354. package/docs/types/_saltcorn_types.Types.base_types.Res.html +1 -1
  355. package/docs/types/_saltcorn_types.Types.base_types.ResultType.html +1 -1
  356. package/docs/types/_saltcorn_types.Types.base_types.RouteAction.html +1 -1
  357. package/docs/types/_saltcorn_types.Types.base_types.RunExtra.html +1 -1
  358. package/docs/types/_saltcorn_types.Types.base_types.SlugStepType.html +1 -1
  359. package/docs/types/_saltcorn_types.Types.base_types.StepResType.html +1 -1
  360. package/docs/types/_saltcorn_types.Types.base_types.SubField.html +1 -1
  361. package/docs/types/_saltcorn_types.Types.base_types.TableProvider.html +1 -1
  362. package/docs/types/_saltcorn_types.Types.base_types.TableQuery.html +1 -1
  363. package/docs/types/_saltcorn_types.Types.base_types.Tablely.html +1 -1
  364. package/docs/types/_saltcorn_types.Types.base_types.ViewTemplate.html +1 -1
  365. package/docs/types/_saltcorn_types.Types.common_types.ErrorMessage.html +1 -1
  366. package/docs/types/_saltcorn_types.Types.common_types.GenObj.html +1 -1
  367. package/docs/types/_saltcorn_types.Types.common_types.ReqRes.html +1 -1
  368. package/docs/types/_saltcorn_types.Types.common_types.ResultMessage.html +1 -1
  369. package/docs/types/_saltcorn_types.Types.common_types.SuccessMessage.html +1 -1
  370. package/docs/types/_saltcorn_types.Types.common_types.Type.html +1 -1
  371. package/docs/variables/_saltcorn_data.db.html +1 -1
  372. package/docs/variables/_saltcorn_data.migrations.html +1 -1
  373. package/docs/variables/_saltcorn_data.models.config.available_languages.html +1 -1
  374. package/docs/variables/_saltcorn_data.models.config.configTypes.html +1 -1
  375. package/docs/variables/_saltcorn_data.models.scheduler.runScheduler.html +1 -1
  376. package/docs/variables/_saltcorn_data.plugin_helper.run_action_column.html +1 -1
  377. package/docs/variables/_saltcorn_data.utils.NotAuthorized.html +1 -1
  378. package/docs/variables/_saltcorn_data.utils.sleep.html +1 -1
  379. package/docs/variables/_saltcorn_db_common.multi_tenant.tenantNamespace.html +1 -1
  380. package/help/Template tables.tmd +9 -0
  381. package/locales/en.json +16 -1
  382. package/locales/pt.json +2 -2
  383. package/markup/admin.js +11 -2
  384. package/package.json +9 -9
  385. package/plugin_routes_handler.js +42 -0
  386. package/public/assets/databases/databases.json +3 -0
  387. package/public/assets/databases/prepopulated.db +0 -0
  388. package/public/assets/sql-wasm.wasm +0 -0
  389. package/public/gridedit.js +1 -1
  390. package/public/saltcorn-common.js +114 -42
  391. package/public/saltcorn.css +8 -0
  392. package/public/saltcorn.js +9 -1
  393. package/routes/admin.js +95 -37
  394. package/routes/api.js +53 -0
  395. package/routes/files.js +12 -0
  396. package/routes/homepage.js +23 -1
  397. package/routes/list.js +1 -1
  398. package/routes/menu.js +14 -0
  399. package/routes/notifications.js +12 -0
  400. package/routes/page.js +30 -1
  401. package/routes/registry.js +64 -4
  402. package/routes/search.js +10 -0
  403. package/routes/tables.js +137 -59
  404. package/routes/view.js +37 -1
  405. package/routes/viewedit.js +1 -1
  406. package/s3storage.js +1 -1
  407. package/serve.js +41 -1
  408. package/systemd.js +1 -1
  409. package/tests/api.test.js +51 -0
  410. package/tests/clientjs.test.js +16 -0
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 ",
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/tables.js CHANGED
@@ -72,6 +72,7 @@ const {
72
72
  removeAllWhiteSpace,
73
73
  comparingCaseInsensitive,
74
74
  validSqlId,
75
+ interpolate,
75
76
  } = require("@saltcorn/data/utils");
76
77
  const { EOL } = require("os");
77
78
 
@@ -934,14 +935,12 @@ router.get(
934
935
  if (user_can_edit_views) {
935
936
  let create_basic_link = "";
936
937
  if (views.length === 0) {
937
- create_basic_link = post_btn(
938
- `/table/create-basic-views/${table.id}`,
939
- "Create basic views",
940
- req.csrfToken(),
938
+ create_basic_link = a(
941
939
  {
942
- btnClass: "btn-outline-secondary",
943
- formClass: "d-inline me-2",
944
- }
940
+ class: "btn btn-outline-secondary ms-2",
941
+ href: `javascript:ajax_modal('/table/create-basic-views/${table.id}')`,
942
+ },
943
+ req.__("Create basic views")
945
944
  );
946
945
  }
947
946
  viewCard = {
@@ -2452,6 +2451,77 @@ router.post(
2452
2451
  })
2453
2452
  );
2454
2453
 
2454
+ const basicViewForm = async (table, req) => {
2455
+ const tables = await Table.find();
2456
+ const vts = viewtemplates_with_create_basic_option();
2457
+ return new Form({
2458
+ submitLabel: req.__("Create views"),
2459
+ action: `/table/create-basic-views/${table.id}`,
2460
+ formStyle: "vert",
2461
+ fields: [
2462
+ {
2463
+ type: "String",
2464
+ label: "View naming convention",
2465
+ name: "naming_convention",
2466
+ attributes: { spellcheck: false },
2467
+ sublabel:
2468
+ "Use <code>{{ }}</code> to access: <code>viewpattern</code>, <code>tablename</code>",
2469
+ },
2470
+ {
2471
+ type: "String",
2472
+ label: "Template table",
2473
+ name: "template_table",
2474
+ attributes: { options: tables.map((t) => t.name) },
2475
+ help: {
2476
+ topic: "Template tables",
2477
+ },
2478
+ },
2479
+ ...vts.map((vt) => ({
2480
+ type: "Bool",
2481
+ label: vt,
2482
+ name: vt,
2483
+ default: true,
2484
+ })),
2485
+ ],
2486
+ });
2487
+ };
2488
+
2489
+ const viewtemplates_with_create_basic_option = () => {
2490
+ const vts = [];
2491
+ Object.entries(getState().viewtemplates).forEach(([nm, obj]) => {
2492
+ if (obj.createBasicView) vts.push(nm);
2493
+ });
2494
+ return vts;
2495
+ };
2496
+
2497
+ router.get(
2498
+ "/create-basic-views/:id",
2499
+ isAdminOrHasConfigMinRole("min_role_edit_tables"),
2500
+ isAdminOrHasConfigMinRole("min_role_edit_views"),
2501
+ error_catcher(async (req, res) => {
2502
+ const { id } = req.params;
2503
+
2504
+ const table = Table.findOne({ id });
2505
+ if (!table) {
2506
+ req.flash("error", `Table not found`);
2507
+ res.redirect(`/table`);
2508
+ return;
2509
+ }
2510
+ res.set("Page-Title", req.__("Create basic views"));
2511
+ const form = await basicViewForm(table, req);
2512
+ form.values.naming_convention = getState().getConfig(
2513
+ "viewgen_naming_convention"
2514
+ );
2515
+ form.values.template_table = getState().getConfig(
2516
+ "viewgen_template_table",
2517
+ ""
2518
+ );
2519
+ const page = renderForm(form, req.csrfToken());
2520
+
2521
+ res.send(page);
2522
+ })
2523
+ );
2524
+
2455
2525
  router.post(
2456
2526
  "/create-basic-views/:id",
2457
2527
  isAdminOrHasConfigMinRole("min_role_edit_tables"),
@@ -2465,68 +2535,76 @@ router.post(
2465
2535
  res.redirect(`/table`);
2466
2536
  return;
2467
2537
  }
2538
+ const form = await basicViewForm(table, req);
2539
+ form.validate(req.body || {});
2540
+ if (form.hasErrors) {
2541
+ req.flash("error", req.__("An error occurred"));
2542
+ res.redirect(`/table/${table.id}`);
2543
+ return;
2544
+ }
2545
+
2546
+ if (
2547
+ form.values.naming_convention &&
2548
+ form.values.naming_convention !==
2549
+ getState().getConfig("viewgen_naming_convention")
2550
+ )
2551
+ await getState().setConfig(
2552
+ "viewgen_naming_convention",
2553
+ form.values.naming_convention
2554
+ );
2555
+ if (
2556
+ form.values.template_table !==
2557
+ getState().getConfig("viewgen_template_table")
2558
+ )
2559
+ await getState().setConfig(
2560
+ "viewgen_template_table",
2561
+ form.values.template_table
2562
+ );
2563
+
2468
2564
  await db.withTransaction(async () => {
2565
+ const getName = (viewtemplate) =>
2566
+ interpolate(form.values.naming_convention, {
2567
+ viewpattern: viewtemplate,
2568
+ tablename: table.name,
2569
+ }).trim();
2570
+ const all_views_created = {};
2571
+ const vts = viewtemplates_with_create_basic_option();
2572
+ vts.forEach((vt) => {
2573
+ if (form.values[vt]) all_views_created[vt] = getName(vt);
2574
+ });
2575
+
2469
2576
  const initial_view = async (table, viewtemplate) => {
2470
- const configuration = await initial_config_all_fields(
2471
- viewtemplate === "Edit"
2472
- )({ table_id: table.id });
2473
- //console.log(configuration);
2474
- const name = `${viewtemplate} ${table.name}`;
2577
+ const isEdit = viewtemplate === "Edit";
2578
+ const vtObj = getState().viewtemplates[viewtemplate];
2579
+ const name = getName(viewtemplate);
2580
+ const template_view = form.values.template_table
2581
+ ? View.findOne({
2582
+ table_id: Table.findOne(form.values.template_table).id,
2583
+ viewtemplate,
2584
+ })
2585
+ : undefined;
2586
+ const configuration = await vtObj.createBasicView({
2587
+ table,
2588
+ viewname: name,
2589
+ all_views_created,
2590
+ template_table: form.values.template_table
2591
+ ? Table.findOne(form.values.template_table)
2592
+ : undefined,
2593
+ template_view,
2594
+ });
2475
2595
  const view = await View.create({
2476
2596
  name,
2477
2597
  configuration,
2478
2598
  viewtemplate,
2479
2599
  table_id: table.id,
2480
- min_role: 100,
2600
+ attributes: template_view?.attributes,
2601
+ min_role: isEdit ? table.min_role_write : table.min_role_read,
2481
2602
  });
2482
2603
  return view;
2483
2604
  };
2484
- const list = await initial_view(table, "List");
2485
- const edit = await initial_view(table, "Edit");
2486
- const show = await initial_view(table, "Show");
2487
- await View.update(
2488
- {
2489
- configuration: {
2490
- ...list.configuration,
2491
- columns: [
2492
- ...list.configuration.columns,
2493
- {
2494
- type: "ViewLink",
2495
- view: `Own:Show ${table.name}`,
2496
- view_name: `Show ${table.name}`,
2497
- link_style: "",
2498
- view_label: "Show",
2499
- header_label: "Show",
2500
- },
2501
- {
2502
- type: "ViewLink",
2503
- view: `Own:Edit ${table.name}`,
2504
- view_name: `Edit ${table.name}`,
2505
- link_style: "",
2506
- view_label: "Edit",
2507
- header_label: "Edit",
2508
- },
2509
- {
2510
- type: "Action",
2511
- action_name: "Delete",
2512
- action_style: "btn-primary",
2513
- },
2514
- ],
2515
- view_to_create: `Edit ${table.name}`,
2516
- },
2517
- },
2518
- list.id
2519
- );
2520
- await View.update(
2521
- {
2522
- configuration: {
2523
- ...edit.configuration,
2524
- view_when_done: `List ${table.name}`,
2525
- destination_type: "View",
2526
- },
2527
- },
2528
- edit.id
2529
- );
2605
+ for (const vtnm of Object.keys(all_views_created)) {
2606
+ await initial_view(table, vtnm);
2607
+ }
2530
2608
  });
2531
2609
  await getState().refresh_views();
2532
2610
  res.redirect(`/table/${table.id}`);
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;
@@ -416,7 +416,7 @@ router.get(
416
416
  class: "mt-0",
417
417
  titleAjaxIndicator: true,
418
418
  title: req.__(
419
- `%s view - %s on %s`,
419
+ viewrow.table_name ? `%s view - %s on %s` : `%s view - %s`,
420
420
  viewname,
421
421
  viewrow.viewtemplate,
422
422
  viewrow.table_name
package/s3storage.js CHANGED
@@ -12,7 +12,7 @@ function createS3Client() {
12
12
  secretAccessKey: getState().getConfig("storage_s3_access_secret"),
13
13
  accessKeyId: getState().getConfig("storage_s3_access_key"),
14
14
  },
15
- region: getState().getConfig("storage_s3_region"),
15
+ region: getState().getConfig("storage_s3_region") || "us-east-1",
16
16
  endpoint: getState().getConfig("storage_s3_endpoint"),
17
17
  });
18
18
  }
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();
@@ -253,4 +253,20 @@ test("unique_field_from_rows test", () => {
253
253
  "bar"
254
254
  );
255
255
  expect($("#mkuniq11").val()).toBe("bar104");
256
+ $("body").append(`<input id="mkuniq12" value="YPL240724A"></div>`);
257
+ unique_field_from_rows(
258
+ [
259
+ { foo: "YPL240724A2" },
260
+ { foo: "YPL240724A1_COPY-1" },
261
+ { foo: "YPL240724A1" },
262
+ ],
263
+ "mkuniq12",
264
+ "foo",
265
+ false,
266
+ 1,
267
+ true,
268
+ "Digits",
269
+ "YPL240724A"
270
+ );
271
+ expect($("#mkuniq12").val()).toBe("YPL240724A3");
256
272
  });