@saltcorn/server 1.6.0-alpha.0 → 1.6.0-alpha.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.
- package/CHANGELOG.md +37 -0
- package/app.js +13 -9
- package/auth/admin.js +30 -15
- package/auth/routes.js +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/assets/style.css +3 -3
- package/docs/classes/_saltcorn_admin-models.models_snapshot.Snapshot.html +2 -2
- package/docs/classes/_saltcorn_common-code.relations_relation.Relation.html +3 -3
- package/docs/classes/_saltcorn_common-code.relations_relations_finder.RelationsFinder.html +5 -5
- package/docs/classes/_saltcorn_data.diagram_cy_raster.CytoscapeRaster.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_dummy_node.DummyNode.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_node.Node.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_page_node.PageNode.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_table_node.TableNode.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_trigger_node.TriggerNode.html +4 -4
- package/docs/classes/_saltcorn_data.diagram_nodes_view_node.ViewNode.html +4 -4
- package/docs/classes/_saltcorn_data.mobile-mocks_node_async_hooks.AsyncLocalStorage.html +2 -2
- package/docs/classes/_saltcorn_data.models_crash.Crash.html +2 -2
- package/docs/classes/_saltcorn_data.models_eventlog.EventLog.html +2 -2
- package/docs/classes/_saltcorn_data.models_field.Field.html +9 -9
- package/docs/classes/_saltcorn_data.models_fieldrepeat.FieldRepeat.html +2 -2
- package/docs/classes/_saltcorn_data.models_file.File.html +21 -21
- package/docs/classes/_saltcorn_data.models_form.Form.html +3 -2
- package/docs/classes/_saltcorn_data.models_internal_mail_queue.MailQueue.html +4 -4
- package/docs/classes/_saltcorn_data.models_internal_push_message_helper.PushMessageHelper.html +16 -9
- package/docs/classes/_saltcorn_data.models_library.Library.html +2 -2
- package/docs/classes/_saltcorn_data.models_model.Model.html +2 -2
- package/docs/classes/_saltcorn_data.models_model_instance.ModelInstance.html +2 -2
- package/docs/classes/_saltcorn_data.models_notification.Notification.html +2 -2
- package/docs/classes/_saltcorn_data.models_page.Page.html +11 -11
- package/docs/classes/_saltcorn_data.models_page_group.PageGroup.html +16 -16
- package/docs/classes/_saltcorn_data.models_page_group_member.PageGroupMember.html +8 -8
- package/docs/classes/_saltcorn_data.models_plugin.Plugin.html +13 -10
- package/docs/classes/_saltcorn_data.models_role.Role.html +2 -2
- package/docs/classes/_saltcorn_data.models_table.Table.html +73 -69
- package/docs/classes/_saltcorn_data.models_table_constraints.TableConstraint.html +2 -2
- package/docs/classes/_saltcorn_data.models_tag.Tag.html +2 -2
- package/docs/classes/_saltcorn_data.models_tag_entry.TagEntry.html +2 -2
- package/docs/classes/_saltcorn_data.models_trigger.Trigger.html +19 -19
- package/docs/classes/_saltcorn_data.models_user.User.html +32 -32
- package/docs/classes/_saltcorn_data.models_view.View.html +15 -15
- package/docs/classes/_saltcorn_data.models_workflow.Workflow.html +2 -2
- package/docs/classes/_saltcorn_data.models_workflow_run.WorkflowRun.html +2 -2
- package/docs/classes/_saltcorn_data.models_workflow_step.WorkflowStep.html +3 -2
- package/docs/classes/_saltcorn_data.models_workflow_trace.MetaData.html +2 -2
- package/docs/classes/_saltcorn_data.models_workflow_trace.WorkflowTrace.html +2 -2
- package/docs/classes/_saltcorn_mobile-builder.mobile-builder.MobileBuilder.html +8 -3
- package/docs/classes/_saltcorn_mobile-builder.utils_capacitor-helper.CapacitorHelper.html +2 -2
- package/docs/enums/_saltcorn_common-code.relations_relation_types.RelationType.html +2 -2
- package/docs/enums/_saltcorn_common-code.relations_relation_types.ViewDisplayType.html +2 -2
- package/docs/functions/_saltcorn_admin-models.models_config-check.runConfigurationCheck.html +1 -1
- package/docs/functions/_saltcorn_common-code.relations_relation_helpers.buildRelationPath.html +1 -1
- package/docs/functions/_saltcorn_common-code.relations_relation_helpers.buildTableCaches.html +1 -1
- package/docs/functions/_saltcorn_common-code.relations_relation_helpers.parseLegacyRelation.html +1 -1
- package/docs/functions/_saltcorn_common-code.relations_relation_helpers.parseRelationPath.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.fixturesData.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withAnotherUserField.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withKeyFromLayerThree.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withKeyFromLayerTwo.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withMultipleInbounds.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withSecondTopicField.html +1 -1
- package/docs/functions/_saltcorn_common-code.tests_test_data.withSimplePostTopicrelation.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.action_link.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.action_url.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.fill_presets.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.getForm.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.get_view_link_query.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.get_viewable_fields.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.get_viewable_fields_from_layout.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.make_link.html +2 -2
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.objToQueryString.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.parse_view_select.html +3 -3
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.setDateLocales.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.splitUniques.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.standardBlockDispatch.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.standardLayoutRowVisitor.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.transformForm.html +1 -1
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.updateViewSelect.html +2 -2
- package/docs/functions/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.view_linker.html +2 -2
- package/docs/functions/_saltcorn_data.db_connect_mobile.getConnectObject.html +1 -1
- package/docs/functions/_saltcorn_data.db_reset_schema.reset.html +3 -3
- package/docs/functions/_saltcorn_data.diagram_cy_generate_utils.generateCyCode.html +1 -1
- package/docs/functions/_saltcorn_data.diagram_cy_generate_utils.genereateCyCfg.html +1 -1
- package/docs/functions/_saltcorn_data.diagram_node_extract_utils.buildObjectTrees.html +1 -1
- package/docs/functions/_saltcorn_data.diagram_node_extract_utils.extractFromColumns.html +1 -1
- package/docs/functions/_saltcorn_data.diagram_node_extract_utils.extractFromLayout.html +1 -1
- package/docs/functions/_saltcorn_data.diagram_node_extract_utils.extractViewToCreate.html +1 -1
- package/docs/functions/_saltcorn_data.migrate.create_blank_migration.html +1 -1
- package/docs/functions/_saltcorn_data.migrate.getMigrationsInDB.html +1 -1
- package/docs/functions/_saltcorn_data.migrate.migrate.html +3 -3
- package/docs/functions/_saltcorn_data.migrations_202102091312.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202210051058.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202210101540.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202304281224.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202307211459.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202502131103.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202508011455.js.html +1 -1
- package/docs/functions/_saltcorn_data.migrations_202510152058.js.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_child_process.execSync.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs.createReadStream.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs.readdirSync.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs.writeFileSync.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs_promises.mkdir.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs_promises.readFile.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs_promises.stat.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs_promises.unlink.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_fs_promises.writeFile.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_latest-version.latestVersion.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_v8.deserialize.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_node_v8.serialize.html +1 -1
- package/docs/functions/_saltcorn_data.mobile-mocks_npm_env-paths.envPaths.html +1 -1
- package/docs/functions/_saltcorn_data.model-helper.get_predictor.html +1 -1
- package/docs/functions/_saltcorn_data.model-helper.run_jupyter_model.html +1 -1
- package/docs/functions/_saltcorn_data.model-helper.shorten_trackback.html +1 -1
- package/docs/functions/_saltcorn_data.model-helper.write_csv.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_async_json_stream.async_json_stream.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_query.aggregation_query_fields.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_query.getAggAndField.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_query.joinfield_renamer.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_query.process_aggregations.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.buildKeyFromRelative.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.copyObject.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.deleteObject.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.downloadBuffer.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.getPublicFileUrl.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.getResolvedBucket.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.getS3Client.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.getServeUrl.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.getSignedFileUrl.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.headObject.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.isS3Enabled.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.listS3Folder.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.publicUrlToRelativePath.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.relativeKeyToPath.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.setObjectMetadata.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_s3_helpers.uploadBuffer.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.boolExamples.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.colorExamples.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.floatExamples.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.get_formula_examples.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.intExamples.html +1 -1
- package/docs/functions/_saltcorn_data.models_internal_table_helper.stringExamples.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.build_schema_data.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.calcfldViewConfig.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.calcfldViewOptions.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.calcrelViewOptions.html +5 -5
- package/docs/functions/_saltcorn_data.plugin-helper.displayType.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.field_picker_fields.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.generate_joined_query.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.getActionConfigFields.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.get_child_views.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.get_inbound_relation_opts.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.get_inbound_self_relation_opts.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.get_link_view_opts.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.get_many_to_many_relation_opts.html +4 -4
- package/docs/functions/_saltcorn_data.plugin-helper.get_parent_views.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.initial_config_all_fields.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.json_list_to_external_table.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.link_view.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.pathToState.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.picked_fields_to_query.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.readState.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.readStateStrict.html +3 -3
- package/docs/functions/_saltcorn_data.plugin-helper.runCollabEvents.html +4 -4
- package/docs/functions/_saltcorn_data.plugin-helper.run_action_column.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.stateFieldsToQuery.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-helper.stateFieldsToWhere.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.stateToQueryString.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-helper.strictParseInt.html +2 -2
- package/docs/functions/_saltcorn_data.plugin-testing.auto_test_plugin.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-testing.check_view_columns.html +1 -1
- package/docs/functions/_saltcorn_data.plugin-testing.generate_attributes.html +1 -1
- package/docs/functions/_saltcorn_data.standard-menu.create_standard_menu.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertIsErrorMsg.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertIsErrorsMsg.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertIsRow.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertIsSet.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertIsType.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertsIsSuccessMessage.html +1 -1
- package/docs/functions/_saltcorn_data.tests_assertions.assertsObjectIsUser.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.createAnotherUserField.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.createKeyFromLevelTwo.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.createLevelThreeInbound.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.createMultipleInbounds.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.createSecondTopicField.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.prepareEmployeeDepartment.html +1 -1
- package/docs/functions/_saltcorn_data.tests_common_helpers.prepareSimpleTopicPostRelation.html +1 -1
- package/docs/functions/_saltcorn_data.tests_remote_query_helper.deleteViewFromServer.html +1 -1
- package/docs/functions/_saltcorn_data.tests_remote_query_helper.prepareQueryEnviroment.html +1 -1
- package/docs/functions/_saltcorn_data.tests_remote_query_helper.sendViewToServer.html +1 -1
- package/docs/functions/_saltcorn_data.translate.hasLLM.html +1 -1
- package/docs/functions/_saltcorn_data.translate.translate.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.ftsFieldsSqlExpr.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.mkSelectOptions.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.mkWhere.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.orderByIsObject.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.orderByIsOperator.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.prefixFieldsInWhere.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.sqlBinOp.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.sqlFun.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.sqlsanitize.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.sqlsanitizeAllowDots.html +1 -1
- package/docs/functions/_saltcorn_db-common.internal.subSelectWhere.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.enable_multi_tenant.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.getRequestContext.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.getTenantSchema.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.init.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.is_it_multi_tenant.html +1 -1
- package/docs/functions/_saltcorn_db-common.multi-tenant.runWithTenant.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.buildInsertBulkSql.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.buildInsertSql.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.commitAndBeginNewTransaction.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.doCount.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.doDeleteWhere.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.doListScTables.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.doListTables.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.doListUserDefinedTables.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.do_add_index.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.do_drop_index.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.mkVal.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.openOrUseTransaction.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.reprAsJson.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.slugify.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.tryCatchInTransaction.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.whenTransactionisFree.html +1 -1
- package/docs/functions/_saltcorn_db-common.sqlite-commons.withTransaction.html +1 -1
- package/docs/functions/_saltcorn_markup.mktag.mkTag.html +1 -1
- package/docs/functions/_saltcorn_markup.tabs.tabs.html +1 -1
- package/docs/functions/_saltcorn_markup.workflow.renderWorkflow.html +2 -0
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.androidFeatures.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.androidPermissions.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.buildTablesFile.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.copyPrepopulatedDb.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.copyServerFiles.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.copyShareExtFiles.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.copySiteLogo.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.copyTranslationFiles.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.createSqliteDb.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.extractDomain.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.generateAndroidVersionCode.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.hasAuthMethod.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyAndroidManifest.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyAppDelegate.html +1 -0
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyConfigXml.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyGradleConfig.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyInfoPlist.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyShareViewController.html +1 -0
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.modifyXcodeProjectFile.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepAppIcon.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepareAppIcon.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepareBuildDir.html +5 -3
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepareExportOptionsPlist.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepareSplashIcon.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.prepareSplashPage.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.runAddEntitlementsScript.html +1 -0
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writeCapacitorConfig.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writeCfgFile.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writeDataExtractionRules.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writeEntitlementsPlist.html +1 -0
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writeNetworkSecurityConfig.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writePodfile.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.writePrivacyInfo.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.bundleMobileAppCode.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.bundlePackagesAndPlugins.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.copyOptionalSource.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.copyPluginMobileAppDirs.html +1 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.copyPublicDirs.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.add_index.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.add_unique_constraint.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.count.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.deleteWhere.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.drop_index.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.drop_reset_schema.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.drop_unique_constraint.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.init.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.insert.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.insertRows.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.listScTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.listTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.listUserDefinedTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.query.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.select.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.selectMaybeOne.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.selectOne.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.setConnectionObject.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.tableExists.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.time.html +1 -1
- package/docs/functions/_saltcorn_sqlite-mobile.sqlite_capacitor.update.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.add_index.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.add_unique_constraint.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.begin.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.changeConnection.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.close.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.commit.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.count.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.deleteWhere.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.dropTable.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.dropTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.drop_index.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.drop_reset_schema.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.drop_unique_constraint.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.getVersion.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.get_db_filepath.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.get_sql_logging.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.init.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.insert.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.listScTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.listTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.listUserDefinedTables.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.query.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.rollback.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.select.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.selectMaybeOne.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.selectOne.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.set_sql_logging.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.sql_log.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.update.html +1 -1
- package/docs/functions/_saltcorn_sqlite.sqlite.updateWhere.html +1 -1
- package/docs/functions/_saltcorn_types.base_types.instanceOWithHtmlFile.html +1 -1
- package/docs/functions/_saltcorn_types.base_types.instanceOfFieldViewEdit.html +1 -0
- package/docs/functions/_saltcorn_types.base_types.instanceOfFieldViewShow.html +1 -0
- package/docs/functions/_saltcorn_types.base_types.instanceOfPack.html +1 -0
- package/docs/functions/_saltcorn_types.common_types.instanceOfErrorMsg.html +1 -1
- package/docs/functions/_saltcorn_types.common_types.instanceOfSuccessMsg.html +1 -1
- package/docs/functions/_saltcorn_types.common_types.instanceOfType.html +1 -1
- package/docs/functions/_saltcorn_types.model-abstracts_abstract_field.instanceOfField.html +1 -1
- package/docs/functions/_saltcorn_types.model-abstracts_abstract_page.instanceOfPage.html +1 -1
- package/docs/functions/_saltcorn_types.model-abstracts_abstract_plugin.instanceOfPlugin.html +1 -0
- package/docs/functions/_saltcorn_types.model-abstracts_abstract_table.instanceOfTable.html +1 -0
- package/docs/functions/_saltcorn_types.model-abstracts_abstract_view.instanceOfView.html +1 -1
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +4 -2
- package/docs/interfaces/_saltcorn_db-common.dbtypes.UserLike.html +2 -2
- package/docs/interfaces/_saltcorn_markup.types.TagExports.html +2 -2
- package/docs/interfaces/_saltcorn_mobile-builder.utils_common-build-utils.ScCapacitorConfig.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_field.AbstractField.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_field.AbstractFieldRepeat.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_form.AbstractForm.html +3 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_page.AbstractPage.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_page_group.AbstractPageGroup.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_page_group_member.AbstractPageGroupMember.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_plugin.AbstractPlugin.html +13 -0
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_role.AbstractRole.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_table.AbstractTable.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_tag.AbstractTag.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_tag_entry.AbstractTagEntry.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_trigger.AbstractTrigger.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_user.AbstractUser.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_user.ForUserRequest.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_view.AbstractView.html +2 -2
- package/docs/interfaces/_saltcorn_types.model-abstracts_abstract_workflow.AbstractWorkflow.html +2 -2
- package/docs/modules/_saltcorn_admin-models.index.html +1 -1
- package/docs/modules/_saltcorn_common-code..html +1 -1
- package/docs/modules/_saltcorn_common-code.index.html +1 -1
- package/docs/modules/_saltcorn_common-code.relations_relation-1.html +1 -1
- package/docs/modules/_saltcorn_common-code.relations_relation_helpers-1.html +1 -1
- package/docs/modules/_saltcorn_common-code.relations_relation_types-1.html +1 -1
- package/docs/modules/_saltcorn_common-code.relations_relations_finder-1.html +1 -1
- package/docs/modules/_saltcorn_data..html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_actions-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_fileview-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_fileview.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_index-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_index-2.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_types-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_types.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_edit-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_feed-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_filter-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_list-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_listshowlist-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_room-2.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_room-3.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_show-1.html +1 -1
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_viewable_fields-1.html +1 -2
- package/docs/modules/_saltcorn_data.base-plugin_viewtemplates_viewable_fields-2.html +1 -0
- package/docs/modules/_saltcorn_data.contract.html +1 -1
- package/docs/modules/_saltcorn_data.db_connect-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_connect_mobile-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_fa5-icons-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_fixtures-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_index-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_index-2.html +1 -1
- package/docs/modules/_saltcorn_data.db_reset_schema-1.html +1 -1
- package/docs/modules/_saltcorn_data.db_state-1.html +1 -1
- package/docs/modules/_saltcorn_data.html +3 -2
- package/docs/modules/_saltcorn_data.index.html +1 -1
- package/docs/modules/{_saltcorn_data.tests_exact_views.test.html → _saltcorn_data.mobile-mocks_npm_apns2.html} +1 -1
- package/docs/modules/_saltcorn_data.mobile-mocks_npm_vm2.html +1 -0
- package/docs/modules/{_saltcorn_data.tests_workflow_run.test.html → _saltcorn_data.mobile-mocks_npm_xml2js.html} +1 -1
- package/docs/modules/_saltcorn_data.model-helper.html +2 -1
- package/docs/modules/_saltcorn_data.models_config-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_config.configExports.html +1 -1
- package/docs/modules/_saltcorn_data.models_crash-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_discovery-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_email-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_eventlog-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_eventlog.EventLog.html +1 -1
- package/docs/modules/_saltcorn_data.models_expression-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_field-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_fieldrepeat-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_file-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_file.File.html +1 -1
- package/docs/modules/_saltcorn_data.models_form-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_form.Form.html +1 -1
- package/docs/modules/_saltcorn_data.models_index-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_index.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_async_json_stream-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_mail_queue-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_push_message_helper-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_push_message_helper.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_query-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_s3_helpers-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_internal_table_helper-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_layout-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_library-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_model-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_model_instance-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_notification-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_page-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_page_group-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_page_group.PageGroup.html +1 -1
- package/docs/modules/_saltcorn_data.models_page_group_member-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_plugin-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_random-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_role-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_scheduler-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_table-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_table.Table.html +1 -1
- package/docs/modules/_saltcorn_data.models_table_constraints-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_tag-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_tag_entry-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_tag_entry.TagEntry.html +1 -1
- package/docs/modules/_saltcorn_data.models_trigger-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_user-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_view-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_view.View.html +1 -1
- package/docs/modules/_saltcorn_data.models_workflow-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_workflow_run-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_workflow_step-1.html +1 -1
- package/docs/modules/_saltcorn_data.models_workflow_trace-2.html +1 -1
- package/docs/modules/_saltcorn_data.models_workflow_trace-3.html +1 -1
- package/docs/modules/_saltcorn_data.standard-menu.html +2 -1
- package/docs/modules/_saltcorn_db-common..html +1 -1
- package/docs/modules/_saltcorn_db-common.index.html +1 -1
- package/docs/modules/_saltcorn_db-common.internal.html +1 -1
- package/docs/modules/_saltcorn_markup.emergency_layout.EmergencyLayoutExports.html +1 -1
- package/docs/modules/_saltcorn_markup.helpers.HelpersExports.html +1 -1
- package/docs/modules/_saltcorn_markup.html +1 -1
- package/docs/modules/_saltcorn_markup.index.html +1 -1
- package/docs/modules/_saltcorn_markup.layout.LayoutExports-1.html +1 -1
- package/docs/modules/_saltcorn_markup.layout.LayoutExports.html +1 -1
- package/docs/modules/_saltcorn_markup.mjml-layout.LayoutExports.html +1 -1
- package/docs/modules/_saltcorn_markup.table.TableExports.html +1 -1
- package/docs/{variables/_saltcorn_data.base-plugin_types.float.sql_name.html → modules/_saltcorn_markup.workflow.html} +1 -1
- package/docs/modules/_saltcorn_mobile-builder..html +1 -1
- package/docs/modules/_saltcorn_mobile-builder.index.html +1 -1
- package/docs/modules/_saltcorn_mobile-builder.utils_common-build-utils.html +1 -1
- package/docs/modules/_saltcorn_sqlite-mobile.index.html +1 -1
- package/docs/modules/_saltcorn_sqlite-mobile.sqlite_capacitor.html +1 -1
- package/docs/modules/_saltcorn_sqlite..html +1 -1
- package/docs/modules/_saltcorn_sqlite.index.html +1 -1
- package/docs/modules/_saltcorn_sqlite.sqlite.html +1 -1
- package/docs/modules/_saltcorn_types..Types.html +1 -1
- package/docs/modules/_saltcorn_types..html +1 -1
- package/docs/modules/_saltcorn_types.base_types.html +1 -1
- package/docs/modules/_saltcorn_types.index.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_event_log-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_field-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_form-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_library-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_model-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_model_instance-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_page-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_page_group-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_page_group_member-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_plugin-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_plugin.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_role-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_table-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_table.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_tag-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_tag_entry-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_trigger-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_user-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_view-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_workflow-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_workflow_run-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_workflow_step-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_abstract_workflow_trace-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_index-1.html +1 -1
- package/docs/modules/_saltcorn_types.model-abstracts_index.ModelAbstracts.html +1 -1
- package/docs/types/_saltcorn_data.diagram_node_extract_utils.ExtractOpts.html +2 -2
- package/docs/types/_saltcorn_data.diagram_node_extract_utils.ExtractResult.html +2 -2
- package/docs/types/_saltcorn_data.diagram_nodes_node.NodeType.html +1 -1
- package/docs/types/_saltcorn_data.models_config.ConfigTypes.html +1 -1
- package/docs/types/_saltcorn_data.models_config.SingleConfig.html +1 -1
- package/docs/types/_saltcorn_data.models_eventlog.EventLogCfg.html +2 -2
- package/docs/types/_saltcorn_data.models_file.FileCfg.html +2 -2
- package/docs/types/_saltcorn_data.models_form.AdditionalButton.html +1 -1
- package/docs/types/_saltcorn_data.models_form.FormCfg.html +3 -2
- package/docs/types/_saltcorn_data.models_internal_push_message_helper.MobileSubscription.html +4 -0
- package/docs/types/_saltcorn_data.models_internal_push_message_helper.WebPushSubscription.html +2 -2
- package/docs/types/_saltcorn_data.models_internal_s3_helpers.S3HeadResult.html +1 -1
- package/docs/types/_saltcorn_data.models_internal_s3_helpers.S3ListResult.html +2 -2
- package/docs/types/_saltcorn_data.models_page_group.ScreenInfoParams.html +2 -2
- package/docs/types/_saltcorn_data.models_table.ChildRelations.html +2 -2
- package/docs/types/_saltcorn_data.models_table.ParentRelations.html +2 -2
- package/docs/types/_saltcorn_data.models_table.RelationData.html +2 -2
- package/docs/types/_saltcorn_data.models_tag_entry.TagEntryCfg.html +1 -1
- package/docs/types/_saltcorn_data.models_view.FindViewsPred.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.AggregationOptions.html +2 -2
- package/docs/types/_saltcorn_db-common.dbtypes.CoordOpts.html +2 -2
- package/docs/types/_saltcorn_db-common.dbtypes.DatabaseClient.html +2 -2
- package/docs/types/_saltcorn_db-common.dbtypes.JoinField.html +2 -2
- package/docs/types/_saltcorn_db-common.dbtypes.JoinFields.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.JoinOptions.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.JsonPath.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.JsonPathElem.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.Operator.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.PartialSome.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.PrimaryKeyValue.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.Row.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.SelectOptions.html +4 -2
- package/docs/types/_saltcorn_db-common.dbtypes.StrongRow.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.SubselectOptions.html +2 -2
- package/docs/types/_saltcorn_db-common.dbtypes.Value.html +1 -1
- package/docs/types/_saltcorn_db-common.dbtypes.Where.html +2 -2
- package/docs/types/_saltcorn_db-common.sqlite-commons.SqlAndValues.html +2 -2
- package/docs/types/_saltcorn_db-common.types.DbExportsType.html +2 -2
- package/docs/types/_saltcorn_db-common.types.GenObj.html +1 -1
- package/docs/types/_saltcorn_markup.emergency_layout.WrapParams.html +2 -2
- package/docs/types/_saltcorn_markup.helpers.CheckBoxGroupOpts.html +2 -2
- package/docs/types/_saltcorn_markup.helpers.PaginationOpts.html +2 -2
- package/docs/types/_saltcorn_markup.helpers.RadioGroupOpts.html +2 -2
- package/docs/types/_saltcorn_markup.helpers.SearchBarOpts.html +2 -2
- package/docs/types/_saltcorn_markup.layout.RenderOpts-1.html +2 -2
- package/docs/types/_saltcorn_markup.layout.RenderOpts.html +2 -2
- package/docs/types/_saltcorn_markup.mjml-layout.RenderOpts.html +2 -2
- package/docs/types/_saltcorn_markup.table.HeadersParams.html +2 -2
- package/docs/types/_saltcorn_markup.table.OptsParams.html +3 -2
- package/docs/types/_saltcorn_markup.types.AttributeVal.html +1 -1
- package/docs/types/_saltcorn_markup.types.Attributes.html +2 -2
- package/docs/types/_saltcorn_markup.types.ClassVal.html +1 -1
- package/docs/types/_saltcorn_markup.types.Element.html +1 -1
- package/docs/types/_saltcorn_markup.types.Falsy.html +1 -1
- package/docs/types/_saltcorn_markup.types.StyleVal.html +1 -1
- package/docs/types/_saltcorn_markup.types.TagFunction.html +1 -1
- package/docs/types/_saltcorn_mobile-builder.mobile-builder.IosCfg.html +4 -3
- package/docs/types/_saltcorn_mobile-builder.utils_capacitor-helper.CapacitorCfg.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Action.html +3 -3
- package/docs/types/_saltcorn_types.base_types.AuthenticationMethod.html +2 -2
- package/docs/types/_saltcorn_types.base_types.CalcJoinfield.html +2 -2
- package/docs/types/_saltcorn_types.base_types.CapacitorPlugin.html +2 -2
- package/docs/types/_saltcorn_types.base_types.CodePagePack.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Column.html +16 -2
- package/docs/types/_saltcorn_types.base_types.ConnectObjType.html +2 -2
- package/docs/types/_saltcorn_types.base_types.ConnectedObjects.html +2 -2
- package/docs/types/_saltcorn_types.base_types.CopilotSkill.html +2 -2
- package/docs/types/_saltcorn_types.base_types.ErrorObj.html +2 -2
- package/docs/types/_saltcorn_types.base_types.FieldLike.html +1 -1
- package/docs/types/_saltcorn_types.base_types.FieldView.html +1 -1
- package/docs/types/_saltcorn_types.base_types.Header.html +2 -2
- package/docs/types/_saltcorn_types.base_types.JoinFieldOption.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Layout.html +1 -1
- package/docs/types/_saltcorn_types.base_types.MenuItem.html +22 -0
- package/docs/types/_saltcorn_types.base_types.MobileConfig.html +3 -2
- package/docs/types/_saltcorn_types.base_types.ModelPattern.html +6 -6
- package/docs/types/_saltcorn_types.base_types.Pack.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Plugin.html +1 -1
- package/docs/types/_saltcorn_types.base_types.PluginFunction.html +2 -2
- package/docs/types/_saltcorn_types.base_types.PluginLayout.html +2 -2
- package/docs/types/_saltcorn_types.base_types.PluginRoute.html +2 -2
- package/docs/types/_saltcorn_types.base_types.PluginSourceType.html +1 -1
- package/docs/types/_saltcorn_types.base_types.PluginType.html +5 -2
- package/docs/types/_saltcorn_types.base_types.PluginWrap.html +1 -1
- package/docs/types/_saltcorn_types.base_types.PluginWrapArg.html +2 -2
- package/docs/types/_saltcorn_types.base_types.RelationOption.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Req.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Res.html +2 -2
- package/docs/types/_saltcorn_types.base_types.ResultType.html +2 -2
- package/docs/types/_saltcorn_types.base_types.RouteAction.html +1 -1
- package/docs/types/_saltcorn_types.base_types.RunExtra.html +1 -1
- package/docs/types/_saltcorn_types.base_types.SlugStepType.html +2 -2
- package/docs/types/_saltcorn_types.base_types.StepResType.html +1 -1
- package/docs/types/_saltcorn_types.base_types.SubField.html +2 -2
- package/docs/types/_saltcorn_types.base_types.TableProvider.html +2 -2
- package/docs/types/_saltcorn_types.base_types.TableQuery.html +2 -2
- package/docs/types/_saltcorn_types.base_types.Tablely.html +1 -1
- package/docs/types/_saltcorn_types.base_types.ViewTemplate.html +3 -2
- package/docs/types/_saltcorn_types.common_types.ErrorMessage.html +2 -2
- package/docs/types/_saltcorn_types.common_types.GenObj.html +1 -1
- package/docs/types/_saltcorn_types.common_types.ReqRes.html +2 -2
- package/docs/types/_saltcorn_types.common_types.ResultMessage.html +1 -1
- package/docs/types/_saltcorn_types.common_types.SuccessMessage.html +2 -2
- package/docs/types/_saltcorn_types.common_types.Type.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_event_log.EventLogPack.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_field.FieldCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_field.InputType.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_form.AdditionalButton.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_library.LibraryCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_library.LibraryPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_model.ModelCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_model.ModelPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_model_instance.ModelInstanceCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_model_instance.ModelInstancePack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page.PageCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page.PagePack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page_group.PageGroupCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page_group.PageGroupPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page_group_member.PageGroupMemberCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_page_group_member.PageGroupMemberPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_plugin.PluginCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_plugin.PluginPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_role.RoleCfg.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_role.RolePack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_table.TableCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_table.TablePack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_tag.TagPack.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_tag_entry.TagEntryPack.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_trigger.TriggerCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_trigger.TriggerPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_view.ViewCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_view.ViewPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow.ConfigWorkflowStep.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow.RunResult.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow_run.WorkflowRunCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow_step.WorkflowStepCfg.html +2 -2
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow_step.WorkflowStepPack.html +1 -1
- package/docs/types/_saltcorn_types.model-abstracts_abstract_workflow_trace.WorkflowTraceCfg.html +2 -2
- package/docs/variables/_saltcorn_admin-models..backup.create_backup.html +1 -1
- package/docs/variables/_saltcorn_admin-models..backup.create_csv_from_rows.html +1 -1
- package/docs/variables/_saltcorn_admin-models..backup.restore.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.add_to_menu.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.can_install_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.fetch_available_packs.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.fetch_pack_by_name.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.install_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.library_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.model_instance_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.model_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.page_group_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.page_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.plugin_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.role_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.table_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.trigger_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.uninstall_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..pack.view_pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.copy_tenant_template.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.create_tenant.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.deleteTenant.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.domain_sanitize.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.eachTenant.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.getAllTenantRows.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.getAllTenants.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.insertTenant.html +1 -1
- package/docs/variables/_saltcorn_admin-models..tenant.switchToTenant.html +1 -1
- package/docs/variables/_saltcorn_admin-models.models_backup.backup.html +1 -1
- package/docs/variables/_saltcorn_admin-models.pack.pack.html +1 -1
- package/docs/variables/_saltcorn_admin-models.tenant.tenant.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedFive.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedFour.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedOne.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedSix.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedThree.html +1 -1
- package/docs/variables/_saltcorn_common-code.tests_expected_relations.expectedTwo.html +1 -1
- package/docs/variables/_saltcorn_data..migrations.html +1 -1
- package/docs/variables/_saltcorn_data..plugin_helper.run_action_column.html +2 -1
- package/docs/variables/_saltcorn_data..utils.NotAuthorized.html +1 -1
- package/docs/variables/_saltcorn_data..utils.isPushEnabled.html +1 -1
- package/docs/variables/_saltcorn_data..utils.sleep.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_actions.actions.html +18 -18
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.fieldviews.html +5 -0
- package/docs/variables/_saltcorn_data.base-plugin_fileview.fileviews.html +1 -0
- package/docs/variables/_saltcorn_data.base-plugin_index.index.html +22 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.types.html +50 -0
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_edit.edit.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_feed.feed.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_filter.filter.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_list.list.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_listshowlist.listshowlist.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_room.room-1.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_room.room.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_show.show.html +1 -1
- package/docs/variables/_saltcorn_data.base-plugin_viewtemplates_viewable_fields.edit_build_in_actions.html +1 -1
- package/docs/variables/_saltcorn_data.contract.contract.html +1 -0
- package/docs/variables/_saltcorn_data.db_connect.connect.html +1 -1
- package/docs/variables/_saltcorn_data.db_fa5-icons.fa5Icons.html +1 -1
- package/docs/variables/_saltcorn_data.db_fixtures.fixtures.html +1 -1
- package/docs/variables/_saltcorn_data.db_index.dbExports.html +1 -1
- package/docs/variables/_saltcorn_data.db_state.state.html +3 -3
- package/docs/variables/_saltcorn_data.migrations_202005141503.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202005241712.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202005251037.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202005282134.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202006022156.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202006051507.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202006240906.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202007091707.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202007202144.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202008031500.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202008051415.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202008121149.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202008121149.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009112140.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009112140.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009181655.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009221105.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009231331.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202009301531.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202010231444.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202010251412.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202011021749.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202011051353.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202011111127.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202012011203.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202012100841.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202012281835.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202101061051.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202101141128.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202102091312.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202102101624.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202102172148.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202102261650.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106102347.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106112120.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106120012.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106120220.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106121701.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106121703.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106121703.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202106251126.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202107281619.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202107302158.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202107302158.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202108022257.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202109201624.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202109301031.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202109301031.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202111290253.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202111290253.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202112282254.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202112282254.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202207022002.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202207252150.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202207252150.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202207261221.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202208101144.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202208101144.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202211040031.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202212112152.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202212112152.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202301130917.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202303201126.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202303201126.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202303221944.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202303221944.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202304281224.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202305031518.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202305031518.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202308211648.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202311011755.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202311011755.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202311231356.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202402071125.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202406260915.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202412051957.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202412051957.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202412111526.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202412111526.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202501081226.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202501081226.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202501201239.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202501262157.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202503071353.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202506050958.sql.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202510110312.sql_pg.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202510110312.sql_sqlite.html +1 -1
- package/docs/variables/_saltcorn_data.migrations_202511081024.sql.html +1 -1
- package/docs/variables/_saltcorn_data.mobile-mocks_saltcorn_html-pdf-node.htmlPdfNode.html +1 -1
- package/docs/variables/_saltcorn_data.models_config.configExports.html +2 -2
- package/docs/variables/_saltcorn_data.models_discovery.discovery.html +1 -1
- package/docs/variables/_saltcorn_data.models_email.email.html +1 -1
- package/docs/variables/_saltcorn_data.models_expression.expression.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.available_languages.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.check_email_mask.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.configTypes.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.deleteConfig.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.getAllConfig.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.getConfig.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.get_base_url.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.get_latest_npm_version.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.remove_from_menu.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.save_menu_items.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.config.setConfig.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.discovery.discover_tables.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.discovery.discoverable_tables.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.discovery.findType.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.discovery.get_existing_views.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.discovery.implement_discovery.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.email.getMailTransport.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.email.send_verification_email.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.email.viewToEmailHtml.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.apply_calculated_fields.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.apply_calculated_fields_stored.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.eval_expression.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.expressionValidator.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.get_async_expression_function.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.get_expression_function.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.jsexprToWhere.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.recalculate_for_stored.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.expression.transform_for_async.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.eachView.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.getStringsForI18n.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.getViews.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.translateLayout.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.traverse.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.layout.traverseSync.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.random.all_views.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.random.fill_table_row.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.random.initial_view.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.random.random_table.html +1 -1
- package/docs/variables/_saltcorn_data.models_index.scheduler.runScheduler.html +1 -1
- package/docs/variables/_saltcorn_data.models_layout.layout.html +2 -2
- package/docs/variables/_saltcorn_data.models_random.random.html +1 -1
- package/docs/variables/_saltcorn_data.models_scheduler.scheduler.html +1 -1
- package/docs/variables/_saltcorn_data.plugin-helper.add_free_variables_to_joinfields.html +2 -2
- package/docs/variables/_saltcorn_data.plugin-helper.sqlBinOp.html +1 -1
- package/docs/variables/_saltcorn_data.plugin-helper.sqlFun.html +1 -1
- package/docs/variables/_saltcorn_data.tests_mocks.mocks.html +1 -1
- package/docs/variables/_saltcorn_data.tests_remote_query_helper.renderEditInEditConfig.html +1 -1
- package/docs/variables/_saltcorn_data.utils.utils.html +3 -3
- package/docs/variables/_saltcorn_data.web-mobile-commons.webMobileCommons.html +3 -3
- package/docs/variables/_saltcorn_db-common.internal.dbCommonModulePath.html +1 -1
- package/docs/variables/_saltcorn_db-common.multi-tenant.tenantNamespace.html +1 -1
- package/docs/variables/_saltcorn_db-common.tenants.tenants.html +1 -1
- package/docs/variables/_saltcorn_markup..export_.html +3 -2
- package/docs/variables/_saltcorn_markup.builder.builder.html +1 -1
- package/docs/variables/_saltcorn_markup.emergency_layout.EmergencyLayoutExports.html +1 -1
- package/docs/variables/_saltcorn_markup.form.form.html +1 -1
- package/docs/variables/_saltcorn_markup.helpers.HelpersExports.html +1 -1
- package/docs/variables/_saltcorn_markup.layout.LayoutExports-1.html +1 -1
- package/docs/variables/_saltcorn_markup.layout.LayoutExports.html +1 -1
- package/docs/variables/_saltcorn_markup.layout_utils.layoutUtils.html +1 -1
- package/docs/variables/_saltcorn_markup.mjml-layout.LayoutExports.html +1 -1
- package/docs/variables/_saltcorn_markup.mjml-tags.tagsExports.html +1 -1
- package/docs/variables/_saltcorn_markup.table.TableExports.html +1 -1
- package/docs/variables/_saltcorn_markup.tags.tagsExports.html +1 -1
- package/docs/variables/_saltcorn_types..generators.generateBool.html +1 -1
- package/docs/variables/_saltcorn_types..generators.generateString.html +1 -1
- package/docs/variables/_saltcorn_types..generators.num_between.html +1 -1
- package/docs/variables/_saltcorn_types..generators.oneOf.html +1 -1
- package/docs/variables/_saltcorn_types.generators.generators.html +1 -1
- package/help/APN Signing Key.tmd +31 -0
- package/help/Menu item shortcuts.tmd +37 -0
- package/help/Provisioning Profile.tmd +1 -1
- package/help/iOS Build tools.tmd +18 -0
- package/load_plugins.js +25 -8
- package/locales/ar.json +213 -2
- package/locales/bn.json +1521 -2
- package/locales/cs.json +1522 -3
- package/locales/de.json +195 -2
- package/locales/el.json +1792 -273
- package/locales/en.json +322 -2
- package/locales/es.json +194 -1
- package/locales/et.json +1520 -1
- package/locales/fil.json +1793 -0
- package/locales/fr.json +195 -2
- package/locales/id.json +1578 -62
- package/locales/ja.json +1520 -1
- package/locales/ko.json +1793 -0
- package/locales/lt.json +1520 -1
- package/locales/lv.json +1520 -1
- package/locales/ne.json +1520 -1
- package/locales/ro.json +1793 -0
- package/locales/sk.json +1522 -3
- package/locales/sl.json +1520 -1
- package/locales/sr.json +1520 -1
- package/locales/th.json +1793 -274
- package/locales/tr.json +1520 -1
- package/locales/uk.json +214 -3
- package/locales/ur.json +1793 -0
- package/locales/vt.json +1793 -0
- package/package.json +17 -10
- package/public/ios_share_tutorial/01_xcode_open_exisiting.png +0 -0
- package/public/ios_share_tutorial/02_open_xc_ws_file.png +0 -0
- package/public/ios_share_tutorial/03_share_extension_dialog.png +0 -0
- package/public/ios_share_tutorial/04_share_extension_dialog_b.png +0 -0
- package/public/ios_share_tutorial/05_activate.png +0 -0
- package/public/ios_share_tutorial/06_show_new_share_ext_target.png +0 -0
- package/public/ios_share_tutorial/07_convert_to_group.png +0 -0
- package/public/saltcorn-builder.css +232 -0
- package/public/saltcorn-common.js +64 -60
- package/public/saltcorn-mobile.css +5 -0
- package/public/saltcorn.css +12 -1
- package/public/saltcorn.js +83 -38
- package/restart_watcher.js +41 -3
- package/routes/actions.js +407 -92
- package/routes/admin.js +1434 -954
- package/routes/api.js +1 -1
- package/routes/common_lists.js +28 -26
- package/routes/entities.js +2209 -69
- package/routes/files.js +191 -0
- package/routes/menu.js +101 -1
- package/routes/notifications.js +7 -18
- package/routes/packs.js +23 -8
- package/routes/page.js +4 -1
- package/routes/pageedit.js +16 -0
- package/routes/plugins.js +46 -14
- package/routes/registry.js +1 -0
- package/routes/sync.js +3 -1
- package/routes/tables.js +20 -15
- package/routes/utils.js +2 -1
- package/routes/viewedit.js +6 -1
- package/serve.js +96 -25
- package/tests/files.test.js +116 -9
- package/tests/menu.test.js +113 -0
- package/wrapper.js +44 -2
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.radio_select.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.search_or_create.configFields.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.search_or_create.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.select.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.select_from_table.fill_options.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_fieldviews.select_from_table.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.fieldviews.TrueFalse.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.fieldviews.checkboxes.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.fieldviews.edit.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.fieldviews.show.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.fieldviews.tristate.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.listAs.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.readFromDB.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.readFromFormRecord.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.bool.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.color.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.color.fieldviews.edit.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.color.fieldviews.show.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.color.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.color.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.equals.html +0 -3
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.edit.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.format.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.relative.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.show.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.showDay.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.fieldviews.yearsAgo.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.presets.Now.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.date.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.float.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.float.equals.html +0 -3
- package/docs/functions/_saltcorn_data.base-plugin_types.float.fieldviews.edit.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.float.fieldviews.show.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.float.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.float.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.int.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.int.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.int.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.int.validate_attributes.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.attributes.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.contract.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.as_header.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.as_link.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.as_text.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.edit.configFields.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.edit.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.img_from_url.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.password.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.radio_group.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.run.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.presets.IP.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.presets.SessionID.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.read.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.validate.html +0 -1
- package/docs/functions/_saltcorn_data.base-plugin_types.string.validate_attributes.html +0 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_common-build-utils.decodeProvisioningProfile.html +0 -1
- package/docs/functions/_saltcorn_mobile-builder.utils_package-bundle-utils.copyMobileAppDirs.html +0 -1
- package/docs/modules/_saltcorn_admin-models.tests_backup.test.html +0 -1
- package/docs/modules/_saltcorn_admin-models.tests_cfgcheck.test.html +0 -1
- package/docs/modules/_saltcorn_admin-models.tests_pack.test.html +0 -1
- package/docs/modules/_saltcorn_admin-models.tests_random.test.html +0 -1
- package/docs/modules/_saltcorn_admin-models.tests_tenant.test.html +0 -1
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews.radio_select.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews.search_or_create.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews.select.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_fieldviews.select_from_table.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.TrueFalse.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.checkboxes.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.edit.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.show.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.fieldviews.tristate.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.bool.html +0 -3
- package/docs/modules/_saltcorn_data.base-plugin_types.color.fieldviews.edit.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.color.fieldviews.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.color.fieldviews.show.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.color.html +0 -4
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.edit.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.format.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.relative.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.show.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.showDay.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.fieldviews.yearsAgo.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.date.html +0 -3
- package/docs/modules/_saltcorn_data.base-plugin_types.date.presets.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.float.fieldviews.edit.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.float.fieldviews.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.float.fieldviews.show.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.float.html +0 -3
- package/docs/modules/_saltcorn_data.base-plugin_types.int.distance_operators.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.int.html +0 -3
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.as_header.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.as_link.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.as_text.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.edit.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.img_from_url.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.password.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.radio_group.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.html +0 -2
- package/docs/modules/_saltcorn_data.base-plugin_types.string.html +0 -3
- package/docs/modules/_saltcorn_data.base-plugin_types.string.presets.html +0 -2
- package/docs/modules/_saltcorn_data.test-utils_mocks.html +0 -1
- package/docs/modules/_saltcorn_data.tests_actions.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_auth.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_auxtest.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_base.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_calc.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_composite_pk.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_config.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_db.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_discover.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_edit.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_email.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_field.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_fieldviews.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_file.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_filter.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_form.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_list.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_mail_queue.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_models.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_page.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_page_group.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_plugin.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_show.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_state.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_table.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_table_history.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_table_sync_info.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_tag.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_user.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_view.test.html +0 -1
- package/docs/modules/_saltcorn_data.tests_workflow.test.html +0 -1
- package/docs/modules/_saltcorn_mobile-builder.appium_tests_ui.test.html +0 -1
- package/docs/modules/_saltcorn_mobile-builder.tests_versioncode.test.html +0 -1
- package/docs/modules/_saltcorn_mobile-builder.tests_webpack.test.html +0 -1
- package/docs/types/_saltcorn_data.models_internal_push_message_helper.FcmSubscription.html +0 -4
- package/docs/types/_saltcorn_data.models_internal_push_message_helper.Subscription.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.AggregationOptions.html +0 -11
- package/docs/types/_saltcorn_db-common.internal.CoordOpts.html +0 -5
- package/docs/types/_saltcorn_db-common.internal.DatabaseClient.html +0 -2
- package/docs/types/_saltcorn_db-common.internal.JoinField.html +0 -6
- package/docs/types/_saltcorn_db-common.internal.JoinFields.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.JoinOptions.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.JsonPath.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.JsonPathElem.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.Operator.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.PartialSome.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.PrimaryKeyValue.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.Row.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.SelectOptions.html +0 -21
- package/docs/types/_saltcorn_db-common.internal.StrongRow.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.SubselectOptions.html +0 -5
- package/docs/types/_saltcorn_db-common.internal.Value.html +0 -1
- package/docs/types/_saltcorn_db-common.internal.Where.html +0 -5
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.radio_select.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.radio_select.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.radio_select.type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.search_join_field.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.search_or_create.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.search_or_create.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.search_or_create.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.search_or_create.type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select.type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_by_code.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_by_view.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_from_table.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_from_table.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_from_table.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_from_table.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.select_from_table.type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fieldviews.two_level_select.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_fileview.fileview.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.attributes.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.TrueFalse.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.TrueFalse.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.checkboxes.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.checkboxes.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.edit.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.edit.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.edit.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.show.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.show.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.show_with_html.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.switch.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.thumbs_up_down.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.tristate.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.tristate.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.fieldviews.tristate.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.bool.sql_name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.attributes.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.edit.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.edit.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.edit.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.show.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.show.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.fieldviews.show_with_html.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.color.sql_name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.attributes.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.edit.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.edit.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.edit.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.edit.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.editDay.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.format.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.format.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.format.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.relative.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.relative.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.show.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.show.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.showDay.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.showDay.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.show_with_html.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.yearsAgo.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.fieldviews.yearsAgo.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.date.sql_name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.attributes.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.distance_operators.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.above_input.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.below_input.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.edit.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.edit.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.edit.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.edit.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.heat_cell.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.number_slider.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.progress_bar.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.range_interval.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.show.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.show.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.show_with_html.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.fieldviews.to_locale_string.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.float.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.attributes.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.distance_operators.near.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.fieldviews.html +0 -3
- package/docs/variables/_saltcorn_data.base-plugin_types.int.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.primaryKey.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.int.sql_name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_header.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_header.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_link.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_link.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_link.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_text.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.as_text.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.checkbox_group.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.code.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.code_editor.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.edit.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.edit.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.edit.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.ellipsize.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.fill_formula_btn.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.img_from_url.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.img_from_url.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.make_unique.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.monospace_block.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.password.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.password.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.password.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.password.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.preFormatted.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.radio_group.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.radio_group.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.radio_group.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.select_by_code.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.show_with_html.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.blockDisplay.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.configFields.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.description.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.fieldviews.textarea.isEdit.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.js_type.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.name.html +0 -1
- package/docs/variables/_saltcorn_data.base-plugin_types.string.sql_name.html +0 -1
- package/docs/variables/_saltcorn_data.contract.fieldlike.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_column.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_header.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_pack.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_plugin.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_plugin_layout.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_plugin_type.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_plugin_wrap.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_plugin_wrap_arg.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_table_query.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_tablely.html +0 -1
- package/docs/variables/_saltcorn_data.contract.is_viewtemplate.html +0 -1
- package/docs/variables/_saltcorn_data.test-utils_mocks.mocks.html +0 -1
package/routes/entities.js
CHANGED
|
@@ -13,6 +13,8 @@ const Trigger = require("@saltcorn/data/models/trigger");
|
|
|
13
13
|
const Tag = require("@saltcorn/data/models/tag");
|
|
14
14
|
const TagEntry = require("@saltcorn/data/models/tag_entry");
|
|
15
15
|
const User = require("@saltcorn/data/models/user");
|
|
16
|
+
const Role = require("@saltcorn/data/models/role");
|
|
17
|
+
const Plugin = require("@saltcorn/data/models/plugin");
|
|
16
18
|
const db = require("@saltcorn/data/db");
|
|
17
19
|
const { getState } = require("@saltcorn/data/db/state");
|
|
18
20
|
const {
|
|
@@ -31,14 +33,32 @@ const {
|
|
|
31
33
|
tr,
|
|
32
34
|
th,
|
|
33
35
|
td,
|
|
36
|
+
label,
|
|
37
|
+
select,
|
|
38
|
+
option,
|
|
34
39
|
} = require("@saltcorn/markup/tags");
|
|
35
|
-
const {
|
|
40
|
+
const {
|
|
41
|
+
post_dropdown_item,
|
|
42
|
+
settingsDropdown,
|
|
43
|
+
post_btn,
|
|
44
|
+
} = require("@saltcorn/markup");
|
|
36
45
|
const {
|
|
37
46
|
view_dropdown,
|
|
38
47
|
page_dropdown,
|
|
39
48
|
trigger_dropdown,
|
|
40
49
|
} = require("./common_lists.js");
|
|
41
50
|
const { error_catcher, isAdminOrHasConfigMinRole } = require("./utils.js");
|
|
51
|
+
const {
|
|
52
|
+
fetch_pack_by_name,
|
|
53
|
+
fetch_available_packs,
|
|
54
|
+
table_pack,
|
|
55
|
+
view_pack,
|
|
56
|
+
page_pack,
|
|
57
|
+
trigger_pack,
|
|
58
|
+
uninstall_pack,
|
|
59
|
+
plugin_pack,
|
|
60
|
+
} = require("@saltcorn/admin-models/models/pack");
|
|
61
|
+
const { escapeHtml } = require("@saltcorn/data/utils");
|
|
42
62
|
|
|
43
63
|
/**
|
|
44
64
|
* @type {object}
|
|
@@ -54,6 +74,325 @@ module.exports = router;
|
|
|
54
74
|
const stripLeadingSlash = (path = "") =>
|
|
55
75
|
path.startsWith("/") ? path.slice(1) : path;
|
|
56
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Get additional entities (modules, users)
|
|
79
|
+
*/
|
|
80
|
+
const req__ = (req, s) => (req && req.__(s)) || s;
|
|
81
|
+
|
|
82
|
+
const getExtendedEntites = async (req, { includeAllModules = false } = {}) => {
|
|
83
|
+
const entities = [];
|
|
84
|
+
const can_reset = getState().getConfig("smtp_host", "") !== "";
|
|
85
|
+
|
|
86
|
+
const users = await User.find({}, { cached: true });
|
|
87
|
+
users.forEach((u) => {
|
|
88
|
+
entities.push({
|
|
89
|
+
type: "user",
|
|
90
|
+
name: u.email,
|
|
91
|
+
id: u.id,
|
|
92
|
+
viewLink: `/useradmin/${u.id}`,
|
|
93
|
+
editLink: `/useradmin/${u.id}`,
|
|
94
|
+
metadata: {
|
|
95
|
+
email: u.email,
|
|
96
|
+
username: u.username,
|
|
97
|
+
role_id: u.role_id,
|
|
98
|
+
disabled: u.disabled,
|
|
99
|
+
},
|
|
100
|
+
actionsHtml: buildUserActionsDropdown(u, req, can_reset),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const statePlugins = getState().plugins;
|
|
105
|
+
const csrfToken = req?.csrfToken ? req.csrfToken() : null;
|
|
106
|
+
const packs = getState().getConfig("installed_packs", []);
|
|
107
|
+
const installedPackNames = new Set(packs);
|
|
108
|
+
const packDetails = await Promise.all(
|
|
109
|
+
packs.map(async (pname) => {
|
|
110
|
+
try {
|
|
111
|
+
return (await fetch_pack_by_name(pname)) || { name: pname };
|
|
112
|
+
} catch (e) {
|
|
113
|
+
getState().log?.(
|
|
114
|
+
2,
|
|
115
|
+
`Failed to fetch installed pack ${pname}: ${e.message}`
|
|
116
|
+
);
|
|
117
|
+
return { name: pname };
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
);
|
|
121
|
+
const availablePackSummaries = new Map();
|
|
122
|
+
let storeModules = [];
|
|
123
|
+
const storeModuleSummaries = new Map();
|
|
124
|
+
try {
|
|
125
|
+
storeModules = await Plugin.store_plugins_available();
|
|
126
|
+
storeModules.forEach((mod) => {
|
|
127
|
+
if (mod?.name) storeModuleSummaries.set(mod.name, mod);
|
|
128
|
+
});
|
|
129
|
+
} catch (e) {
|
|
130
|
+
getState().log?.(2, `Failed to fetch available modules: ${e.message}`);
|
|
131
|
+
}
|
|
132
|
+
if (includeAllModules) {
|
|
133
|
+
try {
|
|
134
|
+
const availablePacks = await fetch_available_packs();
|
|
135
|
+
availablePacks.forEach((pack) => {
|
|
136
|
+
if (pack?.name) availablePackSummaries.set(pack.name, pack);
|
|
137
|
+
});
|
|
138
|
+
} catch (e) {
|
|
139
|
+
getState().log?.(2, `Failed to fetch available packs: ${e.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const buildModuleActions = (moduleName, installed) => {
|
|
144
|
+
if (!csrfToken) return "";
|
|
145
|
+
if (installed) {
|
|
146
|
+
return post_btn(
|
|
147
|
+
`/plugins/delete/${encodeURIComponent(moduleName)}`,
|
|
148
|
+
req.__("Uninstall"),
|
|
149
|
+
csrfToken,
|
|
150
|
+
{
|
|
151
|
+
formClass: "d-inline",
|
|
152
|
+
btnClass: "btn btn-sm btn-danger",
|
|
153
|
+
klass: "extended-entity-remove",
|
|
154
|
+
confirm: true,
|
|
155
|
+
req,
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return post_btn(
|
|
160
|
+
`/plugins/install/${encodeURIComponent(moduleName)}`,
|
|
161
|
+
req.__("Install"),
|
|
162
|
+
csrfToken,
|
|
163
|
+
{
|
|
164
|
+
formClass: "d-inline",
|
|
165
|
+
btnClass: "btn btn-sm btn-primary",
|
|
166
|
+
klass: "extended-entity-install",
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const modules = await Plugin.find();
|
|
172
|
+
const installedModuleNames = new Set();
|
|
173
|
+
modules
|
|
174
|
+
.filter((mod) => mod.name !== "base")
|
|
175
|
+
.forEach((mod) => {
|
|
176
|
+
installedModuleNames.add(mod.name);
|
|
177
|
+
const has_theme =
|
|
178
|
+
typeof mod.has_theme !== "undefined"
|
|
179
|
+
? mod.has_theme
|
|
180
|
+
: !!statePlugins[mod.name]?.layout;
|
|
181
|
+
const has_auth =
|
|
182
|
+
typeof mod.has_auth !== "undefined"
|
|
183
|
+
? mod.has_auth
|
|
184
|
+
: !!statePlugins[mod.name]?.authentication;
|
|
185
|
+
const ready_for_mobile = !!statePlugins[mod.name]?.ready_for_mobile;
|
|
186
|
+
const source = mod.source;
|
|
187
|
+
const description =
|
|
188
|
+
storeModuleSummaries.get(mod.name)?.description ||
|
|
189
|
+
mod.description ||
|
|
190
|
+
statePlugins[mod.name]?.description ||
|
|
191
|
+
"";
|
|
192
|
+
entities.push({
|
|
193
|
+
type: "module",
|
|
194
|
+
name: mod.name,
|
|
195
|
+
id: mod.id,
|
|
196
|
+
viewLink: `/plugins/info/${mod.name}`,
|
|
197
|
+
editLink: statePlugins[mod.name]?.configuration_workflow
|
|
198
|
+
? `/plugins/configure/${mod.name}`
|
|
199
|
+
: null,
|
|
200
|
+
metadata: {
|
|
201
|
+
version: mod.version,
|
|
202
|
+
hasConfig: !!statePlugins[mod.name]?.configuration_workflow,
|
|
203
|
+
has_theme,
|
|
204
|
+
has_auth,
|
|
205
|
+
ready_for_mobile,
|
|
206
|
+
source,
|
|
207
|
+
description,
|
|
208
|
+
local: source === "local",
|
|
209
|
+
installed: true,
|
|
210
|
+
type: "module",
|
|
211
|
+
},
|
|
212
|
+
actionsHtml: buildModuleActions(mod.name, true),
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (includeAllModules) {
|
|
217
|
+
try {
|
|
218
|
+
storeModules
|
|
219
|
+
.filter(
|
|
220
|
+
(mod) => mod.name !== "base" && !installedModuleNames.has(mod.name)
|
|
221
|
+
)
|
|
222
|
+
.forEach((mod) => {
|
|
223
|
+
const source = mod.source;
|
|
224
|
+
entities.push({
|
|
225
|
+
type: "module",
|
|
226
|
+
name: mod.name,
|
|
227
|
+
id: mod.id,
|
|
228
|
+
viewLink: `/plugins/info/${mod.name}`,
|
|
229
|
+
editLink: null,
|
|
230
|
+
metadata: {
|
|
231
|
+
version: mod.version,
|
|
232
|
+
hasConfig: false,
|
|
233
|
+
has_theme: !!mod.has_theme,
|
|
234
|
+
has_auth: !!mod.has_auth,
|
|
235
|
+
ready_for_mobile: !!mod.ready_for_mobile,
|
|
236
|
+
source,
|
|
237
|
+
description: mod.description || "",
|
|
238
|
+
local: source === "local",
|
|
239
|
+
installed: false,
|
|
240
|
+
type: "module",
|
|
241
|
+
},
|
|
242
|
+
actionsHtml: buildModuleActions(mod.name, false),
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
} catch (e) {
|
|
246
|
+
getState().log?.(2, `Failed to fetch available modules: ${e.message}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const buildPackActions = (packName, installed) => {
|
|
251
|
+
if (!csrfToken) return "";
|
|
252
|
+
if (installed) {
|
|
253
|
+
return post_btn(
|
|
254
|
+
`/packs/uninstall/${encodeURIComponent(packName)}`,
|
|
255
|
+
req.__("Uninstall"),
|
|
256
|
+
csrfToken,
|
|
257
|
+
{
|
|
258
|
+
formClass: "d-inline",
|
|
259
|
+
btnClass: "btn btn-sm btn-danger",
|
|
260
|
+
klass: "extended-entity-remove",
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return post_btn(
|
|
265
|
+
`/packs/install-named/${encodeURIComponent(packName)}`,
|
|
266
|
+
req.__("Install"),
|
|
267
|
+
csrfToken,
|
|
268
|
+
{
|
|
269
|
+
formClass: "d-inline",
|
|
270
|
+
btnClass: "btn btn-sm btn-primary",
|
|
271
|
+
klass: "extended-entity-install",
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
packDetails.forEach((pack) => {
|
|
277
|
+
if (!pack || !pack.name) return;
|
|
278
|
+
const summary = availablePackSummaries.get(pack.name);
|
|
279
|
+
if (summary) availablePackSummaries.delete(pack.name);
|
|
280
|
+
const version = pack.version ?? pack.pack?.version ?? null;
|
|
281
|
+
const description =
|
|
282
|
+
pack.description || pack.pack?.description || summary?.description || "";
|
|
283
|
+
entities.push({
|
|
284
|
+
type: "module",
|
|
285
|
+
name: pack.name,
|
|
286
|
+
id: pack.id || pack.pack?.id || pack.name,
|
|
287
|
+
viewLink: null,
|
|
288
|
+
editLink: null,
|
|
289
|
+
metadata: {
|
|
290
|
+
version,
|
|
291
|
+
description,
|
|
292
|
+
hasConfig: false,
|
|
293
|
+
has_theme: false,
|
|
294
|
+
local: false,
|
|
295
|
+
installed: true,
|
|
296
|
+
type: "pack",
|
|
297
|
+
},
|
|
298
|
+
actionsHtml: buildPackActions(pack.name, true),
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (availablePackSummaries.size) {
|
|
303
|
+
for (const [packName, pack] of availablePackSummaries.entries()) {
|
|
304
|
+
if (installedPackNames.has(packName)) continue;
|
|
305
|
+
entities.push({
|
|
306
|
+
type: "module",
|
|
307
|
+
name: packName,
|
|
308
|
+
id: pack.id || packName,
|
|
309
|
+
viewLink: null,
|
|
310
|
+
editLink: null,
|
|
311
|
+
metadata: {
|
|
312
|
+
version: null,
|
|
313
|
+
description: pack.description || "",
|
|
314
|
+
hasConfig: false,
|
|
315
|
+
has_theme: false,
|
|
316
|
+
local: false,
|
|
317
|
+
installed: false,
|
|
318
|
+
type: "pack",
|
|
319
|
+
},
|
|
320
|
+
actionsHtml: buildPackActions(packName, false),
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return entities;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const buildUserActionsDropdown = (user, req, can_reset) => {
|
|
329
|
+
if (!req) return "";
|
|
330
|
+
const dropdownId = `entityUserDropdown${user.id}`;
|
|
331
|
+
const items = [
|
|
332
|
+
a(
|
|
333
|
+
{
|
|
334
|
+
class: "dropdown-item",
|
|
335
|
+
href: `/useradmin/${user.id}`,
|
|
336
|
+
},
|
|
337
|
+
'<i class="fas fa-edit"></i> ' + req__(req, "Edit")
|
|
338
|
+
),
|
|
339
|
+
post_dropdown_item(
|
|
340
|
+
`/useradmin/become-user/${user.id}`,
|
|
341
|
+
'<i class="fas fa-ghost"></i> ' + req__(req, "Become user"),
|
|
342
|
+
req
|
|
343
|
+
),
|
|
344
|
+
post_dropdown_item(
|
|
345
|
+
`/useradmin/set-random-password/${user.id}`,
|
|
346
|
+
'<i class="fas fa-random"></i> ' + req__(req, "Set random password"),
|
|
347
|
+
req,
|
|
348
|
+
true
|
|
349
|
+
),
|
|
350
|
+
can_reset &&
|
|
351
|
+
post_dropdown_item(
|
|
352
|
+
`/useradmin/reset-password/${user.id}`,
|
|
353
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
354
|
+
req__(req, "Send password reset email"),
|
|
355
|
+
req
|
|
356
|
+
),
|
|
357
|
+
can_reset &&
|
|
358
|
+
!user.verified_on &&
|
|
359
|
+
getState().getConfig("verification_view", "") &&
|
|
360
|
+
post_dropdown_item(
|
|
361
|
+
`/useradmin/send-verification/${user.id}`,
|
|
362
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
363
|
+
req__(req, "Send verification email"),
|
|
364
|
+
req
|
|
365
|
+
),
|
|
366
|
+
user.disabled &&
|
|
367
|
+
post_dropdown_item(
|
|
368
|
+
`/useradmin/enable/${user.id}`,
|
|
369
|
+
'<i class="fas fa-play"></i> ' + req__(req, "Enable"),
|
|
370
|
+
req
|
|
371
|
+
),
|
|
372
|
+
!user.disabled &&
|
|
373
|
+
post_dropdown_item(
|
|
374
|
+
`/useradmin/disable/${user.id}`,
|
|
375
|
+
'<i class="fas fa-pause"></i> ' + req__(req, "Disable"),
|
|
376
|
+
req
|
|
377
|
+
),
|
|
378
|
+
!user.disabled &&
|
|
379
|
+
post_dropdown_item(
|
|
380
|
+
`/useradmin/force-logout/${user.id}`,
|
|
381
|
+
'<i class="fas fa-sign-out-alt"></i> ' +
|
|
382
|
+
req__(req, "Force logout"),
|
|
383
|
+
req
|
|
384
|
+
),
|
|
385
|
+
post_dropdown_item(
|
|
386
|
+
`/useradmin/delete/${user.id}`,
|
|
387
|
+
'<i class="far fa-trash-alt"></i> ' + req__(req, "Delete"),
|
|
388
|
+
req,
|
|
389
|
+
true,
|
|
390
|
+
user.email
|
|
391
|
+
),
|
|
392
|
+
].filter(Boolean);
|
|
393
|
+
return settingsDropdown(dropdownId, items);
|
|
394
|
+
};
|
|
395
|
+
|
|
57
396
|
/**
|
|
58
397
|
* Get all entities with their type and metadata
|
|
59
398
|
*/
|
|
@@ -88,6 +427,10 @@ const getAllEntities = async () => {
|
|
|
88
427
|
|
|
89
428
|
// Add views
|
|
90
429
|
views.forEach((v) => {
|
|
430
|
+
const has_config =
|
|
431
|
+
v.configuration &&
|
|
432
|
+
typeof v.configuration === "object" &&
|
|
433
|
+
Object.keys(v.configuration).length > 0;
|
|
91
434
|
entities.push({
|
|
92
435
|
type: "view",
|
|
93
436
|
name: v.name,
|
|
@@ -102,6 +445,7 @@ const getAllEntities = async () => {
|
|
|
102
445
|
table_name: v.table_id ? tableNameById.get(v.table_id) : null,
|
|
103
446
|
singleton: v.singleton,
|
|
104
447
|
min_role: v.min_role,
|
|
448
|
+
has_config,
|
|
105
449
|
},
|
|
106
450
|
});
|
|
107
451
|
});
|
|
@@ -158,6 +502,9 @@ const entityTypeBadge = (type) => {
|
|
|
158
502
|
view: { class: "success", icon: "eye", label: "View" },
|
|
159
503
|
page: { class: "info", icon: "file", label: "Page" },
|
|
160
504
|
trigger: { class: "warning", icon: "play", label: "Trigger" },
|
|
505
|
+
module: { class: "secondary", icon: "cube", label: "Module" },
|
|
506
|
+
user: { class: "dark", icon: "user", label: "User" },
|
|
507
|
+
role: { class: "danger", icon: "lock", label: "Role" },
|
|
161
508
|
};
|
|
162
509
|
const badge = badges[type];
|
|
163
510
|
return span(
|
|
@@ -168,7 +515,7 @@ const entityTypeBadge = (type) => {
|
|
|
168
515
|
};
|
|
169
516
|
|
|
170
517
|
// Helper: build details column content based on entity type
|
|
171
|
-
const detailsContent = (entity, req) => {
|
|
518
|
+
const detailsContent = (entity, req, roles) => {
|
|
172
519
|
const bits = [];
|
|
173
520
|
if (entity.type === "table") {
|
|
174
521
|
if (entity.metadata.external)
|
|
@@ -217,6 +564,23 @@ const detailsContent = (entity, req) => {
|
|
|
217
564
|
text(entity.metadata.action)
|
|
218
565
|
)
|
|
219
566
|
);
|
|
567
|
+
} else if (entity.type === "user") {
|
|
568
|
+
const disabled = entity.metadata.disabled;
|
|
569
|
+
const roleName = Array.isArray(roles)
|
|
570
|
+
? roles.find((r) => r.id === entity.metadata.role_id)?.role
|
|
571
|
+
: null;
|
|
572
|
+
if (roleName)
|
|
573
|
+
bits.push(span({ class: "badge bg-secondary me-1" }, text(roleName)));
|
|
574
|
+
if (disabled)
|
|
575
|
+
bits.push(span({ class: "badge bg-danger me-1" }, req.__("Disabled")));
|
|
576
|
+
} else if (entity.type === "module") {
|
|
577
|
+
if (entity.metadata.version)
|
|
578
|
+
bits.push(
|
|
579
|
+
span(
|
|
580
|
+
{ class: "text-muted small me-2" },
|
|
581
|
+
text(`v${entity.metadata.version}`)
|
|
582
|
+
)
|
|
583
|
+
);
|
|
220
584
|
}
|
|
221
585
|
return bits.length ? div(...bits) : "";
|
|
222
586
|
};
|
|
@@ -312,8 +676,51 @@ router.get(
|
|
|
312
676
|
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
313
677
|
error_catcher(async (req, res) => {
|
|
314
678
|
const entities = await getAllEntities();
|
|
679
|
+
const deepSearchIndex = {};
|
|
680
|
+
const addDeepSearch = (key, pack) => {
|
|
681
|
+
if (!pack) return;
|
|
682
|
+
try {
|
|
683
|
+
deepSearchIndex[key] = escapeHtml(JSON.stringify(pack).toLowerCase());
|
|
684
|
+
} catch (e) {
|
|
685
|
+
console.error(
|
|
686
|
+
`Failed to stringify pack ${pack.name} for deep search index:`,
|
|
687
|
+
e
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
for (const entity of entities) {
|
|
693
|
+
const keyById = `${entity.type}:${entity.id}`;
|
|
694
|
+
try {
|
|
695
|
+
if (entity.type === "table") {
|
|
696
|
+
const table = Table.findOne({ id: entity.id });
|
|
697
|
+
if (table) addDeepSearch(keyById, await table_pack(table));
|
|
698
|
+
} else if (entity.type === "view") {
|
|
699
|
+
const view = View.findOne({ name: entity.name });
|
|
700
|
+
if (view) {
|
|
701
|
+
const viewKeyById = `view:${view.id ?? entity.id ?? entity.name}`;
|
|
702
|
+
const viewKeyByName = `view:${entity.name}`;
|
|
703
|
+
const vpack = await view_pack(view);
|
|
704
|
+
addDeepSearch(viewKeyById, vpack);
|
|
705
|
+
if (viewKeyByName !== viewKeyById)
|
|
706
|
+
addDeepSearch(viewKeyByName, vpack);
|
|
707
|
+
}
|
|
708
|
+
} else if (entity.type === "page") {
|
|
709
|
+
const page = Page.findOne({ name: entity.name });
|
|
710
|
+
if (page) addDeepSearch(keyById, await page_pack(page));
|
|
711
|
+
} else if (entity.type === "trigger") {
|
|
712
|
+
const trigger = Trigger.findOne({ id: entity.id });
|
|
713
|
+
if (trigger) addDeepSearch(keyById, await trigger_pack(trigger));
|
|
714
|
+
}
|
|
715
|
+
} catch (e) {
|
|
716
|
+
getState().log?.(
|
|
717
|
+
2,
|
|
718
|
+
`Failed to build deep search index for ${keyById}: ${e.message}`
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
315
722
|
// fetch roles and tags
|
|
316
|
-
const roles = await
|
|
723
|
+
const roles = await Role.find({}, { orderBy: "id" });
|
|
317
724
|
const tags = await Tag.find();
|
|
318
725
|
const tagEntries = await TagEntry.find();
|
|
319
726
|
const userRoleId = req.user?.role_id ?? Infinity;
|
|
@@ -327,11 +734,11 @@ router.get(
|
|
|
327
734
|
if (entity.type === "table")
|
|
328
735
|
return tableActionsDropdown(entity, req, user_can_edit_tables);
|
|
329
736
|
if (entity.type === "view")
|
|
330
|
-
return view_dropdown(entity, req, on_done_redirect_str);
|
|
737
|
+
return view_dropdown(entity, req, on_done_redirect_str, false);
|
|
331
738
|
if (entity.type === "page")
|
|
332
|
-
return page_dropdown(entity, req, on_done_redirect_str, true);
|
|
739
|
+
return page_dropdown(entity, req, on_done_redirect_str, true, false);
|
|
333
740
|
if (entity.type === "trigger")
|
|
334
|
-
return trigger_dropdown(entity, req, on_done_redirect_str,
|
|
741
|
+
return trigger_dropdown(entity, req, on_done_redirect_str, false);
|
|
335
742
|
return "";
|
|
336
743
|
};
|
|
337
744
|
|
|
@@ -353,7 +760,7 @@ router.get(
|
|
|
353
760
|
|
|
354
761
|
const filterToggles = div(
|
|
355
762
|
{
|
|
356
|
-
class: "btn-group btn-group-sm",
|
|
763
|
+
class: "btn-group btn-group-sm entity-type-group",
|
|
357
764
|
role: "group",
|
|
358
765
|
"aria-label": "Entity type filters",
|
|
359
766
|
},
|
|
@@ -362,6 +769,7 @@ router.get(
|
|
|
362
769
|
type: "button",
|
|
363
770
|
class: "btn btn-sm btn-outline-primary entity-filter-btn",
|
|
364
771
|
"data-entity-type": "table",
|
|
772
|
+
title: req.__("Show tables (Alt+T)"),
|
|
365
773
|
},
|
|
366
774
|
i({ class: "fas fa-table me-1" }),
|
|
367
775
|
req.__("Tables")
|
|
@@ -371,6 +779,7 @@ router.get(
|
|
|
371
779
|
type: "button",
|
|
372
780
|
class: "btn btn-sm btn-outline-primary entity-filter-btn",
|
|
373
781
|
"data-entity-type": "view",
|
|
782
|
+
title: req.__("Show views (Alt+V)"),
|
|
374
783
|
},
|
|
375
784
|
i({ class: "fas fa-eye me-1" }),
|
|
376
785
|
req.__("Views")
|
|
@@ -380,6 +789,7 @@ router.get(
|
|
|
380
789
|
type: "button",
|
|
381
790
|
class: "btn btn-sm btn-outline-primary entity-filter-btn",
|
|
382
791
|
"data-entity-type": "page",
|
|
792
|
+
title: req.__("Show pages (Alt+P)"),
|
|
383
793
|
},
|
|
384
794
|
i({ class: "fas fa-file me-1" }),
|
|
385
795
|
req.__("Pages")
|
|
@@ -389,24 +799,92 @@ router.get(
|
|
|
389
799
|
type: "button",
|
|
390
800
|
class: "btn btn-sm btn-outline-primary entity-filter-btn",
|
|
391
801
|
"data-entity-type": "trigger",
|
|
802
|
+
title: req.__("Show triggers (Alt+R)"),
|
|
392
803
|
},
|
|
393
804
|
i({ class: "fas fa-play me-1" }),
|
|
394
805
|
req.__("Triggers")
|
|
806
|
+
),
|
|
807
|
+
button(
|
|
808
|
+
{
|
|
809
|
+
type: "button",
|
|
810
|
+
class:
|
|
811
|
+
"btn btn-sm btn-outline-primary entity-filter-btn entity-extended-btn d-none",
|
|
812
|
+
"data-entity-type": "user",
|
|
813
|
+
title: req.__("Show users (Alt+U)"),
|
|
814
|
+
},
|
|
815
|
+
i({ class: "fas fa-user me-1" }),
|
|
816
|
+
req.__("Users")
|
|
817
|
+
),
|
|
818
|
+
button(
|
|
819
|
+
{
|
|
820
|
+
type: "button",
|
|
821
|
+
class:
|
|
822
|
+
"btn btn-sm btn-outline-primary entity-filter-btn entity-extended-btn d-none",
|
|
823
|
+
"data-entity-type": "module",
|
|
824
|
+
title: req.__("Show modules (Alt+M)"),
|
|
825
|
+
},
|
|
826
|
+
i({ class: "fas fa-cube me-1" }),
|
|
827
|
+
req.__("Modules")
|
|
828
|
+
),
|
|
829
|
+
button(
|
|
830
|
+
{
|
|
831
|
+
type: "button",
|
|
832
|
+
class: "btn btn-sm btn-outline-secondary",
|
|
833
|
+
id: "entity-more-btn",
|
|
834
|
+
onclick: "toggleEntityExpanded(true)",
|
|
835
|
+
},
|
|
836
|
+
req.__("More...")
|
|
837
|
+
),
|
|
838
|
+
button(
|
|
839
|
+
{
|
|
840
|
+
type: "button",
|
|
841
|
+
class: "btn btn-sm btn-outline-secondary d-none",
|
|
842
|
+
id: "entity-less-btn",
|
|
843
|
+
onclick: "toggleEntityExpanded(false)",
|
|
844
|
+
},
|
|
845
|
+
req.__("Less...")
|
|
395
846
|
)
|
|
396
847
|
);
|
|
397
848
|
|
|
398
849
|
const searchBox = div(
|
|
399
|
-
{ class: "mb-
|
|
850
|
+
{ class: "input-group mb-2" },
|
|
400
851
|
input({
|
|
401
|
-
type: "
|
|
852
|
+
type: "search",
|
|
402
853
|
class: "form-control",
|
|
403
|
-
|
|
854
|
+
name: "q",
|
|
404
855
|
placeholder: req.__("Search entities by name or type..."),
|
|
856
|
+
"aria-label": req.__("Search entities by name or type..."),
|
|
405
857
|
autocomplete: "off",
|
|
406
|
-
|
|
858
|
+
id: "entity-search",
|
|
859
|
+
}),
|
|
860
|
+
span({ class: "input-group-text" }, [
|
|
861
|
+
input({
|
|
862
|
+
class: "form-check-input mt-0 me-2",
|
|
863
|
+
type: "checkbox",
|
|
864
|
+
id: "entity-deep-search",
|
|
865
|
+
title: req.__("Toggle deep search (Alt+S)"),
|
|
866
|
+
}),
|
|
867
|
+
label(
|
|
868
|
+
{
|
|
869
|
+
class: "form-check-label mb-0",
|
|
870
|
+
for: "entity-deep-search",
|
|
871
|
+
title: req.__("Toggle deep search (Alt+S)"),
|
|
872
|
+
},
|
|
873
|
+
req.__("Deep search")
|
|
874
|
+
),
|
|
875
|
+
])
|
|
876
|
+
);
|
|
877
|
+
|
|
878
|
+
const manageTagsLink = a(
|
|
879
|
+
{
|
|
880
|
+
class: "btn btn-sm btn-outline-secondary",
|
|
881
|
+
href: `/tag${on_done_redirect_str}`,
|
|
882
|
+
title: req.__("Manage tags"),
|
|
883
|
+
},
|
|
884
|
+
i({ class: "fas fa-cog" })
|
|
407
885
|
);
|
|
408
886
|
|
|
409
|
-
// Tag filter buttons
|
|
887
|
+
// Tag filter buttons + manage
|
|
410
888
|
const tagFilterBar = div(
|
|
411
889
|
{ class: "d-flex flex-wrap align-items-center gap-1" },
|
|
412
890
|
span(
|
|
@@ -423,17 +901,20 @@ router.get(
|
|
|
423
901
|
},
|
|
424
902
|
text(t.name)
|
|
425
903
|
)
|
|
426
|
-
)
|
|
904
|
+
),
|
|
905
|
+
manageTagsLink
|
|
427
906
|
);
|
|
428
907
|
|
|
429
908
|
// One row for type filters and tag filters
|
|
430
909
|
const filtersRow = div(
|
|
431
910
|
{
|
|
911
|
+
id: "entity-filters-row",
|
|
432
912
|
class:
|
|
433
|
-
"d-flex flex-wrap align-items-center justify-content-between mb-
|
|
913
|
+
"d-flex flex-wrap align-items-center justify-content-between mb-2 gap-2 p-2 border rounded",
|
|
914
|
+
style: "border-color: transparent !important;",
|
|
434
915
|
},
|
|
435
916
|
div(
|
|
436
|
-
{ class: "d-flex align-items-center gap-2" },
|
|
917
|
+
{ class: "d-flex align-items-center gap-2 flex-wrap" },
|
|
437
918
|
span(
|
|
438
919
|
{ class: "me-1 text-muted" },
|
|
439
920
|
i({ class: "fas fa-filter me-1" }),
|
|
@@ -444,10 +925,152 @@ router.get(
|
|
|
444
925
|
tagFilterBar
|
|
445
926
|
);
|
|
446
927
|
|
|
928
|
+
const selectionBar = div(
|
|
929
|
+
{
|
|
930
|
+
id: "entity-selection-bar",
|
|
931
|
+
class:
|
|
932
|
+
"d-flex align-items-center justify-content-between mb-2 gap-2 d-none p-2 border rounded",
|
|
933
|
+
style:
|
|
934
|
+
"background-color: var(--bs-secondary-bg, var(--bs-secondary-bg-fallback)); border-color: transparent !important; flex-wrap: wrap;",
|
|
935
|
+
},
|
|
936
|
+
div(
|
|
937
|
+
{ class: "d-flex align-items-center gap-2" },
|
|
938
|
+
button(
|
|
939
|
+
{
|
|
940
|
+
type: "button",
|
|
941
|
+
class: "btn btn-sm btn-outline-secondary selection-control-btn",
|
|
942
|
+
id: "entity-clear-selection",
|
|
943
|
+
"aria-label": req.__("Clear selection"),
|
|
944
|
+
},
|
|
945
|
+
i({ class: "fas fa-times" })
|
|
946
|
+
),
|
|
947
|
+
span(
|
|
948
|
+
{ id: "entity-selection-count", class: "fw-semibold" },
|
|
949
|
+
req.__("%s selected", "0")
|
|
950
|
+
)
|
|
951
|
+
),
|
|
952
|
+
div(
|
|
953
|
+
{
|
|
954
|
+
class: "d-flex align-items-center gap-2",
|
|
955
|
+
style: "flex: 1; flex-direction: row-reverse;",
|
|
956
|
+
},
|
|
957
|
+
button(
|
|
958
|
+
{
|
|
959
|
+
type: "button",
|
|
960
|
+
class: "btn btn-sm btn-danger selection-control-btn",
|
|
961
|
+
id: "entity-bulk-delete",
|
|
962
|
+
"aria-label": req.__("Delete selected"),
|
|
963
|
+
disabled: true,
|
|
964
|
+
},
|
|
965
|
+
i({ class: "fas fa-trash" })
|
|
966
|
+
),
|
|
967
|
+
button(
|
|
968
|
+
{
|
|
969
|
+
type: "button",
|
|
970
|
+
class: "btn btn-sm btn-outline-secondary selection-control-btn",
|
|
971
|
+
style: "min-width: 147px;",
|
|
972
|
+
id: "entity-bulk-download-pack",
|
|
973
|
+
title: req.__("Download pack for selected modules/packs"),
|
|
974
|
+
disabled: true,
|
|
975
|
+
},
|
|
976
|
+
i({ class: "fas fa-download me-1" }),
|
|
977
|
+
req.__("Download pack")
|
|
978
|
+
),
|
|
979
|
+
div(
|
|
980
|
+
{
|
|
981
|
+
id: "entity-bulk-role-write-group",
|
|
982
|
+
class: "input-group input-group-sm",
|
|
983
|
+
style: "max-width: 180px; min-width: 150px",
|
|
984
|
+
},
|
|
985
|
+
select(
|
|
986
|
+
{
|
|
987
|
+
class:
|
|
988
|
+
"form-select border border-secondary btn-outline-secondary",
|
|
989
|
+
id: "entity-bulk-role-write-select",
|
|
990
|
+
"aria-label": req.__("Select write role"),
|
|
991
|
+
style:
|
|
992
|
+
"--entity-bulk-role-border: var(--bs-secondary); border: 2px solid var(--entity-bulk-role-border) !important;",
|
|
993
|
+
},
|
|
994
|
+
option({ value: "" }, req.__("Set write role")),
|
|
995
|
+
...roles.map((r) => option({ value: r.id }, r.role))
|
|
996
|
+
),
|
|
997
|
+
button(
|
|
998
|
+
{
|
|
999
|
+
type: "button",
|
|
1000
|
+
class: "btn btn-sm btn-outline-secondary",
|
|
1001
|
+
id: "entity-bulk-apply-role-write",
|
|
1002
|
+
title: req.__("Apply write role to selected tables"),
|
|
1003
|
+
disabled: true,
|
|
1004
|
+
},
|
|
1005
|
+
req.__("Set write")
|
|
1006
|
+
)
|
|
1007
|
+
),
|
|
1008
|
+
div(
|
|
1009
|
+
{
|
|
1010
|
+
id: "entity-bulk-role-read-group",
|
|
1011
|
+
class: "input-group input-group-sm",
|
|
1012
|
+
style: "max-width: 180px; min-width: 150px",
|
|
1013
|
+
},
|
|
1014
|
+
select(
|
|
1015
|
+
{
|
|
1016
|
+
class:
|
|
1017
|
+
"form-select border border-secondary btn-outline-secondary",
|
|
1018
|
+
id: "entity-bulk-role-read-select",
|
|
1019
|
+
"aria-label": req.__("Select access role"),
|
|
1020
|
+
style:
|
|
1021
|
+
"--entity-bulk-role-border: var(--bs-secondary); border: 2px solid var(--entity-bulk-role-border) !important;",
|
|
1022
|
+
},
|
|
1023
|
+
option({ value: "" }, req.__("Set access role")),
|
|
1024
|
+
...roles.map((r) => option({ value: r.id }, r.role))
|
|
1025
|
+
),
|
|
1026
|
+
button(
|
|
1027
|
+
{
|
|
1028
|
+
type: "button",
|
|
1029
|
+
class: "btn btn-sm btn-outline-secondary",
|
|
1030
|
+
id: "entity-bulk-apply-role-read",
|
|
1031
|
+
title: req.__("Apply access role to selected"),
|
|
1032
|
+
disabled: true,
|
|
1033
|
+
},
|
|
1034
|
+
req.__("Set access")
|
|
1035
|
+
)
|
|
1036
|
+
),
|
|
1037
|
+
div(
|
|
1038
|
+
{
|
|
1039
|
+
class: "input-group input-group-sm",
|
|
1040
|
+
style: "max-width: 200px; min-width: 150px;",
|
|
1041
|
+
},
|
|
1042
|
+
// span({ class: "input-group-text" }, i({ class: "fas fa-tag" })),
|
|
1043
|
+
select(
|
|
1044
|
+
{
|
|
1045
|
+
class:
|
|
1046
|
+
"form-select border border-secondary btn-outline-secondary",
|
|
1047
|
+
style:
|
|
1048
|
+
"--entity-bulk-tag-border: var(--bs-secondary); border: 2px solid var(--entity-bulk-tag-border) !important;",
|
|
1049
|
+
id: "entity-bulk-tag-select",
|
|
1050
|
+
"aria-label": req.__("Select tag to apply"),
|
|
1051
|
+
},
|
|
1052
|
+
option({ value: "" }, req.__("Select tag")),
|
|
1053
|
+
...tags.map((t) => option({ value: t.id }, t.name))
|
|
1054
|
+
),
|
|
1055
|
+
button(
|
|
1056
|
+
{
|
|
1057
|
+
type: "button",
|
|
1058
|
+
class: "btn btn-sm btn-outline-secondary",
|
|
1059
|
+
id: "entity-bulk-apply-tag",
|
|
1060
|
+
title: req.__("Apply tag to selected"),
|
|
1061
|
+
disabled: true,
|
|
1062
|
+
},
|
|
1063
|
+
req.__("Apply tag")
|
|
1064
|
+
)
|
|
1065
|
+
)
|
|
1066
|
+
)
|
|
1067
|
+
);
|
|
1068
|
+
|
|
447
1069
|
// Build table
|
|
448
1070
|
const headerRow = tr(
|
|
449
1071
|
th(req.__("Type")),
|
|
450
1072
|
th(req.__("Name")),
|
|
1073
|
+
th(req.__("Run")),
|
|
451
1074
|
th(req.__("Details")),
|
|
452
1075
|
th(req.__("Access | Read/Write")),
|
|
453
1076
|
th(req.__("Tags")),
|
|
@@ -467,8 +1090,15 @@ router.get(
|
|
|
467
1090
|
};
|
|
468
1091
|
|
|
469
1092
|
const bodyRows = entities.map((entity) => {
|
|
470
|
-
const key = `${entity.type}:${
|
|
1093
|
+
const key = `${entity.type}:${
|
|
1094
|
+
entity.type === "view" ? (entity.id ?? entity.name) : entity.id
|
|
1095
|
+
}`;
|
|
471
1096
|
const tagIds = tagsByEntityKey.get(key) || [];
|
|
1097
|
+
const deepSearchable =
|
|
1098
|
+
deepSearchIndex[key] ||
|
|
1099
|
+
(entity.type === "view"
|
|
1100
|
+
? deepSearchIndex[`${entity.type}:${entity.name}`]
|
|
1101
|
+
: undefined);
|
|
472
1102
|
const tagBadges = tagIds.map((tid) =>
|
|
473
1103
|
a(
|
|
474
1104
|
{
|
|
@@ -522,37 +1152,100 @@ router.get(
|
|
|
522
1152
|
: entity.type === "view"
|
|
523
1153
|
? `/viewedit/config/${encodeURIComponent(entity.name)}${on_done_redirect_str}`
|
|
524
1154
|
: entity.viewLink;
|
|
1155
|
+
const tableMeta =
|
|
1156
|
+
entity.type === "table" ? Table.findOne(entity.name) : null;
|
|
1157
|
+
const minRoleRead =
|
|
1158
|
+
entity.type === "table" ? tableMeta?.min_role_read : undefined;
|
|
1159
|
+
const minRoleWrite =
|
|
1160
|
+
entity.type === "table" ? tableMeta?.min_role_write : undefined;
|
|
1161
|
+
const external =
|
|
1162
|
+
entity.type === "table" ? tableMeta?.external : undefined;
|
|
1163
|
+
const minRole =
|
|
1164
|
+
entity.type !== "table" ? entity.metadata?.min_role : undefined;
|
|
1165
|
+
const roleMetadata =
|
|
1166
|
+
entity.type === "table"
|
|
1167
|
+
? {
|
|
1168
|
+
...entity.metadata,
|
|
1169
|
+
min_role_read: minRoleRead,
|
|
1170
|
+
min_role_write: minRoleWrite,
|
|
1171
|
+
external,
|
|
1172
|
+
}
|
|
1173
|
+
: { ...entity.metadata, min_role: minRole };
|
|
525
1174
|
const actionsMenu = buildActionMenu(entity);
|
|
1175
|
+
const runCell = (() => {
|
|
1176
|
+
if (entity.type === "view") {
|
|
1177
|
+
return a(
|
|
1178
|
+
{
|
|
1179
|
+
href: entity.viewLink,
|
|
1180
|
+
class: "link-primary text-decoration-none",
|
|
1181
|
+
},
|
|
1182
|
+
// i({ class: "fas fa-play me-1" }),
|
|
1183
|
+
req.__("Run")
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
if (entity.type === "page") {
|
|
1187
|
+
return a(
|
|
1188
|
+
{
|
|
1189
|
+
href: entity.viewLink,
|
|
1190
|
+
class: "link-primary text-decoration-none",
|
|
1191
|
+
},
|
|
1192
|
+
// i({ class: "fas fa-play me-1" }),
|
|
1193
|
+
req.__("Run")
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
if (entity.type === "trigger") {
|
|
1197
|
+
return a(
|
|
1198
|
+
{
|
|
1199
|
+
href: `/actions/testrun/${entity.id}${on_done_redirect_str}`,
|
|
1200
|
+
class: "link-primary text-decoration-none text-nowrap",
|
|
1201
|
+
},
|
|
1202
|
+
// i({ class: "fas fa-running me-1" }),
|
|
1203
|
+
req.__("Test run")
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
return "";
|
|
1207
|
+
})();
|
|
526
1208
|
return tr(
|
|
527
1209
|
{
|
|
528
1210
|
class: "entity-row",
|
|
529
1211
|
"data-entity-type": entity.type,
|
|
530
1212
|
"data-entity-name": entity.name.toLowerCase(),
|
|
1213
|
+
"data-entity-label": entity.name,
|
|
1214
|
+
"data-entity-id": entity?.id ?? "",
|
|
1215
|
+
"data-entity-key": key,
|
|
1216
|
+
"data-installed":
|
|
1217
|
+
typeof entity.metadata?.installed === "boolean"
|
|
1218
|
+
? String(entity.metadata.installed)
|
|
1219
|
+
: "",
|
|
1220
|
+
"data-module-kind": entity.metadata?.type || "",
|
|
531
1221
|
"data-searchable": searchableValues.join(" "),
|
|
1222
|
+
"data-deep-searchable": deepSearchable || searchableValues.join(" "),
|
|
532
1223
|
"data-tags": tagIds.join(" "),
|
|
1224
|
+
"data-min-role-read":
|
|
1225
|
+
typeof minRoleRead !== "undefined" ? String(minRoleRead) : "",
|
|
1226
|
+
"data-min-role-write":
|
|
1227
|
+
typeof minRoleWrite !== "undefined" ? String(minRoleWrite) : "",
|
|
1228
|
+
"data-min-role":
|
|
1229
|
+
typeof minRole !== "undefined" ? String(minRole) : "",
|
|
1230
|
+
"data-external":
|
|
1231
|
+
typeof external !== "undefined" ? String(external) : "",
|
|
533
1232
|
},
|
|
534
1233
|
td(entityTypeBadge(entity.type)),
|
|
535
|
-
td(
|
|
536
|
-
|
|
1234
|
+
td(
|
|
1235
|
+
entity.type === "view" &&
|
|
1236
|
+
!entity.metadata.table_id &&
|
|
1237
|
+
!entity.metadata.has_config
|
|
1238
|
+
? span({ class: "fw-bold" }, text(entity.name))
|
|
1239
|
+
: a({ href: mainLinkHref, class: "fw-bold" }, text(entity.name))
|
|
1240
|
+
),
|
|
1241
|
+
td(runCell),
|
|
1242
|
+
td(detailsContent(entity, req, roles)),
|
|
537
1243
|
td(
|
|
538
1244
|
text(
|
|
539
1245
|
roleLabel(
|
|
540
1246
|
{
|
|
541
1247
|
...entity,
|
|
542
|
-
metadata:
|
|
543
|
-
entity.type === "table"
|
|
544
|
-
? {
|
|
545
|
-
...entity.metadata,
|
|
546
|
-
min_role_read: Table.findOne(entity.name)
|
|
547
|
-
?.min_role_read,
|
|
548
|
-
min_role_write: Table.findOne(entity.name)
|
|
549
|
-
?.min_role_write,
|
|
550
|
-
}
|
|
551
|
-
: {
|
|
552
|
-
...entity.metadata,
|
|
553
|
-
min_role:
|
|
554
|
-
entity.metadata.min_role ?? entity.metadata.min_role,
|
|
555
|
-
},
|
|
1248
|
+
metadata: roleMetadata,
|
|
556
1249
|
},
|
|
557
1250
|
roles
|
|
558
1251
|
)
|
|
@@ -585,33 +1278,271 @@ router.get(
|
|
|
585
1278
|
);
|
|
586
1279
|
|
|
587
1280
|
const clientScript = script(
|
|
588
|
-
domReady(`
|
|
1281
|
+
domReady(/*js*/ `
|
|
589
1282
|
const searchInput = document.getElementById("entity-search");
|
|
1283
|
+
const deepSearchToggle = document.getElementById("entity-deep-search");
|
|
590
1284
|
const entitiesList = document.getElementById("entities-list");
|
|
591
1285
|
const noResults = document.getElementById("no-results");
|
|
592
1286
|
const filterButtons = document.querySelectorAll(".entity-filter-btn");
|
|
593
|
-
const
|
|
1287
|
+
const filterButtonsByType = {};
|
|
1288
|
+
filterButtons.forEach((btn) => {
|
|
1289
|
+
const type = btn.dataset.entityType;
|
|
1290
|
+
if (type) filterButtonsByType[type] = btn;
|
|
1291
|
+
});
|
|
594
1292
|
const tagButtons = document.querySelectorAll(".tag-filter-btn");
|
|
595
1293
|
const LEGACY_LINK_META = ${JSON.stringify(legacyLinkMeta)};
|
|
596
1294
|
const legacyButton = document.getElementById("legacy-entity-link");
|
|
597
1295
|
const legacyLabel = legacyButton ? legacyButton.querySelector(".legacy-label") : null;
|
|
1296
|
+
const filtersRow = document.getElementById("entity-filters-row");
|
|
1297
|
+
const selectionBar = document.getElementById("entity-selection-bar");
|
|
1298
|
+
const selectionCountEl = document.getElementById("entity-selection-count");
|
|
1299
|
+
const clearSelectionBtn = document.getElementById("entity-clear-selection");
|
|
1300
|
+
const bulkDeleteBtn = document.getElementById("entity-bulk-delete");
|
|
1301
|
+
const bulkTagSelect = document.getElementById("entity-bulk-tag-select");
|
|
1302
|
+
const bulkApplyTagBtn = document.getElementById("entity-bulk-apply-tag");
|
|
1303
|
+
const bulkDownloadPackBtn = document.getElementById("entity-bulk-download-pack");
|
|
1304
|
+
const bulkRoleReadSelect = document.getElementById("entity-bulk-role-read-select");
|
|
1305
|
+
const bulkApplyRoleReadBtn = document.getElementById("entity-bulk-apply-role-read");
|
|
1306
|
+
const bulkRoleWriteSelect = document.getElementById("entity-bulk-role-write-select");
|
|
1307
|
+
const bulkApplyRoleWriteBtn = document.getElementById("entity-bulk-apply-role-write");
|
|
1308
|
+
const bulkRoleReadGroup = document.getElementById("entity-bulk-role-read-group");
|
|
1309
|
+
const bulkRoleWriteGroup = document.getElementById("entity-bulk-role-write-group");
|
|
1310
|
+
const entitiesTbody = entitiesList ? entitiesList.querySelector("tbody") : null;
|
|
1311
|
+
const TAGS_BY_ID = ${JSON.stringify(Object.fromEntries(tags.map((t) => [t.id, t.name])))};
|
|
1312
|
+
const ROLES_BY_ID = ${JSON.stringify(Object.fromEntries(roles.map((r) => [r.id, r.role])))};
|
|
1313
|
+
|
|
1314
|
+
const TXT_SELECTED = ${JSON.stringify(req.__("selected"))};
|
|
1315
|
+
const TXT_DELETE_SELECTED_CONFIRM = ${JSON.stringify(req.__("Delete %s selected items?"))};
|
|
1316
|
+
const TXT_DELETE_SELECTED_FALLBACK = ${JSON.stringify(req.__("Delete selected items?"))};
|
|
1317
|
+
const TXT_DELETE_FAILED = ${JSON.stringify(req.__("Failed to delete selected items"))};
|
|
1318
|
+
|
|
1319
|
+
const BASE_TYPES = ["table","view","page","trigger"];
|
|
1320
|
+
const EXTENDED_TYPES = window.ENTITY_EXTENDED_TYPES || ["module","user"];
|
|
1321
|
+
const ALL_TYPES = BASE_TYPES.concat(EXTENDED_TYPES);
|
|
1322
|
+
|
|
1323
|
+
const selectedKeys = new Set();
|
|
1324
|
+
let lastSelectedIndex = null;
|
|
1325
|
+
|
|
1326
|
+
const isRowSelectable = (row) => {
|
|
1327
|
+
if (!row) return false;
|
|
1328
|
+
const type = row.dataset.entityType;
|
|
1329
|
+
const installed = row.dataset.installed !== 'false';
|
|
1330
|
+
const moduleKind = (row.dataset.moduleKind || '').toLowerCase();
|
|
1331
|
+
if (type === 'module' && !installed) return false;
|
|
1332
|
+
return true;
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
const findRowByKey = (key) =>
|
|
1336
|
+
Array.from(document.querySelectorAll('.entity-row')).find(
|
|
1337
|
+
(row) => row.dataset.entityKey === key
|
|
1338
|
+
);
|
|
1339
|
+
|
|
1340
|
+
const selectionPayloadFromRow = (row) => {
|
|
1341
|
+
if (!row) return null;
|
|
1342
|
+
return {
|
|
1343
|
+
key: row.dataset.entityKey,
|
|
1344
|
+
type: row.dataset.entityType,
|
|
1345
|
+
id: row.dataset.entityId || null,
|
|
1346
|
+
name: row.dataset.entityLabel || row.dataset.entityName || "",
|
|
1347
|
+
installed: row.dataset.installed,
|
|
1348
|
+
moduleKind: row.dataset.moduleKind,
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
const getVisibleRows = () =>
|
|
1353
|
+
Array.from(document.querySelectorAll('.entity-row')).filter(
|
|
1354
|
+
(row) => row.style.display !== 'none'
|
|
1355
|
+
);
|
|
1356
|
+
|
|
1357
|
+
const getSelectableVisibleRows = () =>
|
|
1358
|
+
getVisibleRows().filter((row) => isRowSelectable(row));
|
|
1359
|
+
|
|
1360
|
+
const isTypingTarget = (el) => {
|
|
1361
|
+
if (!el) return false;
|
|
1362
|
+
if (el.isContentEditable) return true;
|
|
1363
|
+
const tag = el.tagName;
|
|
1364
|
+
if (!tag) return false;
|
|
1365
|
+
const tagName = tag.toUpperCase();
|
|
1366
|
+
if (tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') return true;
|
|
1367
|
+
return !!el.closest('[contenteditable="true"]');
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
const refreshSelectionStyles = () => {
|
|
1371
|
+
document.querySelectorAll('.entity-row').forEach((row) => {
|
|
1372
|
+
const key = row.dataset.entityKey;
|
|
1373
|
+
if (!isRowSelectable(row) && selectedKeys.has(key)) {
|
|
1374
|
+
selectedKeys.delete(key);
|
|
1375
|
+
}
|
|
1376
|
+
if (selectedKeys.has(key)) {
|
|
1377
|
+
row.classList.add('table-active', 'entity-row-selected');
|
|
1378
|
+
} else {
|
|
1379
|
+
row.classList.remove('table-active', 'entity-row-selected');
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
};
|
|
1383
|
+
|
|
1384
|
+
const syncSelectBorder = (el, varName) => {
|
|
1385
|
+
if (!el) return;
|
|
1386
|
+
const disabledBorder =
|
|
1387
|
+
'color-mix(in srgb, var(--bs-btn-disabled-color, var(--bs-secondary)) 70%, transparent)';
|
|
1388
|
+
const enabledBorder = 'var(--bs-secondary)';
|
|
1389
|
+
const borderColor = el.disabled ? disabledBorder : enabledBorder;
|
|
1390
|
+
el.style.setProperty(varName, borderColor);
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
const markSelectChangedByUser = (sel) => {
|
|
1394
|
+
if (sel) sel.dataset.userSelected = 'true';
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
const resetSelectUserFlag = (sel) => {
|
|
1398
|
+
if (sel) sel.dataset.userSelected = '';
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
const updateSelectionUI = () => {
|
|
1402
|
+
refreshSelectionStyles();
|
|
1403
|
+
const count = selectedKeys.size ?? 0;
|
|
1404
|
+
if (selectionCountEl) {
|
|
1405
|
+
const suffix = TXT_SELECTED || 'selected';
|
|
1406
|
+
selectionCountEl.textContent = count + ' ' + suffix;
|
|
1407
|
+
}
|
|
1408
|
+
if (filtersRow && selectionBar) {
|
|
1409
|
+
if (count > 0) {
|
|
1410
|
+
filtersRow.classList.add('d-none');
|
|
1411
|
+
selectionBar.classList.remove('d-none');
|
|
1412
|
+
} else {
|
|
1413
|
+
filtersRow.classList.remove('d-none');
|
|
1414
|
+
selectionBar.classList.add('d-none');
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
if (bulkDeleteBtn) bulkDeleteBtn.disabled = count === 0;
|
|
1418
|
+
if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0;
|
|
1419
|
+
const items = Array.from(selectedKeys)
|
|
1420
|
+
.map((key) => selectionPayloadFromRow(findRowByKey(key)))
|
|
1421
|
+
.filter(Boolean);
|
|
1422
|
+
const hasTaggable = items.some((item) => isTaggableType(item.type));
|
|
1423
|
+
const hasDownloadable = items.some((item) => isDownloadableEntity(item));
|
|
1424
|
+
const hasAccessRoleEntities = items.some((item) =>
|
|
1425
|
+
["table","view","page"].includes(item.type)
|
|
1426
|
+
);
|
|
1427
|
+
const hasWriteRoleEntities = items.some((item) => item.type === "table");
|
|
1428
|
+
if (items.length === 1) {
|
|
1429
|
+
const only = items[0];
|
|
1430
|
+
const row = findRowByKey(only.key);
|
|
1431
|
+
if (row && bulkRoleReadSelect && bulkRoleReadSelect.dataset.userSelected !== 'true') {
|
|
1432
|
+
const initRead =
|
|
1433
|
+
only.type === 'table'
|
|
1434
|
+
? row.dataset.minRoleRead || ''
|
|
1435
|
+
: row.dataset.minRole || '';
|
|
1436
|
+
bulkRoleReadSelect.value = initRead || '';
|
|
1437
|
+
}
|
|
1438
|
+
if (row && bulkRoleWriteSelect && only.type === 'table' && bulkRoleWriteSelect.dataset.userSelected !== 'true') {
|
|
1439
|
+
const initWrite = row.dataset.minRoleWrite || '';
|
|
1440
|
+
bulkRoleWriteSelect.value = initWrite || '';
|
|
1441
|
+
}
|
|
1442
|
+
} else if (items.length === 0) {
|
|
1443
|
+
if (bulkRoleReadSelect) {
|
|
1444
|
+
bulkRoleReadSelect.value = '';
|
|
1445
|
+
resetSelectUserFlag(bulkRoleReadSelect);
|
|
1446
|
+
}
|
|
1447
|
+
if (bulkRoleWriteSelect) {
|
|
1448
|
+
bulkRoleWriteSelect.value = '';
|
|
1449
|
+
resetSelectUserFlag(bulkRoleWriteSelect);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (bulkTagSelect) {
|
|
1453
|
+
bulkTagSelect.disabled = !(count > 0 && hasTaggable);
|
|
1454
|
+
syncSelectBorder(bulkTagSelect, '--entity-bulk-tag-border');
|
|
1455
|
+
}
|
|
1456
|
+
if (bulkApplyTagBtn) {
|
|
1457
|
+
const tagSelected = bulkTagSelect && bulkTagSelect.value;
|
|
1458
|
+
bulkApplyTagBtn.disabled = !(count > 0 && hasTaggable && tagSelected);
|
|
1459
|
+
}
|
|
1460
|
+
if (bulkRoleReadSelect) {
|
|
1461
|
+
bulkRoleReadSelect.disabled = !(count > 0 && hasAccessRoleEntities);
|
|
1462
|
+
syncSelectBorder(bulkRoleReadSelect, '--entity-bulk-role-border');
|
|
1463
|
+
}
|
|
1464
|
+
if (bulkApplyRoleReadBtn) {
|
|
1465
|
+
const roleSelected = bulkRoleReadSelect && bulkRoleReadSelect.value;
|
|
1466
|
+
bulkApplyRoleReadBtn.disabled = !(count > 0 && hasAccessRoleEntities && roleSelected);
|
|
1467
|
+
}
|
|
1468
|
+
if (bulkRoleWriteSelect) {
|
|
1469
|
+
bulkRoleWriteSelect.disabled = !(count > 0 && hasWriteRoleEntities);
|
|
1470
|
+
syncSelectBorder(bulkRoleWriteSelect, '--entity-bulk-role-border');
|
|
1471
|
+
}
|
|
1472
|
+
if (bulkApplyRoleWriteBtn) {
|
|
1473
|
+
const roleSelected = bulkRoleWriteSelect && bulkRoleWriteSelect.value;
|
|
1474
|
+
bulkApplyRoleWriteBtn.disabled = !(count > 0 && hasWriteRoleEntities && roleSelected);
|
|
1475
|
+
}
|
|
1476
|
+
if (bulkRoleWriteGroup) {
|
|
1477
|
+
if (hasWriteRoleEntities) bulkRoleWriteGroup.classList.remove('d-none');
|
|
1478
|
+
else bulkRoleWriteGroup.classList.add('d-none');
|
|
1479
|
+
}
|
|
1480
|
+
if (bulkDownloadPackBtn) {
|
|
1481
|
+
// bulkDownloadPackBtn.disabled = !(count > 0 && hasDownloadable);
|
|
1482
|
+
bulkDownloadPackBtn.disabled = !(count > 0);
|
|
1483
|
+
}
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
const clearSelection = () => {
|
|
1487
|
+
selectedKeys.clear();
|
|
1488
|
+
lastSelectedIndex = null;
|
|
1489
|
+
updateSelectionUI();
|
|
1490
|
+
};
|
|
598
1491
|
|
|
599
1492
|
// Track active filters
|
|
600
1493
|
const activeFilters = new Set([]);
|
|
601
1494
|
const activeTags = new Set([]);
|
|
1495
|
+
const isModulesFilterExclusive = () =>
|
|
1496
|
+
activeFilters.size === 1 && activeFilters.has("module");
|
|
1497
|
+
window.isModulesFilterExclusive = isModulesFilterExclusive;
|
|
1498
|
+
|
|
1499
|
+
const isTaggableType = (type) => ["table","view","page","trigger"].includes(type);
|
|
1500
|
+
const isDownloadableEntity = (item) => {
|
|
1501
|
+
if (!item) return false;
|
|
1502
|
+
return ["table","view","page","trigger"].includes(item.type);
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1505
|
+
const updateRowTags = (row, tagId, tagName, entityType) => {
|
|
1506
|
+
if (!row || !tagId) return;
|
|
1507
|
+
const tagsCell = row.querySelector('td:nth-child(6)');
|
|
1508
|
+
if (!tagsCell) return;
|
|
1509
|
+
const dropdown = tagsCell.querySelector('.dropdown');
|
|
1510
|
+
const currentTags = (row.dataset.tags || '').split(' ').filter(Boolean);
|
|
1511
|
+
if (!currentTags.includes(String(tagId))) currentTags.push(String(tagId));
|
|
1512
|
+
row.dataset.tags = currentTags.join(' ');
|
|
1513
|
+
tagsCell.innerHTML = '';
|
|
1514
|
+
const pluralMap = { table: 'tables', view: 'views', page: 'pages', trigger: 'triggers' };
|
|
1515
|
+
currentTags.forEach((tid) => {
|
|
1516
|
+
const name = TAGS_BY_ID[tid] || tagName || tid;
|
|
1517
|
+
const plural = pluralMap[entityType] || 'tables';
|
|
1518
|
+
const badge = document.createElement('a');
|
|
1519
|
+
badge.className = 'badge bg-secondary me-1';
|
|
1520
|
+
badge.setAttribute('href', '/tag/' + encodeURIComponent(tid) + '?show_list=' + plural);
|
|
1521
|
+
badge.textContent = name;
|
|
1522
|
+
tagsCell.appendChild(badge);
|
|
1523
|
+
});
|
|
1524
|
+
if (dropdown) tagsCell.appendChild(dropdown);
|
|
1525
|
+
};
|
|
602
1526
|
|
|
603
1527
|
// URL state helpers
|
|
604
|
-
const TYPES = ["table","view","page","trigger"];
|
|
605
1528
|
const updateUrl = () => {
|
|
606
1529
|
const params = new URLSearchParams(window.location.search);
|
|
607
1530
|
// search
|
|
608
1531
|
if (searchInput.value) params.set('q', searchInput.value);
|
|
609
1532
|
else params.delete('q');
|
|
1533
|
+
if (deepSearchToggle && deepSearchToggle.checked) params.set('deep', 'on');
|
|
1534
|
+
else params.delete('deep');
|
|
610
1535
|
// types
|
|
611
|
-
|
|
1536
|
+
ALL_TYPES.forEach(t => {
|
|
612
1537
|
if (activeFilters.has(t)) params.set(t+'s', 'on');
|
|
613
1538
|
else params.delete(t+'s');
|
|
614
1539
|
});
|
|
1540
|
+
// extended flag
|
|
1541
|
+
if (typeof isExtendedExpanded !== 'undefined' && isExtendedExpanded) {
|
|
1542
|
+
params.set('extended', 'on');
|
|
1543
|
+
} else {
|
|
1544
|
+
params.delete('extended');
|
|
1545
|
+
}
|
|
615
1546
|
// tags (comma-separated ids)
|
|
616
1547
|
if (activeTags.size > 0) params.set('tags', Array.from(activeTags).join(','));
|
|
617
1548
|
else params.delete('tags');
|
|
@@ -619,35 +1550,53 @@ router.get(
|
|
|
619
1550
|
window.history.replaceState(null, '', newUrl);
|
|
620
1551
|
};
|
|
621
1552
|
|
|
622
|
-
const
|
|
1553
|
+
const getCurrentOnDoneTarget = () => {
|
|
623
1554
|
const path = window.location.pathname.startsWith("/")
|
|
624
1555
|
? window.location.pathname.slice(1)
|
|
625
1556
|
: window.location.pathname;
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
1557
|
+
return path + window.location.search;
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1560
|
+
const shouldSkipOnDoneHref = (raw) => {
|
|
1561
|
+
if (!raw) return true;
|
|
1562
|
+
const trimmed = raw.trim();
|
|
1563
|
+
const lowered = trimmed.toLowerCase();
|
|
1564
|
+
return trimmed === "#" || trimmed === "" || lowered.startsWith("javascript:");
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
const toRelativeHrefWithOnDone = (raw) => {
|
|
1568
|
+
if (shouldSkipOnDoneHref(raw)) return null;
|
|
1569
|
+
try {
|
|
1570
|
+
const url = new URL(raw, window.location.origin);
|
|
1571
|
+
url.searchParams.set("on_done_redirect", getCurrentOnDoneTarget());
|
|
1572
|
+
return url.pathname + url.search + url.hash;
|
|
1573
|
+
} catch (e) {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
const updateElementOnDoneHref = (el, attr) => {
|
|
1579
|
+
const raw = el.getAttribute(attr) || el[attr];
|
|
1580
|
+
const updated = toRelativeHrefWithOnDone(raw);
|
|
1581
|
+
if (updated) el.setAttribute(attr, updated);
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
const ensureOnDoneHiddenInput = (form) => {
|
|
1585
|
+
if (form.querySelector('input[name="on_done_redirect"]')) return;
|
|
1586
|
+
const hidden = document.createElement('input');
|
|
1587
|
+
hidden.type = 'hidden';
|
|
1588
|
+
hidden.name = 'on_done_redirect';
|
|
1589
|
+
hidden.value = getCurrentOnDoneTarget();
|
|
1590
|
+
form.appendChild(hidden);
|
|
1591
|
+
};
|
|
1592
|
+
|
|
1593
|
+
const updateOnDoneRedirectTargets = () => {
|
|
645
1594
|
document
|
|
646
1595
|
.querySelectorAll('a[href*="on_done_redirect="]')
|
|
647
|
-
.forEach((link) =>
|
|
1596
|
+
.forEach((link) => updateElementOnDoneHref(link, "href"));
|
|
648
1597
|
document
|
|
649
1598
|
.querySelectorAll('form[action*="on_done_redirect="]')
|
|
650
|
-
.forEach((form) =>
|
|
1599
|
+
.forEach((form) => updateElementOnDoneHref(form, "action"));
|
|
651
1600
|
};
|
|
652
1601
|
|
|
653
1602
|
const updateLegacyButton = () => {
|
|
@@ -670,8 +1619,13 @@ router.get(
|
|
|
670
1619
|
// search
|
|
671
1620
|
const q = params.get('q') || '';
|
|
672
1621
|
if (q) searchInput.value = q;
|
|
1622
|
+
const deep = params.get('deep') === 'on';
|
|
1623
|
+
if (deep && deepSearchToggle) deepSearchToggle.checked = true;
|
|
1624
|
+
const shouldExpandExtended =
|
|
1625
|
+
params.get('extended') === 'on' ||
|
|
1626
|
+
EXTENDED_TYPES.some((t) => params.get(t + 's') === 'on');
|
|
673
1627
|
// types
|
|
674
|
-
|
|
1628
|
+
ALL_TYPES.forEach(t => {
|
|
675
1629
|
if (params.get(t+'s') === 'on') activeFilters.add(t);
|
|
676
1630
|
});
|
|
677
1631
|
// apply button classes for types
|
|
@@ -695,17 +1649,39 @@ router.get(
|
|
|
695
1649
|
btn.classList.remove('btn-outline-secondary');
|
|
696
1650
|
}
|
|
697
1651
|
});
|
|
1652
|
+
return { shouldExpandExtended };
|
|
698
1653
|
};
|
|
699
1654
|
|
|
700
1655
|
// Filter function
|
|
701
1656
|
function filterEntities() {
|
|
1657
|
+
const entityRows = document.querySelectorAll(".entity-row");
|
|
702
1658
|
const searchTerm = searchInput.value.toLowerCase();
|
|
1659
|
+
const useDeep = deepSearchToggle && deepSearchToggle.checked;
|
|
703
1660
|
let visibleCount = 0;
|
|
1661
|
+
const visibleKeys = new Set();
|
|
1662
|
+
const allowAllModules = isModulesFilterExclusive();
|
|
1663
|
+
const canShowAllModules =
|
|
1664
|
+
allowAllModules && typeof isExtendedExpanded !== "undefined" && isExtendedExpanded;
|
|
1665
|
+
if (
|
|
1666
|
+
canShowAllModules &&
|
|
1667
|
+
typeof ensureAllModulesLoaded === "function" &&
|
|
1668
|
+
typeof hasLoadedAllModules !== "undefined" &&
|
|
1669
|
+
!hasLoadedAllModules
|
|
1670
|
+
) {
|
|
1671
|
+
ensureAllModulesLoaded();
|
|
1672
|
+
}
|
|
704
1673
|
|
|
705
|
-
entityRows.forEach((row) => {
|
|
1674
|
+
entityRows.forEach((row, id) => {
|
|
706
1675
|
const entityType = row.dataset.entityType;
|
|
707
|
-
const
|
|
1676
|
+
const key = row.dataset.entityKey;
|
|
1677
|
+
const deepText =
|
|
1678
|
+
useDeep && window.ENTITY_DEEP_SEARCH
|
|
1679
|
+
? window.ENTITY_DEEP_SEARCH[key]
|
|
1680
|
+
: null;
|
|
1681
|
+
const searchableText = useDeep ? deepText || row.dataset.deepSearchable || "" : row.dataset.searchable || "";
|
|
1682
|
+
|
|
708
1683
|
const rowTags = (row.dataset.tags || "").split(" ").filter(Boolean);
|
|
1684
|
+
const rowInstalled = row.dataset.installed !== "false";
|
|
709
1685
|
|
|
710
1686
|
// Check if entity type is active
|
|
711
1687
|
const typeMatch = activeFilters.has(entityType);
|
|
@@ -722,15 +1698,28 @@ router.get(
|
|
|
722
1698
|
tagMatch = rowTags.some((tid) => activeTags.has(tid));
|
|
723
1699
|
}
|
|
724
1700
|
|
|
1701
|
+
const moduleVisibilityOk =
|
|
1702
|
+
entityType !== "module" || rowInstalled || canShowAllModules;
|
|
1703
|
+
|
|
725
1704
|
// Show/hide row
|
|
726
|
-
if (
|
|
1705
|
+
if (
|
|
1706
|
+
(activeFilters.size === 0 || typeMatch) &&
|
|
1707
|
+
searchMatch &&
|
|
1708
|
+
tagMatch &&
|
|
1709
|
+
moduleVisibilityOk
|
|
1710
|
+
) {
|
|
727
1711
|
row.style.display = "";
|
|
1712
|
+
visibleKeys.add(row.dataset.entityKey);
|
|
728
1713
|
visibleCount++;
|
|
729
1714
|
} else {
|
|
730
1715
|
row.style.display = "none";
|
|
731
1716
|
}
|
|
732
1717
|
});
|
|
733
1718
|
|
|
1719
|
+
selectedKeys.forEach((key) => {
|
|
1720
|
+
if (!visibleKeys.has(key)) selectedKeys.delete(key);
|
|
1721
|
+
});
|
|
1722
|
+
|
|
734
1723
|
// Show/hide no results message
|
|
735
1724
|
if (visibleCount === 0) {
|
|
736
1725
|
entitiesList.parentElement.classList.add("d-none");
|
|
@@ -743,10 +1732,20 @@ router.get(
|
|
|
743
1732
|
updateUrl();
|
|
744
1733
|
updateOnDoneRedirectTargets();
|
|
745
1734
|
updateLegacyButton();
|
|
1735
|
+
updateSelectionUI();
|
|
746
1736
|
}
|
|
747
1737
|
|
|
748
1738
|
// Search input handler
|
|
749
1739
|
searchInput.addEventListener("input", filterEntities);
|
|
1740
|
+
searchInput.addEventListener("keydown", (e) => {
|
|
1741
|
+
if (e.key === "Escape" || e.key === "Esc") {
|
|
1742
|
+
e.preventDefault();
|
|
1743
|
+
searchInput.blur();
|
|
1744
|
+
}
|
|
1745
|
+
});
|
|
1746
|
+
if (deepSearchToggle) {
|
|
1747
|
+
deepSearchToggle.addEventListener("change", filterEntities);
|
|
1748
|
+
}
|
|
750
1749
|
|
|
751
1750
|
// Filter button handlers
|
|
752
1751
|
filterButtons.forEach((btn) => {
|
|
@@ -764,6 +1763,9 @@ router.get(
|
|
|
764
1763
|
}
|
|
765
1764
|
|
|
766
1765
|
filterEntities();
|
|
1766
|
+
if (searchInput && typeof searchInput.focus === 'function') {
|
|
1767
|
+
searchInput.focus({ preventScroll: true });
|
|
1768
|
+
}
|
|
767
1769
|
});
|
|
768
1770
|
});
|
|
769
1771
|
|
|
@@ -784,22 +1786,456 @@ router.get(
|
|
|
784
1786
|
});
|
|
785
1787
|
});
|
|
786
1788
|
|
|
1789
|
+
const keyboardShortcutTypeMap = {
|
|
1790
|
+
KeyT: "table",
|
|
1791
|
+
KeyV: "view",
|
|
1792
|
+
KeyP: "page",
|
|
1793
|
+
KeyR: "trigger",
|
|
1794
|
+
KeyM: "module",
|
|
1795
|
+
KeyU: "user",
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
document.addEventListener("keydown", async (e) => {
|
|
1799
|
+
const isFromSearchInput = e.target === searchInput;
|
|
1800
|
+
const typingTarget = isTypingTarget(e.target);
|
|
1801
|
+
|
|
1802
|
+
if (e.altKey && !e.ctrlKey && !e.metaKey) {
|
|
1803
|
+
const type = keyboardShortcutTypeMap[e.code];
|
|
1804
|
+
if (type) {
|
|
1805
|
+
e.preventDefault();
|
|
1806
|
+
const isExtendedType = EXTENDED_TYPES.includes(type);
|
|
1807
|
+
if (
|
|
1808
|
+
isExtendedType &&
|
|
1809
|
+
typeof isExtendedExpanded !== "undefined" &&
|
|
1810
|
+
!isExtendedExpanded &&
|
|
1811
|
+
typeof toggleEntityExpanded === "function"
|
|
1812
|
+
) {
|
|
1813
|
+
await toggleEntityExpanded(true);
|
|
1814
|
+
}
|
|
1815
|
+
const btn = filterButtonsByType[type];
|
|
1816
|
+
if (btn) {
|
|
1817
|
+
btn.click();
|
|
1818
|
+
if (searchInput && typeof searchInput.focus === 'function') {
|
|
1819
|
+
searchInput.focus({ preventScroll: true });
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (deepSearchToggle && e.code === "KeyS") {
|
|
1825
|
+
e.preventDefault();
|
|
1826
|
+
deepSearchToggle.checked = !deepSearchToggle.checked;
|
|
1827
|
+
filterEntities();
|
|
1828
|
+
if (searchInput && typeof searchInput.focus === 'function') {
|
|
1829
|
+
searchInput.focus({ preventScroll: true });
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
if (typingTarget && !isFromSearchInput) return;
|
|
1835
|
+
|
|
1836
|
+
const isSelectAllKey = e.key === "a" || e.key === "A";
|
|
1837
|
+
if ((e.metaKey || e.ctrlKey) && !e.altKey && isSelectAllKey) {
|
|
1838
|
+
const visibleRows = getSelectableVisibleRows();
|
|
1839
|
+
if (!visibleRows.length) return;
|
|
1840
|
+
e.preventDefault();
|
|
1841
|
+
visibleRows.forEach((row) => {
|
|
1842
|
+
const key = row.dataset.entityKey;
|
|
1843
|
+
if (key) selectedKeys.add(key);
|
|
1844
|
+
});
|
|
1845
|
+
lastSelectedIndex = visibleRows.length - 1;
|
|
1846
|
+
updateSelectionUI();
|
|
1847
|
+
}
|
|
1848
|
+
});
|
|
1849
|
+
|
|
1850
|
+
if (clearSelectionBtn) {
|
|
1851
|
+
clearSelectionBtn.addEventListener('click', () => {
|
|
1852
|
+
clearSelection();
|
|
1853
|
+
filterEntities();
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
if(bulkTagSelect) {
|
|
1858
|
+
bulkTagSelect.addEventListener('change', () => updateSelectionUI());
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
if (bulkRoleReadSelect) {
|
|
1862
|
+
bulkRoleReadSelect.addEventListener('change', () => {
|
|
1863
|
+
markSelectChangedByUser(bulkRoleReadSelect);
|
|
1864
|
+
updateSelectionUI();
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
if (bulkRoleWriteSelect) {
|
|
1869
|
+
bulkRoleWriteSelect.addEventListener('change', () => {
|
|
1870
|
+
markSelectChangedByUser(bulkRoleWriteSelect);
|
|
1871
|
+
updateSelectionUI();
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
const doBulkApplyTag = async () => {
|
|
1876
|
+
if(!bulkApplyTagBtn || !bulkTagSelect) return;
|
|
1877
|
+
const tagId = bulkTagSelect.value;
|
|
1878
|
+
if (!tagId) return;
|
|
1879
|
+
const items = collectSelectionItems().filter((item) => isTaggableType(item.type));
|
|
1880
|
+
if (!items.length) return;
|
|
1881
|
+
bulkApplyTagBtn.disabled = true;
|
|
1882
|
+
try {
|
|
1883
|
+
const res = await fetch('/entities/bulk-apply-tag', {
|
|
1884
|
+
method: 'POST',
|
|
1885
|
+
headers: {
|
|
1886
|
+
"Content-Type": "application/json",
|
|
1887
|
+
'CSRF-Token': window._sc_globalCsrf || '',
|
|
1888
|
+
},
|
|
1889
|
+
body: JSON.stringify({ tag_id: tagId, items }),
|
|
1890
|
+
});
|
|
1891
|
+
if (!res.ok) throw new Error(await res.text());
|
|
1892
|
+
await res.json();
|
|
1893
|
+
const tagName = TAGS_BY_ID[tagId] || '';
|
|
1894
|
+
items.forEach((item) => {
|
|
1895
|
+
const row = findRowByKey(item.key);
|
|
1896
|
+
if (row) updateRowTags(row, tagId, tagName, item.type);
|
|
1897
|
+
});
|
|
1898
|
+
filterEntities();
|
|
1899
|
+
} catch (e) {
|
|
1900
|
+
console.error('Failed to apply tag to selected items', e);
|
|
1901
|
+
alert("Failed to apply tag to selected items");
|
|
1902
|
+
}
|
|
1903
|
+
bulkApplyTagBtn.disabled = false;
|
|
1904
|
+
};
|
|
1905
|
+
|
|
1906
|
+
if(bulkApplyTagBtn) {
|
|
1907
|
+
bulkApplyTagBtn.addEventListener('click', doBulkApplyTag);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
const triggerDownload = (filename, content) => {
|
|
1911
|
+
const blob = new Blob([content], { type: 'application/json' });
|
|
1912
|
+
const url = URL.createObjectURL(blob);
|
|
1913
|
+
const a = document.createElement('a');
|
|
1914
|
+
a.href = url;
|
|
1915
|
+
a.download = filename;
|
|
1916
|
+
document.body.appendChild(a);
|
|
1917
|
+
a.click();
|
|
1918
|
+
document.body.removeChild(a);
|
|
1919
|
+
URL.revokeObjectURL(url);
|
|
1920
|
+
};
|
|
1921
|
+
|
|
1922
|
+
const doBulkDownloadPack = async () => {
|
|
1923
|
+
if (!bulkDownloadPackBtn) return;
|
|
1924
|
+
const items = collectSelectionItems()
|
|
1925
|
+
// .filter((item) => isDownloadableEntity(item));
|
|
1926
|
+
if (!items.length) return;
|
|
1927
|
+
bulkDownloadPackBtn.disabled = true;
|
|
1928
|
+
try {
|
|
1929
|
+
const res = await fetch('/entities/download-pack', {
|
|
1930
|
+
method: 'POST',
|
|
1931
|
+
headers: {
|
|
1932
|
+
'Content-Type': 'application/json',
|
|
1933
|
+
'CSRF-Token': window._sc_globalCsrf || '',
|
|
1934
|
+
},
|
|
1935
|
+
body: JSON.stringify({ items }),
|
|
1936
|
+
});
|
|
1937
|
+
if (!res.ok) throw new Error(await res.text());
|
|
1938
|
+
const payload = await res.json();
|
|
1939
|
+
if (Array.isArray(payload?.packs)) {
|
|
1940
|
+
payload.packs.forEach((pack) => {
|
|
1941
|
+
if (pack && pack.name && pack.content) {
|
|
1942
|
+
const content =
|
|
1943
|
+
typeof pack.content === 'string'
|
|
1944
|
+
? pack.content
|
|
1945
|
+
: JSON.stringify(pack.content, null, 2);
|
|
1946
|
+
triggerDownload(pack.name + '.json', content);
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
} catch (e) {
|
|
1951
|
+
console.error('Failed to download pack(s)', e);
|
|
1952
|
+
alert("Failed to download pack for selected items");
|
|
1953
|
+
}
|
|
1954
|
+
bulkDownloadPackBtn.disabled = false;
|
|
1955
|
+
};
|
|
1956
|
+
|
|
1957
|
+
if (bulkDownloadPackBtn) {
|
|
1958
|
+
bulkDownloadPackBtn.addEventListener('click', doBulkDownloadPack);
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
if (bulkApplyRoleReadBtn) {
|
|
1962
|
+
bulkApplyRoleReadBtn.addEventListener('click', () => doBulkApplyRole('read'));
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
if (bulkApplyRoleWriteBtn) {
|
|
1966
|
+
bulkApplyRoleWriteBtn.addEventListener('click', () => doBulkApplyRole('write'));
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
const collectSelectionItems = () =>
|
|
1970
|
+
Array.from(selectedKeys)
|
|
1971
|
+
.map((key) => selectionPayloadFromRow(findRowByKey(key)))
|
|
1972
|
+
.filter(Boolean);
|
|
1973
|
+
|
|
1974
|
+
const getRoleName = (rid) => {
|
|
1975
|
+
if (typeof rid === 'undefined') return '';
|
|
1976
|
+
const key = String(rid);
|
|
1977
|
+
if (!ROLES_BY_ID) return '';
|
|
1978
|
+
return Object.prototype.hasOwnProperty.call(ROLES_BY_ID, key) ? ROLES_BY_ID[key] : '?';
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1981
|
+
const toNumberOrUndefined = (val) => {
|
|
1982
|
+
if (val === '' || typeof val === 'undefined' || val === null) return undefined;
|
|
1983
|
+
const num = Number(val);
|
|
1984
|
+
return Number.isNaN(num) ? undefined : num;
|
|
1985
|
+
};
|
|
1986
|
+
|
|
1987
|
+
const updateRowAccess = (row, payload) => {
|
|
1988
|
+
if (!row) return;
|
|
1989
|
+
if (typeof payload.min_role_read !== 'undefined') row.dataset.minRoleRead = String(payload.min_role_read ?? '');
|
|
1990
|
+
if (typeof payload.min_role_write !== 'undefined') row.dataset.minRoleWrite = String(payload.min_role_write ?? '');
|
|
1991
|
+
if (typeof payload.min_role !== 'undefined') row.dataset.minRole = String(payload.min_role ?? '');
|
|
1992
|
+
const cell = row.querySelector('td:nth-child(5)');
|
|
1993
|
+
if (cell) {
|
|
1994
|
+
const label = (() => {
|
|
1995
|
+
if (payload.type === 'table') {
|
|
1996
|
+
const ext = row.dataset.external === 'true';
|
|
1997
|
+
const rr = toNumberOrUndefined(payload.min_role_read);
|
|
1998
|
+
const rw = toNumberOrUndefined(payload.min_role_write);
|
|
1999
|
+
if (ext) return getRoleName(rr) + " (read only)";
|
|
2000
|
+
if (typeof rr !== 'undefined' && typeof rw !== 'undefined') return getRoleName(rr) + "/" + getRoleName(rw);
|
|
2001
|
+
return '';
|
|
2002
|
+
}
|
|
2003
|
+
const mr = toNumberOrUndefined(payload.min_role);
|
|
2004
|
+
return typeof mr !== 'undefined' ? getRoleName(mr) : '';
|
|
2005
|
+
})();
|
|
2006
|
+
cell.textContent = label;
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
const doBulkApplyRole = async (mode) => {
|
|
2011
|
+
const isWriteMode = mode === 'write';
|
|
2012
|
+
const selectEl = isWriteMode ? bulkRoleWriteSelect : bulkRoleReadSelect;
|
|
2013
|
+
const buttonEl = isWriteMode ? bulkApplyRoleWriteBtn : bulkApplyRoleReadBtn;
|
|
2014
|
+
if (!selectEl || !buttonEl) return;
|
|
2015
|
+
const roleId = selectEl.value;
|
|
2016
|
+
if (!roleId) return;
|
|
2017
|
+
const items = collectSelectionItems().filter((item) => {
|
|
2018
|
+
if (isWriteMode) return item.type === 'table';
|
|
2019
|
+
return ['table', 'view', 'page'].includes(item.type);
|
|
2020
|
+
});
|
|
2021
|
+
if (!items.length) return;
|
|
2022
|
+
buttonEl.disabled = true;
|
|
2023
|
+
try {
|
|
2024
|
+
const res = await fetch('/entities/bulk-set-role', {
|
|
2025
|
+
method: 'POST',
|
|
2026
|
+
headers: {
|
|
2027
|
+
'Content-Type': 'application/json',
|
|
2028
|
+
'CSRF-Token': window._sc_globalCsrf || '',
|
|
2029
|
+
},
|
|
2030
|
+
body: JSON.stringify({ items, role_id: roleId, mode }),
|
|
2031
|
+
});
|
|
2032
|
+
if (!res.ok) throw new Error(await res.text());
|
|
2033
|
+
const payload = await res.json();
|
|
2034
|
+
const updatedKeys = new Set(payload?.updatedKeys || []);
|
|
2035
|
+
const errors = payload?.errors || [];
|
|
2036
|
+
if (errors.length) {
|
|
2037
|
+
console.error('Failed to set role for some items', errors);
|
|
2038
|
+
alert('Failed to set role for some selected items');
|
|
2039
|
+
}
|
|
2040
|
+
items.forEach((item) => {
|
|
2041
|
+
if (updatedKeys.size && !updatedKeys.has(item.key)) return;
|
|
2042
|
+
const row = findRowByKey(item.key);
|
|
2043
|
+
if (!row) return;
|
|
2044
|
+
if (isWriteMode && item.type === 'table') {
|
|
2045
|
+
updateRowAccess(row, { type: 'table', min_role_write: Number(roleId), min_role_read: toNumberOrUndefined(row.dataset.minRoleRead) });
|
|
2046
|
+
} else if (!isWriteMode) {
|
|
2047
|
+
if (item.type === 'table') {
|
|
2048
|
+
updateRowAccess(row, { type: 'table', min_role_read: Number(roleId), min_role_write: toNumberOrUndefined(row.dataset.minRoleWrite) });
|
|
2049
|
+
} else if (item.type === 'view') {
|
|
2050
|
+
updateRowAccess(row, { type: 'view', min_role: Number(roleId) });
|
|
2051
|
+
} else if (item.type === 'page') {
|
|
2052
|
+
updateRowAccess(row, { type: 'page', min_role: Number(roleId) });
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
} catch (e) {
|
|
2057
|
+
console.error('Failed to set role for selected items', e);
|
|
2058
|
+
alert('Failed to set role for selected items');
|
|
2059
|
+
}
|
|
2060
|
+
buttonEl.disabled = false;
|
|
2061
|
+
updateSelectionUI();
|
|
2062
|
+
};
|
|
2063
|
+
|
|
2064
|
+
const formatDeleteError = (err) => {
|
|
2065
|
+
const displayType = err?.isPack
|
|
2066
|
+
? "Pack"
|
|
2067
|
+
: (() => {
|
|
2068
|
+
const t = (err?.type || "").toString();
|
|
2069
|
+
if (!t) return "Item";
|
|
2070
|
+
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
2071
|
+
})();
|
|
2072
|
+
const label = err?.name || err?.id || err?.key || "(unknown)";
|
|
2073
|
+
const message = err?.message || TXT_DELETE_FAILED || "Failed to delete selected items";
|
|
2074
|
+
return displayType + " (" + label + "): " + message;
|
|
2075
|
+
};
|
|
2076
|
+
|
|
2077
|
+
const showBulkDeleteErrors = (errs) => {
|
|
2078
|
+
if (!errs || !errs.length) return;
|
|
2079
|
+
const body = errs
|
|
2080
|
+
.map((e) => formatDeleteError(e))
|
|
2081
|
+
.join("\\n-----\\n");
|
|
2082
|
+
alert(body);
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
const removeRowsByKeys = (keysToRemove) => {
|
|
2086
|
+
if (!keysToRemove || !keysToRemove.size) return;
|
|
2087
|
+
document.querySelectorAll('.entity-row').forEach((row) => {
|
|
2088
|
+
if (keysToRemove.has(row.dataset.entityKey)) row.remove();
|
|
2089
|
+
});
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
const refreshExtendedEntitiesAfterDelete = async () => {
|
|
2093
|
+
if (typeof isExtendedExpanded !== 'undefined' && !isExtendedExpanded) return;
|
|
2094
|
+
if (typeof loadExtendedEntities !== 'function' || typeof renderExtendedEntityRows !== 'function') return;
|
|
2095
|
+
const tbody = document.querySelector('#entities-list tbody');
|
|
2096
|
+
if (!tbody) return;
|
|
2097
|
+
const shouldLoadAll = typeof window.isModulesFilterExclusive === 'function'
|
|
2098
|
+
? window.isModulesFilterExclusive()
|
|
2099
|
+
: false;
|
|
2100
|
+
try {
|
|
2101
|
+
const extendedEntities = await loadExtendedEntities(shouldLoadAll);
|
|
2102
|
+
window.extendedEntities = extendedEntities;
|
|
2103
|
+
renderExtendedEntityRows(extendedEntities, tbody);
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
console.error('Failed to refresh extended entities after delete:', err);
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
|
|
2109
|
+
if (bulkDeleteBtn) {
|
|
2110
|
+
bulkDeleteBtn.addEventListener('click', async () => {
|
|
2111
|
+
const items = collectSelectionItems();
|
|
2112
|
+
if (!items.length) return;
|
|
2113
|
+
const template = TXT_DELETE_SELECTED_CONFIRM || TXT_DELETE_SELECTED_FALLBACK;
|
|
2114
|
+
const msg = template.includes('%s')
|
|
2115
|
+
? template.replace('%s', items.length)
|
|
2116
|
+
: template;
|
|
2117
|
+
if (!window.confirm(msg)) return;
|
|
2118
|
+
bulkDeleteBtn.disabled = true;
|
|
2119
|
+
try {
|
|
2120
|
+
const res = await fetch('/entities/bulk-delete', {
|
|
2121
|
+
method: 'POST',
|
|
2122
|
+
headers: {
|
|
2123
|
+
'Content-Type': 'application/json',
|
|
2124
|
+
'CSRF-Token': window._sc_globalCsrf || '',
|
|
2125
|
+
},
|
|
2126
|
+
body: JSON.stringify({ items }),
|
|
2127
|
+
});
|
|
2128
|
+
if (!res.ok) throw new Error(await res.text());
|
|
2129
|
+
const payload = await res.json();
|
|
2130
|
+
const keysToRemove = new Set(
|
|
2131
|
+
(payload.deletedKeys && payload.deletedKeys.length
|
|
2132
|
+
? payload.deletedKeys
|
|
2133
|
+
: items.map((i) => i.key))
|
|
2134
|
+
);
|
|
2135
|
+
removeRowsByKeys(keysToRemove);
|
|
2136
|
+
if (payload.errors && payload.errors.length) {
|
|
2137
|
+
console.error('Bulk delete errors', payload.errors);
|
|
2138
|
+
showBulkDeleteErrors(payload.errors);
|
|
2139
|
+
}
|
|
2140
|
+
clearSelection();
|
|
2141
|
+
await refreshExtendedEntitiesAfterDelete();
|
|
2142
|
+
filterEntities();
|
|
2143
|
+
} catch (e) {
|
|
2144
|
+
console.error(e);
|
|
2145
|
+
alert(TXT_DELETE_FAILED || 'Failed to delete selected items');
|
|
2146
|
+
}
|
|
2147
|
+
bulkDeleteBtn.disabled = false;
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
if (entitiesTbody) {
|
|
2152
|
+
entitiesTbody.addEventListener('click', (e) => {
|
|
2153
|
+
const row = e.target.closest('.entity-row');
|
|
2154
|
+
if (!row) return;
|
|
2155
|
+
if (e.target.closest('a, button, input, select, textarea, label'))
|
|
2156
|
+
return;
|
|
2157
|
+
if (!isRowSelectable(row)) {
|
|
2158
|
+
lastSelectedIndex = null;
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
const visibleRows = getSelectableVisibleRows();
|
|
2162
|
+
const index = visibleRows.indexOf(row);
|
|
2163
|
+
const key = row.dataset.entityKey;
|
|
2164
|
+
if (!key) return;
|
|
2165
|
+
const isShift = e.shiftKey;
|
|
2166
|
+
const isMeta = e.metaKey || e.ctrlKey;
|
|
2167
|
+
|
|
2168
|
+
if (isShift && lastSelectedIndex !== null && visibleRows[lastSelectedIndex]) {
|
|
2169
|
+
selectedKeys.clear();
|
|
2170
|
+
const start = Math.min(lastSelectedIndex, index);
|
|
2171
|
+
const end = Math.max(lastSelectedIndex, index);
|
|
2172
|
+
for (let i = start; i <= end; i++) {
|
|
2173
|
+
const rangeKey = visibleRows[i].dataset.entityKey;
|
|
2174
|
+
if (rangeKey) selectedKeys.add(rangeKey);
|
|
2175
|
+
}
|
|
2176
|
+
} else if (isMeta) {
|
|
2177
|
+
if (selectedKeys.has(key)) {
|
|
2178
|
+
selectedKeys.delete(key);
|
|
2179
|
+
} else {
|
|
2180
|
+
selectedKeys.add(key);
|
|
2181
|
+
}
|
|
2182
|
+
lastSelectedIndex = index;
|
|
2183
|
+
} else {
|
|
2184
|
+
const onlyThisSelected = selectedKeys.size === 1 && selectedKeys.has(key);
|
|
2185
|
+
selectedKeys.clear();
|
|
2186
|
+
if (!onlyThisSelected) {
|
|
2187
|
+
selectedKeys.add(key);
|
|
2188
|
+
lastSelectedIndex = index;
|
|
2189
|
+
} else {
|
|
2190
|
+
lastSelectedIndex = null;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
updateSelectionUI();
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
|
|
787
2197
|
// Init from URL and run first filter
|
|
788
|
-
initFromUrl();
|
|
789
|
-
|
|
2198
|
+
const { shouldExpandExtended } = initFromUrl();
|
|
2199
|
+
if (shouldExpandExtended) {
|
|
2200
|
+
toggleEntityExpanded(true);
|
|
2201
|
+
} else {
|
|
2202
|
+
filterEntities();
|
|
2203
|
+
}
|
|
790
2204
|
// Focus search on load
|
|
791
2205
|
searchInput.focus();
|
|
2206
|
+
updateSelectionUI();
|
|
792
2207
|
`)
|
|
793
2208
|
);
|
|
794
2209
|
|
|
795
2210
|
const styles = `
|
|
796
2211
|
<style>
|
|
2212
|
+
/* Temporary fallback selection bg color */
|
|
2213
|
+
:root {
|
|
2214
|
+
--bs-secondary-bg-fallback: #ececec;
|
|
2215
|
+
}
|
|
2216
|
+
[data-bs-theme="dark"] {
|
|
2217
|
+
--bs-secondary-bg-fallback: #2c2c2c;
|
|
2218
|
+
}
|
|
797
2219
|
.entity-row td { vertical-align: middle; }
|
|
798
|
-
.entity-
|
|
2220
|
+
.entity-row { user-select: none; }
|
|
2221
|
+
.entity-row-selection-disabled {
|
|
2222
|
+
cursor: not-allowed;
|
|
2223
|
+
/* opacity: 0.8; */
|
|
2224
|
+
}
|
|
2225
|
+
.entity-filter-btn { transition: all 0.15s ease-in-out; max-width: 105px; }
|
|
799
2226
|
.tag-filter-btn { transition: all 0.15s ease-in-out; }
|
|
800
2227
|
/* Show plus badge only on hover over tag cell */
|
|
801
|
-
td:nth-child(
|
|
802
|
-
tr:hover td:nth-child(
|
|
2228
|
+
td:nth-child(6) .add-tag { visibility: hidden; cursor: pointer; }
|
|
2229
|
+
tr:hover td:nth-child(6) .add-tag { visibility: visible; }
|
|
2230
|
+
|
|
2231
|
+
#entity-more-btn:not(.d-none) {
|
|
2232
|
+
border-top-right-radius: 0.25rem !important;
|
|
2233
|
+
border-bottom-right-radius: 0.25rem !important;
|
|
2234
|
+
max-width: 80px;
|
|
2235
|
+
}
|
|
2236
|
+
#entity-less-btn:not(.d-none) {
|
|
2237
|
+
max-width: 80px;
|
|
2238
|
+
}
|
|
803
2239
|
</style>
|
|
804
2240
|
`;
|
|
805
2241
|
|
|
@@ -816,16 +2252,334 @@ router.get(
|
|
|
816
2252
|
title: req.__("All entities"),
|
|
817
2253
|
contents: [
|
|
818
2254
|
div(
|
|
819
|
-
{ class: "d-flex flex-column gap-
|
|
2255
|
+
{ class: "d-flex flex-column gap-0" },
|
|
820
2256
|
searchBox,
|
|
821
2257
|
filtersRow,
|
|
2258
|
+
selectionBar,
|
|
822
2259
|
div(
|
|
823
2260
|
{ class: "flex-grow-1 card-max-full-screen-scroll" },
|
|
824
2261
|
entitiesList,
|
|
825
2262
|
noResultsMessage
|
|
826
2263
|
)
|
|
827
2264
|
),
|
|
828
|
-
clientScript,
|
|
2265
|
+
// clientScript,
|
|
2266
|
+
script(
|
|
2267
|
+
domReady(/*js*/ `
|
|
2268
|
+
window.ENTITY_ROLES = ${JSON.stringify(roles)};
|
|
2269
|
+
window.TXT_DISABLED = ${JSON.stringify(req.__("Disabled"))};
|
|
2270
|
+
window.TXT_CONFIGURABLE = ${JSON.stringify(req.__("Configurable"))};
|
|
2271
|
+
window.TXT_THEME = ${JSON.stringify(req.__("Theme"))};
|
|
2272
|
+
window.TXT_LOCAL = ${JSON.stringify(req.__("Local"))};
|
|
2273
|
+
window.TXT_INSTALLED = ${JSON.stringify(req.__("Installed"))};
|
|
2274
|
+
window.TXT_MODULE = ${JSON.stringify(req.__("Module"))};
|
|
2275
|
+
window.TXT_PACK = ${JSON.stringify(req.__("Pack"))};
|
|
2276
|
+
window.TXT_INFO = ${JSON.stringify(req.__("Info"))};
|
|
2277
|
+
window.TXT_AUTH = ${JSON.stringify(req.__("Authentication"))};
|
|
2278
|
+
window.TXT_MOBILE = ${JSON.stringify(req.__("Mobile"))};
|
|
2279
|
+
window.ENTITY_DEEP_SEARCH = ${JSON.stringify(deepSearchIndex)};
|
|
2280
|
+
|
|
2281
|
+
const EXTENDED_ENTITY_TYPES = ["module","user"];
|
|
2282
|
+
window.ENTITY_EXTENDED_TYPES = EXTENDED_ENTITY_TYPES;
|
|
2283
|
+
let isExtendedExpanded = false;
|
|
2284
|
+
let hasLoadedAllModules = false;
|
|
2285
|
+
let isLoadingAllModules = false;
|
|
2286
|
+
const clearExtendedTypeFilters = () => {
|
|
2287
|
+
if (typeof activeFilters === 'undefined') return;
|
|
2288
|
+
EXTENDED_ENTITY_TYPES.forEach((type) => {
|
|
2289
|
+
if (activeFilters.has(type)) {
|
|
2290
|
+
activeFilters.delete(type);
|
|
2291
|
+
const btn = document.querySelector('.entity-filter-btn[data-entity-type="' + type + '"]');
|
|
2292
|
+
if (btn) {
|
|
2293
|
+
btn.classList.remove('btn-primary');
|
|
2294
|
+
btn.classList.add('btn-outline-primary');
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
});
|
|
2298
|
+
};
|
|
2299
|
+
// Fetch extended entities via AJAX
|
|
2300
|
+
const loadExtendedEntities = async (includeAllModules = false) => {
|
|
2301
|
+
try {
|
|
2302
|
+
const query = includeAllModules ? '?include_all_modules=1' : '';
|
|
2303
|
+
const res = await fetch('/entities/extended' + query);
|
|
2304
|
+
const data = await res.json();
|
|
2305
|
+
return data.entities || [];
|
|
2306
|
+
} catch (e) {
|
|
2307
|
+
console.error('Failed to load extended entities:', e);
|
|
2308
|
+
return [];
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
|
|
2312
|
+
const renderExtendedEntityRows = (extendedEntities, tbody) => {
|
|
2313
|
+
document
|
|
2314
|
+
.querySelectorAll('[data-is-extended]')
|
|
2315
|
+
.forEach((row) => row.remove());
|
|
2316
|
+
extendedEntities.forEach((entity) => {
|
|
2317
|
+
const row = createExtendedEntityRow(entity);
|
|
2318
|
+
tbody.appendChild(row);
|
|
2319
|
+
});
|
|
2320
|
+
if (typeof updateSelectionUI === 'function') updateSelectionUI();
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
const ensureAllModulesLoaded = async () => {
|
|
2324
|
+
if (hasLoadedAllModules || isLoadingAllModules) return;
|
|
2325
|
+
if (!isExtendedExpanded) return;
|
|
2326
|
+
isLoadingAllModules = true;
|
|
2327
|
+
let updated = false;
|
|
2328
|
+
try {
|
|
2329
|
+
const extendedEntities = await loadExtendedEntities(true);
|
|
2330
|
+
window.extendedEntities = extendedEntities;
|
|
2331
|
+
const tbody = document.querySelector('#entities-list tbody');
|
|
2332
|
+
renderExtendedEntityRows(extendedEntities, tbody);
|
|
2333
|
+
hasLoadedAllModules = true;
|
|
2334
|
+
updated = true;
|
|
2335
|
+
} catch (e) {
|
|
2336
|
+
console.error('Failed to load all modules:', e);
|
|
2337
|
+
} finally {
|
|
2338
|
+
isLoadingAllModules = false;
|
|
2339
|
+
if (updated && typeof filterEntities === 'function') filterEntities();
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
|
|
2343
|
+
// Toggle expanded state
|
|
2344
|
+
window.toggleEntityExpanded = async (expand) => {
|
|
2345
|
+
const moreBtn = document.getElementById('entity-more-btn');
|
|
2346
|
+
const lessBtn = document.getElementById('entity-less-btn');
|
|
2347
|
+
const extendedButtons = document.querySelectorAll('.entity-extended-btn');
|
|
2348
|
+
const tbody = document.querySelector('#entities-list tbody');
|
|
2349
|
+
|
|
2350
|
+
if (expand) {
|
|
2351
|
+
if (isExtendedExpanded) return;
|
|
2352
|
+
extendedButtons.forEach(btn => btn.classList.remove('d-none'));
|
|
2353
|
+
moreBtn.classList.add('d-none');
|
|
2354
|
+
lessBtn.classList.remove('d-none');
|
|
2355
|
+
isExtendedExpanded = true;
|
|
2356
|
+
const shouldLoadAll = typeof window.isModulesFilterExclusive === 'function'
|
|
2357
|
+
? window.isModulesFilterExclusive()
|
|
2358
|
+
: false;
|
|
2359
|
+
// Load extended entities
|
|
2360
|
+
const extendedEntities = await loadExtendedEntities(shouldLoadAll);
|
|
2361
|
+
window.extendedEntities = extendedEntities;
|
|
2362
|
+
renderExtendedEntityRows(extendedEntities, tbody);
|
|
2363
|
+
hasLoadedAllModules = shouldLoadAll;
|
|
2364
|
+
filterEntities();
|
|
2365
|
+
} else {
|
|
2366
|
+
if (!isExtendedExpanded) return;
|
|
2367
|
+
extendedButtons.forEach(btn => btn.classList.add('d-none'));
|
|
2368
|
+
moreBtn.classList.remove('d-none');
|
|
2369
|
+
lessBtn.classList.add('d-none');
|
|
2370
|
+
isExtendedExpanded = false;
|
|
2371
|
+
hasLoadedAllModules = false;
|
|
2372
|
+
isLoadingAllModules = false;
|
|
2373
|
+
window.extendedEntities = [];
|
|
2374
|
+
renderExtendedEntityRows([], tbody);
|
|
2375
|
+
clearExtendedTypeFilters();
|
|
2376
|
+
// Update filter
|
|
2377
|
+
filterEntities();
|
|
2378
|
+
}
|
|
2379
|
+
};
|
|
2380
|
+
|
|
2381
|
+
// Helper to create entity row for extended entities
|
|
2382
|
+
const createExtendedEntityRow = (entity) => {
|
|
2383
|
+
const tr = document.createElement('tr');
|
|
2384
|
+
tr.className = 'entity-row';
|
|
2385
|
+
tr.dataset.entityType = entity.type;
|
|
2386
|
+
tr.dataset.entityName = entity.name.toLowerCase();
|
|
2387
|
+
if (entity.id) {
|
|
2388
|
+
tr.dataset.entityId = entity.id;
|
|
2389
|
+
} else {
|
|
2390
|
+
tr.dataset.entityId = '';
|
|
2391
|
+
}
|
|
2392
|
+
tr.dataset.entityLabel = entity.name;
|
|
2393
|
+
const key = entity.type + ':' + (entity.type === 'module' ? entity.name : entity.id);
|
|
2394
|
+
tr.dataset.entityKey = key;
|
|
2395
|
+
let searchable = ((entity.name || '').toLowerCase() + ' ' + entity.type).trim();
|
|
2396
|
+
if (entity.metadata) {
|
|
2397
|
+
Object.keys(entity.metadata).forEach((key) => {
|
|
2398
|
+
const val = entity.metadata[key];
|
|
2399
|
+
const shouldSkipDescription =
|
|
2400
|
+
entity.type === 'module' && key === 'description';
|
|
2401
|
+
const shouldSkipForSearchable =
|
|
2402
|
+
entity.type === 'user' && key === 'username';
|
|
2403
|
+
if (!shouldSkipDescription && !shouldSkipForSearchable && val && typeof val === 'string') {
|
|
2404
|
+
searchable += ' ' + val.toLowerCase();
|
|
2405
|
+
}
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
tr.dataset.tags = '';
|
|
2409
|
+
tr.dataset.isExtended = 'true';
|
|
2410
|
+
tr.dataset.installed =
|
|
2411
|
+
entity.metadata && entity.metadata.installed === false
|
|
2412
|
+
? 'false'
|
|
2413
|
+
: 'true';
|
|
2414
|
+
tr.dataset.moduleKind = entity.metadata && entity.metadata.type ? entity.metadata.type : '';
|
|
2415
|
+
|
|
2416
|
+
if (!isRowSelectable(tr)) {
|
|
2417
|
+
tr.classList.add('entity-row-selection-disabled');
|
|
2418
|
+
tr.setAttribute('aria-disabled', 'true');
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// Type badge
|
|
2422
|
+
const badges = {
|
|
2423
|
+
module: { class: "secondary", icon: "cube", label: "Module" },
|
|
2424
|
+
user: { class: "dark", icon: "user", label: "User" },
|
|
2425
|
+
};
|
|
2426
|
+
const badge = badges[entity.type];
|
|
2427
|
+
const typeBadge = document.createElement('td');
|
|
2428
|
+
typeBadge.innerHTML = '<span class="badge bg-' + badge.class + ' me-2"><i class="fas fa-' + badge.icon + ' me-1"></i>' + badge.label + '</span>';
|
|
2429
|
+
tr.appendChild(typeBadge);
|
|
2430
|
+
|
|
2431
|
+
const hasConfig = entity.metadata && entity.metadata.hasConfig;
|
|
2432
|
+
const isInstalled = entity.metadata && entity.metadata.installed;
|
|
2433
|
+
|
|
2434
|
+
// Name
|
|
2435
|
+
const nameTd = document.createElement('td');
|
|
2436
|
+
const isStaticModule = entity.type === 'module' && !hasConfig;
|
|
2437
|
+
const nameLink = document.createElement(isStaticModule ? 'span' : 'a');
|
|
2438
|
+
if (!isStaticModule) {
|
|
2439
|
+
const baseHref = entity.editLink || '#';
|
|
2440
|
+
const updatedHref = toRelativeHrefWithOnDone(baseHref);
|
|
2441
|
+
nameLink.setAttribute('href', updatedHref || baseHref);
|
|
2442
|
+
}
|
|
2443
|
+
nameLink.className = 'fw-bold';
|
|
2444
|
+
nameLink.textContent = entity.name;
|
|
2445
|
+
nameTd.appendChild(nameLink);
|
|
2446
|
+
tr.appendChild(nameTd);
|
|
2447
|
+
|
|
2448
|
+
// Run cell (info link for modules)
|
|
2449
|
+
const runTd = document.createElement('td');
|
|
2450
|
+
if (
|
|
2451
|
+
entity.type === 'module' &&
|
|
2452
|
+
entity.metadata &&
|
|
2453
|
+
entity.metadata.type !== 'pack' &&
|
|
2454
|
+
entity.viewLink &&
|
|
2455
|
+
isInstalled
|
|
2456
|
+
) {
|
|
2457
|
+
const infoLink = document.createElement('a');
|
|
2458
|
+
infoLink.className = 'link-primary text-decoration-none';
|
|
2459
|
+
infoLink.innerHTML =
|
|
2460
|
+
// '<i class="fas fa-info-circle me-1"></i>' +
|
|
2461
|
+
(window.TXT_INFO || 'Info');
|
|
2462
|
+
const updatedInfoHref = toRelativeHrefWithOnDone(entity.viewLink);
|
|
2463
|
+
infoLink.setAttribute('href', updatedInfoHref || entity.viewLink);
|
|
2464
|
+
runTd.appendChild(infoLink);
|
|
2465
|
+
}
|
|
2466
|
+
tr.appendChild(runTd);
|
|
2467
|
+
|
|
2468
|
+
// Details cell
|
|
2469
|
+
const detailsTd = document.createElement('td');
|
|
2470
|
+
let detailsHtml = '';
|
|
2471
|
+
if (entity.type === 'user') {
|
|
2472
|
+
const disabled = entity.metadata && entity.metadata.disabled;
|
|
2473
|
+
const roleId = entity.metadata && entity.metadata.role_id;
|
|
2474
|
+
if (Array.isArray(window.ENTITY_ROLES)) {
|
|
2475
|
+
const role = window.ENTITY_ROLES.find(function (r) {
|
|
2476
|
+
return String(r.id) === String(roleId);
|
|
2477
|
+
});
|
|
2478
|
+
if (role && role.role) {
|
|
2479
|
+
detailsHtml += '<span class="text-muted small me-2">' + role.role + '</span>';
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
if (disabled) {
|
|
2483
|
+
detailsHtml += '<span class="badge bg-danger me-1">' + (window.TXT_DISABLED || 'Disabled') + '</span>';
|
|
2484
|
+
searchable += ' disabled';
|
|
2485
|
+
}
|
|
2486
|
+
} else if (entity.type === 'module') {
|
|
2487
|
+
const version = entity.metadata && entity.metadata.version;
|
|
2488
|
+
const hasTheme = entity.metadata && entity.metadata.has_theme;
|
|
2489
|
+
const hasAuth = entity.metadata && entity.metadata.has_auth;
|
|
2490
|
+
const isReadyForMobile = entity.metadata && entity.metadata.ready_for_mobile;
|
|
2491
|
+
const isLocal = entity.metadata && entity.metadata.local;
|
|
2492
|
+
const isPack = entity.metadata && entity.metadata.type === 'pack';
|
|
2493
|
+
if (version) {
|
|
2494
|
+
detailsHtml += '<span class="text-muted small me-2">v' + version + '</span>';
|
|
2495
|
+
}
|
|
2496
|
+
if (isPack) {
|
|
2497
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_PACK || 'Pack') + '</span>';
|
|
2498
|
+
}
|
|
2499
|
+
if (hasTheme) {
|
|
2500
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_THEME || 'Theme') + '</span>';
|
|
2501
|
+
searchable += ' theme';
|
|
2502
|
+
}
|
|
2503
|
+
if (isLocal) {
|
|
2504
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_LOCAL || 'Local') + '</span>';
|
|
2505
|
+
searchable += ' local';
|
|
2506
|
+
}
|
|
2507
|
+
if (isInstalled) {
|
|
2508
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_INSTALLED || 'Installed') + '</span>';
|
|
2509
|
+
searchable += ' installed';
|
|
2510
|
+
}
|
|
2511
|
+
if (hasAuth) {
|
|
2512
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_AUTH || 'Authentication') + '</span>';
|
|
2513
|
+
searchable += ' authentication auth';
|
|
2514
|
+
}
|
|
2515
|
+
if (isReadyForMobile) {
|
|
2516
|
+
detailsHtml += '<span class="badge bg-secondary me-1">' + (window.TXT_MOBILE || 'Mobile') + '</span>';
|
|
2517
|
+
searchable += ' mobile';
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
if (detailsHtml) detailsTd.innerHTML = detailsHtml;
|
|
2521
|
+
tr.appendChild(detailsTd);
|
|
2522
|
+
|
|
2523
|
+
// Access cell (empty for extended entities)
|
|
2524
|
+
const accessTd = document.createElement('td');
|
|
2525
|
+
tr.appendChild(accessTd);
|
|
2526
|
+
|
|
2527
|
+
// Tags cell
|
|
2528
|
+
const tagsTd = document.createElement('td');
|
|
2529
|
+
tr.appendChild(tagsTd);
|
|
2530
|
+
|
|
2531
|
+
// Actions cell (empty for extended entities)
|
|
2532
|
+
const actionsTd = document.createElement('td');
|
|
2533
|
+
if (entity.actionsHtml) {
|
|
2534
|
+
actionsTd.innerHTML = entity.actionsHtml;
|
|
2535
|
+
actionsTd
|
|
2536
|
+
.querySelectorAll('a')
|
|
2537
|
+
.forEach((link) => {
|
|
2538
|
+
const href = link.getAttribute('href');
|
|
2539
|
+
const updated = toRelativeHrefWithOnDone(href);
|
|
2540
|
+
if (updated) link.setAttribute('href', updated);
|
|
2541
|
+
});
|
|
2542
|
+
actionsTd
|
|
2543
|
+
.querySelectorAll('form')
|
|
2544
|
+
.forEach((form) => {
|
|
2545
|
+
const action = form.getAttribute('action');
|
|
2546
|
+
const updated = toRelativeHrefWithOnDone(action);
|
|
2547
|
+
if (updated) form.setAttribute('action', updated);
|
|
2548
|
+
if (entity.type === 'user') ensureOnDoneHiddenInput(form);
|
|
2549
|
+
});
|
|
2550
|
+
const dropdownToggle = actionsTd.querySelector('[data-bs-toggle="dropdown"]');
|
|
2551
|
+
if (dropdownToggle && window.bootstrap && window.bootstrap.Dropdown) {
|
|
2552
|
+
window.bootstrap.Dropdown.getOrCreateInstance(dropdownToggle);
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
tr.appendChild(actionsTd);
|
|
2556
|
+
|
|
2557
|
+
tr.dataset.searchable = searchable.trim();
|
|
2558
|
+
let deepSearchable = (entity.deepSearchable || searchable).trim();
|
|
2559
|
+
if (entity.type === 'module') {
|
|
2560
|
+
const description =
|
|
2561
|
+
entity.metadata && typeof entity.metadata.description === 'string'
|
|
2562
|
+
? entity.metadata.description.toLowerCase()
|
|
2563
|
+
: '';
|
|
2564
|
+
if (description && !deepSearchable.includes(description)) {
|
|
2565
|
+
deepSearchable = (deepSearchable + ' ' + description).trim();
|
|
2566
|
+
}
|
|
2567
|
+
} else if (entity.type === 'user' && entity.metadata && typeof entity.metadata.username === 'string') {
|
|
2568
|
+
const usernameLower = entity.metadata.username.toLowerCase();
|
|
2569
|
+
if (!deepSearchable.includes(usernameLower)) {
|
|
2570
|
+
deepSearchable = (deepSearchable + ' ' + usernameLower).trim();
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
tr.dataset.deepSearchable = deepSearchable;
|
|
2574
|
+
if (window.ENTITY_DEEP_SEARCH) {
|
|
2575
|
+
window.ENTITY_DEEP_SEARCH[key] = tr.dataset.deepSearchable;
|
|
2576
|
+
}
|
|
2577
|
+
return tr;
|
|
2578
|
+
};
|
|
2579
|
+
|
|
2580
|
+
${clientScript.substring(clientScript.indexOf("const searchInput"), clientScript.lastIndexOf("}"))}
|
|
2581
|
+
`)
|
|
2582
|
+
),
|
|
829
2583
|
],
|
|
830
2584
|
footer: div(
|
|
831
2585
|
{
|
|
@@ -879,3 +2633,389 @@ router.get(
|
|
|
879
2633
|
);
|
|
880
2634
|
})
|
|
881
2635
|
);
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* AJAX endpoint to fetch extended entities (modules, users)
|
|
2639
|
+
*/
|
|
2640
|
+
router.get(
|
|
2641
|
+
"/extended",
|
|
2642
|
+
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
2643
|
+
error_catcher(async (req, res) => {
|
|
2644
|
+
const includeAllModules =
|
|
2645
|
+
req.query.include_all_modules === "1" ||
|
|
2646
|
+
req.query.include_all_modules === "true";
|
|
2647
|
+
const extendedEntities = await getExtendedEntites(req, {
|
|
2648
|
+
includeAllModules,
|
|
2649
|
+
});
|
|
2650
|
+
res.json({
|
|
2651
|
+
entities: extendedEntities.map((entity) => ({
|
|
2652
|
+
type: entity.type,
|
|
2653
|
+
name: entity.name,
|
|
2654
|
+
id: entity.id,
|
|
2655
|
+
viewLink: entity.viewLink,
|
|
2656
|
+
editLink: entity.editLink,
|
|
2657
|
+
metadata: entity.metadata,
|
|
2658
|
+
actionsHtml: entity.actionsHtml || "",
|
|
2659
|
+
})),
|
|
2660
|
+
});
|
|
2661
|
+
})
|
|
2662
|
+
);
|
|
2663
|
+
|
|
2664
|
+
router.post(
|
|
2665
|
+
"/bulk-delete",
|
|
2666
|
+
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
2667
|
+
error_catcher(async (req, res) => {
|
|
2668
|
+
const items = Array.isArray(req.body.items) ? req.body.items : [];
|
|
2669
|
+
if (!items.length)
|
|
2670
|
+
return res.status(400).json({ error: "No items selected" });
|
|
2671
|
+
|
|
2672
|
+
const deletedKeys = [];
|
|
2673
|
+
const errors = [];
|
|
2674
|
+
const installedPackNames = new Set(
|
|
2675
|
+
getState().getConfig("installed_packs", []) || []
|
|
2676
|
+
);
|
|
2677
|
+
const asNumber = (val) => {
|
|
2678
|
+
if (val === null || typeof val === "undefined") return null;
|
|
2679
|
+
if (val === "") return null;
|
|
2680
|
+
const num = Number(val);
|
|
2681
|
+
return Number.isNaN(num) ? null : num;
|
|
2682
|
+
};
|
|
2683
|
+
|
|
2684
|
+
for (const item of items) {
|
|
2685
|
+
const type = item?.type;
|
|
2686
|
+
const id = asNumber(item?.id);
|
|
2687
|
+
const name = item?.name;
|
|
2688
|
+
const key = item?.key;
|
|
2689
|
+
try {
|
|
2690
|
+
if (type === "table" && id) {
|
|
2691
|
+
const table = Table.findOne({ id });
|
|
2692
|
+
if (!table) throw new Error("Table not found");
|
|
2693
|
+
await table.delete(false);
|
|
2694
|
+
if (key) deletedKeys.push(key);
|
|
2695
|
+
} else if (type === "view" && id) {
|
|
2696
|
+
const view = View.findOne({ id });
|
|
2697
|
+
if (!view) throw new Error("View not found");
|
|
2698
|
+
await view.delete();
|
|
2699
|
+
if (key) deletedKeys.push(key);
|
|
2700
|
+
} else if (type === "page" && id) {
|
|
2701
|
+
const page = Page.findOne({ id });
|
|
2702
|
+
if (!page) throw new Error("Page not found");
|
|
2703
|
+
await page.delete();
|
|
2704
|
+
if (key) deletedKeys.push(key);
|
|
2705
|
+
} else if (type === "trigger" && id) {
|
|
2706
|
+
const trigger = await Trigger.findOne({ id });
|
|
2707
|
+
if (!trigger) throw new Error("Trigger not found");
|
|
2708
|
+
await trigger.delete();
|
|
2709
|
+
if (key) deletedKeys.push(key);
|
|
2710
|
+
} else if (type === "module" && name) {
|
|
2711
|
+
const isPack = installedPackNames.has(name);
|
|
2712
|
+
if (isPack) {
|
|
2713
|
+
const pack = await fetch_pack_by_name(name);
|
|
2714
|
+
if (!pack) throw new Error("Pack not found");
|
|
2715
|
+
await db.withTransaction(async () => {
|
|
2716
|
+
await uninstall_pack(pack.pack, name);
|
|
2717
|
+
});
|
|
2718
|
+
await getState().refresh();
|
|
2719
|
+
} else {
|
|
2720
|
+
const plugin = await Plugin.findOne({ name });
|
|
2721
|
+
if (!plugin) throw new Error("Plugin not found");
|
|
2722
|
+
await plugin.delete();
|
|
2723
|
+
}
|
|
2724
|
+
if (key) deletedKeys.push(key);
|
|
2725
|
+
} else if (type === "user" && id) {
|
|
2726
|
+
const user = await User.findOne({ id });
|
|
2727
|
+
if (!user) throw new Error("User not found");
|
|
2728
|
+
await user.delete();
|
|
2729
|
+
if (key) deletedKeys.push(key);
|
|
2730
|
+
} else {
|
|
2731
|
+
throw new Error("Invalid item type or id: " + JSON.stringify(item));
|
|
2732
|
+
}
|
|
2733
|
+
} catch (e) {
|
|
2734
|
+
const isPack = type === "module" && installedPackNames.has(name);
|
|
2735
|
+
errors.push({
|
|
2736
|
+
type: isPack ? "pack" : type,
|
|
2737
|
+
isPack,
|
|
2738
|
+
id,
|
|
2739
|
+
name,
|
|
2740
|
+
key,
|
|
2741
|
+
message: e.message,
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
res.status(errors.length ? 207 : 200).json({
|
|
2747
|
+
ok: errors.length === 0,
|
|
2748
|
+
deletedKeys,
|
|
2749
|
+
errors,
|
|
2750
|
+
});
|
|
2751
|
+
})
|
|
2752
|
+
);
|
|
2753
|
+
|
|
2754
|
+
const idField = (entryType) => {
|
|
2755
|
+
switch (entryType) {
|
|
2756
|
+
case "table":
|
|
2757
|
+
case "tables":
|
|
2758
|
+
return "table_id";
|
|
2759
|
+
case "view":
|
|
2760
|
+
case "views":
|
|
2761
|
+
return "view_id";
|
|
2762
|
+
case "page":
|
|
2763
|
+
case "pages":
|
|
2764
|
+
return "page_id";
|
|
2765
|
+
case "trigger":
|
|
2766
|
+
case "triggers":
|
|
2767
|
+
return "trigger_id";
|
|
2768
|
+
default:
|
|
2769
|
+
return null;
|
|
2770
|
+
}
|
|
2771
|
+
};
|
|
2772
|
+
|
|
2773
|
+
router.post(
|
|
2774
|
+
"/bulk-apply-tag",
|
|
2775
|
+
isAdminOrHasConfigMinRole([
|
|
2776
|
+
"min_role_edit_tables",
|
|
2777
|
+
"min_role_edit_views",
|
|
2778
|
+
"min_role_edit_pages",
|
|
2779
|
+
"min_role_edit_triggers",
|
|
2780
|
+
]),
|
|
2781
|
+
error_catcher(async (req, res) => {
|
|
2782
|
+
const { items, tag_id } = req.body || {};
|
|
2783
|
+
const tagIdNum = Number(tag_id);
|
|
2784
|
+
if (!Array.isArray(items) || !items.length || Number.isNaN(tagIdNum)) {
|
|
2785
|
+
return res.status(400).json({ error: "Invalid request" });
|
|
2786
|
+
}
|
|
2787
|
+
const tag = await Tag.findOne({ id: tagIdNum });
|
|
2788
|
+
if (!tag) return res.status(404).json({ error: "Tag not found" });
|
|
2789
|
+
for (const item of items) {
|
|
2790
|
+
const field = idField(item?.type);
|
|
2791
|
+
const id = Number(item?.id);
|
|
2792
|
+
if (!field || Number.isNaN(id)) continue;
|
|
2793
|
+
await db.withTransaction(async () => {
|
|
2794
|
+
await tag.addEntry({ [field]: id });
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
res.json({ ok: true });
|
|
2798
|
+
})
|
|
2799
|
+
);
|
|
2800
|
+
|
|
2801
|
+
router.post(
|
|
2802
|
+
"/bulk-set-role",
|
|
2803
|
+
isAdminOrHasConfigMinRole([
|
|
2804
|
+
"min_role_edit_tables",
|
|
2805
|
+
"min_role_edit_views",
|
|
2806
|
+
"min_role_edit_pages",
|
|
2807
|
+
]),
|
|
2808
|
+
error_catcher(async (req, res) => {
|
|
2809
|
+
const { items, role_id, mode } = req.body || {};
|
|
2810
|
+
const roleIdNum = Number(role_id);
|
|
2811
|
+
const validMode = mode === "read" || mode === "write";
|
|
2812
|
+
if (
|
|
2813
|
+
!Array.isArray(items) ||
|
|
2814
|
+
!items.length ||
|
|
2815
|
+
Number.isNaN(roleIdNum) ||
|
|
2816
|
+
!validMode
|
|
2817
|
+
) {
|
|
2818
|
+
return res.status(400).json({ error: "Invalid request" });
|
|
2819
|
+
}
|
|
2820
|
+
const role = await Role.findOne({ id: roleIdNum });
|
|
2821
|
+
if (!role) return res.status(404).json({ error: "Role not found" });
|
|
2822
|
+
|
|
2823
|
+
const errors = [];
|
|
2824
|
+
const updatedKeys = [];
|
|
2825
|
+
|
|
2826
|
+
for (const item of items) {
|
|
2827
|
+
const type = item?.type;
|
|
2828
|
+
const idNum = Number(item?.id);
|
|
2829
|
+
const id = Number.isNaN(idNum) ? null : idNum;
|
|
2830
|
+
const key = item?.key;
|
|
2831
|
+
try {
|
|
2832
|
+
if (type === "table") {
|
|
2833
|
+
const table =
|
|
2834
|
+
(id !== null ? Table.findOne({ id }) : null) ||
|
|
2835
|
+
Table.findOne({ name: item?.name });
|
|
2836
|
+
if (!table) throw new Error("Table not found");
|
|
2837
|
+
const update = {};
|
|
2838
|
+
if (mode === "read") update.min_role_read = roleIdNum;
|
|
2839
|
+
if (mode === "write") update.min_role_write = roleIdNum;
|
|
2840
|
+
if (!Object.keys(update).length)
|
|
2841
|
+
throw new Error("No fields to update");
|
|
2842
|
+
await table.update(update);
|
|
2843
|
+
if (key) updatedKeys.push(key);
|
|
2844
|
+
} else if (mode === "read" && type === "view") {
|
|
2845
|
+
const view =
|
|
2846
|
+
(id !== null ? View.findOne({ id }) : null) ||
|
|
2847
|
+
View.findOne({ name: item?.name });
|
|
2848
|
+
console.log({ view });
|
|
2849
|
+
if (!view) throw new Error("View not found");
|
|
2850
|
+
if (view.id && typeof view.id !== "undefined") {
|
|
2851
|
+
await View.update({ min_role: roleIdNum }, id);
|
|
2852
|
+
} // Might need to add an option to update tableless views like SQL which have no id but only name
|
|
2853
|
+
if (key) updatedKeys.push(key);
|
|
2854
|
+
} else if (mode === "read" && type === "page") {
|
|
2855
|
+
const page =
|
|
2856
|
+
(id !== null ? Page.findOne({ id }) : null) ||
|
|
2857
|
+
Page.findOne({ name: item?.name });
|
|
2858
|
+
if (!page) throw new Error("Page not found");
|
|
2859
|
+
await Page.update(id, { min_role: roleIdNum });
|
|
2860
|
+
if (key) updatedKeys.push(key);
|
|
2861
|
+
} else {
|
|
2862
|
+
throw new Error("Unsupported item type for role change");
|
|
2863
|
+
}
|
|
2864
|
+
} catch (e) {
|
|
2865
|
+
errors.push({ type, id, key, message: e.message });
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
res.status(errors.length ? 207 : 200).json({
|
|
2870
|
+
ok: errors.length === 0,
|
|
2871
|
+
updatedKeys,
|
|
2872
|
+
errors,
|
|
2873
|
+
});
|
|
2874
|
+
})
|
|
2875
|
+
);
|
|
2876
|
+
|
|
2877
|
+
router.post(
|
|
2878
|
+
"/download-pack",
|
|
2879
|
+
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
2880
|
+
error_catcher(async (req, res) => {
|
|
2881
|
+
const items = Array.isArray(req.body.items) ? req.body.items : [];
|
|
2882
|
+
if (!items.length) return res.status(400).json({ error: "No items" });
|
|
2883
|
+
|
|
2884
|
+
const pack = {
|
|
2885
|
+
tables: [],
|
|
2886
|
+
views: [],
|
|
2887
|
+
plugins: [],
|
|
2888
|
+
pages: [],
|
|
2889
|
+
page_groups: [],
|
|
2890
|
+
roles: [],
|
|
2891
|
+
library: [],
|
|
2892
|
+
triggers: [],
|
|
2893
|
+
tags: [],
|
|
2894
|
+
models: [],
|
|
2895
|
+
model_instances: [],
|
|
2896
|
+
event_logs: [],
|
|
2897
|
+
code_pages: [],
|
|
2898
|
+
};
|
|
2899
|
+
|
|
2900
|
+
const added = {
|
|
2901
|
+
table: new Set(),
|
|
2902
|
+
view: new Set(),
|
|
2903
|
+
page: new Set(),
|
|
2904
|
+
trigger: new Set(),
|
|
2905
|
+
module: new Set(),
|
|
2906
|
+
};
|
|
2907
|
+
|
|
2908
|
+
for (const item of items) {
|
|
2909
|
+
const type = item?.type;
|
|
2910
|
+
const id = Number(item?.id);
|
|
2911
|
+
const name = item?.name;
|
|
2912
|
+
if (
|
|
2913
|
+
!type ||
|
|
2914
|
+
!["table", "view", "page", "trigger", "module"].includes(type)
|
|
2915
|
+
)
|
|
2916
|
+
continue;
|
|
2917
|
+
|
|
2918
|
+
if (!Number.isNaN(id) && added[type].has(id)) continue;
|
|
2919
|
+
|
|
2920
|
+
switch (type) {
|
|
2921
|
+
case "table": {
|
|
2922
|
+
const table = !Number.isNaN(id)
|
|
2923
|
+
? Table.findOne({ id })
|
|
2924
|
+
: name
|
|
2925
|
+
? Table.findOne({ name })
|
|
2926
|
+
: null;
|
|
2927
|
+
if (table) {
|
|
2928
|
+
pack.tables.push(await table_pack(table));
|
|
2929
|
+
if (!Number.isNaN(id)) added.table.add(id);
|
|
2930
|
+
}
|
|
2931
|
+
break;
|
|
2932
|
+
}
|
|
2933
|
+
case "view": {
|
|
2934
|
+
const view = !Number.isNaN(id)
|
|
2935
|
+
? View.findOne({ id })
|
|
2936
|
+
: name
|
|
2937
|
+
? View.findOne({ name })
|
|
2938
|
+
: null;
|
|
2939
|
+
if (view) {
|
|
2940
|
+
pack.views.push(await view_pack(view));
|
|
2941
|
+
if (!Number.isNaN(id)) added.view.add(id);
|
|
2942
|
+
}
|
|
2943
|
+
break;
|
|
2944
|
+
}
|
|
2945
|
+
case "page": {
|
|
2946
|
+
const page = !Number.isNaN(id)
|
|
2947
|
+
? Page.findOne({ id })
|
|
2948
|
+
: name
|
|
2949
|
+
? Page.findOne({ name })
|
|
2950
|
+
: null;
|
|
2951
|
+
if (page) {
|
|
2952
|
+
pack.pages.push(await page_pack(page));
|
|
2953
|
+
if (!Number.isNaN(id)) added.page.add(id);
|
|
2954
|
+
}
|
|
2955
|
+
break;
|
|
2956
|
+
}
|
|
2957
|
+
case "trigger": {
|
|
2958
|
+
const trigger = !Number.isNaN(id)
|
|
2959
|
+
? await Trigger.findOne({ id })
|
|
2960
|
+
: name
|
|
2961
|
+
? await Trigger.findOne({ name })
|
|
2962
|
+
: null;
|
|
2963
|
+
if (trigger) {
|
|
2964
|
+
pack.triggers.push(await trigger_pack(trigger));
|
|
2965
|
+
if (!Number.isNaN(id)) added.trigger.add(id);
|
|
2966
|
+
}
|
|
2967
|
+
break;
|
|
2968
|
+
}
|
|
2969
|
+
case "module": {
|
|
2970
|
+
const plugin = !Number.isNaN(id)
|
|
2971
|
+
? await Plugin.findOne({ id })
|
|
2972
|
+
: name
|
|
2973
|
+
? await Plugin.findOne({ name })
|
|
2974
|
+
: null;
|
|
2975
|
+
const packModule = await fetch_pack_by_name(name);
|
|
2976
|
+
if (plugin) {
|
|
2977
|
+
pack.plugins.push(await plugin_pack(plugin.name));
|
|
2978
|
+
if (!Number.isNaN(id)) added.module.add(id);
|
|
2979
|
+
break;
|
|
2980
|
+
}
|
|
2981
|
+
if (packModule) {
|
|
2982
|
+
pack.plugins.push(packModule);
|
|
2983
|
+
if (!Number.isNaN(id)) added.module.add(id);
|
|
2984
|
+
break;
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
default:
|
|
2988
|
+
break;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
const hasContent =
|
|
2993
|
+
pack.tables.length ||
|
|
2994
|
+
pack.views.length ||
|
|
2995
|
+
pack.pages.length ||
|
|
2996
|
+
pack.triggers.length ||
|
|
2997
|
+
pack.plugins.length;
|
|
2998
|
+
|
|
2999
|
+
if (!hasContent) {
|
|
3000
|
+
return res.status(404).json({ error: "No packs available" });
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
const filenameBase = (() => {
|
|
3004
|
+
if (items.length === 1) {
|
|
3005
|
+
const label = items[0].name || items[0].type || "pack";
|
|
3006
|
+
return label.toString().replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
3007
|
+
}
|
|
3008
|
+
return "selected-entities-pack";
|
|
3009
|
+
})();
|
|
3010
|
+
|
|
3011
|
+
res.json({
|
|
3012
|
+
ok: true,
|
|
3013
|
+
packs: [
|
|
3014
|
+
{
|
|
3015
|
+
name: filenameBase || "entities-pack",
|
|
3016
|
+
content: pack,
|
|
3017
|
+
},
|
|
3018
|
+
],
|
|
3019
|
+
});
|
|
3020
|
+
})
|
|
3021
|
+
);
|