@saltcorn/server 1.3.0-beta.12 → 1.3.0-beta.14

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 (389) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/docs/classes/_saltcorn_common_code.Relation.html +10 -10
  3. package/docs/classes/_saltcorn_common_code.RelationsFinder.html +5 -5
  4. package/docs/classes/_saltcorn_data.models.Crash.html +17 -17
  5. package/docs/classes/_saltcorn_data.models.EventLog-1.html +19 -19
  6. package/docs/classes/_saltcorn_data.models.Field.html +74 -74
  7. package/docs/classes/_saltcorn_data.models.FieldRepeat.html +16 -16
  8. package/docs/classes/_saltcorn_data.models.File-1.html +48 -48
  9. package/docs/classes/_saltcorn_data.models.Form-1.html +39 -39
  10. package/docs/classes/_saltcorn_data.models.Library.html +13 -13
  11. package/docs/classes/_saltcorn_data.models.Page.html +24 -24
  12. package/docs/classes/_saltcorn_data.models.PageGroup-1.html +25 -25
  13. package/docs/classes/_saltcorn_data.models.Plugin.html +25 -25
  14. package/docs/classes/_saltcorn_data.models.Role.html +9 -9
  15. package/docs/classes/_saltcorn_data.models.Table-1.html +92 -92
  16. package/docs/classes/_saltcorn_data.models.TableConstraint.html +14 -14
  17. package/docs/classes/_saltcorn_data.models.Trigger.html +36 -36
  18. package/docs/classes/_saltcorn_data.models.User.html +48 -48
  19. package/docs/classes/_saltcorn_data.models.View-1.html +54 -54
  20. package/docs/classes/_saltcorn_data.models.Workflow.html +17 -17
  21. package/docs/classes/_saltcorn_data.models.WorkflowRun.html +35 -35
  22. package/docs/classes/_saltcorn_data.models.WorkflowStep.html +25 -25
  23. package/docs/classes/_saltcorn_data.models.WorkflowTrace.html +18 -18
  24. package/docs/classes/_saltcorn_mobile_builder.MobileBuilder.html +36 -36
  25. package/docs/enums/_saltcorn_common_code.RelationType.html +7 -7
  26. package/docs/enums/_saltcorn_common_code.ViewDisplayType.html +4 -4
  27. package/docs/functions/_saltcorn_admin_models.backup.create_backup.html +1 -1
  28. package/docs/functions/_saltcorn_admin_models.backup.create_csv_from_rows.html +1 -1
  29. package/docs/functions/_saltcorn_admin_models.backup.restore.html +1 -1
  30. package/docs/functions/_saltcorn_admin_models.pack.add_to_menu.html +1 -1
  31. package/docs/functions/_saltcorn_admin_models.pack.can_install_pack.html +1 -1
  32. package/docs/functions/_saltcorn_admin_models.pack.fetch_available_packs.html +1 -1
  33. package/docs/functions/_saltcorn_admin_models.pack.fetch_pack_by_name.html +1 -1
  34. package/docs/functions/_saltcorn_admin_models.pack.install_pack.html +1 -1
  35. package/docs/functions/_saltcorn_admin_models.pack.library_pack.html +1 -1
  36. package/docs/functions/_saltcorn_admin_models.pack.model_instance_pack.html +1 -1
  37. package/docs/functions/_saltcorn_admin_models.pack.model_pack.html +1 -1
  38. package/docs/functions/_saltcorn_admin_models.pack.page_group_pack.html +1 -1
  39. package/docs/functions/_saltcorn_admin_models.pack.page_pack.html +1 -1
  40. package/docs/functions/_saltcorn_admin_models.pack.plugin_pack.html +1 -1
  41. package/docs/functions/_saltcorn_admin_models.pack.role_pack.html +1 -1
  42. package/docs/functions/_saltcorn_admin_models.pack.table_pack.html +1 -1
  43. package/docs/functions/_saltcorn_admin_models.pack.trigger_pack.html +1 -1
  44. package/docs/functions/_saltcorn_admin_models.pack.uninstall_pack.html +1 -1
  45. package/docs/functions/_saltcorn_admin_models.pack.view_pack.html +1 -1
  46. package/docs/functions/_saltcorn_admin_models.tenant.copy_tenant_template.html +1 -1
  47. package/docs/functions/_saltcorn_admin_models.tenant.create_tenant.html +1 -1
  48. package/docs/functions/_saltcorn_admin_models.tenant.deleteTenant.html +1 -1
  49. package/docs/functions/_saltcorn_admin_models.tenant.domain_sanitize.html +1 -1
  50. package/docs/functions/_saltcorn_admin_models.tenant.eachTenant.html +1 -1
  51. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenantRows.html +1 -1
  52. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenants.html +1 -1
  53. package/docs/functions/_saltcorn_admin_models.tenant.insertTenant.html +1 -1
  54. package/docs/functions/_saltcorn_admin_models.tenant.switchToTenant.html +1 -1
  55. package/docs/functions/_saltcorn_common_code.buildTableCaches.html +1 -1
  56. package/docs/functions/_saltcorn_common_code.parseLegacyRelation.html +1 -1
  57. package/docs/functions/_saltcorn_common_code.parseRelationPath.html +1 -1
  58. package/docs/functions/_saltcorn_data.models.config.check_email_mask.html +1 -1
  59. package/docs/functions/_saltcorn_data.models.config.deleteConfig.html +1 -1
  60. package/docs/functions/_saltcorn_data.models.config.getAllConfig.html +1 -1
  61. package/docs/functions/_saltcorn_data.models.config.getConfig.html +1 -1
  62. package/docs/functions/_saltcorn_data.models.config.get_base_url.html +1 -1
  63. package/docs/functions/_saltcorn_data.models.config.get_latest_npm_version.html +1 -1
  64. package/docs/functions/_saltcorn_data.models.config.remove_from_menu.html +1 -1
  65. package/docs/functions/_saltcorn_data.models.config.save_menu_items.html +1 -1
  66. package/docs/functions/_saltcorn_data.models.config.setConfig.html +1 -1
  67. package/docs/functions/_saltcorn_data.models.discovery.discover_tables.html +1 -1
  68. package/docs/functions/_saltcorn_data.models.discovery.discoverable_tables.html +1 -1
  69. package/docs/functions/_saltcorn_data.models.discovery.findType.html +1 -1
  70. package/docs/functions/_saltcorn_data.models.discovery.get_existing_views.html +1 -1
  71. package/docs/functions/_saltcorn_data.models.discovery.implement_discovery.html +1 -1
  72. package/docs/functions/_saltcorn_data.models.email.getMailTransport.html +1 -1
  73. package/docs/functions/_saltcorn_data.models.email.send_verification_email.html +1 -1
  74. package/docs/functions/_saltcorn_data.models.email.viewToEmailHtml.html +1 -1
  75. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields.html +1 -1
  76. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields_stored.html +1 -1
  77. package/docs/functions/_saltcorn_data.models.expression.eval_expression.html +1 -1
  78. package/docs/functions/_saltcorn_data.models.expression.expressionValidator.html +1 -1
  79. package/docs/functions/_saltcorn_data.models.expression.get_async_expression_function.html +1 -1
  80. package/docs/functions/_saltcorn_data.models.expression.get_expression_function.html +1 -1
  81. package/docs/functions/_saltcorn_data.models.expression.jsexprToWhere.html +1 -1
  82. package/docs/functions/_saltcorn_data.models.expression.recalculate_for_stored.html +1 -1
  83. package/docs/functions/_saltcorn_data.models.expression.transform_for_async.html +1 -1
  84. package/docs/functions/_saltcorn_data.models.layout.eachView.html +1 -1
  85. package/docs/functions/_saltcorn_data.models.layout.getStringsForI18n.html +1 -1
  86. package/docs/functions/_saltcorn_data.models.layout.getViews.html +1 -1
  87. package/docs/functions/_saltcorn_data.models.layout.translateLayout.html +1 -1
  88. package/docs/functions/_saltcorn_data.models.layout.traverse.html +1 -1
  89. package/docs/functions/_saltcorn_data.models.layout.traverseSync.html +1 -1
  90. package/docs/functions/_saltcorn_data.models.random.all_views.html +1 -1
  91. package/docs/functions/_saltcorn_data.models.random.fill_table_row.html +1 -1
  92. package/docs/functions/_saltcorn_data.models.random.initial_view.html +1 -1
  93. package/docs/functions/_saltcorn_data.models.random.random_table.html +1 -1
  94. package/docs/functions/_saltcorn_db_common.buildInsertBulkSql.html +1 -1
  95. package/docs/functions/_saltcorn_db_common.buildInsertSql.html +1 -1
  96. package/docs/functions/_saltcorn_db_common.doCount.html +1 -1
  97. package/docs/functions/_saltcorn_db_common.doDeleteWhere.html +1 -1
  98. package/docs/functions/_saltcorn_db_common.doListScTables.html +1 -1
  99. package/docs/functions/_saltcorn_db_common.doListTables.html +1 -1
  100. package/docs/functions/_saltcorn_db_common.doListUserDefinedTables.html +1 -1
  101. package/docs/functions/_saltcorn_db_common.do_add_index.html +1 -1
  102. package/docs/functions/_saltcorn_db_common.do_drop_index.html +1 -1
  103. package/docs/functions/_saltcorn_db_common.ftsFieldsSqlExpr.html +1 -1
  104. package/docs/functions/_saltcorn_db_common.mkSelectOptions.html +1 -1
  105. package/docs/functions/_saltcorn_db_common.mkVal.html +1 -1
  106. package/docs/functions/_saltcorn_db_common.mkWhere.html +1 -1
  107. package/docs/functions/_saltcorn_db_common.multi_tenant.enable_multi_tenant.html +1 -1
  108. package/docs/functions/_saltcorn_db_common.multi_tenant.getRequestContext.html +1 -1
  109. package/docs/functions/_saltcorn_db_common.multi_tenant.getTenantSchema.html +1 -1
  110. package/docs/functions/_saltcorn_db_common.multi_tenant.init.html +1 -1
  111. package/docs/functions/_saltcorn_db_common.multi_tenant.is_it_multi_tenant.html +1 -1
  112. package/docs/functions/_saltcorn_db_common.multi_tenant.runWithTenant.html +1 -1
  113. package/docs/functions/_saltcorn_db_common.orderByIsObject.html +1 -1
  114. package/docs/functions/_saltcorn_db_common.orderByIsOperator.html +1 -1
  115. package/docs/functions/_saltcorn_db_common.prefixFieldsInWhere.html +1 -1
  116. package/docs/functions/_saltcorn_db_common.reprAsJson.html +1 -1
  117. package/docs/functions/_saltcorn_db_common.slugify.html +1 -1
  118. package/docs/functions/_saltcorn_db_common.sqlBinOp.html +1 -1
  119. package/docs/functions/_saltcorn_db_common.sqlFun.html +1 -1
  120. package/docs/functions/_saltcorn_db_common.sqlsanitize.html +1 -1
  121. package/docs/functions/_saltcorn_db_common.sqlsanitizeAllowDots.html +1 -1
  122. package/docs/functions/_saltcorn_db_common.subSelectWhere.html +1 -1
  123. package/docs/functions/_saltcorn_db_common.tryCatchInTransaction.html +1 -1
  124. package/docs/functions/_saltcorn_db_common.withTransaction.html +1 -1
  125. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidFeatures.html +1 -1
  126. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidPermissions.html +1 -1
  127. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.buildTablesFile.html +1 -1
  128. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyPrepopulatedDb.html +1 -1
  129. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyServerFiles.html +1 -1
  130. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyShareExtFiles.html +1 -1
  131. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copySiteLogo.html +1 -1
  132. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyTranslationFiles.html +1 -1
  133. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.createSqliteDb.html +1 -1
  134. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.decodeProvisioningProfile.html +1 -1
  135. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.extractDomain.html +1 -1
  136. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.generateAndroidVersionCode.html +1 -1
  137. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyAndroidManifest.html +1 -1
  138. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyConfigXml.html +1 -1
  139. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyGradleConfig.html +1 -1
  140. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyInfoPlist.html +1 -1
  141. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyXcodeProjectFile.html +1 -1
  142. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepAppIcon.html +1 -1
  143. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareAppIcon.html +1 -1
  144. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareBuildDir.html +1 -1
  145. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareExportOptionsPlist.html +1 -1
  146. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashIcon.html +1 -1
  147. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashPage.html +1 -1
  148. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCapacitorConfig.html +1 -1
  149. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCfgFile.html +1 -1
  150. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeDataExtractionRules.html +1 -1
  151. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeNetworkSecurityConfig.html +1 -1
  152. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePodfile.html +1 -1
  153. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePrivacyInfo.html +1 -1
  154. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundleMobileAppCode.html +1 -1
  155. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundlePackagesAndPlugins.html +1 -1
  156. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyMobileAppDirs.html +1 -1
  157. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyPublicDirs.html +1 -1
  158. package/docs/functions/_saltcorn_sqlite.add_index.html +1 -1
  159. package/docs/functions/_saltcorn_sqlite.add_unique_constraint.html +1 -1
  160. package/docs/functions/_saltcorn_sqlite.begin.html +1 -1
  161. package/docs/functions/_saltcorn_sqlite.changeConnection.html +1 -1
  162. package/docs/functions/_saltcorn_sqlite.close.html +1 -1
  163. package/docs/functions/_saltcorn_sqlite.commit.html +1 -1
  164. package/docs/functions/_saltcorn_sqlite.count.html +1 -1
  165. package/docs/functions/_saltcorn_sqlite.deleteWhere.html +1 -1
  166. package/docs/functions/_saltcorn_sqlite.dropTable.html +1 -1
  167. package/docs/functions/_saltcorn_sqlite.dropTables.html +1 -1
  168. package/docs/functions/_saltcorn_sqlite.drop_index.html +1 -1
  169. package/docs/functions/_saltcorn_sqlite.drop_reset_schema.html +1 -1
  170. package/docs/functions/_saltcorn_sqlite.drop_unique_constraint.html +1 -1
  171. package/docs/functions/_saltcorn_sqlite.getVersion.html +1 -1
  172. package/docs/functions/_saltcorn_sqlite.get_db_filepath.html +1 -1
  173. package/docs/functions/_saltcorn_sqlite.get_sql_logging.html +1 -1
  174. package/docs/functions/_saltcorn_sqlite.init.html +1 -1
  175. package/docs/functions/_saltcorn_sqlite.insert.html +1 -1
  176. package/docs/functions/_saltcorn_sqlite.listScTables.html +1 -1
  177. package/docs/functions/_saltcorn_sqlite.listTables.html +1 -1
  178. package/docs/functions/_saltcorn_sqlite.listUserDefinedTables.html +1 -1
  179. package/docs/functions/_saltcorn_sqlite.query.html +1 -1
  180. package/docs/functions/_saltcorn_sqlite.rollback.html +1 -1
  181. package/docs/functions/_saltcorn_sqlite.select.html +1 -1
  182. package/docs/functions/_saltcorn_sqlite.selectMaybeOne.html +1 -1
  183. package/docs/functions/_saltcorn_sqlite.selectOne.html +1 -1
  184. package/docs/functions/_saltcorn_sqlite.set_sql_logging.html +1 -1
  185. package/docs/functions/_saltcorn_sqlite.sql_log.html +1 -1
  186. package/docs/functions/_saltcorn_sqlite.update.html +1 -1
  187. package/docs/functions/_saltcorn_sqlite.updateWhere.html +1 -1
  188. package/docs/functions/_saltcorn_sqlite_mobile.add_index.html +1 -1
  189. package/docs/functions/_saltcorn_sqlite_mobile.add_unique_constraint.html +1 -1
  190. package/docs/functions/_saltcorn_sqlite_mobile.count.html +1 -1
  191. package/docs/functions/_saltcorn_sqlite_mobile.deleteWhere.html +1 -1
  192. package/docs/functions/_saltcorn_sqlite_mobile.drop_index.html +1 -1
  193. package/docs/functions/_saltcorn_sqlite_mobile.drop_reset_schema.html +1 -1
  194. package/docs/functions/_saltcorn_sqlite_mobile.drop_unique_constraint.html +1 -1
  195. package/docs/functions/_saltcorn_sqlite_mobile.init.html +1 -1
  196. package/docs/functions/_saltcorn_sqlite_mobile.insert.html +1 -1
  197. package/docs/functions/_saltcorn_sqlite_mobile.insertRows.html +1 -1
  198. package/docs/functions/_saltcorn_sqlite_mobile.listScTables.html +1 -1
  199. package/docs/functions/_saltcorn_sqlite_mobile.listTables.html +1 -1
  200. package/docs/functions/_saltcorn_sqlite_mobile.listUserDefinedTables.html +1 -1
  201. package/docs/functions/_saltcorn_sqlite_mobile.query.html +1 -1
  202. package/docs/functions/_saltcorn_sqlite_mobile.select.html +1 -1
  203. package/docs/functions/_saltcorn_sqlite_mobile.selectMaybeOne.html +1 -1
  204. package/docs/functions/_saltcorn_sqlite_mobile.selectOne.html +1 -1
  205. package/docs/functions/_saltcorn_sqlite_mobile.setConnectionObject.html +1 -1
  206. package/docs/functions/_saltcorn_sqlite_mobile.tableExists.html +1 -1
  207. package/docs/functions/_saltcorn_sqlite_mobile.time.html +1 -1
  208. package/docs/functions/_saltcorn_sqlite_mobile.update.html +1 -1
  209. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_field.instanceOfField.html +1 -1
  210. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_page.instanceOfPage.html +1 -1
  211. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_view.instanceOfView.html +1 -1
  212. package/docs/functions/_saltcorn_types.Types.base_types.instanceOWithHtmlFile.html +1 -1
  213. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfErrorMsg.html +1 -1
  214. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfSuccessMsg.html +1 -1
  215. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfType.html +1 -1
  216. package/docs/functions/_saltcorn_types.generators.generateBool.html +1 -1
  217. package/docs/functions/_saltcorn_types.generators.generateString.html +1 -1
  218. package/docs/functions/_saltcorn_types.generators.num_between.html +1 -1
  219. package/docs/functions/_saltcorn_types.generators.oneOf.html +1 -1
  220. package/docs/interfaces/_saltcorn_mobile_builder.common_build_utils.ScCapacitorConfig.html +10 -10
  221. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractField.html +15 -15
  222. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractFieldRepeat.html +3 -3
  223. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_form.AbstractForm.html +27 -27
  224. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_page.AbstractPage.html +7 -7
  225. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_role.AbstractRole.html +3 -3
  226. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_table.AbstractTable.html +11 -11
  227. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_trigger.AbstractTrigger.html +16 -16
  228. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_view.AbstractView.html +10 -10
  229. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_workflow.AbstractWorkflow.html +13 -13
  230. package/docs/modules/_saltcorn_admin_models.backup.html +1 -1
  231. package/docs/modules/_saltcorn_admin_models.html +1 -1
  232. package/docs/modules/_saltcorn_admin_models.pack.html +1 -1
  233. package/docs/modules/_saltcorn_admin_models.tenant.html +1 -1
  234. package/docs/modules/_saltcorn_common_code.html +1 -1
  235. package/docs/modules/_saltcorn_data.html +3 -3
  236. package/docs/modules/_saltcorn_data.models.EventLog.html +2 -2
  237. package/docs/modules/_saltcorn_data.models.File.html +2 -2
  238. package/docs/modules/_saltcorn_data.models.Form.html +2 -2
  239. package/docs/modules/_saltcorn_data.models.PageGroup.html +2 -2
  240. package/docs/modules/_saltcorn_data.models.Table.html +2 -2
  241. package/docs/modules/_saltcorn_data.models.View.html +2 -2
  242. package/docs/modules/_saltcorn_data.models.config.html +1 -1
  243. package/docs/modules/_saltcorn_data.models.discovery.html +1 -1
  244. package/docs/modules/_saltcorn_data.models.email.html +1 -1
  245. package/docs/modules/_saltcorn_data.models.expression.html +1 -1
  246. package/docs/modules/_saltcorn_data.models.html +1 -1
  247. package/docs/modules/_saltcorn_data.models.layout.html +1 -1
  248. package/docs/modules/_saltcorn_data.models.random.html +1 -1
  249. package/docs/modules/_saltcorn_data.models.scheduler.html +1 -1
  250. package/docs/modules/_saltcorn_data.plugin_helper.html +1 -1
  251. package/docs/modules/_saltcorn_data.utils.html +1 -1
  252. package/docs/modules/_saltcorn_db_common.html +2 -2
  253. package/docs/modules/_saltcorn_db_common.multi_tenant.html +1 -1
  254. package/docs/modules/_saltcorn_markup.html +7 -7
  255. package/docs/modules/_saltcorn_mobile_builder.common_build_utils.html +1 -1
  256. package/docs/modules/_saltcorn_mobile_builder.html +1 -1
  257. package/docs/modules/_saltcorn_mobile_builder.package_bundle_utils.html +1 -1
  258. package/docs/modules/_saltcorn_sqlite.html +1 -1
  259. package/docs/modules/_saltcorn_sqlite_mobile.html +1 -1
  260. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_field.html +1 -1
  261. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_form.html +1 -1
  262. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_library.html +1 -1
  263. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_page.html +1 -1
  264. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_plugin.html +1 -1
  265. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_role.html +1 -1
  266. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_table.html +1 -1
  267. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_trigger.html +1 -1
  268. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_view.html +1 -1
  269. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_workflow.html +1 -1
  270. package/docs/modules/_saltcorn_types.ModelAbstracts.html +1 -1
  271. package/docs/modules/_saltcorn_types.Types.base_types.html +1 -1
  272. package/docs/modules/_saltcorn_types.Types.common_types.html +1 -1
  273. package/docs/modules/_saltcorn_types.Types.html +1 -1
  274. package/docs/modules/_saltcorn_types.generators.html +1 -1
  275. package/docs/modules/_saltcorn_types.html +1 -1
  276. package/docs/types/_saltcorn_data.models.EventLog.EventLogCfg.html +1 -1
  277. package/docs/types/_saltcorn_data.models.File.FileCfg.html +1 -1
  278. package/docs/types/_saltcorn_data.models.Form.AdditionalButton.html +1 -1
  279. package/docs/types/_saltcorn_data.models.Form.FormCfg.html +1 -1
  280. package/docs/types/_saltcorn_data.models.PageGroup.ScreenInfoParams.html +1 -1
  281. package/docs/types/_saltcorn_data.models.Table.ChildRelations.html +1 -1
  282. package/docs/types/_saltcorn_data.models.Table.ParentRelations.html +1 -1
  283. package/docs/types/_saltcorn_data.models.Table.RelationData.html +1 -1
  284. package/docs/types/_saltcorn_data.models.View.FindViewsPred.html +1 -1
  285. package/docs/types/_saltcorn_db_common.AggregationOptions.html +1 -1
  286. package/docs/types/_saltcorn_db_common.CoordOpts.html +1 -1
  287. package/docs/types/_saltcorn_db_common.DatabaseClient.html +1 -1
  288. package/docs/types/_saltcorn_db_common.JoinField.html +1 -1
  289. package/docs/types/_saltcorn_db_common.JoinFields.html +1 -1
  290. package/docs/types/_saltcorn_db_common.JoinOptions.html +1 -1
  291. package/docs/types/_saltcorn_db_common.JsonPath.html +1 -1
  292. package/docs/types/_saltcorn_db_common.JsonPathElem.html +1 -1
  293. package/docs/types/_saltcorn_db_common.Operator.html +1 -1
  294. package/docs/types/_saltcorn_db_common.PartialSome.html +1 -1
  295. package/docs/types/_saltcorn_db_common.PrimaryKeyValue.html +1 -1
  296. package/docs/types/_saltcorn_db_common.Row.html +1 -1
  297. package/docs/types/_saltcorn_db_common.SelectOptions.html +1 -1
  298. package/docs/types/_saltcorn_db_common.SqlAndValues.html +1 -1
  299. package/docs/types/_saltcorn_db_common.StrongRow.html +1 -1
  300. package/docs/types/_saltcorn_db_common.SubselectOptions.html +1 -1
  301. package/docs/types/_saltcorn_db_common.Value.html +1 -1
  302. package/docs/types/_saltcorn_db_common.Where.html +1 -1
  303. package/docs/types/_saltcorn_mobile_builder.IosCfg.html +1 -1
  304. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.FieldCfg.html +1 -1
  305. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.InputType.html +1 -1
  306. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_form.AdditionalButton.html +1 -1
  307. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryCfg.html +1 -1
  308. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryPack.html +1 -1
  309. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PageCfg.html +1 -1
  310. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PagePack.html +1 -1
  311. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginCfg.html +1 -1
  312. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginPack.html +1 -1
  313. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RoleCfg.html +1 -1
  314. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RolePack.html +1 -1
  315. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TableCfg.html +1 -1
  316. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TablePack.html +1 -1
  317. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerCfg.html +1 -1
  318. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerPack.html +1 -1
  319. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewCfg.html +1 -1
  320. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewPack.html +1 -1
  321. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.ConfigWorkflowStep.html +1 -1
  322. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.RunResult.html +1 -1
  323. package/docs/types/_saltcorn_types.Types.base_types.Action.html +1 -1
  324. package/docs/types/_saltcorn_types.Types.base_types.AuthenticationMethod.html +1 -1
  325. package/docs/types/_saltcorn_types.Types.base_types.CalcJoinfield.html +1 -1
  326. package/docs/types/_saltcorn_types.Types.base_types.CapacitorPlugin.html +1 -1
  327. package/docs/types/_saltcorn_types.Types.base_types.CodePagePack.html +1 -1
  328. package/docs/types/_saltcorn_types.Types.base_types.Column.html +1 -1
  329. package/docs/types/_saltcorn_types.Types.base_types.ConnectObjType.html +1 -1
  330. package/docs/types/_saltcorn_types.Types.base_types.ConnectedObjects.html +1 -1
  331. package/docs/types/_saltcorn_types.Types.base_types.CopilotSkill.html +1 -1
  332. package/docs/types/_saltcorn_types.Types.base_types.ErrorObj.html +1 -1
  333. package/docs/types/_saltcorn_types.Types.base_types.FieldLike.html +1 -1
  334. package/docs/types/_saltcorn_types.Types.base_types.FieldView.html +1 -1
  335. package/docs/types/_saltcorn_types.Types.base_types.Header.html +1 -1
  336. package/docs/types/_saltcorn_types.Types.base_types.JoinFieldOption.html +1 -1
  337. package/docs/types/_saltcorn_types.Types.base_types.Layout.html +1 -1
  338. package/docs/types/_saltcorn_types.Types.base_types.MobileConfig.html +1 -1
  339. package/docs/types/_saltcorn_types.Types.base_types.ModelPattern.html +1 -1
  340. package/docs/types/_saltcorn_types.Types.base_types.Pack.html +1 -1
  341. package/docs/types/_saltcorn_types.Types.base_types.Plugin.html +1 -1
  342. package/docs/types/_saltcorn_types.Types.base_types.PluginFunction.html +1 -1
  343. package/docs/types/_saltcorn_types.Types.base_types.PluginLayout.html +1 -1
  344. package/docs/types/_saltcorn_types.Types.base_types.PluginRoute.html +1 -1
  345. package/docs/types/_saltcorn_types.Types.base_types.PluginSourceType.html +1 -1
  346. package/docs/types/_saltcorn_types.Types.base_types.PluginType.html +1 -1
  347. package/docs/types/_saltcorn_types.Types.base_types.PluginWrap.html +1 -1
  348. package/docs/types/_saltcorn_types.Types.base_types.PluginWrapArg.html +1 -1
  349. package/docs/types/_saltcorn_types.Types.base_types.RelationOption.html +1 -1
  350. package/docs/types/_saltcorn_types.Types.base_types.Req.html +1 -1
  351. package/docs/types/_saltcorn_types.Types.base_types.Res.html +1 -1
  352. package/docs/types/_saltcorn_types.Types.base_types.ResultType.html +1 -1
  353. package/docs/types/_saltcorn_types.Types.base_types.RouteAction.html +1 -1
  354. package/docs/types/_saltcorn_types.Types.base_types.RunExtra.html +1 -1
  355. package/docs/types/_saltcorn_types.Types.base_types.SlugStepType.html +1 -1
  356. package/docs/types/_saltcorn_types.Types.base_types.StepResType.html +1 -1
  357. package/docs/types/_saltcorn_types.Types.base_types.SubField.html +1 -1
  358. package/docs/types/_saltcorn_types.Types.base_types.TableProvider.html +1 -1
  359. package/docs/types/_saltcorn_types.Types.base_types.TableQuery.html +1 -1
  360. package/docs/types/_saltcorn_types.Types.base_types.Tablely.html +1 -1
  361. package/docs/types/_saltcorn_types.Types.base_types.ViewTemplate.html +1 -1
  362. package/docs/types/_saltcorn_types.Types.common_types.ErrorMessage.html +1 -1
  363. package/docs/types/_saltcorn_types.Types.common_types.GenObj.html +1 -1
  364. package/docs/types/_saltcorn_types.Types.common_types.ReqRes.html +1 -1
  365. package/docs/types/_saltcorn_types.Types.common_types.ResultMessage.html +1 -1
  366. package/docs/types/_saltcorn_types.Types.common_types.SuccessMessage.html +1 -1
  367. package/docs/types/_saltcorn_types.Types.common_types.Type.html +1 -1
  368. package/docs/variables/_saltcorn_data.db.html +1 -1
  369. package/docs/variables/_saltcorn_data.migrations.html +1 -1
  370. package/docs/variables/_saltcorn_data.models.config.available_languages.html +1 -1
  371. package/docs/variables/_saltcorn_data.models.config.configTypes.html +1 -1
  372. package/docs/variables/_saltcorn_data.models.scheduler.runScheduler.html +1 -1
  373. package/docs/variables/_saltcorn_data.plugin_helper.run_action_column.html +1 -1
  374. package/docs/variables/_saltcorn_data.utils.NotAuthorized.html +1 -1
  375. package/docs/variables/_saltcorn_data.utils.sleep.html +1 -1
  376. package/docs/variables/_saltcorn_db_common.multi_tenant.tenantNamespace.html +1 -1
  377. package/locales/en.json +5 -1
  378. package/package.json +10 -10
  379. package/public/saltcorn-common.js +114 -0
  380. package/public/saltcorn.js +14 -3
  381. package/public/serviceworker.js +11 -0
  382. package/routes/admin.js +56 -1
  383. package/routes/fields.js +10 -0
  384. package/routes/notifications.js +141 -4
  385. package/routes/search.js +23 -2
  386. package/routes/tables.js +1 -0
  387. package/serve.js +29 -6
  388. package/tests/plugin_install.test.js +1 -1
  389. package/wrapper.js +18 -0
@@ -19,7 +19,7 @@
19
19
  <h1>Variable NotAuthorized</h1></div>
20
20
  <div class="tsd-signature"><span class="tsd-kind-variable">Not<wbr/>Authorized</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span></div><aside class="tsd-sources">
21
21
  <ul>
22
- <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/fafb795597/packages/saltcorn-data/index.ts#L20">saltcorn-data/index.ts:20</a></li></ul></aside></div>
22
+ <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/a072fcff0e/packages/saltcorn-data/index.ts#L20">saltcorn-data/index.ts:20</a></li></ul></aside></div>
23
23
  <div class="col-sidebar">
24
24
  <div class="page-menu">
25
25
  <div class="tsd-navigation settings">
@@ -19,7 +19,7 @@
19
19
  <h1>Variable sleep</h1></div>
20
20
  <div class="tsd-signature"><span class="tsd-kind-variable">sleep</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span></div><aside class="tsd-sources">
21
21
  <ul>
22
- <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/fafb795597/packages/saltcorn-data/index.ts#L20">saltcorn-data/index.ts:20</a></li></ul></aside></div>
22
+ <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/a072fcff0e/packages/saltcorn-data/index.ts#L20">saltcorn-data/index.ts:20</a></li></ul></aside></div>
23
23
  <div class="col-sidebar">
24
24
  <div class="page-menu">
25
25
  <div class="tsd-navigation settings">
@@ -19,7 +19,7 @@
19
19
  <h1>Variable tenantNamespace<code class="tsd-tag ts-flagConst">Const</code> </h1></div>
20
20
  <div class="tsd-signature"><span class="tsd-kind-variable">tenant<wbr/>Namespace</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type ">AsyncLocalStorage</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type ">RequestContext</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol"> = ...</span></div><aside class="tsd-sources">
21
21
  <ul>
22
- <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/fafb795597/packages/db-common/multi-tenant.ts#L17">db-common/multi-tenant.ts:17</a></li></ul></aside></div>
22
+ <li>Defined in <a href="https://github.com/saltcorn/saltcorn/blob/a072fcff0e/packages/db-common/multi-tenant.ts#L17">db-common/multi-tenant.ts:17</a></li></ul></aside></div>
23
23
  <div class="col-sidebar">
24
24
  <div class="page-menu">
25
25
  <div class="tsd-navigation settings">
package/locales/en.json CHANGED
@@ -1619,5 +1619,9 @@
1619
1619
  "Decimal places": "Decimal places",
1620
1620
  "%s view - %s": "%s view - %s",
1621
1621
  "Password to encrypt the backup file. Leave empty for no encryption": "Password to encrypt the backup file. Leave empty for no encryption",
1622
- "Show full error to user on crash, enable editing field type": "Show full error to user on crash, enable editing field type"
1622
+ "Show full error to user on crash, enable editing field type": "Show full error to user on crash, enable editing field type",
1623
+ "Shown to the user if foreign key constraint is violated": "Shown to the user if foreign key constraint is violated",
1624
+ "Button Style": "Button Style",
1625
+ "Disable full-text search": "Disable full-text search",
1626
+ "Use LIKE instead of tsvector. Use to match against phrase in the middle of a word.": "Use LIKE instead of tsvector. Use to match against phrase in the middle of a word."
1623
1627
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "1.3.0-beta.12",
3
+ "version": "1.3.0-beta.14",
4
4
  "description": "Server app for Saltcorn, open-source no-code platform",
5
5
  "homepage": "https://saltcorn.com",
6
6
  "main": "index.js",
@@ -8,14 +8,14 @@
8
8
  "dependencies": {
9
9
  "@aws-sdk/client-s3": "^3.735.0",
10
10
  "@dr.pogodin/csurf": "1.15.0",
11
- "@saltcorn/admin-models": "1.3.0-beta.12",
12
- "@saltcorn/base-plugin": "1.3.0-beta.12",
13
- "@saltcorn/builder": "1.3.0-beta.12",
14
- "@saltcorn/data": "1.3.0-beta.12",
15
- "@saltcorn/filemanager": "1.3.0-beta.12",
16
- "@saltcorn/markup": "1.3.0-beta.12",
17
- "@saltcorn/plugins-loader": "1.3.0-beta.12",
18
- "@saltcorn/sbadmin2": "1.3.0-beta.12",
11
+ "@saltcorn/admin-models": "1.3.0-beta.14",
12
+ "@saltcorn/base-plugin": "1.3.0-beta.14",
13
+ "@saltcorn/builder": "1.3.0-beta.14",
14
+ "@saltcorn/data": "1.3.0-beta.14",
15
+ "@saltcorn/filemanager": "1.3.0-beta.14",
16
+ "@saltcorn/markup": "1.3.0-beta.14",
17
+ "@saltcorn/plugins-loader": "1.3.0-beta.14",
18
+ "@saltcorn/sbadmin2": "1.3.0-beta.14",
19
19
  "@socket.io/cluster-adapter": "^0.2.1",
20
20
  "@socket.io/sticky": "^1.0.1",
21
21
  "adm-zip": "0.5.16",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "repository": "github:saltcorn/saltcorn",
74
74
  "devDependencies": {
75
- "jest": "^29.7.0",
75
+ "jest": "29.7.0",
76
76
  "jest-environment-jsdom": "29.7.0",
77
77
  "supertest": "7.0.0"
78
78
  },
@@ -2428,3 +2428,117 @@ const observer = new IntersectionObserver(
2428
2428
  document.querySelectorAll("[data-animate]").forEach((element) => {
2429
2429
  observer.observe(element);
2430
2430
  });
2431
+
2432
+ function isPWA() {
2433
+ if (!window.matchMedia) return false;
2434
+ const isStandaloneDisplay = window.matchMedia(
2435
+ "(display-mode: standalone)"
2436
+ ).matches;
2437
+ const isStandaloneNavigator = window.navigator.standalone === true; // iOS Safari
2438
+ const isTrustedDisplayMode = ["fullscreen", "standalone", "minimal-ui"].some(
2439
+ (mode) => window.matchMedia(`(display-mode: ${mode})`).matches
2440
+ );
2441
+ return isStandaloneDisplay || isStandaloneNavigator || isTrustedDisplayMode;
2442
+ }
2443
+
2444
+ const subscribeHelper = (config, swReg) => {
2445
+ if (!config.vapidPublicKey) throw new Error("VAPID public key is missing");
2446
+
2447
+ function urlBase64ToUint8Array(base64String) {
2448
+ const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
2449
+ const base64 = (base64String + padding)
2450
+ .replace(/\-/g, "+")
2451
+ .replace(/_/g, "/");
2452
+
2453
+ const rawData = atob(base64);
2454
+ const outputArray = new Uint8Array(rawData.length);
2455
+
2456
+ for (let i = 0; i < rawData.length; ++i) {
2457
+ outputArray[i] = rawData.charCodeAt(i);
2458
+ }
2459
+ return outputArray;
2460
+ }
2461
+
2462
+ const subscribe = async () => {
2463
+ const subscription = await swReg.pushManager.subscribe({
2464
+ userVisibleOnly: true,
2465
+ applicationServerKey: urlBase64ToUint8Array(config.vapidPublicKey),
2466
+ });
2467
+ return subscription;
2468
+ };
2469
+
2470
+ const uploadSubscription = async (subscription) => {
2471
+ const response = await fetch("/notifications/subscribe", {
2472
+ method: "POST",
2473
+ body: JSON.stringify(subscription),
2474
+ headers: {
2475
+ "Content-Type": "application/json",
2476
+ "CSRF-Token": _sc_globalCsrf,
2477
+ },
2478
+ });
2479
+ if (response.status === 200) {
2480
+ const data = await response.json();
2481
+ console.log("Subscription uploaded successfully:", data);
2482
+ } else console.error("Failed to upload subscription:", response.statusText);
2483
+ };
2484
+
2485
+ const removeSubscription = async (subscription) => {
2486
+ const response = await fetch("/notifications/remove-subscription", {
2487
+ method: "POST",
2488
+ body: JSON.stringify(subscription),
2489
+ headers: {
2490
+ "Content-Type": "application/json",
2491
+ "CSRF-Token": _sc_globalCsrf,
2492
+ },
2493
+ });
2494
+ if (response.status === 200) {
2495
+ console.log("Subscription removed successfully");
2496
+ } else {
2497
+ console.error("Failed to remove subscription:", response.statusText);
2498
+ }
2499
+ };
2500
+
2501
+ return {
2502
+ handle: async () => {
2503
+ const enabled = config?.enabled && config.userEnabled;
2504
+ let currentSub = await swReg.pushManager.getSubscription();
2505
+ if (!enabled) {
2506
+ if (currentSub) {
2507
+ await currentSub.unsubscribe();
2508
+ await removeSubscription(currentSub);
2509
+ }
2510
+ } else {
2511
+ if (
2512
+ currentSub &&
2513
+ !config.endpoints.find((endpoint) => endpoint === currentSub.endpoint)
2514
+ ) {
2515
+ console.log(
2516
+ "Current subscription does not exist server-side, renewing..."
2517
+ );
2518
+ await currentSub.unsubscribe();
2519
+ currentSub = null;
2520
+ }
2521
+
2522
+ if (!currentSub) {
2523
+ const permission = await Notification.requestPermission();
2524
+ if (permission !== "granted")
2525
+ throw new Error(`Push permission denied ${permission}`);
2526
+ const newSub = await subscribe();
2527
+ await uploadSubscription(newSub);
2528
+ }
2529
+ }
2530
+ },
2531
+ };
2532
+ };
2533
+
2534
+ async function initPushNotify() {
2535
+ try {
2536
+ const webPushConfig = window.push_notify_cfg;
2537
+ if (webPushConfig) {
2538
+ const swReg = await navigator.serviceWorker.ready;
2539
+ await subscribeHelper(webPushConfig, swReg).handle();
2540
+ }
2541
+ } catch (error) {
2542
+ console.error("Push notification initialization failed:", error);
2543
+ }
2544
+ }
@@ -158,14 +158,16 @@ function invalidate_pagings(href) {
158
158
 
159
159
  function set_state_fields(kvs, disable_pjax, e) {
160
160
  let newhref = get_current_state_url(e);
161
+ const oldhref = newhref;
161
162
  if (Object.keys(kvs).some((k) => !is_paging_param(k))) {
162
163
  newhref = invalidate_pagings(newhref);
163
164
  }
164
165
  Object.entries(kvs).forEach((kv) => {
165
- if (kv[1].unset && kv[1].unset === true)
166
+ if (kv[1]?.unset && kv[1]?.unset === true)
166
167
  newhref = removeQueryStringParameter(newhref, kv[0]);
167
168
  else newhref = updateQueryStringParameter(newhref, kv[0], kv[1]);
168
169
  });
170
+ if (newhref === oldhref) return;
169
171
  if (disable_pjax) href_to(newhref.replace("&&", "&").replace("?&", "?"));
170
172
  else pjax_to(newhref.replace("&&", "&").replace("?&", "?"), e);
171
173
  }
@@ -1241,6 +1243,15 @@ window.addEventListener("beforeinstallprompt", (e) => {
1241
1243
  defferedPrompt = e;
1242
1244
  });
1243
1245
 
1246
+ window.addEventListener("appinstalled", async (event) => {
1247
+ console.log("App was installed.", event);
1248
+ await initPushNotify();
1249
+ });
1250
+
1251
+ document.addEventListener("DOMContentLoaded", async () => {
1252
+ await initPushNotify();
1253
+ });
1254
+
1244
1255
  function isAndroidMobile() {
1245
1256
  const ua = navigator.userAgent || navigator.vendor || window.opera;
1246
1257
  return /android/i.test(ua) && /mobile/i.test(ua);
@@ -1439,14 +1450,14 @@ function cfu_translate(that) {
1439
1450
  l = function (a, b) {
1440
1451
  d = setTimeout(function () {
1441
1452
  d = !1;
1442
- if (h || c) e.apply(a, b), c && (j = +new Date());
1453
+ if (h || c) (e.apply(a, b), c && (j = +new Date()));
1443
1454
  i && g.apply(a, b);
1444
1455
  }, f);
1445
1456
  },
1446
1457
  k = function () {
1447
1458
  if (!d || a) {
1448
1459
  if (!d && !h && (!c || +new Date() - j > f))
1449
- e.apply(this, arguments), c && (j = +new Date());
1460
+ (e.apply(this, arguments), c && (j = +new Date()));
1450
1461
  (a || !c) && clearTimeout(d);
1451
1462
  l(this, arguments);
1452
1463
  }
@@ -3,3 +3,14 @@
3
3
  self.addEventListener("fetch", function () {
4
4
  return;
5
5
  });
6
+
7
+ self.addEventListener("push", function (event) {
8
+ const data = event.data.json();
9
+ event.waitUntil(
10
+ self.registration.showNotification(data.title, {
11
+ body: data.body,
12
+ icon: data.icon,
13
+ badge: data.badge,
14
+ })
15
+ );
16
+ });
package/routes/admin.js CHANGED
@@ -4501,6 +4501,28 @@ admin_config_route({
4501
4501
  name: "pwa_icons",
4502
4502
  showIf: { pwa_enabled: true },
4503
4503
  },
4504
+ { section_header: "Push Notifications" },
4505
+ "enable_push_notify",
4506
+ {
4507
+ name: "vapid_public_key",
4508
+ showIf: { enable_push_notify: true },
4509
+ },
4510
+ {
4511
+ name: "vapid_private_key",
4512
+ showIf: { enable_push_notify: true },
4513
+ },
4514
+ {
4515
+ name: "vapid_email",
4516
+ showIf: { enable_push_notify: true },
4517
+ },
4518
+ {
4519
+ name: "push_notification_icon",
4520
+ showIf: { enable_push_notify: true },
4521
+ },
4522
+ {
4523
+ name: "push_notification_badge",
4524
+ showIf: { enable_push_notify: true },
4525
+ },
4504
4526
  ],
4505
4527
  response(form, req, res) {
4506
4528
  send_admin_page({
@@ -4511,7 +4533,40 @@ admin_config_route({
4511
4533
  type: "card",
4512
4534
  title: req.__("Notification settings"),
4513
4535
  titleAjaxIndicator: true,
4514
- contents: [renderForm(form, req.csrfToken())],
4536
+ contents: [
4537
+ renderForm(form, req.csrfToken()) +
4538
+ button(
4539
+ {
4540
+ id: "generate-vapid-keys-btn",
4541
+ class: "btn btn-primary d-none",
4542
+ onclick:
4543
+ "if (confirm('Are you sure? The old keys will be lost, and existing subscriptions will be deleted.')) ajax_post_btn('/notifications/generate-vapid-keys', true)",
4544
+ },
4545
+ "Generate VAPID keys"
4546
+ ) +
4547
+ script(
4548
+ domReady(`
4549
+ const fn = () => {
4550
+ const pushEnabled = document.getElementById("inputenable_push_notify");
4551
+ const generateBtn = document.getElementById("generate-vapid-keys-btn");
4552
+ if (pushEnabled && pushEnabled.checked) {
4553
+ generateBtn.classList.remove("d-none");
4554
+ generateBtn.classList.add("d-inline");
4555
+ }
4556
+ else {
4557
+ generateBtn.classList.remove("d-inline");
4558
+ generateBtn.classList.add("d-none");
4559
+ }
4560
+ };
4561
+ setTimeout(fn, 0);
4562
+ const mainForm = document.querySelector("form[action='/admin/notifications']");
4563
+ if (mainForm) {
4564
+ mainForm.addEventListener("change", (e) => {
4565
+ fn();
4566
+ });
4567
+ }`)
4568
+ ),
4569
+ ],
4515
4570
  },
4516
4571
  });
4517
4572
  },
package/routes/fields.js CHANGED
@@ -251,6 +251,7 @@ const fieldFlow = (req) =>
251
251
  attributes.include_fts = context.include_fts;
252
252
  attributes.on_delete_cascade = context.on_delete_cascade;
253
253
  attributes.on_delete = context.on_delete;
254
+ attributes.fkey_error_msg = context.fkey_error_msg;
254
255
  attributes.unique_error_msg = context.unique_error_msg;
255
256
  if (context.protected) attributes.min_role_write = context.min_role_write;
256
257
  else attributes.min_role_write = undefined;
@@ -723,6 +724,15 @@ const fieldFlow = (req) =>
723
724
  "If the parent row is deleted, do this to the child rows."
724
725
  ),
725
726
  }),
727
+ new Field({
728
+ name: "fkey_error_msg",
729
+ label: req.__("Error message"),
730
+ type: "String",
731
+ sublabel: req.__(
732
+ "Shown to the user if foreign key constraint is violated"
733
+ ),
734
+ showIf: { on_delete: "Fail" },
735
+ }),
726
736
  ],
727
737
  });
728
738
  },
@@ -32,14 +32,23 @@ router.use(
32
32
  })
33
33
  );
34
34
 
35
- const notificationSettingsForm = () =>
36
- new Form({
35
+ const notificationSettingsForm = () => {
36
+ const fields = [{ name: "notify_email", label: "Email", type: "Bool" }];
37
+ if (getState().getConfig("enable_push_notify", false))
38
+ fields.push({
39
+ name: "notify_push",
40
+ label: "Push",
41
+ type: "Bool",
42
+ });
43
+
44
+ return new Form({
37
45
  action: `/notifications/settings`,
38
46
  noSubmitButton: true,
39
47
  onChange: `saveAndContinue(this)`,
40
48
  labelCols: 4,
41
- fields: [{ name: "notify_email", label: "Email", type: "Bool" }],
49
+ fields,
42
50
  });
51
+ };
43
52
 
44
53
  router.get(
45
54
  "/",
@@ -67,7 +76,10 @@ router.get(
67
76
 
68
77
  const form = notificationSettingsForm();
69
78
  const user = await User.findOne({ id: req.user?.id });
70
- form.values = { notify_email: user?._attributes?.notify_email };
79
+ form.values = {
80
+ notify_email: user?._attributes?.notify_email,
81
+ notify_push: user?._attributes?.notify_push,
82
+ };
71
83
  const notifyCards = nots.length
72
84
  ? nots.map((not) => ({
73
85
  type: "card",
@@ -185,6 +197,16 @@ router.post(
185
197
  form.validate(req.body || {});
186
198
  const _attributes = { ...user._attributes, ...form.values };
187
199
  await user.update({ _attributes });
200
+ const pushEnabled = !!_attributes.notify_push;
201
+ const allSubs = getState().getConfig("push_notification_subscriptions", {});
202
+ const newSubs = { ...allSubs };
203
+ if (!pushEnabled && newSubs[req.user.id]) {
204
+ delete newSubs[req.user.id];
205
+ await getState().setConfig("push_notification_subscriptions", newSubs);
206
+ } else if (pushEnabled && !newSubs[req.user.id]) {
207
+ newSubs[req.user.id] = [];
208
+ await getState().setConfig("push_notification_subscriptions", newSubs);
209
+ }
188
210
  res.json({ success: "ok" });
189
211
  })
190
212
  );
@@ -248,6 +270,121 @@ router.post(
248
270
  })
249
271
  );
250
272
 
273
+ router.post(
274
+ "/subscribe",
275
+ loggedIn,
276
+ error_catcher(async (req, res) => {
277
+ const enabled = getState().getConfig("enable_push_notify", false);
278
+ if (!enabled) {
279
+ res.status(403).json({
280
+ error: req.__("Notifications are not enabled on this server"),
281
+ });
282
+ } else {
283
+ const user = req.user;
284
+ const allSubs = getState().getConfig(
285
+ "push_notification_subscriptions",
286
+ {}
287
+ );
288
+ const userSubs = allSubs[user.id] || [];
289
+ const existingSub = userSubs.find(
290
+ (s) =>
291
+ s.endpoint === req.body.endpoint &&
292
+ s.keys.p256dh === req.body.keys.p256dh &&
293
+ s.keys.auth === req.body.keys.auth
294
+ );
295
+ if (existingSub) {
296
+ res.json({
297
+ success: "ok",
298
+ message: req.__("Subscribed to notifications"),
299
+ });
300
+ } else {
301
+ userSubs.push({
302
+ endpoint: req.body.endpoint,
303
+ keys: {
304
+ auth: req.body.keys.auth,
305
+ p256dh: req.body.keys.p256dh,
306
+ },
307
+ });
308
+ await getState().setConfig("push_notification_subscriptions", {
309
+ ...allSubs,
310
+ [user.id]: userSubs,
311
+ });
312
+ res.json({
313
+ success: "ok",
314
+ message: req.__("Subscribed to notifications"),
315
+ });
316
+ }
317
+ }
318
+ })
319
+ );
320
+
321
+ router.post(
322
+ "/remove-subscription",
323
+ loggedIn,
324
+ error_catcher(async (req, res) => {
325
+ const enabled = getState().getConfig("enable_push_notify", false);
326
+ if (!enabled) {
327
+ res.status(403).json({
328
+ error: req.__("Notifications are not enabled on this server"),
329
+ });
330
+ } else {
331
+ const { subscription } = req.body;
332
+ const user = req.user;
333
+ const oldSubs = getState().getConfig(
334
+ "push_notification_subscriptions",
335
+ {}
336
+ );
337
+ let userSubs = oldSubs[user.id];
338
+ if (userSubs) {
339
+ userSubs = userSubs.filter(
340
+ (s) =>
341
+ s.endpoint !== subscription.endpoint ||
342
+ s.keys.p256dh !== subscription.keys.p256dh ||
343
+ s.keys.auth !== subscription.keys.auth
344
+ );
345
+ await getState().setConfig("push_notification_subscriptions", {
346
+ ...oldSubs,
347
+ [user.id]: userSubs,
348
+ });
349
+ }
350
+ res.json({
351
+ success: "ok",
352
+ message: req.__("Unsubscribed from notifications"),
353
+ });
354
+ }
355
+ })
356
+ );
357
+
358
+ router.post(
359
+ "/generate-vapid-keys",
360
+ isAdmin,
361
+ error_catcher(async (req, res) => {
362
+ const enabled = getState().getConfig("enable_push_notify", false);
363
+ if (!enabled) {
364
+ res.status(403).json({
365
+ error: req.__("Notifications are not enabled on this server"),
366
+ });
367
+ } else {
368
+ const webPush = require("web-push");
369
+ const vapidKeys = webPush.generateVAPIDKeys();
370
+ await getState().setConfig("vapid_public_key", vapidKeys.publicKey);
371
+ await getState().setConfig("vapid_private_key", vapidKeys.privateKey);
372
+ const allSubs = getState().setConfig(
373
+ "push_notification_subscriptions",
374
+ {}
375
+ );
376
+ const newSubs = {};
377
+ for (const k of Object.keys(allSubs)) {
378
+ newSubs[k] = [];
379
+ }
380
+ await getState().setConfig("push_notification_subscriptions", newSubs);
381
+ res.json({
382
+ success: "ok",
383
+ });
384
+ }
385
+ })
386
+ );
387
+
251
388
  router.get(
252
389
  "/manifest.json{:opt_cache_bust}",
253
390
  error_catcher(async (req, res) => {
package/routes/search.js CHANGED
@@ -71,6 +71,14 @@ const searchConfigForm = (tables, views, req) => {
71
71
  input_type: "select",
72
72
  options: ["Cards", "Tabs"],
73
73
  });
74
+ fields.push({
75
+ name: "search_disable_fts",
76
+ label: req.__("Disable full-text search"),
77
+ type: "Bool",
78
+ sublabel: req.__(
79
+ "Use LIKE instead of tsvector. Use to match against phrase in the middle of a word."
80
+ ),
81
+ });
74
82
  const blurb1 = req.__(
75
83
  `Choose views for <a href="/search">search results</a> for each table.<br/>Set to blank to omit table from global search.`
76
84
  );
@@ -112,6 +120,10 @@ router.get(
112
120
  "search_results_decoration",
113
121
  "Cards"
114
122
  );
123
+ form.values.search_disable_fts = getState().getConfig(
124
+ "search_disable_fts",
125
+ true
126
+ );
115
127
  send_infoarch_page({
116
128
  res,
117
129
  req,
@@ -154,6 +166,10 @@ router.post(
154
166
  "search_results_decoration",
155
167
  result.success.search_results_decoration || "Cards"
156
168
  );
169
+ await getState().setConfig(
170
+ "search_disable_fts",
171
+ result.success.search_disable_fts || false
172
+ );
157
173
  await getState().setConfig("search_use_websearch", +dbversion >= 11.0);
158
174
  delete result.success.search_table_description;
159
175
  delete result.success.search_results_decoration;
@@ -235,7 +251,9 @@ const runSearch = async ({ q, _page, table }, req, res) => {
235
251
  viewName === "search_table_description" ||
236
252
  tableName === "search_table_description" ||
237
253
  viewName === "search_results_decoration" ||
238
- tableName === "search_results_decoration"
254
+ tableName === "search_results_decoration" ||
255
+ viewName === "search_disable_fts" ||
256
+ tableName === "search_disable_fts"
239
257
  )
240
258
  continue;
241
259
  tablesConfigured += 1;
@@ -367,7 +385,10 @@ router.get(
367
385
  "/",
368
386
  error_catcher(async (req, res, next) => {
369
387
  const state = getState();
370
- const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
388
+ const maintenanceModeEnabled = state.getConfig(
389
+ "maintenance_mode_enabled",
390
+ false
391
+ );
371
392
 
372
393
  if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
373
394
  res.status(503).send("Page Unavailable: in maintenance mode");
package/routes/tables.js CHANGED
@@ -748,6 +748,7 @@ const attribBadges = (f) => {
748
748
  "summary_field",
749
749
  "importance",
750
750
  "on_delete_cascade",
751
+ "fkey_error_msg",
751
752
  "on_delete",
752
753
  "unique_error_msg",
753
754
  "ref",
package/serve.js CHANGED
@@ -111,7 +111,8 @@ const ensurePluginsFolder = async () => {
111
111
  const pluginDir = path.join(
112
112
  rootFolder,
113
113
  plugin.source === "git" ? "git_plugins" : "plugins_folder",
114
- ...tokens
114
+ ...tokens,
115
+ plugin.version || "unknownversion"
115
116
  );
116
117
  allPluginFolders.add(pluginDir);
117
118
  }
@@ -142,6 +143,29 @@ const ensurePluginsFolder = async () => {
142
143
  }
143
144
  };
144
145
 
146
+ /**
147
+ * Users with push_notify enabled store subscription in push_notification_subscriptions
148
+ * This function ensures that enabled users at least have an empty array
149
+ * and disabled users have no entry
150
+ */
151
+ const ensureNotificationSubscriptions = async () => {
152
+ const allSubs = await getConfig("push_notification_subscriptions", {});
153
+ let changed = false;
154
+ for (const user of await User.find()) {
155
+ const enabled = user._attributes?.notify_push || false;
156
+ if (enabled && !allSubs[user.id]) {
157
+ allSubs[user.id] = [];
158
+ changed = true;
159
+ } else if (!enabled && allSubs[user.id]) {
160
+ delete allSubs[user.id];
161
+ changed = true;
162
+ }
163
+ }
164
+ if (changed) {
165
+ await setConfig("push_notification_subscriptions", { ...allSubs });
166
+ }
167
+ };
168
+
145
169
  // helpful https://gist.github.com/jpoehls/2232358
146
170
  /**
147
171
  * @param {object} opts
@@ -194,7 +218,6 @@ const initMaster = async ({ disableMigrate }, useClusterAdaptor = true) => {
194
218
  /**
195
219
  * @param {object} opts
196
220
  * @param {object} opts.tenant
197
- * @param {...*} opts.msg
198
221
  * @returns {void}
199
222
  */
200
223
  const workerDispatchMsg = ({ tenant, ...msg }) => {
@@ -302,6 +325,7 @@ module.exports =
302
325
  ensureJwtSecret();
303
326
  await ensureEnginesCache();
304
327
  await ensurePluginsFolder();
328
+ await ensureNotificationSubscriptions();
305
329
  }
306
330
  process.on("unhandledRejection", (reason, p) => {
307
331
  console.error(reason, "Unhandled Rejection at Promise");
@@ -594,10 +618,9 @@ const setupSocket = (subdomainOffset, pruneSessionInterval, ...servers) => {
594
618
  "joined_real_time_socket_ids"
595
619
  );
596
620
  socketIds.push(socket.id);
597
- await getState().setConfig(
598
- "joined_real_time_socket_ids",
599
- [...socketIds]
600
- );
621
+ await getState().setConfig("joined_real_time_socket_ids", [
622
+ ...socketIds,
623
+ ]);
601
624
  if (typeof callback === "function") callback({ status: "ok" });
602
625
  } catch (err) {
603
626
  getState().log(1, `Socket join_collab_room: ${err.stack}`);