Merge pull request 'merge_from_upstream' (#457) from merge_from_upstream into @hera/dev
Reviewed-on: daoyoucloud/tachycode#457
This commit is contained in:
		
						commit
						d766eb481a
					
				
							
								
								
									
										19
									
								
								.github/workflows/manual-e2e.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/manual-e2e.yml
									
									
									
									
										vendored
									
									
								
							@ -43,18 +43,11 @@ jobs:
 | 
				
			|||||||
          ref: ${{ inputs.branch }}
 | 
					          ref: ${{ inputs.branch }}
 | 
				
			||||||
          path: packages/pro-plugins
 | 
					          path: packages/pro-plugins
 | 
				
			||||||
          ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }}
 | 
					          ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }}
 | 
				
			||||||
      # - name: Set variables
 | 
					      - name: Set variables
 | 
				
			||||||
      #   run: |
 | 
					        run: |
 | 
				
			||||||
      #     target_directory="./packages/pro-plugins/@nocobase"
 | 
					          APPEND_PRESET_LOCAL_PLUGINS=$(find ./packages/pro-plugins/@nocobase -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed 's/^plugin-//' | tr '\n' ',' | sed 's/,$//')
 | 
				
			||||||
      #     subdirectories=$(find "$target_directory" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | tr '\n' ' ')
 | 
					          echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT
 | 
				
			||||||
      #     trimmed_variable=$(echo "$subdirectories" | xargs)
 | 
					        id: vars
 | 
				
			||||||
      #     packageNames="@nocobase/${trimmed_variable// / @nocobase/}"
 | 
					 | 
				
			||||||
      #     pluginNames="${trimmed_variable//plugin-/}"
 | 
					 | 
				
			||||||
      #     BEFORE_PACK_NOCOBASE="yarn add @nocobase/plugin-notifications @nocobase/plugin-disable-pm-add $packageNames -W"
 | 
					 | 
				
			||||||
      #     APPEND_PRESET_LOCAL_PLUGINS="notifications,disable-pm-add,${pluginNames// /,}"
 | 
					 | 
				
			||||||
      #     echo "var1=$BEFORE_PACK_NOCOBASE" >> $GITHUB_OUTPUT
 | 
					 | 
				
			||||||
      #     echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT
 | 
					 | 
				
			||||||
      #   id: vars
 | 
					 | 
				
			||||||
      - name: Use Node.js ${{ matrix.node_version }}
 | 
					      - name: Use Node.js ${{ matrix.node_version }}
 | 
				
			||||||
        uses: actions/setup-node@v3
 | 
					        uses: actions/setup-node@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@ -89,5 +82,5 @@ jobs:
 | 
				
			|||||||
          DB_USER: nocobase
 | 
					          DB_USER: nocobase
 | 
				
			||||||
          DB_PASSWORD: password
 | 
					          DB_PASSWORD: password
 | 
				
			||||||
          DB_DATABASE: nocobase
 | 
					          DB_DATABASE: nocobase
 | 
				
			||||||
          APPEND_PRESET_BUILT_IN_PLUGINS: mock-collections,workflow-response-message,workflow-request-interceptor,workflow-json-query,workflow-approval,telemetry-prometheus,data-source-external-postgres,embed,data-source-external-mysql,workflow-variable,collection-fdw,demo-platform,departments,data-source-external-mariadb
 | 
					          APPEND_PRESET_LOCAL_PLUGINS: ${{ steps.vars.outputs.var2 }}
 | 
				
			||||||
    timeout-minutes: 120
 | 
					    timeout-minutes: 120
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
 | 
					Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.20.0-alpha.15](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.14...v0.20.0-alpha.15) - 2024-03-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Merged
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- fix(auth): sso auth bug when deploying with subpath [`#3764`](https://github.com/nocobase/nocobase/pull/3764)
 | 
				
			||||||
 | 
					- chore: load roles after start [`#3763`](https://github.com/nocobase/nocobase/pull/3763)
 | 
				
			||||||
 | 
					- fix: uuid & nanoid should be disabled when editing [`#3762`](https://github.com/nocobase/nocobase/pull/3762)
 | 
				
			||||||
 | 
					- fix(logger): output error cause info [`#3760`](https://github.com/nocobase/nocobase/pull/3760)
 | 
				
			||||||
 | 
					- fix: uuid field [`#3736`](https://github.com/nocobase/nocobase/pull/3736)
 | 
				
			||||||
 | 
					- feat: disassociate action [`#3759`](https://github.com/nocobase/nocobase/pull/3759)
 | 
				
			||||||
 | 
					- chore: merge sub app database options [`#3640`](https://github.com/nocobase/nocobase/pull/3640)
 | 
				
			||||||
 | 
					- fix(acl): bug of user filtering when adding them to roles [`#3754`](https://github.com/nocobase/nocobase/pull/3754)
 | 
				
			||||||
 | 
					- fix: app stopped status [`#3723`](https://github.com/nocobase/nocobase/pull/3723)
 | 
				
			||||||
 | 
					- fix: fix the disappearing collections when searching [`#3750`](https://github.com/nocobase/nocobase/pull/3750)
 | 
				
			||||||
 | 
					- fix: configure openSize for table action is only immediately  valid for one row [`#3752`](https://github.com/nocobase/nocobase/pull/3752)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Commits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- test: add e2e for Disassociate [`8e322ae`](https://github.com/nocobase/nocobase/commit/8e322ae1517e0cea5eac289bb5641b85d4997002)
 | 
				
			||||||
 | 
					- chore(versions): 😊 publish v0.20.0-alpha.15 [`bef9c8a`](https://github.com/nocobase/nocobase/commit/bef9c8ab7b54b0400dfd25c9ec85a141448125a2)
 | 
				
			||||||
 | 
					- chore: update yarn.lock [`3da340c`](https://github.com/nocobase/nocobase/commit/3da340c88d3a689e22e20dae798a1b51ed0405f7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [v0.20.0-alpha.14](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.13...v0.20.0-alpha.14) - 2024-03-18
 | 
					## [v0.20.0-alpha.14](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.13...v0.20.0-alpha.14) - 2024-03-18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Merged
 | 
					### Merged
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "npmClient": "yarn",
 | 
					  "npmClient": "yarn",
 | 
				
			||||||
  "useWorkspaces": true,
 | 
					  "useWorkspaces": true,
 | 
				
			||||||
  "npmClientArgs": ["--ignore-engines"],
 | 
					  "npmClientArgs": ["--ignore-engines"],
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/acl",
 | 
					  "name": "@nocobase/acl",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/resourcer": "0.20.0-alpha.14",
 | 
					    "@nocobase/resourcer": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "minimatch": "^5.1.1"
 | 
					    "minimatch": "^5.1.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,14 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/actions",
 | 
					  "name": "@nocobase/actions",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/cache": "0.20.0-alpha.14",
 | 
					    "@nocobase/cache": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/database": "0.20.0-alpha.14",
 | 
					    "@nocobase/database": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/resourcer": "0.20.0-alpha.14"
 | 
					    "@nocobase/resourcer": "0.20.0-alpha.15"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +1,17 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/app",
 | 
					  "name": "@nocobase/app",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/database": "0.20.0-alpha.14",
 | 
					    "@nocobase/database": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/preset-nocobase": "0.20.0-alpha.14",
 | 
					    "@nocobase/preset-nocobase": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/server": "0.20.0-alpha.14"
 | 
					    "@nocobase/server": "0.20.0-alpha.15"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@nocobase/client": "0.20.0-alpha.14"
 | 
					    "@nocobase/client": "0.20.0-alpha.15"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +1,16 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/auth",
 | 
					  "name": "@nocobase/auth",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/actions": "0.20.0-alpha.14",
 | 
					    "@nocobase/actions": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/cache": "0.20.0-alpha.14",
 | 
					    "@nocobase/cache": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/database": "0.20.0-alpha.14",
 | 
					    "@nocobase/database": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/resourcer": "0.20.0-alpha.14",
 | 
					    "@nocobase/resourcer": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "@types/jsonwebtoken": "^8.5.8",
 | 
					    "@types/jsonwebtoken": "^8.5.8",
 | 
				
			||||||
    "jsonwebtoken": "^8.5.1"
 | 
					    "jsonwebtoken": "^8.5.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/build",
 | 
					  "name": "@nocobase/build",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "Library build tool based on rollup.",
 | 
					  "description": "Library build tool based on rollup.",
 | 
				
			||||||
  "main": "lib/index.js",
 | 
					  "main": "lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								packages/core/cache/package.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								packages/core/cache/package.json
									
									
									
									
										vendored
									
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/cache",
 | 
					  "name": "@nocobase/cache",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/cli",
 | 
					  "name": "@nocobase/cli",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./src/index.js",
 | 
					  "main": "./src/index.js",
 | 
				
			||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
    "nocobase": "./bin/index.js"
 | 
					    "nocobase": "./bin/index.js"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/app": "0.20.0-alpha.14",
 | 
					    "@nocobase/app": "0.20.0-alpha.15",
 | 
				
			||||||
    "@types/fs-extra": "^11.0.1",
 | 
					    "@types/fs-extra": "^11.0.1",
 | 
				
			||||||
    "@umijs/utils": "3.5.20",
 | 
					    "@umijs/utils": "3.5.20",
 | 
				
			||||||
    "chalk": "^4.1.1",
 | 
					    "chalk": "^4.1.1",
 | 
				
			||||||
@ -25,7 +25,7 @@
 | 
				
			|||||||
    "tsx": "^4.6.2"
 | 
					    "tsx": "^4.6.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@nocobase/devtools": "0.20.0-alpha.14"
 | 
					    "@nocobase/devtools": "0.20.0-alpha.15"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/client",
 | 
					  "name": "@nocobase/client",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "lib/index.js",
 | 
					  "main": "lib/index.js",
 | 
				
			||||||
  "module": "es/index.mjs",
 | 
					  "module": "es/index.mjs",
 | 
				
			||||||
@ -26,9 +26,9 @@
 | 
				
			|||||||
    "@formily/reactive-react": "^2.2.27",
 | 
					    "@formily/reactive-react": "^2.2.27",
 | 
				
			||||||
    "@formily/shared": "^2.2.27",
 | 
					    "@formily/shared": "^2.2.27",
 | 
				
			||||||
    "@formily/validator": "^2.2.27",
 | 
					    "@formily/validator": "^2.2.27",
 | 
				
			||||||
    "@nocobase/evaluators": "0.20.0-alpha.14",
 | 
					    "@nocobase/evaluators": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/sdk": "0.20.0-alpha.14",
 | 
					    "@nocobase/sdk": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "ahooks": "^3.7.2",
 | 
					    "ahooks": "^3.7.2",
 | 
				
			||||||
    "antd": "^5.12.8",
 | 
					    "antd": "^5.12.8",
 | 
				
			||||||
    "antd-style": "3.4.5",
 | 
					    "antd-style": "3.4.5",
 | 
				
			||||||
 | 
				
			|||||||
@ -349,7 +349,7 @@ export const useParamsFromRecord = () => {
 | 
				
			|||||||
  if (record.__collection && collectionField && !['oho', 'm2o', 'obo'].includes(collectionField.interface)) {
 | 
					  if (record.__collection && collectionField && !['oho', 'm2o', 'obo'].includes(collectionField.interface)) {
 | 
				
			||||||
    obj['targetCollection'] = record.__collection;
 | 
					    obj['targetCollection'] = record.__collection;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (!filterByTk) {
 | 
					  if (!filterByTk && Object.keys(filter).length > 0) {
 | 
				
			||||||
    obj['filter'] = filter;
 | 
					    obj['filter'] = filter;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return obj;
 | 
					  return obj;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
 | 
					import { Field, Form } from '@formily/core';
 | 
				
			||||||
import { SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react';
 | 
					import { SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react';
 | 
				
			||||||
 | 
					import { untracked } from '@formily/reactive';
 | 
				
			||||||
import { isURL, parse } from '@nocobase/utils/client';
 | 
					import { isURL, parse } from '@nocobase/utils/client';
 | 
				
			||||||
import { App, message } from 'antd';
 | 
					import { App, message } from 'antd';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
@ -23,6 +25,7 @@ import { useFilterBlock } from '../../filter-provider/FilterProvider';
 | 
				
			|||||||
import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
 | 
					import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
 | 
				
			||||||
import { useRecord } from '../../record-provider';
 | 
					import { useRecord } from '../../record-provider';
 | 
				
			||||||
import { removeNullCondition, useActionContext, useCompile } from '../../schema-component';
 | 
					import { removeNullCondition, useActionContext, useCompile } from '../../schema-component';
 | 
				
			||||||
 | 
					import { isSubMode } from '../../schema-component/antd/association-field/util';
 | 
				
			||||||
import { useCurrentUserContext } from '../../user';
 | 
					import { useCurrentUserContext } from '../../user';
 | 
				
			||||||
import { useLocalVariables, useVariables } from '../../variables';
 | 
					import { useLocalVariables, useVariables } from '../../variables';
 | 
				
			||||||
import { isVariable } from '../../variables/utils/isVariable';
 | 
					import { isVariable } from '../../variables/utils/isVariable';
 | 
				
			||||||
@ -30,9 +33,6 @@ import { transformVariableValue } from '../../variables/utils/transformVariableV
 | 
				
			|||||||
import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
 | 
					import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
 | 
				
			||||||
import { useDetailsBlockContext } from '../DetailsBlockProvider';
 | 
					import { useDetailsBlockContext } from '../DetailsBlockProvider';
 | 
				
			||||||
import { TableFieldResource } from '../TableFieldProvider';
 | 
					import { TableFieldResource } from '../TableFieldProvider';
 | 
				
			||||||
import { Field, Form } from '@formily/core';
 | 
					 | 
				
			||||||
import { untracked } from '@formily/reactive';
 | 
					 | 
				
			||||||
import { isSubMode } from '../../schema-component/antd/association-field/util';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export * from './useFormActiveFields';
 | 
					export * from './useFormActiveFields';
 | 
				
			||||||
export * from './useParsedFilter';
 | 
					export * from './useParsedFilter';
 | 
				
			||||||
@ -965,6 +965,34 @@ export const useRemoveActionProps = (associationName) => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useDisassociateActionProps = () => {
 | 
				
			||||||
 | 
					  const filterByTk = useFilterByTk();
 | 
				
			||||||
 | 
					  const { resource, service, block, __parent } = useBlockRequestContext();
 | 
				
			||||||
 | 
					  const { setVisible } = useActionContext();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async onClick() {
 | 
				
			||||||
 | 
					      await resource.remove({
 | 
				
			||||||
 | 
					        values: [filterByTk],
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const { count = 0, page = 0, pageSize = 0 } = service?.data?.meta || {};
 | 
				
			||||||
 | 
					      if (count % pageSize === 1 && page !== 1) {
 | 
				
			||||||
 | 
					        service.run({
 | 
				
			||||||
 | 
					          ...service?.params?.[0],
 | 
				
			||||||
 | 
					          page: page - 1,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        service?.refresh?.();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (block && block !== 'TableField') {
 | 
				
			||||||
 | 
					        __parent?.service?.refresh?.();
 | 
				
			||||||
 | 
					        setVisible?.(false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useDetailPrintActionProps = () => {
 | 
					export const useDetailPrintActionProps = () => {
 | 
				
			||||||
  const { formBlockRef } = useFormBlockContext();
 | 
					  const { formBlockRef } = useFormBlockContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -284,7 +284,7 @@ export const ForeignKey = observer(
 | 
				
			|||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onChange={(value, option) => {
 | 
					          onChange={(value, option) => {
 | 
				
			||||||
            props?.onChange?.(value);
 | 
					            props?.onChange?.(value);
 | 
				
			||||||
            setInitialValue(option.label);
 | 
					            setInitialValue(option.label || value);
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -28,9 +28,9 @@ export class NanoidFieldInterface extends CollectionFieldInterface {
 | 
				
			|||||||
      type: 'string',
 | 
					      type: 'string',
 | 
				
			||||||
      title: '{{t("Field name")}}',
 | 
					      title: '{{t("Field name")}}',
 | 
				
			||||||
      required: true,
 | 
					      required: true,
 | 
				
			||||||
      'x-disabled': true,
 | 
					 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					      'x-decorator': 'FormItem',
 | 
				
			||||||
      'x-component': 'Input',
 | 
					      'x-component': 'Input',
 | 
				
			||||||
 | 
					      'x-disabled': '{{ !createOnly }}',
 | 
				
			||||||
      description:
 | 
					      description:
 | 
				
			||||||
        "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
 | 
					        "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -30,9 +30,9 @@ export class UUIDFieldInterface extends CollectionFieldInterface {
 | 
				
			|||||||
      type: 'string',
 | 
					      type: 'string',
 | 
				
			||||||
      title: '{{t("Field name")}}',
 | 
					      title: '{{t("Field name")}}',
 | 
				
			||||||
      required: true,
 | 
					      required: true,
 | 
				
			||||||
      'x-disabled': true,
 | 
					 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					      'x-decorator': 'FormItem',
 | 
				
			||||||
      'x-component': 'Input',
 | 
					      'x-component': 'Input',
 | 
				
			||||||
 | 
					      'x-disabled': '{{ !createOnly }}',
 | 
				
			||||||
      description:
 | 
					      description:
 | 
				
			||||||
        "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
 | 
					        "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,9 @@
 | 
				
			|||||||
  "Insert right": "Insert right",
 | 
					  "Insert right": "Insert right",
 | 
				
			||||||
  "Insert inner": "Insert inner",
 | 
					  "Insert inner": "Insert inner",
 | 
				
			||||||
  "Delete": "Delete",
 | 
					  "Delete": "Delete",
 | 
				
			||||||
 | 
					  "Disassociate": "Disassociate",
 | 
				
			||||||
 | 
					  "Disassociate record": "Disassociate record",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Are you sure you want to disassociate it?",
 | 
				
			||||||
  "UI editor": "UI editor",
 | 
					  "UI editor": "UI editor",
 | 
				
			||||||
  "Collection": "Collection",
 | 
					  "Collection": "Collection",
 | 
				
			||||||
  "Collection selector": "Collection selector",
 | 
					  "Collection selector": "Collection selector",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "Insertar a la derecha",
 | 
					  "Insert right": "Insertar a la derecha",
 | 
				
			||||||
  "Insert inner": "Insertar al interior",
 | 
					  "Insert inner": "Insertar al interior",
 | 
				
			||||||
  "Delete": "Borrar",
 | 
					  "Delete": "Borrar",
 | 
				
			||||||
 | 
					  "Disassociate": "Desasociar",
 | 
				
			||||||
 | 
					  "Disassociate record": "Desasociar registro",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "¿Seguro que quieres desasociarlo?",
 | 
				
			||||||
  "UI editor": "IU editor",
 | 
					  "UI editor": "IU editor",
 | 
				
			||||||
  "Collection": "Colección",
 | 
					  "Collection": "Colección",
 | 
				
			||||||
  "Collections & Fields": "Colección & Campos",
 | 
					  "Collections & Fields": "Colección & Campos",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "Insérer à droite",
 | 
					  "Insert right": "Insérer à droite",
 | 
				
			||||||
  "Insert inner": "Insérer à l'intérieur",
 | 
					  "Insert inner": "Insérer à l'intérieur",
 | 
				
			||||||
  "Delete": "Supprimer",
 | 
					  "Delete": "Supprimer",
 | 
				
			||||||
 | 
					  "Disassociate": "Dissocier",
 | 
				
			||||||
 | 
					  "Disassociate record": "Dissocier l'enregistrement",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Êtes-vous sûr de vouloir le dissocier ?",
 | 
				
			||||||
  "UI editor": "Éditeur d'interface utilisateur",
 | 
					  "UI editor": "Éditeur d'interface utilisateur",
 | 
				
			||||||
  "Collection": "Collection",
 | 
					  "Collection": "Collection",
 | 
				
			||||||
  "Collections & Fields": "Collections et champs",
 | 
					  "Collections & Fields": "Collections et champs",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "右に挿入",
 | 
					  "Insert right": "右に挿入",
 | 
				
			||||||
  "Insert inner": "中に挿入",
 | 
					  "Insert inner": "中に挿入",
 | 
				
			||||||
  "Delete": "削除",
 | 
					  "Delete": "削除",
 | 
				
			||||||
 | 
					  "Disassociate": "関連付けを解除",
 | 
				
			||||||
 | 
					  "Disassociate record": "レコードの関連付けを解除",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "本当に関連付けを解除しますか?",
 | 
				
			||||||
  "UI editor": "UI エディタ",
 | 
					  "UI editor": "UI エディタ",
 | 
				
			||||||
  "Collection": "コレクション",
 | 
					  "Collection": "コレクション",
 | 
				
			||||||
  "Enable child collections": "启用子表",
 | 
					  "Enable child collections": "启用子表",
 | 
				
			||||||
 | 
				
			|||||||
@ -60,6 +60,9 @@
 | 
				
			|||||||
  "Insert right": "오른쪽에 삽입",
 | 
					  "Insert right": "오른쪽에 삽입",
 | 
				
			||||||
  "Insert inner": "내부에 삽입",
 | 
					  "Insert inner": "내부에 삽입",
 | 
				
			||||||
  "Delete": "삭제",
 | 
					  "Delete": "삭제",
 | 
				
			||||||
 | 
					  "Disassociate": "연결 해제",
 | 
				
			||||||
 | 
					  "Disassociate record": "레코드 연결 해제",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "정말로 연결을 해제하시겠습니까?",
 | 
				
			||||||
  "UI editor": "UI 편집기",
 | 
					  "UI editor": "UI 편집기",
 | 
				
			||||||
  "Collection": "컬렉션",
 | 
					  "Collection": "컬렉션",
 | 
				
			||||||
  "Collection selector": "컬렉션 선택기",
 | 
					  "Collection selector": "컬렉션 선택기",
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,9 @@
 | 
				
			|||||||
  "Insert right": "Inserir à direita",
 | 
					  "Insert right": "Inserir à direita",
 | 
				
			||||||
  "Insert inner": "Inserir interno",
 | 
					  "Insert inner": "Inserir interno",
 | 
				
			||||||
  "Delete": "Excluir",
 | 
					  "Delete": "Excluir",
 | 
				
			||||||
 | 
					  "Disassociate": "Desassociar",
 | 
				
			||||||
 | 
					  "Disassociate record": "Desassociar registro",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Tem certeza de que deseja desassociá-lo?",
 | 
				
			||||||
  "UI editor": "Editor de UI",
 | 
					  "UI editor": "Editor de UI",
 | 
				
			||||||
  "Collection": "Coleção",
 | 
					  "Collection": "Coleção",
 | 
				
			||||||
  "Collections & Fields": "Coleções e campos",
 | 
					  "Collections & Fields": "Coleções e campos",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "Вставить справа",
 | 
					  "Insert right": "Вставить справа",
 | 
				
			||||||
  "Insert inner": "Вставить внутрь",
 | 
					  "Insert inner": "Вставить внутрь",
 | 
				
			||||||
  "Delete": "Удалить",
 | 
					  "Delete": "Удалить",
 | 
				
			||||||
 | 
					  "Disassociate": "Разъединить",
 | 
				
			||||||
 | 
					  "Disassociate record": "Разъединить запись",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Вы уверены, что хотите разъединить это?",
 | 
				
			||||||
  "UI editor": "UI редактор",
 | 
					  "UI editor": "UI редактор",
 | 
				
			||||||
  "Collection": "Коллекция",
 | 
					  "Collection": "Коллекция",
 | 
				
			||||||
  "Collections & Fields": "Коллекции & Поля",
 | 
					  "Collections & Fields": "Коллекции & Поля",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "Sağa yerleştir",
 | 
					  "Insert right": "Sağa yerleştir",
 | 
				
			||||||
  "Insert inner": "İçine yerleştir",
 | 
					  "Insert inner": "İçine yerleştir",
 | 
				
			||||||
  "Delete": "Sil",
 | 
					  "Delete": "Sil",
 | 
				
			||||||
 | 
					  "Disassociate": "Bağlantıyı kes",
 | 
				
			||||||
 | 
					  "Disassociate record": "Kaydı bağlantıyı kes",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Bağlantıyı kesmek istediğinizden emin misiniz?",
 | 
				
			||||||
  "UI editor": "UI editor",
 | 
					  "UI editor": "UI editor",
 | 
				
			||||||
  "Collection": "Koleksiyonlar",
 | 
					  "Collection": "Koleksiyonlar",
 | 
				
			||||||
  "Collections & Fields": "Koleksiyonlar & Alanlar",
 | 
					  "Collections & Fields": "Koleksiyonlar & Alanlar",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@
 | 
				
			|||||||
  "Insert right": "Вставити справа",
 | 
					  "Insert right": "Вставити справа",
 | 
				
			||||||
  "Insert inner": "Вставити всередину",
 | 
					  "Insert inner": "Вставити всередину",
 | 
				
			||||||
  "Delete": "Видалити",
 | 
					  "Delete": "Видалити",
 | 
				
			||||||
 | 
					  "Disassociate": "Роз'єднати",
 | 
				
			||||||
 | 
					  "Disassociate record": "Роз'єднати запис",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "Ви впевнені, що хочете роз'єднати це?",
 | 
				
			||||||
  "UI editor": "Редактор UI",
 | 
					  "UI editor": "Редактор UI",
 | 
				
			||||||
  "Collection": "Колекція",
 | 
					  "Collection": "Колекція",
 | 
				
			||||||
  "Collections & Fields": "Колекції та поля",
 | 
					  "Collections & Fields": "Колекції та поля",
 | 
				
			||||||
 | 
				
			|||||||
@ -60,6 +60,9 @@
 | 
				
			|||||||
  "Insert right": "在右边插入",
 | 
					  "Insert right": "在右边插入",
 | 
				
			||||||
  "Insert inner": "在里面插入",
 | 
					  "Insert inner": "在里面插入",
 | 
				
			||||||
  "Delete": "删除",
 | 
					  "Delete": "删除",
 | 
				
			||||||
 | 
					  "Disassociate": "解除关联",
 | 
				
			||||||
 | 
					  "Disassociate record": "解除关联记录",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "你确定要解除关联吗?",
 | 
				
			||||||
  "UI editor": "界面配置",
 | 
					  "UI editor": "界面配置",
 | 
				
			||||||
  "Collection": "数据表",
 | 
					  "Collection": "数据表",
 | 
				
			||||||
  "Collection selector": "数据表选择器",
 | 
					  "Collection selector": "数据表选择器",
 | 
				
			||||||
 | 
				
			|||||||
@ -60,6 +60,9 @@
 | 
				
			|||||||
  "Insert right": "從右邊插入",
 | 
					  "Insert right": "從右邊插入",
 | 
				
			||||||
  "Insert inner": "從裡面插入",
 | 
					  "Insert inner": "從裡面插入",
 | 
				
			||||||
  "Delete": "刪除",
 | 
					  "Delete": "刪除",
 | 
				
			||||||
 | 
					  "Disassociate": "解除關聯",
 | 
				
			||||||
 | 
					  "Disassociate record": "解除關聯記錄",
 | 
				
			||||||
 | 
					  "Are you sure you want to disassociate it?": "你確定要解除關聯嗎?",
 | 
				
			||||||
  "UI editor": "介面編輯",
 | 
					  "UI editor": "介面編輯",
 | 
				
			||||||
  "Collection": "資料表",
 | 
					  "Collection": "資料表",
 | 
				
			||||||
  "Collection selector": "資料表選擇器",
 | 
					  "Collection selector": "資料表選擇器",
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const DisassociateActionInitializer = (props) => {
 | 
				
			||||||
 | 
					  const schema = {
 | 
				
			||||||
 | 
					    title: '{{ t("Disassociate") }}',
 | 
				
			||||||
 | 
					    'x-action': 'disassociate',
 | 
				
			||||||
 | 
					    'x-component': 'Action',
 | 
				
			||||||
 | 
					    'x-toolbar': 'ActionSchemaToolbar',
 | 
				
			||||||
 | 
					    'x-settings': 'actionSettings:disassociate',
 | 
				
			||||||
 | 
					    'x-component-props': {
 | 
				
			||||||
 | 
					      icon: 'DeleteOutlined',
 | 
				
			||||||
 | 
					      confirm: {
 | 
				
			||||||
 | 
					        title: "{{t('Disassociate record')}}",
 | 
				
			||||||
 | 
					        content: "{{t('Are you sure you want to disassociate it?')}}",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      useProps: '{{ useDisassociateActionProps }}',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    'x-action-settings': {
 | 
				
			||||||
 | 
					      triggerWorkflows: [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return <ActionInitializer {...props} schema={schema} />;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import { test, expect } from '@nocobase/test/e2e';
 | 
				
			||||||
 | 
					import { disassociatePage } from './templatesOfPage';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('basic', async ({ page, mockPage, mockRecord }) => {
 | 
				
			||||||
 | 
					  await mockPage(disassociatePage).goto();
 | 
				
			||||||
 | 
					  const record = await mockRecord('collection1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 1. 打开弹窗,并创建一个 Table 关系区块
 | 
				
			||||||
 | 
					  await page.getByLabel('action-Action.Link-Edit record-update-collection1-table-0').click();
 | 
				
			||||||
 | 
					  await page.getByLabel('schema-initializer-Grid-popup').hover();
 | 
				
			||||||
 | 
					  await page.getByRole('menuitem', { name: 'table Table right' }).hover();
 | 
				
			||||||
 | 
					  await page.getByRole('menuitem', { name: 'manyToMany -> collection2' }).click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 2. Table 中显示 Role UID 字段
 | 
				
			||||||
 | 
					  await page
 | 
				
			||||||
 | 
					    .getByTestId('drawer-Action.Container-collection1-Edit record')
 | 
				
			||||||
 | 
					    .getByLabel('schema-initializer-TableV2-')
 | 
				
			||||||
 | 
					    .hover();
 | 
				
			||||||
 | 
					  await page.getByRole('menuitem', { name: 'singleLineText' }).click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 3. 显示 Disassociate 按钮
 | 
				
			||||||
 | 
					  await page
 | 
				
			||||||
 | 
					    .getByTestId('drawer-Action.Container-collection1-Edit record')
 | 
				
			||||||
 | 
					    .getByRole('button', { name: 'Actions', exact: true })
 | 
				
			||||||
 | 
					    .hover();
 | 
				
			||||||
 | 
					  await page
 | 
				
			||||||
 | 
					    .getByTestId('drawer-Action.Container-collection1-Edit record')
 | 
				
			||||||
 | 
					    .getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-collection2')
 | 
				
			||||||
 | 
					    .hover();
 | 
				
			||||||
 | 
					  await page.getByRole('menuitem', { name: 'Disassociate' }).click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 4. 点击 Disassociate 按钮,解除关联
 | 
				
			||||||
 | 
					  await expect(
 | 
				
			||||||
 | 
					    page
 | 
				
			||||||
 | 
					      .getByTestId('drawer-Action.Container-collection1-Edit record')
 | 
				
			||||||
 | 
					      .getByLabel('block-item-CardItem-')
 | 
				
			||||||
 | 
					      .getByText(record.manyToMany[0].singleLineText),
 | 
				
			||||||
 | 
					  ).toBeVisible();
 | 
				
			||||||
 | 
					  await page.getByLabel('action-Action.Link-Disassociate-disassociate-collection2-table-0').click();
 | 
				
			||||||
 | 
					  await page.getByRole('button', { name: 'OK', exact: true }).click();
 | 
				
			||||||
 | 
					  await expect(
 | 
				
			||||||
 | 
					    page
 | 
				
			||||||
 | 
					      .getByTestId('drawer-Action.Container-collection1-Edit record')
 | 
				
			||||||
 | 
					      .getByLabel('block-item-CardItem-')
 | 
				
			||||||
 | 
					      .getByText(record.manyToMany[0].singleLineText),
 | 
				
			||||||
 | 
					  ).toBeHidden();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 5. 刷新页面后,页面中 collection2 的表格中的 singleLineText 字段不应该被删除
 | 
				
			||||||
 | 
					  await page.reload();
 | 
				
			||||||
 | 
					  await expect(
 | 
				
			||||||
 | 
					    page.getByLabel('block-item-CardItem-collection2-table').getByText(record.manyToMany[0].singleLineText),
 | 
				
			||||||
 | 
					  ).toBeVisible();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,384 @@
 | 
				
			|||||||
 | 
					import { PageConfig } from '@nocobase/test/e2e';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const disassociatePage: PageConfig = {
 | 
				
			||||||
 | 
					  collections: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'collection1',
 | 
				
			||||||
 | 
					      fields: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'manyToMany',
 | 
				
			||||||
 | 
					          interface: 'm2m',
 | 
				
			||||||
 | 
					          target: 'collection2',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'collection2',
 | 
				
			||||||
 | 
					      fields: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'singleLineText',
 | 
				
			||||||
 | 
					          interface: 'input',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  pageSchema: {
 | 
				
			||||||
 | 
					    _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					    version: '2.0',
 | 
				
			||||||
 | 
					    type: 'void',
 | 
				
			||||||
 | 
					    'x-component': 'Page',
 | 
				
			||||||
 | 
					    'x-index': 1,
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      wpr26fau9xr: {
 | 
				
			||||||
 | 
					        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					        version: '2.0',
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'Grid',
 | 
				
			||||||
 | 
					        'x-initializer': 'page:addBlock',
 | 
				
			||||||
 | 
					        'x-index': 1,
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          en9rmxzezha: {
 | 
				
			||||||
 | 
					            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					            version: '2.0',
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              yxbglvb5hog: {
 | 
				
			||||||
 | 
					                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                version: '2.0',
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  '8j54tok1ami': {
 | 
				
			||||||
 | 
					                    _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                    version: '2.0',
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-decorator': 'TableBlockProvider',
 | 
				
			||||||
 | 
					                    'x-acl-action': 'collection1:list',
 | 
				
			||||||
 | 
					                    'x-decorator-props': {
 | 
				
			||||||
 | 
					                      collection: 'collection1',
 | 
				
			||||||
 | 
					                      dataSource: 'main',
 | 
				
			||||||
 | 
					                      action: 'list',
 | 
				
			||||||
 | 
					                      params: {
 | 
				
			||||||
 | 
					                        pageSize: 20,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      rowKey: 'id',
 | 
				
			||||||
 | 
					                      showIndex: true,
 | 
				
			||||||
 | 
					                      dragSort: false,
 | 
				
			||||||
 | 
					                      disableTemplate: false,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    'x-toolbar': 'BlockSchemaToolbar',
 | 
				
			||||||
 | 
					                    'x-settings': 'blockSettings:table',
 | 
				
			||||||
 | 
					                    'x-component': 'CardItem',
 | 
				
			||||||
 | 
					                    'x-filter-targets': [],
 | 
				
			||||||
 | 
					                    properties: {
 | 
				
			||||||
 | 
					                      actions: {
 | 
				
			||||||
 | 
					                        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                        version: '2.0',
 | 
				
			||||||
 | 
					                        type: 'void',
 | 
				
			||||||
 | 
					                        'x-initializer': 'table:configureActions',
 | 
				
			||||||
 | 
					                        'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          style: {
 | 
				
			||||||
 | 
					                            marginBottom: 'var(--nb-spacing)',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'x-uid': 'b678n93qa6y',
 | 
				
			||||||
 | 
					                        'x-async': false,
 | 
				
			||||||
 | 
					                        'x-index': 1,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      qikcey9adni: {
 | 
				
			||||||
 | 
					                        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                        version: '2.0',
 | 
				
			||||||
 | 
					                        type: 'array',
 | 
				
			||||||
 | 
					                        'x-initializer': 'table:configureColumns',
 | 
				
			||||||
 | 
					                        'x-component': 'TableV2',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          rowKey: 'id',
 | 
				
			||||||
 | 
					                          rowSelection: {
 | 
				
			||||||
 | 
					                            type: 'checkbox',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          useProps: '{{ useTableBlockProps }}',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        properties: {
 | 
				
			||||||
 | 
					                          actions: {
 | 
				
			||||||
 | 
					                            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                            version: '2.0',
 | 
				
			||||||
 | 
					                            type: 'void',
 | 
				
			||||||
 | 
					                            title: '{{ t("Actions") }}',
 | 
				
			||||||
 | 
					                            'x-action-column': 'actions',
 | 
				
			||||||
 | 
					                            'x-decorator': 'TableV2.Column.ActionBar',
 | 
				
			||||||
 | 
					                            'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                            'x-designer': 'TableV2.ActionColumnDesigner',
 | 
				
			||||||
 | 
					                            'x-initializer': 'table:configureItemActions',
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              m7jxx6ybqin: {
 | 
				
			||||||
 | 
					                                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                version: '2.0',
 | 
				
			||||||
 | 
					                                type: 'void',
 | 
				
			||||||
 | 
					                                'x-decorator': 'DndContext',
 | 
				
			||||||
 | 
					                                'x-component': 'Space',
 | 
				
			||||||
 | 
					                                'x-component-props': {
 | 
				
			||||||
 | 
					                                  split: '|',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                properties: {
 | 
				
			||||||
 | 
					                                  xm4xv98j8rq: {
 | 
				
			||||||
 | 
					                                    'x-uid': 'zzpqq51vya7',
 | 
				
			||||||
 | 
					                                    _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                    version: '2.0',
 | 
				
			||||||
 | 
					                                    type: 'void',
 | 
				
			||||||
 | 
					                                    title: 'Edit record',
 | 
				
			||||||
 | 
					                                    'x-action': 'update',
 | 
				
			||||||
 | 
					                                    'x-toolbar': 'ActionSchemaToolbar',
 | 
				
			||||||
 | 
					                                    'x-settings': 'actionSettings:edit',
 | 
				
			||||||
 | 
					                                    'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					                                    'x-component-props': {
 | 
				
			||||||
 | 
					                                      openMode: 'drawer',
 | 
				
			||||||
 | 
					                                      danger: false,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    'x-decorator': 'ACLActionProvider',
 | 
				
			||||||
 | 
					                                    'x-designer-props': {
 | 
				
			||||||
 | 
					                                      linkageAction: true,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    properties: {
 | 
				
			||||||
 | 
					                                      drawer: {
 | 
				
			||||||
 | 
					                                        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                        version: '2.0',
 | 
				
			||||||
 | 
					                                        type: 'void',
 | 
				
			||||||
 | 
					                                        title: '{{ t("Edit record") }}',
 | 
				
			||||||
 | 
					                                        'x-component': 'Action.Container',
 | 
				
			||||||
 | 
					                                        'x-component-props': {
 | 
				
			||||||
 | 
					                                          className: 'nb-action-popup',
 | 
				
			||||||
 | 
					                                        },
 | 
				
			||||||
 | 
					                                        properties: {
 | 
				
			||||||
 | 
					                                          tabs: {
 | 
				
			||||||
 | 
					                                            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                            version: '2.0',
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Tabs',
 | 
				
			||||||
 | 
					                                            'x-component-props': {},
 | 
				
			||||||
 | 
					                                            'x-initializer': 'TabPaneInitializers',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              tab1: {
 | 
				
			||||||
 | 
					                                                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                                version: '2.0',
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                title: '{{t("Edit")}}',
 | 
				
			||||||
 | 
					                                                'x-component': 'Tabs.TabPane',
 | 
				
			||||||
 | 
					                                                'x-designer': 'Tabs.Designer',
 | 
				
			||||||
 | 
					                                                'x-component-props': {},
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  grid: {
 | 
				
			||||||
 | 
					                                                    _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                                    version: '2.0',
 | 
				
			||||||
 | 
					                                                    type: 'void',
 | 
				
			||||||
 | 
					                                                    'x-component': 'Grid',
 | 
				
			||||||
 | 
					                                                    'x-initializer': 'popup:common:addBlock',
 | 
				
			||||||
 | 
					                                                    'x-uid': '4ywsuzafbcb',
 | 
				
			||||||
 | 
					                                                    'x-async': false,
 | 
				
			||||||
 | 
					                                                    'x-index': 1,
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                                'x-uid': 'i9vjup0exgk',
 | 
				
			||||||
 | 
					                                                'x-async': false,
 | 
				
			||||||
 | 
					                                                'x-index': 1,
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                            'x-uid': 'v193kvjot2a',
 | 
				
			||||||
 | 
					                                            'x-async': false,
 | 
				
			||||||
 | 
					                                            'x-index': 1,
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                        },
 | 
				
			||||||
 | 
					                                        'x-uid': 'cm1v9u7tfsu',
 | 
				
			||||||
 | 
					                                        'x-async': false,
 | 
				
			||||||
 | 
					                                        'x-index': 1,
 | 
				
			||||||
 | 
					                                      },
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    'x-async': false,
 | 
				
			||||||
 | 
					                                    'x-index': 1,
 | 
				
			||||||
 | 
					                                  },
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                'x-uid': '1wxlbm4mmvg',
 | 
				
			||||||
 | 
					                                'x-async': false,
 | 
				
			||||||
 | 
					                                'x-index': 1,
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            'x-uid': '5sqdt97tixj',
 | 
				
			||||||
 | 
					                            'x-async': false,
 | 
				
			||||||
 | 
					                            'x-index': 1,
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'x-uid': 'kplsu47q2a6',
 | 
				
			||||||
 | 
					                        'x-async': false,
 | 
				
			||||||
 | 
					                        'x-index': 2,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    'x-uid': 'pq9i71986i8',
 | 
				
			||||||
 | 
					                    'x-async': false,
 | 
				
			||||||
 | 
					                    'x-index': 1,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'x-uid': 'oce2w1t8coi',
 | 
				
			||||||
 | 
					                'x-async': false,
 | 
				
			||||||
 | 
					                'x-index': 1,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'x-uid': 'i7ti4qryd4o',
 | 
				
			||||||
 | 
					            'x-async': false,
 | 
				
			||||||
 | 
					            'x-index': 1,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          gq928ipecvy: {
 | 
				
			||||||
 | 
					            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					            version: '2.0',
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              zue50ioabjl: {
 | 
				
			||||||
 | 
					                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                version: '2.0',
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  dv7csive187: {
 | 
				
			||||||
 | 
					                    _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                    version: '2.0',
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-decorator': 'TableBlockProvider',
 | 
				
			||||||
 | 
					                    'x-acl-action': 'collection2:list',
 | 
				
			||||||
 | 
					                    'x-decorator-props': {
 | 
				
			||||||
 | 
					                      collection: 'collection2',
 | 
				
			||||||
 | 
					                      dataSource: 'main',
 | 
				
			||||||
 | 
					                      action: 'list',
 | 
				
			||||||
 | 
					                      params: {
 | 
				
			||||||
 | 
					                        pageSize: 20,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      rowKey: 'id',
 | 
				
			||||||
 | 
					                      showIndex: true,
 | 
				
			||||||
 | 
					                      dragSort: false,
 | 
				
			||||||
 | 
					                      disableTemplate: false,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    'x-toolbar': 'BlockSchemaToolbar',
 | 
				
			||||||
 | 
					                    'x-settings': 'blockSettings:table',
 | 
				
			||||||
 | 
					                    'x-component': 'CardItem',
 | 
				
			||||||
 | 
					                    'x-filter-targets': [],
 | 
				
			||||||
 | 
					                    properties: {
 | 
				
			||||||
 | 
					                      actions: {
 | 
				
			||||||
 | 
					                        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                        version: '2.0',
 | 
				
			||||||
 | 
					                        type: 'void',
 | 
				
			||||||
 | 
					                        'x-initializer': 'table:configureActions',
 | 
				
			||||||
 | 
					                        'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          style: {
 | 
				
			||||||
 | 
					                            marginBottom: 'var(--nb-spacing)',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'x-uid': 'oe1qrytmueq',
 | 
				
			||||||
 | 
					                        'x-async': false,
 | 
				
			||||||
 | 
					                        'x-index': 1,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      gjd57a4bks3: {
 | 
				
			||||||
 | 
					                        _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                        version: '2.0',
 | 
				
			||||||
 | 
					                        type: 'array',
 | 
				
			||||||
 | 
					                        'x-initializer': 'table:configureColumns',
 | 
				
			||||||
 | 
					                        'x-component': 'TableV2',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          rowKey: 'id',
 | 
				
			||||||
 | 
					                          rowSelection: {
 | 
				
			||||||
 | 
					                            type: 'checkbox',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          useProps: '{{ useTableBlockProps }}',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        properties: {
 | 
				
			||||||
 | 
					                          actions: {
 | 
				
			||||||
 | 
					                            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                            version: '2.0',
 | 
				
			||||||
 | 
					                            type: 'void',
 | 
				
			||||||
 | 
					                            title: '{{ t("Actions") }}',
 | 
				
			||||||
 | 
					                            'x-action-column': 'actions',
 | 
				
			||||||
 | 
					                            'x-decorator': 'TableV2.Column.ActionBar',
 | 
				
			||||||
 | 
					                            'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                            'x-designer': 'TableV2.ActionColumnDesigner',
 | 
				
			||||||
 | 
					                            'x-initializer': 'table:configureItemActions',
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              '3ysynbg1lv6': {
 | 
				
			||||||
 | 
					                                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                version: '2.0',
 | 
				
			||||||
 | 
					                                type: 'void',
 | 
				
			||||||
 | 
					                                'x-decorator': 'DndContext',
 | 
				
			||||||
 | 
					                                'x-component': 'Space',
 | 
				
			||||||
 | 
					                                'x-component-props': {
 | 
				
			||||||
 | 
					                                  split: '|',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                'x-uid': 'aelf0u0qx6q',
 | 
				
			||||||
 | 
					                                'x-async': false,
 | 
				
			||||||
 | 
					                                'x-index': 1,
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            'x-uid': '5iadqvuebvd',
 | 
				
			||||||
 | 
					                            'x-async': false,
 | 
				
			||||||
 | 
					                            'x-index': 1,
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          '10a10qkpiz7': {
 | 
				
			||||||
 | 
					                            _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                            version: '2.0',
 | 
				
			||||||
 | 
					                            type: 'void',
 | 
				
			||||||
 | 
					                            'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                            'x-toolbar': 'TableColumnSchemaToolbar',
 | 
				
			||||||
 | 
					                            'x-settings': 'fieldSettings:TableColumn',
 | 
				
			||||||
 | 
					                            'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              singleLineText: {
 | 
				
			||||||
 | 
					                                _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					                                version: '2.0',
 | 
				
			||||||
 | 
					                                'x-collection-field': 'collection2.singleLineText',
 | 
				
			||||||
 | 
					                                'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                'x-component-props': {
 | 
				
			||||||
 | 
					                                  ellipsis: true,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                'x-decorator': null,
 | 
				
			||||||
 | 
					                                'x-decorator-props': {
 | 
				
			||||||
 | 
					                                  labelStyle: {
 | 
				
			||||||
 | 
					                                    display: 'none',
 | 
				
			||||||
 | 
					                                  },
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                'x-uid': 'fixqxflxl3p',
 | 
				
			||||||
 | 
					                                'x-async': false,
 | 
				
			||||||
 | 
					                                'x-index': 1,
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            'x-uid': '8huj8o6hk58',
 | 
				
			||||||
 | 
					                            'x-async': false,
 | 
				
			||||||
 | 
					                            'x-index': 2,
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'x-uid': 'zyewv4tfzsm',
 | 
				
			||||||
 | 
					                        'x-async': false,
 | 
				
			||||||
 | 
					                        'x-index': 2,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    'x-uid': 'c5o951ypirb',
 | 
				
			||||||
 | 
					                    'x-async': false,
 | 
				
			||||||
 | 
					                    'x-index': 1,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'x-uid': 'i50ffbtryxp',
 | 
				
			||||||
 | 
					                'x-async': false,
 | 
				
			||||||
 | 
					                'x-index': 1,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'x-uid': 'w6dx01br9dy',
 | 
				
			||||||
 | 
					            'x-async': false,
 | 
				
			||||||
 | 
					            'x-index': 2,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        'x-uid': 'aro2fcypx34',
 | 
				
			||||||
 | 
					        'x-async': false,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    'x-uid': '8ykc66k5p12',
 | 
				
			||||||
 | 
					    'x-async': true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import { useSchemaToolbar } from '../../../application';
 | 
				
			||||||
 | 
					import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
 | 
				
			||||||
 | 
					import { useCollection_deprecated } from '../../../collection-manager';
 | 
				
			||||||
 | 
					import { ButtonEditor, SecondConFirm } from '../../../schema-component/antd/action/Action.Designer';
 | 
				
			||||||
 | 
					import { SchemaSettingsLinkageRules } from '../../../schema-settings';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const disassociateActionSettings = new SchemaSettings({
 | 
				
			||||||
 | 
					  name: 'actionSettings:disassociate',
 | 
				
			||||||
 | 
					  items: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'editButton',
 | 
				
			||||||
 | 
					      Component: ButtonEditor,
 | 
				
			||||||
 | 
					      useComponentProps() {
 | 
				
			||||||
 | 
					        const { buttonEditorProps } = useSchemaToolbar();
 | 
				
			||||||
 | 
					        return buttonEditorProps;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'linkageRules',
 | 
				
			||||||
 | 
					      Component: SchemaSettingsLinkageRules,
 | 
				
			||||||
 | 
					      useComponentProps() {
 | 
				
			||||||
 | 
					        const { name } = useCollection_deprecated();
 | 
				
			||||||
 | 
					        const { linkageRulesProps } = useSchemaToolbar();
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          ...linkageRulesProps,
 | 
				
			||||||
 | 
					          collectionName: name,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'secondConFirm',
 | 
				
			||||||
 | 
					      Component: SecondConFirm,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'delete',
 | 
				
			||||||
 | 
					      type: 'remove',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -4,13 +4,14 @@ import _ from 'lodash';
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { useAPIClient } from '../../../../api-client';
 | 
					import { useAPIClient } from '../../../../api-client';
 | 
				
			||||||
 | 
					import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
 | 
				
			||||||
 | 
					import { SchemaInitializerActionModal } from '../../../../application/schema-initializer/components/SchemaInitializerActionModal';
 | 
				
			||||||
 | 
					import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem';
 | 
				
			||||||
 | 
					import { useSchemaInitializer } from '../../../../application/schema-initializer/context';
 | 
				
			||||||
import { useCollection_deprecated } from '../../../../collection-manager';
 | 
					import { useCollection_deprecated } from '../../../../collection-manager';
 | 
				
			||||||
 | 
					import { useDataBlockProps } from '../../../../data-source';
 | 
				
			||||||
import { createDesignable, useDesignable } from '../../../../schema-component';
 | 
					import { createDesignable, useDesignable } from '../../../../schema-component';
 | 
				
			||||||
import { useGetAriaLabelOfDesigner } from '../../../../schema-settings/hooks/useGetAriaLabelOfDesigner';
 | 
					import { useGetAriaLabelOfDesigner } from '../../../../schema-settings/hooks/useGetAriaLabelOfDesigner';
 | 
				
			||||||
import { SchemaInitializerActionModal } from '../../../../application/schema-initializer/components/SchemaInitializerActionModal';
 | 
					 | 
				
			||||||
import { useSchemaInitializer } from '../../../../application/schema-initializer/context';
 | 
					 | 
				
			||||||
import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem';
 | 
					 | 
				
			||||||
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Resizable = () => {
 | 
					export const Resizable = () => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
@ -65,11 +66,7 @@ export const Resizable = () => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					const commonOptions = {
 | 
				
			||||||
 * @deprecated
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
 | 
					 | 
				
			||||||
  name: 'TableActionColumnInitializers',
 | 
					 | 
				
			||||||
  insertPosition: 'beforeEnd',
 | 
					  insertPosition: 'beforeEnd',
 | 
				
			||||||
  useInsert: function useInsert() {
 | 
					  useInsert: function useInsert() {
 | 
				
			||||||
    const { refresh } = useDesignable();
 | 
					    const { refresh } = useDesignable();
 | 
				
			||||||
@ -156,6 +153,27 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit
 | 
				
			|||||||
            return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
					            return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          type: 'item',
 | 
				
			||||||
 | 
					          title: '{{t("Disassociate")}}',
 | 
				
			||||||
 | 
					          name: 'disassociate',
 | 
				
			||||||
 | 
					          Component: 'DisassociateActionInitializer',
 | 
				
			||||||
 | 
					          schema: {
 | 
				
			||||||
 | 
					            'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					            'x-action': 'disassociate',
 | 
				
			||||||
 | 
					            'x-acl-action': 'destroy',
 | 
				
			||||||
 | 
					            'x-decorator': 'ACLActionProvider',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          useVisible() {
 | 
				
			||||||
 | 
					            const props = useDataBlockProps();
 | 
				
			||||||
 | 
					            const collection = useCollection_deprecated();
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					              !!props?.association &&
 | 
				
			||||||
 | 
					              (collection.template !== 'view' || collection?.writableView) &&
 | 
				
			||||||
 | 
					              collection.template !== 'sql'
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          type: 'item',
 | 
					          type: 'item',
 | 
				
			||||||
          title: '{{t("Add child")}}',
 | 
					          title: '{{t("Add child")}}',
 | 
				
			||||||
@ -225,166 +243,20 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit
 | 
				
			|||||||
      Component: Resizable,
 | 
					      Component: Resizable,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @deprecated
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
 | 
				
			||||||
 | 
					  name: 'TableActionColumnInitializers',
 | 
				
			||||||
 | 
					  ...commonOptions,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const tableActionColumnInitializers = new CompatibleSchemaInitializer(
 | 
					export const tableActionColumnInitializers = new CompatibleSchemaInitializer(
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: 'table:configureItemActions',
 | 
					    name: 'table:configureItemActions',
 | 
				
			||||||
    insertPosition: 'beforeEnd',
 | 
					    ...commonOptions,
 | 
				
			||||||
    useInsert: function useInsert() {
 | 
					 | 
				
			||||||
      const { refresh } = useDesignable();
 | 
					 | 
				
			||||||
      const fieldSchema = useFieldSchema();
 | 
					 | 
				
			||||||
      const api = useAPIClient();
 | 
					 | 
				
			||||||
      const { t } = useTranslation();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return function insert(schema) {
 | 
					 | 
				
			||||||
        const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
 | 
					 | 
				
			||||||
          if (schema['x-component'] === 'Space') {
 | 
					 | 
				
			||||||
            return schema;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          return buf;
 | 
					 | 
				
			||||||
        }, null);
 | 
					 | 
				
			||||||
        if (!spaceSchema) {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        _.set(schema, 'x-designer-props.linkageAction', true);
 | 
					 | 
				
			||||||
        const dn = createDesignable({
 | 
					 | 
				
			||||||
          t,
 | 
					 | 
				
			||||||
          api,
 | 
					 | 
				
			||||||
          refresh,
 | 
					 | 
				
			||||||
          current: spaceSchema,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        dn.loadAPIClientEvents();
 | 
					 | 
				
			||||||
        dn.insertBeforeEnd(schema);
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    Component: (props: any) => {
 | 
					 | 
				
			||||||
      const { getAriaLabel } = useGetAriaLabelOfDesigner();
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <MenuOutlined
 | 
					 | 
				
			||||||
          {...props}
 | 
					 | 
				
			||||||
          role="button"
 | 
					 | 
				
			||||||
          aria-label={getAriaLabel('schema-settings')}
 | 
					 | 
				
			||||||
          style={{ cursor: 'pointer' }}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    items: [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        type: 'itemGroup',
 | 
					 | 
				
			||||||
        name: 'actions',
 | 
					 | 
				
			||||||
        title: '{{t("Enable actions")}}',
 | 
					 | 
				
			||||||
        children: [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            title: '{{t("View")}}',
 | 
					 | 
				
			||||||
            name: 'view',
 | 
					 | 
				
			||||||
            Component: 'ViewActionInitializer',
 | 
					 | 
				
			||||||
            schema: {
 | 
					 | 
				
			||||||
              'x-component': 'Action.Link',
 | 
					 | 
				
			||||||
              'x-action': 'view',
 | 
					 | 
				
			||||||
              'x-decorator': 'ACLActionProvider',
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            name: 'edit',
 | 
					 | 
				
			||||||
            title: '{{t("Edit")}}',
 | 
					 | 
				
			||||||
            Component: 'UpdateActionInitializer',
 | 
					 | 
				
			||||||
            schema: {
 | 
					 | 
				
			||||||
              'x-component': 'Action.Link',
 | 
					 | 
				
			||||||
              'x-action': 'update',
 | 
					 | 
				
			||||||
              'x-decorator': 'ACLActionProvider',
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            useVisible() {
 | 
					 | 
				
			||||||
              const collection = useCollection_deprecated();
 | 
					 | 
				
			||||||
              return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            title: '{{t("Delete")}}',
 | 
					 | 
				
			||||||
            name: 'delete',
 | 
					 | 
				
			||||||
            Component: 'DestroyActionInitializer',
 | 
					 | 
				
			||||||
            schema: {
 | 
					 | 
				
			||||||
              'x-component': 'Action.Link',
 | 
					 | 
				
			||||||
              'x-action': 'destroy',
 | 
					 | 
				
			||||||
              'x-decorator': 'ACLActionProvider',
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            useVisible() {
 | 
					 | 
				
			||||||
              const collection = useCollection_deprecated();
 | 
					 | 
				
			||||||
              return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            title: '{{t("Add child")}}',
 | 
					 | 
				
			||||||
            name: 'addChildren',
 | 
					 | 
				
			||||||
            Component: 'CreateChildInitializer',
 | 
					 | 
				
			||||||
            schema: {
 | 
					 | 
				
			||||||
              'x-component': 'Action.Link',
 | 
					 | 
				
			||||||
              'x-action': 'create',
 | 
					 | 
				
			||||||
              'x-decorator': 'ACLActionProvider',
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            useVisible() {
 | 
					 | 
				
			||||||
              const fieldSchema = useFieldSchema();
 | 
					 | 
				
			||||||
              const collection = useCollection_deprecated();
 | 
					 | 
				
			||||||
              const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props'] || {};
 | 
					 | 
				
			||||||
              return collection.tree && treeTable !== false;
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        name: 'divider',
 | 
					 | 
				
			||||||
        type: 'divider',
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        type: 'subMenu',
 | 
					 | 
				
			||||||
        title: '{{t("Customize")}}',
 | 
					 | 
				
			||||||
        name: 'customize',
 | 
					 | 
				
			||||||
        children: [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            title: '{{t("Popup")}}',
 | 
					 | 
				
			||||||
            name: 'popup',
 | 
					 | 
				
			||||||
            Component: 'PopupActionInitializer',
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'item',
 | 
					 | 
				
			||||||
            title: '{{t("Update record")}}',
 | 
					 | 
				
			||||||
            name: 'updateRecord',
 | 
					 | 
				
			||||||
            Component: 'UpdateRecordActionInitializer',
 | 
					 | 
				
			||||||
            useVisible() {
 | 
					 | 
				
			||||||
              const collection = useCollection_deprecated();
 | 
					 | 
				
			||||||
              return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            name: 'customRequest',
 | 
					 | 
				
			||||||
            title: '{{t("Custom request")}}',
 | 
					 | 
				
			||||||
            Component: 'CustomRequestInitializer',
 | 
					 | 
				
			||||||
            schema: {
 | 
					 | 
				
			||||||
              'x-action': 'customize:table:request',
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            useVisible() {
 | 
					 | 
				
			||||||
              const collection = useCollection_deprecated();
 | 
					 | 
				
			||||||
              return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        name: 'divider2',
 | 
					 | 
				
			||||||
        type: 'divider',
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        type: 'item',
 | 
					 | 
				
			||||||
        name: 'columnWidth',
 | 
					 | 
				
			||||||
        title: 't("Column width")',
 | 
					 | 
				
			||||||
        Component: Resizable,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  tableActionColumnInitializers_deprecated,
 | 
					  tableActionColumnInitializers_deprecated,
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ import {
 | 
				
			|||||||
} from '../modules/actions/add-record/customizeCreateFormBlockInitializers';
 | 
					} from '../modules/actions/add-record/customizeCreateFormBlockInitializers';
 | 
				
			||||||
import { BulkDestroyActionInitializer } from '../modules/actions/bulk-destroy/BulkDestroyActionInitializer';
 | 
					import { BulkDestroyActionInitializer } from '../modules/actions/bulk-destroy/BulkDestroyActionInitializer';
 | 
				
			||||||
import { DestroyActionInitializer } from '../modules/actions/delete/DestroyActionInitializer';
 | 
					import { DestroyActionInitializer } from '../modules/actions/delete/DestroyActionInitializer';
 | 
				
			||||||
 | 
					import { DisassociateActionInitializer } from '../modules/actions/disassociate/DisassociateActionInitializer';
 | 
				
			||||||
import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer';
 | 
					import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer';
 | 
				
			||||||
import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer';
 | 
					import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer';
 | 
				
			||||||
import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer';
 | 
					import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer';
 | 
				
			||||||
@ -121,10 +122,10 @@ import * as items from './items';
 | 
				
			|||||||
export * from './buttons';
 | 
					export * from './buttons';
 | 
				
			||||||
export * from './items';
 | 
					export * from './items';
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
 | 
					  createDetailsBlockSchema,
 | 
				
			||||||
  createFilterFormBlockSchema,
 | 
					  createFilterFormBlockSchema,
 | 
				
			||||||
  createFormBlockSchema,
 | 
					  createFormBlockSchema,
 | 
				
			||||||
  createReadPrettyFormBlockSchema,
 | 
					  createReadPrettyFormBlockSchema,
 | 
				
			||||||
  createDetailsBlockSchema,
 | 
					 | 
				
			||||||
  createTableBlockSchema,
 | 
					  createTableBlockSchema,
 | 
				
			||||||
  gridRowColWrap,
 | 
					  gridRowColWrap,
 | 
				
			||||||
  itemsMerge,
 | 
					  itemsMerge,
 | 
				
			||||||
@ -144,6 +145,7 @@ export class SchemaInitializerPlugin extends Plugin {
 | 
				
			|||||||
    this.app.addComponents({
 | 
					    this.app.addComponents({
 | 
				
			||||||
      ...initializerComponents,
 | 
					      ...initializerComponents,
 | 
				
			||||||
      ...items,
 | 
					      ...items,
 | 
				
			||||||
 | 
					      DestroyActionInitializer,
 | 
				
			||||||
      CreateFormBlockInitializer,
 | 
					      CreateFormBlockInitializer,
 | 
				
			||||||
      FormBlockInitializer,
 | 
					      FormBlockInitializer,
 | 
				
			||||||
      RecordFormBlockInitializer,
 | 
					      RecordFormBlockInitializer,
 | 
				
			||||||
@ -171,7 +173,7 @@ export class SchemaInitializerPlugin extends Plugin {
 | 
				
			|||||||
      UpdateSubmitActionInitializer,
 | 
					      UpdateSubmitActionInitializer,
 | 
				
			||||||
      BulkDestroyActionInitializer,
 | 
					      BulkDestroyActionInitializer,
 | 
				
			||||||
      ExpandableActionInitializer,
 | 
					      ExpandableActionInitializer,
 | 
				
			||||||
      DestroyActionInitializer,
 | 
					      DisassociateActionInitializer,
 | 
				
			||||||
      FilterActionInitializer,
 | 
					      FilterActionInitializer,
 | 
				
			||||||
      RefreshActionInitializer,
 | 
					      RefreshActionInitializer,
 | 
				
			||||||
    } as any);
 | 
					    } as any);
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import { addNewActionSettings } from '../modules/actions/add-new/addNewActionSet
 | 
				
			|||||||
import { customizeAddRecordActionSettings } from '../modules/actions/add-record/customizeAddRecordActionSettings';
 | 
					import { customizeAddRecordActionSettings } from '../modules/actions/add-record/customizeAddRecordActionSettings';
 | 
				
			||||||
import { bulkDeleteActionSettings } from '../modules/actions/bulk-destroy/bulkDeleteActionSettings';
 | 
					import { bulkDeleteActionSettings } from '../modules/actions/bulk-destroy/bulkDeleteActionSettings';
 | 
				
			||||||
import { deleteActionSettings } from '../modules/actions/delete/deleteActionSettings';
 | 
					import { deleteActionSettings } from '../modules/actions/delete/deleteActionSettings';
 | 
				
			||||||
 | 
					import { disassociateActionSettings } from '../modules/actions/disassociate/disassociateActionSettings';
 | 
				
			||||||
import { expendableActionSettings } from '../modules/actions/expand-collapse/expendableActionSettings';
 | 
					import { expendableActionSettings } from '../modules/actions/expand-collapse/expendableActionSettings';
 | 
				
			||||||
import { filterActionSettings } from '../modules/actions/filter/filterActionSettings';
 | 
					import { filterActionSettings } from '../modules/actions/filter/filterActionSettings';
 | 
				
			||||||
import { refreshActionSettings } from '../modules/actions/refresh/refreshActionSettings';
 | 
					import { refreshActionSettings } from '../modules/actions/refresh/refreshActionSettings';
 | 
				
			||||||
@ -69,6 +70,7 @@ export class SchemaSettingsPlugin extends Plugin {
 | 
				
			|||||||
    this.schemaSettingsManager.add(viewActionSettings);
 | 
					    this.schemaSettingsManager.add(viewActionSettings);
 | 
				
			||||||
    this.schemaSettingsManager.add(editActionSettings);
 | 
					    this.schemaSettingsManager.add(editActionSettings);
 | 
				
			||||||
    this.schemaSettingsManager.add(deleteActionSettings);
 | 
					    this.schemaSettingsManager.add(deleteActionSettings);
 | 
				
			||||||
 | 
					    this.schemaSettingsManager.add(disassociateActionSettings);
 | 
				
			||||||
    this.schemaSettingsManager.add(bulkDeleteActionSettings);
 | 
					    this.schemaSettingsManager.add(bulkDeleteActionSettings);
 | 
				
			||||||
    this.schemaSettingsManager.add(customizeAddRecordActionSettings);
 | 
					    this.schemaSettingsManager.add(customizeAddRecordActionSettings);
 | 
				
			||||||
    this.schemaSettingsManager.add(customizePopupActionSettings);
 | 
					    this.schemaSettingsManager.add(customizePopupActionSettings);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "create-nocobase-app",
 | 
					  "name": "create-nocobase-app",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "src/index.js",
 | 
					  "main": "src/index.js",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +1,16 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/data-source-manager",
 | 
					  "name": "@nocobase/data-source-manager",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/actions": "0.20.0-alpha.14",
 | 
					    "@nocobase/actions": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/cache": "0.20.0-alpha.14",
 | 
					    "@nocobase/cache": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/database": "0.20.0-alpha.14",
 | 
					    "@nocobase/database": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/resourcer": "0.20.0-alpha.14",
 | 
					    "@nocobase/resourcer": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "@types/jsonwebtoken": "^8.5.8",
 | 
					    "@types/jsonwebtoken": "^8.5.8",
 | 
				
			||||||
    "jsonwebtoken": "^8.5.1"
 | 
					    "jsonwebtoken": "^8.5.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/database",
 | 
					  "name": "@nocobase/database",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/logger": "0.20.0-alpha.14",
 | 
					    "@nocobase/logger": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "async-mutex": "^0.3.2",
 | 
					    "async-mutex": "^0.3.2",
 | 
				
			||||||
    "chalk": "^4.1.1",
 | 
					    "chalk": "^4.1.1",
 | 
				
			||||||
    "cron-parser": "4.4.0",
 | 
					    "cron-parser": "4.4.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -13,19 +13,20 @@ describe('string field', () => {
 | 
				
			|||||||
    await db.close();
 | 
					    await db.close();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('define', async () => {
 | 
					  it('should create uuid field', async () => {
 | 
				
			||||||
    const Test = db.collection({
 | 
					    const Test = db.collection({
 | 
				
			||||||
      name: 'tests',
 | 
					      name: 'tests',
 | 
				
			||||||
      autoGenId: false,
 | 
					 | 
				
			||||||
      fields: [
 | 
					      fields: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'uuid',
 | 
				
			||||||
          type: 'uuid',
 | 
					          type: 'uuid',
 | 
				
			||||||
          name: 'id',
 | 
					 | 
				
			||||||
          primaryKey: true,
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await Test.sync();
 | 
					    await Test.sync();
 | 
				
			||||||
    await Test.model.create();
 | 
					    const item = await Test.model.create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(item['uuid']).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@ export class UuidField extends Field {
 | 
				
			|||||||
  constructor(options?: any, context?: FieldContext) {
 | 
					  constructor(options?: any, context?: FieldContext) {
 | 
				
			||||||
    super(
 | 
					    super(
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        defaultValue: DataTypes.UUIDV4,
 | 
					        defaultValue: new DataTypes.UUIDV4(),
 | 
				
			||||||
        ...options,
 | 
					        ...options,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      context,
 | 
					      context,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/devtools",
 | 
					  "name": "@nocobase/devtools",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./src/index.js",
 | 
					  "main": "./src/index.js",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/build": "0.20.0-alpha.14",
 | 
					    "@nocobase/build": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/client": "0.20.0-alpha.14",
 | 
					    "@nocobase/client": "0.20.0-alpha.15",
 | 
				
			||||||
    "@nocobase/test": "0.20.0-alpha.14",
 | 
					    "@nocobase/test": "0.20.0-alpha.15",
 | 
				
			||||||
    "@types/koa": "^2.13.4",
 | 
					    "@types/koa": "^2.13.4",
 | 
				
			||||||
    "@types/koa-bodyparser": "^4.3.4",
 | 
					    "@types/koa-bodyparser": "^4.3.4",
 | 
				
			||||||
    "@types/lodash": "^4.14.177",
 | 
					    "@types/lodash": "^4.14.177",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/evaluators",
 | 
					  "name": "@nocobase/evaluators",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@formulajs/formulajs": "4.2.0",
 | 
					    "@formulajs/formulajs": "4.2.0",
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "mathjs": "^10.6.0"
 | 
					    "mathjs": "^10.6.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/logger",
 | 
					  "name": "@nocobase/logger",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "nocobase logging library",
 | 
					  "description": "nocobase logging library",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -49,13 +49,13 @@ class SystemLoggerTransport extends Transport {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  log(info: any, callback: any) {
 | 
					  log(info: any, callback: any) {
 | 
				
			||||||
    const { level, message, reqId, app, stack, [SPLAT]: args } = info;
 | 
					    const { level, message, reqId, app, stack, cause, [SPLAT]: args } = info;
 | 
				
			||||||
    const logger = level === 'error' && this.errorLogger ? this.errorLogger : this.logger;
 | 
					    const logger = level === 'error' && this.errorLogger ? this.errorLogger : this.logger;
 | 
				
			||||||
    const { module, submodule, method, ...meta } = args?.[0] || {};
 | 
					    const { module, submodule, method, ...meta } = args?.[0] || {};
 | 
				
			||||||
    logger.log({
 | 
					    logger.log({
 | 
				
			||||||
      level,
 | 
					      level,
 | 
				
			||||||
      stack,
 | 
					 | 
				
			||||||
      message,
 | 
					      message,
 | 
				
			||||||
 | 
					      stack,
 | 
				
			||||||
      meta,
 | 
					      meta,
 | 
				
			||||||
      module: module || info['module'] || '',
 | 
					      module: module || info['module'] || '',
 | 
				
			||||||
      submodule: submodule || info['submodule'] || '',
 | 
					      submodule: submodule || info['submodule'] || '',
 | 
				
			||||||
@ -63,11 +63,51 @@ class SystemLoggerTransport extends Transport {
 | 
				
			|||||||
      app,
 | 
					      app,
 | 
				
			||||||
      reqId,
 | 
					      reqId,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    if (cause) {
 | 
				
			||||||
 | 
					      logger.log({
 | 
				
			||||||
 | 
					        level,
 | 
				
			||||||
 | 
					        message: cause.message,
 | 
				
			||||||
 | 
					        stack: cause.stack,
 | 
				
			||||||
 | 
					        app,
 | 
				
			||||||
 | 
					        reqId,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    callback(null, true);
 | 
					    callback(null, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createSystemLogger = (options: SystemLoggerOptions): SystemLogger =>
 | 
					function child(defaultRequestMetadata: any) {
 | 
				
			||||||
  winston.createLogger({
 | 
					  const logger = this;
 | 
				
			||||||
 | 
					  return Object.create(logger, {
 | 
				
			||||||
 | 
					    write: {
 | 
				
			||||||
 | 
					      value: function (info: any) {
 | 
				
			||||||
 | 
					        const infoClone = Object.assign({}, defaultRequestMetadata, info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (info instanceof Error) {
 | 
				
			||||||
 | 
					          infoClone.stack = info.stack;
 | 
				
			||||||
 | 
					          infoClone.message = info.message;
 | 
				
			||||||
 | 
					          infoClone.cause = info.cause;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logger.write(infoClone);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const createSystemLogger = (options: SystemLoggerOptions): SystemLogger => {
 | 
				
			||||||
 | 
					  const logger = winston.createLogger({
 | 
				
			||||||
    transports: [new SystemLoggerTransport(options)],
 | 
					    transports: [new SystemLoggerTransport(options)],
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Since error.cause is not supported by child logger of winston
 | 
				
			||||||
 | 
					  // we have to use a proxy to rewrite child method
 | 
				
			||||||
 | 
					  return new Proxy(logger, {
 | 
				
			||||||
 | 
					    get(target, prop) {
 | 
				
			||||||
 | 
					      if (prop === 'child') {
 | 
				
			||||||
 | 
					        return child.bind(target);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return Reflect.get(target, prop);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/resourcer",
 | 
					  "name": "@nocobase/resourcer",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "deepmerge": "^4.2.2",
 | 
					    "deepmerge": "^4.2.2",
 | 
				
			||||||
    "koa-compose": "^4.1.0",
 | 
					    "koa-compose": "^4.1.0",
 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/sdk",
 | 
					  "name": "@nocobase/sdk",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "lib/index.js",
 | 
					  "main": "lib/index.js",
 | 
				
			||||||
  "types": "lib/index.d.ts",
 | 
					  "types": "lib/index.d.ts",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "@nocobase/server",
 | 
					    "name": "@nocobase/server",
 | 
				
			||||||
    "version": "0.20.0-alpha.14",
 | 
					    "version": "0.20.0-alpha.15",
 | 
				
			||||||
    "main": "lib/index.js",
 | 
					    "main": "lib/index.js",
 | 
				
			||||||
    "types": "./lib/index.d.ts",
 | 
					    "types": "./lib/index.d.ts",
 | 
				
			||||||
    "license": "Apache-2.0",
 | 
					    "license": "Apache-2.0",
 | 
				
			||||||
@ -10,18 +10,18 @@
 | 
				
			|||||||
        "@koa/cors": "^3.1.0",
 | 
					        "@koa/cors": "^3.1.0",
 | 
				
			||||||
        "@koa/multer": "^3.0.2",
 | 
					        "@koa/multer": "^3.0.2",
 | 
				
			||||||
        "@koa/router": "^9.4.0",
 | 
					        "@koa/router": "^9.4.0",
 | 
				
			||||||
        "@nocobase/acl": "0.20.0-alpha.14",
 | 
					        "@nocobase/acl": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/actions": "0.20.0-alpha.14",
 | 
					        "@nocobase/actions": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/auth": "0.20.0-alpha.14",
 | 
					        "@nocobase/auth": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/cache": "0.20.0-alpha.14",
 | 
					        "@nocobase/cache": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/data-source-manager": "0.20.0-alpha.14",
 | 
					        "@nocobase/data-source-manager": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/database": "0.20.0-alpha.14",
 | 
					        "@nocobase/database": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/evaluators": "0.20.0-alpha.14",
 | 
					        "@nocobase/evaluators": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/logger": "0.20.0-alpha.14",
 | 
					        "@nocobase/logger": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/resourcer": "0.20.0-alpha.14",
 | 
					        "@nocobase/resourcer": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/sdk": "0.20.0-alpha.14",
 | 
					        "@nocobase/sdk": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/telemetry": "0.20.0-alpha.14",
 | 
					        "@nocobase/telemetry": "0.20.0-alpha.15",
 | 
				
			||||||
        "@nocobase/utils": "0.20.0-alpha.14",
 | 
					        "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
        "@types/decompress": "4.2.4",
 | 
					        "@types/decompress": "4.2.4",
 | 
				
			||||||
        "@types/ini": "^1.3.31",
 | 
					        "@types/ini": "^1.3.31",
 | 
				
			||||||
        "@types/koa-send": "^4.1.3",
 | 
					        "@types/koa-send": "^4.1.3",
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ const availableActions: {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  destroy: {
 | 
					  destroy: {
 | 
				
			||||||
    displayName: '{{t("Delete")}}',
 | 
					    displayName: '{{t("Delete")}}',
 | 
				
			||||||
 | 
					    aliases: ['destroy', 'remove'],
 | 
				
			||||||
    type: 'old-data',
 | 
					    type: 'old-data',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/telemetry",
 | 
					  "name": "@nocobase/telemetry",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "nocobase telemetry library",
 | 
					  "description": "nocobase telemetry library",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
  "main": "./lib/index.js",
 | 
					  "main": "./lib/index.js",
 | 
				
			||||||
@ -11,7 +11,7 @@
 | 
				
			|||||||
    "directory": "packages/telemetry"
 | 
					    "directory": "packages/telemetry"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@nocobase/utils": "0.20.0-alpha.14",
 | 
					    "@nocobase/utils": "0.20.0-alpha.15",
 | 
				
			||||||
    "@opentelemetry/api": "^1.7.0",
 | 
					    "@opentelemetry/api": "^1.7.0",
 | 
				
			||||||
    "@opentelemetry/instrumentation": "^0.46.0",
 | 
					    "@opentelemetry/instrumentation": "^0.46.0",
 | 
				
			||||||
    "@opentelemetry/resources": "^1.19.0",
 | 
					    "@opentelemetry/resources": "^1.19.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/test",
 | 
					  "name": "@nocobase/test",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "lib/index.js",
 | 
					  "main": "lib/index.js",
 | 
				
			||||||
  "module": "./src/index.ts",
 | 
					  "module": "./src/index.ts",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
@ -40,7 +40,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@faker-js/faker": "8.1.0",
 | 
					    "@faker-js/faker": "8.1.0",
 | 
				
			||||||
    "@nocobase/server": "0.20.0-alpha.14",
 | 
					    "@nocobase/server": "0.20.0-alpha.15",
 | 
				
			||||||
    "@playwright/test": "^1.42.1",
 | 
					    "@playwright/test": "^1.42.1",
 | 
				
			||||||
    "@testing-library/react": "^14.0.0",
 | 
					    "@testing-library/react": "^14.0.0",
 | 
				
			||||||
    "@testing-library/user-event": "^14.4.3",
 | 
					    "@testing-library/user-event": "^14.4.3",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/utils",
 | 
					  "name": "@nocobase/utils",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "lib/index.js",
 | 
					  "main": "lib/index.js",
 | 
				
			||||||
  "types": "./lib/index.d.ts",
 | 
					  "types": "./lib/index.d.ts",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "权限控制",
 | 
					  "displayName.zh-CN": "权限控制",
 | 
				
			||||||
  "description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
 | 
					  "description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
 | 
				
			||||||
  "description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
 | 
					  "description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/acl",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/acl",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,13 @@
 | 
				
			|||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { Card, Row, Col, Tabs, Divider } from 'antd';
 | 
					import { Card, Row, Col, Tabs, Divider } from 'antd';
 | 
				
			||||||
import { CollectionProvider, CollectionProvider_deprecated, ResourceActionProvider, usePlugin } from '@nocobase/client';
 | 
					import {
 | 
				
			||||||
 | 
					  CollectionProvider,
 | 
				
			||||||
 | 
					  CollectionProvider_deprecated,
 | 
				
			||||||
 | 
					  ResourceActionProvider,
 | 
				
			||||||
 | 
					  SchemaComponentContext,
 | 
				
			||||||
 | 
					  usePlugin,
 | 
				
			||||||
 | 
					  useSchemaComponentContext,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
import { ISchema, Schema } from '@formily/react';
 | 
					import { ISchema, Schema } from '@formily/react';
 | 
				
			||||||
import { RolesMenu } from './RolesMenu';
 | 
					import { RolesMenu } from './RolesMenu';
 | 
				
			||||||
import { useACLTranslation } from './locale';
 | 
					import { useACLTranslation } from './locale';
 | 
				
			||||||
@ -58,53 +65,55 @@ export const RolesManagement: React.FC = () => {
 | 
				
			|||||||
    children: item.Component ? React.createElement(item.Component, { active: activeKey === name }) : null,
 | 
					    children: item.Component ? React.createElement(item.Component, { active: activeKey === name }) : null,
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
  const [role, setRole] = useState(null);
 | 
					  const [role, setRole] = useState(null);
 | 
				
			||||||
 | 
					  const scCtx = useSchemaComponentContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <RolesManagerContext.Provider value={{ role, setRole }}>
 | 
					    <SchemaComponentContext.Provider value={{ ...scCtx, designable: false }}>
 | 
				
			||||||
      <Card>
 | 
					      <RolesManagerContext.Provider value={{ role, setRole }}>
 | 
				
			||||||
        <Row gutter={24} style={{ flexWrap: 'nowrap' }}>
 | 
					        <Card>
 | 
				
			||||||
          <Col flex="280px" style={{ borderRight: '1px solid #eee', minWidth: '250px' }}>
 | 
					          <Row gutter={24} style={{ flexWrap: 'nowrap' }}>
 | 
				
			||||||
            <ResourceActionProvider
 | 
					            <Col flex="280px" style={{ borderRight: '1px solid #eee', minWidth: '250px' }}>
 | 
				
			||||||
              collection={collection}
 | 
					              <ResourceActionProvider
 | 
				
			||||||
              request={{
 | 
					                collection={collection}
 | 
				
			||||||
                resource: 'roles',
 | 
					                request={{
 | 
				
			||||||
                action: 'list',
 | 
					                  resource: 'roles',
 | 
				
			||||||
                params: {
 | 
					                  action: 'list',
 | 
				
			||||||
                  pagination: false,
 | 
					                  params: {
 | 
				
			||||||
                  filter: {
 | 
					                    filter: {
 | 
				
			||||||
                    'name.$ne': 'root',
 | 
					                      'name.$ne': 'root',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    showAnonymous: true,
 | 
				
			||||||
 | 
					                    sort: ['createdAt'],
 | 
				
			||||||
 | 
					                    appends: [],
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
                  showAnonymous: true,
 | 
					                }}
 | 
				
			||||||
                  sort: ['createdAt'],
 | 
					              >
 | 
				
			||||||
                  appends: [],
 | 
					                <CollectionProvider_deprecated collection={collection}>
 | 
				
			||||||
                },
 | 
					                  <Row>
 | 
				
			||||||
              }}
 | 
					                    <NewRole />
 | 
				
			||||||
            >
 | 
					                  </Row>
 | 
				
			||||||
              <CollectionProvider_deprecated collection={collection}>
 | 
					                  <Divider style={{ margin: '12px 0' }} />
 | 
				
			||||||
                <Row>
 | 
					                  <RolesMenu />
 | 
				
			||||||
                  <NewRole />
 | 
					                </CollectionProvider_deprecated>
 | 
				
			||||||
                </Row>
 | 
					              </ResourceActionProvider>
 | 
				
			||||||
                <Divider style={{ margin: '12px 0' }} />
 | 
					            </Col>
 | 
				
			||||||
                <RolesMenu />
 | 
					            <Col flex="auto" style={{ overflow: 'hidden' }}>
 | 
				
			||||||
              </CollectionProvider_deprecated>
 | 
					              <Tabs
 | 
				
			||||||
            </ResourceActionProvider>
 | 
					                activeKey={activeKey}
 | 
				
			||||||
          </Col>
 | 
					                onChange={(key) => setActiveKey(key)}
 | 
				
			||||||
          <Col flex="auto" style={{ overflow: 'hidden' }}>
 | 
					                items={[
 | 
				
			||||||
            <Tabs
 | 
					                  {
 | 
				
			||||||
              activeKey={activeKey}
 | 
					                    key: 'permissions',
 | 
				
			||||||
              onChange={(key) => setActiveKey(key)}
 | 
					                    label: t('Permissions'),
 | 
				
			||||||
              items={[
 | 
					                    children: <Permissions active={activeKey === 'permissions'} />,
 | 
				
			||||||
                {
 | 
					                  },
 | 
				
			||||||
                  key: 'permissions',
 | 
					                  ...tabs,
 | 
				
			||||||
                  label: t('Permissions'),
 | 
					                ]}
 | 
				
			||||||
                  children: <Permissions active={activeKey === 'permissions'} />,
 | 
					              />
 | 
				
			||||||
                },
 | 
					            </Col>
 | 
				
			||||||
                ...tabs,
 | 
					          </Row>
 | 
				
			||||||
              ]}
 | 
					        </Card>
 | 
				
			||||||
            />
 | 
					      </RolesManagerContext.Provider>
 | 
				
			||||||
          </Col>
 | 
					    </SchemaComponentContext.Provider>
 | 
				
			||||||
        </Row>
 | 
					 | 
				
			||||||
      </Card>
 | 
					 | 
				
			||||||
    </RolesManagerContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -5,55 +5,98 @@ import {
 | 
				
			|||||||
  useAPIClient,
 | 
					  useAPIClient,
 | 
				
			||||||
  useResourceActionContext,
 | 
					  useResourceActionContext,
 | 
				
			||||||
} from '@nocobase/client';
 | 
					} from '@nocobase/client';
 | 
				
			||||||
import { Menu, Empty, Dropdown, App, Tag, Row, Col } from 'antd';
 | 
					import { Menu, Empty, Dropdown, App, Tag, Row, Col, Spin } from 'antd';
 | 
				
			||||||
import { TagOutlined, MoreOutlined } from '@ant-design/icons';
 | 
					import { TagOutlined, MoreOutlined } from '@ant-design/icons';
 | 
				
			||||||
import React, { useContext, useEffect } from 'react';
 | 
					import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
 | 
				
			||||||
import { useACLTranslation } from './locale';
 | 
					import { useACLTranslation } from './locale';
 | 
				
			||||||
import { Schema } from '@formily/react';
 | 
					import { Schema } from '@formily/react';
 | 
				
			||||||
import { RolesManagerContext } from './RolesManagerProvider';
 | 
					import { RolesManagerContext } from './RolesManagerProvider';
 | 
				
			||||||
import { roleEditSchema } from './schemas/roles';
 | 
					import { roleEditSchema } from './schemas/roles';
 | 
				
			||||||
 | 
					import { useLoadMoreObserver } from './hooks/load-more-observer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const RolesMenu: React.FC & {
 | 
					export const RolesMenu: React.FC & {
 | 
				
			||||||
  Item: React.FC<{ item: any; onEdit: () => void }>;
 | 
					  Item: React.FC<{ item: any; onEdit: () => void }>;
 | 
				
			||||||
} = () => {
 | 
					} = () => {
 | 
				
			||||||
  const { t } = useACLTranslation();
 | 
					  const { t } = useACLTranslation();
 | 
				
			||||||
  const { data } = useResourceActionContext();
 | 
					  const { data, run, loading } = useResourceActionContext();
 | 
				
			||||||
  const [visible, setVisible] = React.useState(false);
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
  const [record, setRecord] = React.useState(null);
 | 
					  const [record, setRecord] = useState(null);
 | 
				
			||||||
  const { role, setRole } = useContext(RolesManagerContext);
 | 
					  const { role, setRole } = useContext(RolesManagerContext);
 | 
				
			||||||
  const items = (data?.data || []).map((item: any) => ({
 | 
					  const [roles, setRoles] = useState([]);
 | 
				
			||||||
    key: item.name,
 | 
					
 | 
				
			||||||
    label: (
 | 
					  const loadMore = useCallback(() => {
 | 
				
			||||||
      <RolesMenu.Item
 | 
					    const meta = data?.meta;
 | 
				
			||||||
        item={item}
 | 
					    if (!meta || meta.page >= meta.totalPage) {
 | 
				
			||||||
        onEdit={() => {
 | 
					      return;
 | 
				
			||||||
          setVisible(true);
 | 
					    }
 | 
				
			||||||
          setRecord(item);
 | 
					    run({
 | 
				
			||||||
        }}
 | 
					      page: meta.page + 1,
 | 
				
			||||||
      />
 | 
					    });
 | 
				
			||||||
    ),
 | 
					  }, [data]);
 | 
				
			||||||
  }));
 | 
					  const { lastItem, setLastItem } = useLoadMoreObserver({ loadMore });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSelect = ({ key }) => {
 | 
					  const handleSelect = ({ key }) => {
 | 
				
			||||||
    setRole((data?.data || []).find((item: any) => item.name === key));
 | 
					    setRole(roles.find((item: any) => item.name === key));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (!data?.data.length) {
 | 
					    if (!roles[0]) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    setRole(data?.data[0]);
 | 
					    setRole(roles[0]);
 | 
				
			||||||
  }, [data, setRole]);
 | 
					  }, [roles, setRole]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!data?.data?.length) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ref = React.createRef<any>();
 | 
				
			||||||
 | 
					    setLastItem(ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setRoles((prev) => prev.concat(data.data));
 | 
				
			||||||
 | 
					  }, [data, setLastItem]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const items = useMemo(
 | 
				
			||||||
 | 
					    () =>
 | 
				
			||||||
 | 
					      roles.map((item: any, index: number) => ({
 | 
				
			||||||
 | 
					        key: item.name,
 | 
				
			||||||
 | 
					        label:
 | 
				
			||||||
 | 
					          index === roles.length - 1 ? (
 | 
				
			||||||
 | 
					            <div ref={lastItem}>
 | 
				
			||||||
 | 
					              <RolesMenu.Item
 | 
				
			||||||
 | 
					                item={item}
 | 
				
			||||||
 | 
					                onEdit={() => {
 | 
				
			||||||
 | 
					                  setVisible(true);
 | 
				
			||||||
 | 
					                  setRecord(item);
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <RolesMenu.Item
 | 
				
			||||||
 | 
					              item={item}
 | 
				
			||||||
 | 
					              onEdit={() => {
 | 
				
			||||||
 | 
					                setVisible(true);
 | 
				
			||||||
 | 
					                setRecord(item);
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					      })),
 | 
				
			||||||
 | 
					    [roles, lastItem],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {items.length ? (
 | 
					      {roles.length ? (
 | 
				
			||||||
        <Menu
 | 
					        <>
 | 
				
			||||||
          style={{ border: 'none', maxHeight: '65vh', overflowY: 'auto' }}
 | 
					          <Menu
 | 
				
			||||||
          items={items}
 | 
					            style={{ border: 'none', maxHeight: '65vh', overflowY: 'auto' }}
 | 
				
			||||||
          selectedKeys={[role?.name]}
 | 
					            items={items}
 | 
				
			||||||
          onSelect={handleSelect}
 | 
					            selectedKeys={[role?.name]}
 | 
				
			||||||
        />
 | 
					            onSelect={handleSelect}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          {loading && <Spin />}
 | 
				
			||||||
 | 
					        </>
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
        <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
 | 
					        <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
@ -92,12 +135,15 @@ RolesMenu.Item = function DepartmentTreeItem({ item, onEdit }) {
 | 
				
			|||||||
        deleteDepartment();
 | 
					        deleteDepartment();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  const title = Schema.compile(item.title, { t });
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Row>
 | 
					    <Row>
 | 
				
			||||||
      <Col flex={3} style={{ display: 'inline-flex', alignItems: 'center' }}>
 | 
					      <Col flex={3} style={{ display: 'inline-flex', alignItems: 'center' }}>
 | 
				
			||||||
        <span style={{ whiteSpace: 'nowrap', width: '120px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
 | 
					        <span style={{ whiteSpace: 'nowrap', width: '120px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
 | 
				
			||||||
          <TagOutlined />
 | 
					          <TagOutlined />
 | 
				
			||||||
          <span style={{ marginLeft: '10px' }}>{Schema.compile(item.title, { t })}</span>
 | 
					          <span style={{ marginLeft: '10px' }} title={title}>
 | 
				
			||||||
 | 
					            {title}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </Col>
 | 
					      </Col>
 | 
				
			||||||
      <Col>
 | 
					      <Col>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import React, { useCallback, useEffect, useRef, useState } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useLoadMoreObserver = ({
 | 
				
			||||||
 | 
					  loadMore,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  loadMore: () => void; // callback
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [lastItem, setLastItem] = useState<React.RefObject<any>>(null);
 | 
				
			||||||
 | 
					  const observer = useRef<IntersectionObserver | null>(null);
 | 
				
			||||||
 | 
					  const observeExposure = useCallback(
 | 
				
			||||||
 | 
					    (lastItem: React.RefObject<any>) => {
 | 
				
			||||||
 | 
					      if (!lastItem) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      observer.current && observer.current.disconnect();
 | 
				
			||||||
 | 
					      observer.current = new IntersectionObserver((entries) => {
 | 
				
			||||||
 | 
					        entries.forEach((entry) => {
 | 
				
			||||||
 | 
					          if (entry.target !== lastItem.current) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (entry.isIntersecting) {
 | 
				
			||||||
 | 
					            observer.current && observer.current.unobserve(lastItem.current);
 | 
				
			||||||
 | 
					            loadMore();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      lastItem.current && observer.current && observer.current.observe(lastItem.current);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    [loadMore],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    observeExposure(lastItem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      observer.current && observer.current.disconnect();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, [lastItem, observeExposure]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    lastItem,
 | 
				
			||||||
 | 
					    setLastItem,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -398,11 +398,12 @@ export class PluginACL extends Plugin {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // sync database role data to acl
 | 
					    // sync database role data to acl
 | 
				
			||||||
    this.app.on('afterLoad', async () => {
 | 
					    this.app.on('afterStart', async () => {
 | 
				
			||||||
      await writeRolesToACL(this.app, {
 | 
					      await writeRolesToACL(this.app, {
 | 
				
			||||||
        withOutResources: true,
 | 
					        withOutResources: true,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // this.app.on('afterInstall', writeRolesToACL);
 | 
					    // this.app.on('afterInstall', writeRolesToACL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.app.on('afterInstallPlugin', async (plugin) => {
 | 
					    this.app.on('afterInstallPlugin', async (plugin) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-action-bulk-edit",
 | 
					  "name": "@nocobase/plugin-action-bulk-edit",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-bulk-edit",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-bulk-edit",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-action-bulk-update",
 | 
					  "name": "@nocobase/plugin-action-bulk-update",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-action-duplicate",
 | 
					  "name": "@nocobase/plugin-action-duplicate",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-duplicate",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-duplicate",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-action-print",
 | 
					  "name": "@nocobase/plugin-action-print",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-print",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-print",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-api-doc",
 | 
					  "name": "@nocobase/plugin-api-doc",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "API documentation",
 | 
					  "displayName": "API documentation",
 | 
				
			||||||
  "displayName.zh-CN": "API 文档",
 | 
					  "displayName.zh-CN": "API 文档",
 | 
				
			||||||
  "description": "An OpenAPI documentation generator for NocoBase HTTP API.",
 | 
					  "description": "An OpenAPI documentation generator for NocoBase HTTP API.",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "认证:API 密钥",
 | 
					  "displayName.zh-CN": "认证:API 密钥",
 | 
				
			||||||
  "description": "Allows users to use API key to access application's HTTP API",
 | 
					  "description": "Allows users to use API key to access application's HTTP API",
 | 
				
			||||||
  "description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
 | 
					  "description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/api-keys",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/api-keys",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-audit-logs",
 | 
					  "name": "@nocobase/plugin-audit-logs",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "Audit logs (deprecated)",
 | 
					  "displayName": "Audit logs (deprecated)",
 | 
				
			||||||
  "displayName.zh-CN": "审计日志(废弃)",
 | 
					  "displayName.zh-CN": "审计日志(废弃)",
 | 
				
			||||||
  "description": "This plugin is deprecated. There will be a new audit log plugin in the future.",
 | 
					  "description": "This plugin is deprecated. There will be a new audit log plugin in the future.",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-auth",
 | 
					  "name": "@nocobase/plugin-auth",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/auth",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/auth",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "应用的备份与还原",
 | 
					  "displayName.zh-CN": "应用的备份与还原",
 | 
				
			||||||
  "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
 | 
					  "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
 | 
				
			||||||
  "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
 | 
					  "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/backup-restore",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/backup-restore",
 | 
				
			||||||
 | 
				
			|||||||
@ -85,6 +85,43 @@ describe('dumper', () => {
 | 
				
			|||||||
    expect(items.length).toBe(1);
 | 
					    expect(items.length).toBe(1);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should dump and restore uuid field', async () => {
 | 
				
			||||||
 | 
					    await db.getRepository('collections').create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        name: 'tests',
 | 
				
			||||||
 | 
					        fields: [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            type: 'uuid',
 | 
				
			||||||
 | 
					            name: 'uuid_test',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      context: {},
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await db.getRepository('tests').create({
 | 
				
			||||||
 | 
					      values: {},
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dumper = new Dumper(app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const result = await dumper.dump({
 | 
				
			||||||
 | 
					      groups: new Set(['required', 'custom']),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const restorer = new Restorer(app, {
 | 
				
			||||||
 | 
					      backUpFilePath: result.filePath,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await restorer.restore({
 | 
				
			||||||
 | 
					      groups: new Set(['required', 'custom']),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const testCollection = app.db.getCollection('tests');
 | 
				
			||||||
 | 
					    const items = await testCollection.repository.find();
 | 
				
			||||||
 | 
					    expect(items.length).toBe(1);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('id seq', () => {
 | 
					  describe('id seq', () => {
 | 
				
			||||||
    let allGroups;
 | 
					    let allGroups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -412,12 +412,18 @@ export class Dumper extends AppMigrator {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (collectionField) {
 | 
					      if (collectionField) {
 | 
				
			||||||
        // is a field
 | 
					        // is a field
 | 
				
			||||||
        return {
 | 
					        const fieldAttributes: any = {
 | 
				
			||||||
          field: attr.field,
 | 
					          field: attr.field,
 | 
				
			||||||
          isCollectionField: true,
 | 
					          isCollectionField: true,
 | 
				
			||||||
          type: collectionField.type,
 | 
					          type: collectionField.type,
 | 
				
			||||||
          typeOptions: collectionField.options,
 | 
					          typeOptions: collectionField.options,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fieldAttributes.typeOptions?.defaultValue?.constructor?.name === 'UUIDV4') {
 | 
				
			||||||
 | 
					          delete fieldAttributes.typeOptions.defaultValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return fieldAttributes;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-calendar",
 | 
					  "name": "@nocobase/plugin-calendar",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "Calendar",
 | 
					  "displayName": "Calendar",
 | 
				
			||||||
  "displayName.zh-CN": "日历",
 | 
					  "displayName.zh-CN": "日历",
 | 
				
			||||||
  "description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.",
 | 
					  "description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "认证:CAS",
 | 
					  "displayName.zh-CN": "认证:CAS",
 | 
				
			||||||
  "description": "CAS authentication.",
 | 
					  "description": "CAS authentication.",
 | 
				
			||||||
  "description.zh-CN": "通过 CAS 协议认证身份。",
 | 
					  "description.zh-CN": "通过 CAS 协议认证身份。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/auth-cas",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/auth-cas",
 | 
				
			||||||
 | 
				
			|||||||
@ -3,20 +3,25 @@ import { AppSupervisor } from '@nocobase/server';
 | 
				
			|||||||
import { CASAuth } from '../auth';
 | 
					import { CASAuth } from '../auth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const service = async (ctx: Context, next: Next) => {
 | 
					export const service = async (ctx: Context, next: Next) => {
 | 
				
			||||||
  const { authenticator, __appName: appName, redirect = '/admin' } = ctx.action.params;
 | 
					  const { authenticator, __appName: appName, redirect } = ctx.action.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let prefix = '';
 | 
					  let prefix = process.env.APP_PUBLIC_PATH || '';
 | 
				
			||||||
  if (appName && appName !== 'main') {
 | 
					  if (appName && appName !== 'main') {
 | 
				
			||||||
    const appSupervisor = AppSupervisor.getInstance();
 | 
					    const appSupervisor = AppSupervisor.getInstance();
 | 
				
			||||||
    if (appSupervisor?.runningMode !== 'single') {
 | 
					    if (appSupervisor?.runningMode !== 'single') {
 | 
				
			||||||
      prefix = process.env.APP_PUBLIC_PATH + `apps/${appName}`;
 | 
					      prefix += `apps/${appName}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auth = (await ctx.app.authManager.get(authenticator, ctx)) as CASAuth;
 | 
					  const auth = (await ctx.app.authManager.get(authenticator, ctx)) as CASAuth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (prefix.endsWith('/')) {
 | 
				
			||||||
 | 
					    prefix = prefix.slice(0, -1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const { token } = await auth.signIn();
 | 
					    const { token } = await auth.signIn();
 | 
				
			||||||
    ctx.redirect(`${prefix}${redirect}?authenticator=${authenticator}&token=${token}`);
 | 
					    ctx.redirect(`${prefix}${redirect || '/admin'}?authenticator=${authenticator}&token=${token}`);
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    ctx.redirect(`${prefix}/signin?authenticator=${authenticator}&error=${error.message}&redirect=${redirect}`);
 | 
					    ctx.redirect(`${prefix}/signin?authenticator=${authenticator}&error=${error.message}&redirect=${redirect}`);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "图表(废弃)",
 | 
					  "displayName.zh-CN": "图表(废弃)",
 | 
				
			||||||
  "description": "The plugin has been deprecated, please use the data visualization plugin instead.",
 | 
					  "description": "The plugin has been deprecated, please use the data visualization plugin instead.",
 | 
				
			||||||
  "description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
 | 
					  "description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-china-region",
 | 
					  "name": "@nocobase/plugin-china-region",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "Administrative divisions of China",
 | 
					  "displayName": "Administrative divisions of China",
 | 
				
			||||||
  "displayName.zh-CN": "中国行政区划",
 | 
					  "displayName.zh-CN": "中国行政区划",
 | 
				
			||||||
  "description": "Provides data and field type for administrative divisions of China.",
 | 
					  "description": "Provides data and field type for administrative divisions of China.",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "WEB 客户端",
 | 
					  "displayName.zh-CN": "WEB 客户端",
 | 
				
			||||||
  "description": "Provides a client interface for the NocoBase server",
 | 
					  "description": "Provides a client interface for the NocoBase server",
 | 
				
			||||||
  "description.zh-CN": "为 NocoBase 服务端提供客户端界面",
 | 
					  "description.zh-CN": "为 NocoBase 服务端提供客户端界面",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "数据源:主数据库",
 | 
					  "displayName.zh-CN": "数据源:主数据库",
 | 
				
			||||||
  "description": "NocoBase main database, supports relational databases such as MySQL, PostgreSQL, SQLite and so on.",
 | 
					  "description": "NocoBase main database, supports relational databases such as MySQL, PostgreSQL, SQLite and so on.",
 | 
				
			||||||
  "description.zh-CN": "NocoBase 主数据库,支持 MySQL、PostgreSQL、SQLite 等关系型数据库。",
 | 
					  "description.zh-CN": "NocoBase 主数据库,支持 MySQL、PostgreSQL、SQLite 等关系型数据库。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/data-source-main",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/data-source-main",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main",
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import Database, { Collection as DBCollection } from '@nocobase/database';
 | 
				
			||||||
 | 
					import Application from '@nocobase/server';
 | 
				
			||||||
 | 
					import { createApp } from '..';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('uuid', () => {
 | 
				
			||||||
 | 
					  let db: Database;
 | 
				
			||||||
 | 
					  let app: Application;
 | 
				
			||||||
 | 
					  let Collection: DBCollection;
 | 
				
			||||||
 | 
					  let Field: DBCollection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    app = await createApp();
 | 
				
			||||||
 | 
					    db = app.db;
 | 
				
			||||||
 | 
					    Collection = db.getCollection('collections');
 | 
				
			||||||
 | 
					    Field = db.getCollection('fields');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  afterEach(async () => {
 | 
				
			||||||
 | 
					    await app.destroy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create uuid field', async () => {
 | 
				
			||||||
 | 
					    await Collection.repository.create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        name: 'tests',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      context: {},
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await Field.repository.create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        collectionName: 'tests',
 | 
				
			||||||
 | 
					        type: 'uuid',
 | 
				
			||||||
 | 
					        name: 'uuid',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      context: {},
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @ts-ignore
 | 
				
			||||||
 | 
					    const resp = await app.agent().resource('tests').create({});
 | 
				
			||||||
 | 
					    expect(resp.status).toBe(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const data = resp.body.data;
 | 
				
			||||||
 | 
					    expect(data['uuid']).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-custom-request",
 | 
					  "name": "@nocobase/plugin-custom-request",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-custom-request",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-custom-request",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-data-source-manager",
 | 
					  "name": "@nocobase/plugin-data-source-manager",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "displayName": "Data source manager",
 | 
					  "displayName": "Data source manager",
 | 
				
			||||||
  "displayName.zh-CN": "数据源管理",
 | 
					  "displayName.zh-CN": "数据源管理",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-data-visualization",
 | 
					  "name": "@nocobase/plugin-data-visualization",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "Data visualization",
 | 
					  "displayName": "Data visualization",
 | 
				
			||||||
  "displayName.zh-CN": "数据可视化",
 | 
					  "displayName.zh-CN": "数据可视化",
 | 
				
			||||||
  "description": "Provides data visualization feature, including chart block and chart filter block, support line charts, area charts, bar charts and more than a dozen kinds of charts, you can also extend more chart types.",
 | 
					  "description": "Provides data visualization feature, including chart block and chart filter block, support line charts, area charts, bar charts and more than a dozen kinds of charts, you can also extend more chart types.",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-disable-pm-add",
 | 
					  "name": "@nocobase/plugin-disable-pm-add",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "peerDependencies": {
 | 
					  "peerDependencies": {
 | 
				
			||||||
    "@nocobase/client": "0.x",
 | 
					    "@nocobase/client": "0.x",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "错误处理器",
 | 
					  "displayName.zh-CN": "错误处理器",
 | 
				
			||||||
  "description": "Handling application errors and exceptions.",
 | 
					  "description": "Handling application errors and exceptions.",
 | 
				
			||||||
  "description.zh-CN": "处理应用程序中的错误和异常。",
 | 
					  "description.zh-CN": "处理应用程序中的错误和异常。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-excel-formula-field",
 | 
					  "name": "@nocobase/plugin-excel-formula-field",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "操作:导出记录",
 | 
					  "displayName.zh-CN": "操作:导出记录",
 | 
				
			||||||
  "description": "Export filtered records to excel, you can configure which fields to export.",
 | 
					  "description": "Export filtered records to excel, you can configure which fields to export.",
 | 
				
			||||||
  "description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
 | 
					  "description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-export",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-export",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-file-manager",
 | 
					  "name": "@nocobase/plugin-file-manager",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "File manager",
 | 
					  "displayName": "File manager",
 | 
				
			||||||
  "displayName.zh-CN": "文件管理器",
 | 
					  "displayName.zh-CN": "文件管理器",
 | 
				
			||||||
  "description": "Provides files storage services with files collection template and attachment field.",
 | 
					  "description": "Provides files storage services with files collection template and attachment field.",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,158 +1,6 @@
 | 
				
			|||||||
import { CollectionTemplate, getConfigurableProperties } from '@nocobase/client';
 | 
					import { CollectionTemplate, getConfigurableProperties } from '@nocobase/client';
 | 
				
			||||||
// import { CollectionOptions } from '@nocobase/database';
 | 
					 | 
				
			||||||
import { NAMESPACE } from '../locale';
 | 
					import { NAMESPACE } from '../locale';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// export const fileCollectionTemplate = {
 | 
					 | 
				
			||||||
//   name: 'file',
 | 
					 | 
				
			||||||
//   title: `{{t("File collection", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//   order: 3,
 | 
					 | 
				
			||||||
//   color: 'blue',
 | 
					 | 
				
			||||||
//   default: {
 | 
					 | 
				
			||||||
//     createdBy: true,
 | 
					 | 
				
			||||||
//     updatedBy: true,
 | 
					 | 
				
			||||||
//     fields: [
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'title',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("Title")}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input',
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // '系统文件名(含扩展名)',
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'filename',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("File name", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // '扩展名(含“.”)',
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'extname',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("Extension name", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // '文件体积(字节)',
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'integer',
 | 
					 | 
				
			||||||
//         type: 'integer',
 | 
					 | 
				
			||||||
//         name: 'size',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'number',
 | 
					 | 
				
			||||||
//           title: `{{t("Size", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'InputNumber',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//           'x-component-props': {
 | 
					 | 
				
			||||||
//             stringMode: true,
 | 
					 | 
				
			||||||
//             step: '0',
 | 
					 | 
				
			||||||
//           },
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'mimetype',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("MIME type", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // '相对路径(含“/”前缀)',
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'path',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("Path")}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // 文件的可访问地址
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'input',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'url',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("URL")}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Input.URL',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // 用于预览
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         interface: 'url',
 | 
					 | 
				
			||||||
//         type: 'string',
 | 
					 | 
				
			||||||
//         name: 'preview',
 | 
					 | 
				
			||||||
//         field: 'url', // 直接引用 url 字段
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         uiSchema: {
 | 
					 | 
				
			||||||
//           type: 'string',
 | 
					 | 
				
			||||||
//           title: `{{t("Preview")}}`,
 | 
					 | 
				
			||||||
//           'x-component': 'Preview',
 | 
					 | 
				
			||||||
//           'x-read-pretty': true,
 | 
					 | 
				
			||||||
//         },
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         comment: '存储引擎',
 | 
					 | 
				
			||||||
//         type: 'belongsTo',
 | 
					 | 
				
			||||||
//         name: 'storage',
 | 
					 | 
				
			||||||
//         target: 'storages',
 | 
					 | 
				
			||||||
//         foreignKey: 'storageId',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//       // '其他文件信息(如图片的宽高)',
 | 
					 | 
				
			||||||
//       {
 | 
					 | 
				
			||||||
//         type: 'jsonb',
 | 
					 | 
				
			||||||
//         name: 'meta',
 | 
					 | 
				
			||||||
//         deletable: false,
 | 
					 | 
				
			||||||
//         defaultValue: {},
 | 
					 | 
				
			||||||
//       },
 | 
					 | 
				
			||||||
//     ],
 | 
					 | 
				
			||||||
//   },
 | 
					 | 
				
			||||||
//   configurableProperties: {
 | 
					 | 
				
			||||||
//     ...getConfigurableProperties('title', 'name'),
 | 
					 | 
				
			||||||
//     inherits: {
 | 
					 | 
				
			||||||
//       ...getConfigurableProperties('inherits').inherits,
 | 
					 | 
				
			||||||
//       'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'],
 | 
					 | 
				
			||||||
//     },
 | 
					 | 
				
			||||||
//     ...getConfigurableProperties('category', 'description'),
 | 
					 | 
				
			||||||
//     storage: {
 | 
					 | 
				
			||||||
//       title: `{{t("File storage", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
//       type: 'hasOne',
 | 
					 | 
				
			||||||
//       name: 'storage',
 | 
					 | 
				
			||||||
//       required: true,
 | 
					 | 
				
			||||||
//       'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
//       'x-component': 'Select',
 | 
					 | 
				
			||||||
//       'x-reactions': ['{{useAsyncDataSource(loadStorages)}}'],
 | 
					 | 
				
			||||||
//     },
 | 
					 | 
				
			||||||
//   },
 | 
					 | 
				
			||||||
// } as CollectionOptions;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class FileCollectionTemplate extends CollectionTemplate {
 | 
					export class FileCollectionTemplate extends CollectionTemplate {
 | 
				
			||||||
  name = 'file';
 | 
					  name = 'file';
 | 
				
			||||||
  title = `{{t("File collection", { ns: "${NAMESPACE}" })}}`;
 | 
					  title = `{{t("File collection", { ns: "${NAMESPACE}" })}}`;
 | 
				
			||||||
@ -236,7 +84,7 @@ export class FileCollectionTemplate extends CollectionTemplate {
 | 
				
			|||||||
        deletable: false,
 | 
					        deletable: false,
 | 
				
			||||||
        uiSchema: {
 | 
					        uiSchema: {
 | 
				
			||||||
          type: 'string',
 | 
					          type: 'string',
 | 
				
			||||||
          title: `{{t("Path")}}`,
 | 
					          title: `{{t("Path", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
          'x-component': 'Input',
 | 
					          'x-component': 'Input',
 | 
				
			||||||
          'x-read-pretty': true,
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -263,7 +111,7 @@ export class FileCollectionTemplate extends CollectionTemplate {
 | 
				
			|||||||
        deletable: false,
 | 
					        deletable: false,
 | 
				
			||||||
        uiSchema: {
 | 
					        uiSchema: {
 | 
				
			||||||
          type: 'string',
 | 
					          type: 'string',
 | 
				
			||||||
          title: `{{t("Preview")}}`,
 | 
					          title: `{{t("Preview", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
          'x-component': 'Preview',
 | 
					          'x-component': 'Preview',
 | 
				
			||||||
          'x-read-pretty': true,
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -275,6 +123,12 @@ export class FileCollectionTemplate extends CollectionTemplate {
 | 
				
			|||||||
        target: 'storages',
 | 
					        target: 'storages',
 | 
				
			||||||
        foreignKey: 'storageId',
 | 
					        foreignKey: 'storageId',
 | 
				
			||||||
        deletable: false,
 | 
					        deletable: false,
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          title: `{{t("Storage", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
 | 
					          'x-component': 'Input',
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      // '其他文件信息(如图片的宽高)',
 | 
					      // '其他文件信息(如图片的宽高)',
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "数据表字段:公式",
 | 
					  "displayName.zh-CN": "数据表字段:公式",
 | 
				
			||||||
  "description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.",
 | 
					  "description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.",
 | 
				
			||||||
  "description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎",
 | 
					  "description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/field-formula",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/field-formula",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-gantt",
 | 
					  "name": "@nocobase/plugin-gantt",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "displayName": "Block: Gantt",
 | 
					  "displayName": "Block: Gantt",
 | 
				
			||||||
  "displayName.zh-CN": "区块:甘特图",
 | 
					  "displayName.zh-CN": "区块:甘特图",
 | 
				
			||||||
  "description": "Provides Gantt block.",
 | 
					  "description": "Provides Gantt block.",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "可视化数据表管理",
 | 
					  "displayName.zh-CN": "可视化数据表管理",
 | 
				
			||||||
  "description": "An ER diagram-like tool. Currently only the Master database is supported.",
 | 
					  "description": "An ER diagram-like tool. Currently only the Master database is supported.",
 | 
				
			||||||
  "description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。",
 | 
					  "description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/graph-collection-manager",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/graph-collection-manager",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "区块:iframe",
 | 
					  "displayName.zh-CN": "区块:iframe",
 | 
				
			||||||
  "description": "Create an iframe block on the page to embed and display external web pages or content.",
 | 
					  "description": "Create an iframe block on the page to embed and display external web pages or content.",
 | 
				
			||||||
  "description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。",
 | 
					  "description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/block-iframe",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/block-iframe",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "操作:导入记录",
 | 
					  "displayName.zh-CN": "操作:导入记录",
 | 
				
			||||||
  "description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
 | 
					  "description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
 | 
				
			||||||
  "description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
 | 
					  "description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/action-import",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/action-import",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-kanban",
 | 
					  "name": "@nocobase/plugin-kanban",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/block-kanban",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/block-kanban",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-localization-management",
 | 
					  "name": "@nocobase/plugin-localization-management",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/localization-management",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/localization-management",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "日志",
 | 
					  "displayName.zh-CN": "日志",
 | 
				
			||||||
  "description": "Server-side logs, mainly including API request logs and system runtime logs, and allows to package and download log files.",
 | 
					  "description": "Server-side logs, mainly including API request logs and system runtime logs, and allows to package and download log files.",
 | 
				
			||||||
  "description.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。",
 | 
					  "description.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "dist/server/index.js",
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/logger",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/logger",
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
  "name": "@nocobase/plugin-map",
 | 
					  "name": "@nocobase/plugin-map",
 | 
				
			||||||
  "displayName": "Block: Map",
 | 
					  "displayName": "Block: Map",
 | 
				
			||||||
  "displayName.zh-CN": "区块:地图",
 | 
					  "displayName.zh-CN": "区块:地图",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "description": "Map block, support Gaode map and Google map, you can also extend more map types.",
 | 
					  "description": "Map block, support Gaode map and Google map, you can also extend more map types.",
 | 
				
			||||||
  "description.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。",
 | 
					  "description.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "数学公式字段",
 | 
					  "displayName.zh-CN": "数学公式字段",
 | 
				
			||||||
  "description": "A powerful mathematical formula field plugin designed to provide flexible mathematical and formula calculation capabilities for databases or data management systems. It seamlessly integrates with various database systems such as MySQL, PostgreSQL, and offers an intuitive user interface for defining and executing mathematical formula fields.",
 | 
					  "description": "A powerful mathematical formula field plugin designed to provide flexible mathematical and formula calculation capabilities for databases or data management systems. It seamlessly integrates with various database systems such as MySQL, PostgreSQL, and offers an intuitive user interface for defining and executing mathematical formula fields.",
 | 
				
			||||||
  "description.zh-CN": "一个功能强大的数学公式字段插件,旨在为数据库或数据管理系统提供灵活的数学计算和公式计算功能。它可以与各种数据库系统(如MySQL、PostgreSQL)无缝集成,并提供直观的用户界面来定义和执行数学公式字段。",
 | 
					  "description.zh-CN": "一个功能强大的数学公式字段插件,旨在为数据库或数据管理系统提供灵活的数学计算和公式计算功能。它可以与各种数据库系统(如MySQL、PostgreSQL)无缝集成,并提供直观的用户界面来定义和执行数学公式字段。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@nocobase/plugin-mobile-client",
 | 
					  "name": "@nocobase/plugin-mobile-client",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/mobile-client",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/mobile-client",
 | 
				
			||||||
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client",
 | 
					  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client",
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
  "name": "@nocobase/plugin-mock-collections",
 | 
					  "name": "@nocobase/plugin-mock-collections",
 | 
				
			||||||
  "displayName": "mock-collections",
 | 
					  "displayName": "mock-collections",
 | 
				
			||||||
  "description": "mock-collections",
 | 
					  "description": "mock-collections",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "peerDependencies": {
 | 
					  "peerDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "多应用管理器",
 | 
					  "displayName.zh-CN": "多应用管理器",
 | 
				
			||||||
  "description": "Dynamically create multiple apps without separate deployments.",
 | 
					  "description": "Dynamically create multiple apps without separate deployments.",
 | 
				
			||||||
  "description.zh-CN": "无需单独部署即可动态创建多个应用。",
 | 
					  "description.zh-CN": "无需单独部署即可动态创建多个应用。",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "license": "AGPL-3.0",
 | 
					  "license": "AGPL-3.0",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "homepage": "https://docs.nocobase.com/handbook/multi-app-manager",
 | 
					  "homepage": "https://docs.nocobase.com/handbook/multi-app-manager",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { Database } from '@nocobase/database';
 | 
					import { Database } from '@nocobase/database';
 | 
				
			||||||
import { AppSupervisor, Gateway } from '@nocobase/server';
 | 
					import { AppSupervisor, Gateway } from '@nocobase/server';
 | 
				
			||||||
import { MockServer, createMockServer } from '@nocobase/test';
 | 
					import { createMockServer, MockServer } from '@nocobase/test';
 | 
				
			||||||
import { uid } from '@nocobase/utils';
 | 
					import { uid } from '@nocobase/utils';
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
import { PluginMultiAppManager } from '../server';
 | 
					import { PluginMultiAppManager } from '../server';
 | 
				
			||||||
@ -22,6 +22,29 @@ describe('multiple apps', () => {
 | 
				
			|||||||
    await app.destroy();
 | 
					    await app.destroy();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should merge database options', async () => {
 | 
				
			||||||
 | 
					    const name = `td_${uid()}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await db.getRepository('applications').create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        name,
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					          plugins: [],
 | 
				
			||||||
 | 
					          database: {
 | 
				
			||||||
 | 
					            underscored: true,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      context: {
 | 
				
			||||||
 | 
					        waitSubAppInstall: true,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const subApp = await AppSupervisor.getInstance().getApp(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(subApp.db.options.underscored).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should register db creator', async () => {
 | 
					  it('should register db creator', async () => {
 | 
				
			||||||
    const fn = vi.fn();
 | 
					    const fn = vi.fn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { Model, Transactionable } from '@nocobase/database';
 | 
					import { Model, Transactionable } from '@nocobase/database';
 | 
				
			||||||
import { Application } from '@nocobase/server';
 | 
					import { Application } from '@nocobase/server';
 | 
				
			||||||
import { AppOptionsFactory } from '../server';
 | 
					import { AppOptionsFactory } from '../server';
 | 
				
			||||||
 | 
					import { merge } from '@nocobase/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface registerAppOptions extends Transactionable {
 | 
					export interface registerAppOptions extends Transactionable {
 | 
				
			||||||
  skipInstall?: boolean;
 | 
					  skipInstall?: boolean;
 | 
				
			||||||
@ -10,11 +11,12 @@ export interface registerAppOptions extends Transactionable {
 | 
				
			|||||||
export class ApplicationModel extends Model {
 | 
					export class ApplicationModel extends Model {
 | 
				
			||||||
  registerToSupervisor(mainApp: Application, options: registerAppOptions) {
 | 
					  registerToSupervisor(mainApp: Application, options: registerAppOptions) {
 | 
				
			||||||
    const appName = this.get('name') as string;
 | 
					    const appName = this.get('name') as string;
 | 
				
			||||||
    const appOptions = (this.get('options') as any) || {};
 | 
					    const appModelOptions = (this.get('options') as any) || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const appOptions = options.appOptionsFactory(appName, mainApp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const subAppOptions = {
 | 
					    const subAppOptions = {
 | 
				
			||||||
      ...options.appOptionsFactory(appName, mainApp),
 | 
					      ...(merge(appOptions, appModelOptions) as object),
 | 
				
			||||||
      ...appOptions,
 | 
					 | 
				
			||||||
      name: appName,
 | 
					      name: appName,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import { Database, IDatabaseOptions, Transactionable } from '@nocobase/database';
 | 
					import { Database, IDatabaseOptions, Transactionable } from '@nocobase/database';
 | 
				
			||||||
import Application, { AppSupervisor, Gateway, Plugin } from '@nocobase/server';
 | 
					import Application, { AppSupervisor, Gateway, Plugin } from '@nocobase/server';
 | 
				
			||||||
import { Mutex } from 'async-mutex';
 | 
					 | 
				
			||||||
import lodash from 'lodash';
 | 
					import lodash from 'lodash';
 | 
				
			||||||
import path from 'path';
 | 
					import path from 'path';
 | 
				
			||||||
import { ApplicationModel } from '../server';
 | 
					import { ApplicationModel } from '../server';
 | 
				
			||||||
@ -125,8 +124,6 @@ export class PluginMultiAppManager extends Plugin {
 | 
				
			|||||||
  appOptionsFactory: AppOptionsFactory = defaultAppOptionsFactory;
 | 
					  appOptionsFactory: AppOptionsFactory = defaultAppOptionsFactory;
 | 
				
			||||||
  subAppUpgradeHandler: SubAppUpgradeHandler = defaultSubAppUpgradeHandle;
 | 
					  subAppUpgradeHandler: SubAppUpgradeHandler = defaultSubAppUpgradeHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private beforeGetApplicationMutex = new Mutex();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static getDatabaseConfig(app: Application): IDatabaseOptions {
 | 
					  static getDatabaseConfig(app: Application): IDatabaseOptions {
 | 
				
			||||||
    let oldConfig =
 | 
					    let oldConfig =
 | 
				
			||||||
      app.options.database instanceof Database
 | 
					      app.options.database instanceof Database
 | 
				
			||||||
@ -136,6 +133,7 @@ export class PluginMultiAppManager extends Plugin {
 | 
				
			|||||||
    if (!oldConfig && app.db) {
 | 
					    if (!oldConfig && app.db) {
 | 
				
			||||||
      oldConfig = app.db.options;
 | 
					      oldConfig = app.db.options;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return lodash.cloneDeep(lodash.omit(oldConfig, ['migrator']));
 | 
					    return lodash.cloneDeep(lodash.omit(oldConfig, ['migrator']));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  "displayName.zh-CN": "多应用数据表共享",
 | 
					  "displayName.zh-CN": "多应用数据表共享",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "description.zh-CN": "",
 | 
					  "description.zh-CN": "",
 | 
				
			||||||
  "version": "0.20.0-alpha.14",
 | 
					  "version": "0.20.0-alpha.15",
 | 
				
			||||||
  "main": "./dist/server/index.js",
 | 
					  "main": "./dist/server/index.js",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@formily/react": "2.x",
 | 
					    "@formily/react": "2.x",
 | 
				
			||||||
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user