diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index f558f3661..7b2f8f343 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -43,18 +43,11 @@ jobs: ref: ${{ inputs.branch }} path: packages/pro-plugins ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }} - # - name: Set variables - # run: | - # target_directory="./packages/pro-plugins/@nocobase" - # subdirectories=$(find "$target_directory" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | tr '\n' ' ') - # trimmed_variable=$(echo "$subdirectories" | xargs) - # 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: Set variables + run: | + APPEND_PRESET_LOCAL_PLUGINS=$(find ./packages/pro-plugins/@nocobase -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed 's/^plugin-//' | tr '\n' ',' | sed 's/,$//') + echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT + id: vars - name: Use Node.js ${{ matrix.node_version }} uses: actions/setup-node@v3 with: @@ -89,5 +82,5 @@ jobs: DB_USER: nocobase DB_PASSWORD: password 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 309e25b1b..c64f0e54b 100644 --- a/CHANGELOG.md +++ b/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). +## [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 ### Merged diff --git a/lerna.json b/lerna.json index b1ec16cb3..4ca9037b5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "npmClient": "yarn", "useWorkspaces": true, "npmClientArgs": ["--ignore-engines"], diff --git a/packages/core/acl/package.json b/packages/core/acl/package.json index 53302600c..af0c06900 100644 --- a/packages/core/acl/package.json +++ b/packages/core/acl/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/acl", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/resourcer": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/resourcer": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "minimatch": "^5.1.1" }, "repository": { diff --git a/packages/core/actions/package.json b/packages/core/actions/package.json index 860c86720..a876128c8 100644 --- a/packages/core/actions/package.json +++ b/packages/core/actions/package.json @@ -1,14 +1,14 @@ { "name": "@nocobase/actions", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/cache": "0.20.0-alpha.14", - "@nocobase/database": "0.20.0-alpha.14", - "@nocobase/resourcer": "0.20.0-alpha.14" + "@nocobase/cache": "0.20.0-alpha.15", + "@nocobase/database": "0.20.0-alpha.15", + "@nocobase/resourcer": "0.20.0-alpha.15" }, "repository": { "type": "git", diff --git a/packages/core/app/package.json b/packages/core/app/package.json index cb51d718f..9398b62d7 100644 --- a/packages/core/app/package.json +++ b/packages/core/app/package.json @@ -1,17 +1,17 @@ { "name": "@nocobase/app", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "AGPL-3.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/database": "0.20.0-alpha.14", - "@nocobase/preset-nocobase": "0.20.0-alpha.14", - "@nocobase/server": "0.20.0-alpha.14" + "@nocobase/database": "0.20.0-alpha.15", + "@nocobase/preset-nocobase": "0.20.0-alpha.15", + "@nocobase/server": "0.20.0-alpha.15" }, "devDependencies": { - "@nocobase/client": "0.20.0-alpha.14" + "@nocobase/client": "0.20.0-alpha.15" }, "repository": { "type": "git", diff --git a/packages/core/auth/package.json b/packages/core/auth/package.json index 503af6b7c..7c648dd8b 100644 --- a/packages/core/auth/package.json +++ b/packages/core/auth/package.json @@ -1,16 +1,16 @@ { "name": "@nocobase/auth", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/actions": "0.20.0-alpha.14", - "@nocobase/cache": "0.20.0-alpha.14", - "@nocobase/database": "0.20.0-alpha.14", - "@nocobase/resourcer": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/actions": "0.20.0-alpha.15", + "@nocobase/cache": "0.20.0-alpha.15", + "@nocobase/database": "0.20.0-alpha.15", + "@nocobase/resourcer": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "@types/jsonwebtoken": "^8.5.8", "jsonwebtoken": "^8.5.1" }, diff --git a/packages/core/build/package.json b/packages/core/build/package.json index d4f0634a8..abb456deb 100755 --- a/packages/core/build/package.json +++ b/packages/core/build/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/build", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "Library build tool based on rollup.", "main": "lib/index.js", "types": "./lib/index.d.ts", diff --git a/packages/core/cache/package.json b/packages/core/cache/package.json index a49d73ffa..6d4f3c297 100644 --- a/packages/core/cache/package.json +++ b/packages/core/cache/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/cache", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", diff --git a/packages/core/cli/package.json b/packages/core/cli/package.json index 9b441e4ed..3051fcdb6 100644 --- a/packages/core/cli/package.json +++ b/packages/core/cli/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/cli", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./src/index.js", @@ -8,7 +8,7 @@ "nocobase": "./bin/index.js" }, "dependencies": { - "@nocobase/app": "0.20.0-alpha.14", + "@nocobase/app": "0.20.0-alpha.15", "@types/fs-extra": "^11.0.1", "@umijs/utils": "3.5.20", "chalk": "^4.1.1", @@ -25,7 +25,7 @@ "tsx": "^4.6.2" }, "devDependencies": { - "@nocobase/devtools": "0.20.0-alpha.14" + "@nocobase/devtools": "0.20.0-alpha.15" }, "repository": { "type": "git", diff --git a/packages/core/client/package.json b/packages/core/client/package.json index 23d06a68e..57588cbb5 100644 --- a/packages/core/client/package.json +++ b/packages/core/client/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/client", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.mjs", @@ -26,9 +26,9 @@ "@formily/reactive-react": "^2.2.27", "@formily/shared": "^2.2.27", "@formily/validator": "^2.2.27", - "@nocobase/evaluators": "0.20.0-alpha.14", - "@nocobase/sdk": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/evaluators": "0.20.0-alpha.15", + "@nocobase/sdk": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "ahooks": "^3.7.2", "antd": "^5.12.8", "antd-style": "3.4.5", diff --git a/packages/core/client/src/block-provider/BlockProvider.tsx b/packages/core/client/src/block-provider/BlockProvider.tsx index 483d48b20..da97a5c09 100644 --- a/packages/core/client/src/block-provider/BlockProvider.tsx +++ b/packages/core/client/src/block-provider/BlockProvider.tsx @@ -349,7 +349,7 @@ export const useParamsFromRecord = () => { if (record.__collection && collectionField && !['oho', 'm2o', 'obo'].includes(collectionField.interface)) { obj['targetCollection'] = record.__collection; } - if (!filterByTk) { + if (!filterByTk && Object.keys(filter).length > 0) { obj['filter'] = filter; } return obj; diff --git a/packages/core/client/src/block-provider/hooks/index.ts b/packages/core/client/src/block-provider/hooks/index.ts index 495f5df86..b6d88a516 100644 --- a/packages/core/client/src/block-provider/hooks/index.ts +++ b/packages/core/client/src/block-provider/hooks/index.ts @@ -1,4 +1,6 @@ +import { Field, Form } from '@formily/core'; import { SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react'; +import { untracked } from '@formily/reactive'; import { isURL, parse } from '@nocobase/utils/client'; import { App, message } from 'antd'; import _ from 'lodash'; @@ -23,6 +25,7 @@ import { useFilterBlock } from '../../filter-provider/FilterProvider'; import { mergeFilter, transformToFilter } from '../../filter-provider/utils'; import { useRecord } from '../../record-provider'; import { removeNullCondition, useActionContext, useCompile } from '../../schema-component'; +import { isSubMode } from '../../schema-component/antd/association-field/util'; import { useCurrentUserContext } from '../../user'; import { useLocalVariables, useVariables } from '../../variables'; import { isVariable } from '../../variables/utils/isVariable'; @@ -30,9 +33,6 @@ import { transformVariableValue } from '../../variables/utils/transformVariableV import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider'; import { useDetailsBlockContext } from '../DetailsBlockProvider'; 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 './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 = () => { const { formBlockRef } = useFormBlockContext(); diff --git a/packages/core/client/src/collection-manager/Configuration/components/index.tsx b/packages/core/client/src/collection-manager/Configuration/components/index.tsx index 5e7a60e25..5ff02f77b 100644 --- a/packages/core/client/src/collection-manager/Configuration/components/index.tsx +++ b/packages/core/client/src/collection-manager/Configuration/components/index.tsx @@ -284,7 +284,7 @@ export const ForeignKey = observer( }} onChange={(value, option) => { props?.onChange?.(value); - setInitialValue(option.label); + setInitialValue(option.label || value); }} /> diff --git a/packages/core/client/src/collection-manager/interfaces/nanoid.ts b/packages/core/client/src/collection-manager/interfaces/nanoid.ts index adfd59fa2..594a816d1 100644 --- a/packages/core/client/src/collection-manager/interfaces/nanoid.ts +++ b/packages/core/client/src/collection-manager/interfaces/nanoid.ts @@ -28,9 +28,9 @@ export class NanoidFieldInterface extends CollectionFieldInterface { type: 'string', title: '{{t("Field name")}}', required: true, - 'x-disabled': true, 'x-decorator': 'FormItem', 'x-component': 'Input', + 'x-disabled': '{{ !createOnly }}', description: "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}", }, diff --git a/packages/core/client/src/collection-manager/interfaces/uuid.ts b/packages/core/client/src/collection-manager/interfaces/uuid.ts index f54be0b34..a934d06d3 100644 --- a/packages/core/client/src/collection-manager/interfaces/uuid.ts +++ b/packages/core/client/src/collection-manager/interfaces/uuid.ts @@ -30,9 +30,9 @@ export class UUIDFieldInterface extends CollectionFieldInterface { type: 'string', title: '{{t("Field name")}}', required: true, - 'x-disabled': true, 'x-decorator': 'FormItem', 'x-component': 'Input', + 'x-disabled': '{{ !createOnly }}', description: "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}", }, diff --git a/packages/core/client/src/locale/en_US.json b/packages/core/client/src/locale/en_US.json index 8f75681ec..87a439dd5 100644 --- a/packages/core/client/src/locale/en_US.json +++ b/packages/core/client/src/locale/en_US.json @@ -53,6 +53,9 @@ "Insert right": "Insert right", "Insert inner": "Insert inner", "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", "Collection": "Collection", "Collection selector": "Collection selector", diff --git a/packages/core/client/src/locale/es_ES.json b/packages/core/client/src/locale/es_ES.json index d60ad1632..e2e5dfcfe 100644 --- a/packages/core/client/src/locale/es_ES.json +++ b/packages/core/client/src/locale/es_ES.json @@ -52,6 +52,9 @@ "Insert right": "Insertar a la derecha", "Insert inner": "Insertar al interior", "Delete": "Borrar", + "Disassociate": "Desasociar", + "Disassociate record": "Desasociar registro", + "Are you sure you want to disassociate it?": "¿Seguro que quieres desasociarlo?", "UI editor": "IU editor", "Collection": "Colección", "Collections & Fields": "Colección & Campos", diff --git a/packages/core/client/src/locale/fr_FR.json b/packages/core/client/src/locale/fr_FR.json index 257ae5c2d..06025ca41 100644 --- a/packages/core/client/src/locale/fr_FR.json +++ b/packages/core/client/src/locale/fr_FR.json @@ -52,6 +52,9 @@ "Insert right": "Insérer à droite", "Insert inner": "Insérer à l'intérieur", "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", "Collection": "Collection", "Collections & Fields": "Collections et champs", diff --git a/packages/core/client/src/locale/ja_JP.json b/packages/core/client/src/locale/ja_JP.json index b6bd69884..4b3e4cefa 100644 --- a/packages/core/client/src/locale/ja_JP.json +++ b/packages/core/client/src/locale/ja_JP.json @@ -52,6 +52,9 @@ "Insert right": "右に挿入", "Insert inner": "中に挿入", "Delete": "削除", + "Disassociate": "関連付けを解除", + "Disassociate record": "レコードの関連付けを解除", + "Are you sure you want to disassociate it?": "本当に関連付けを解除しますか?", "UI editor": "UI エディタ", "Collection": "コレクション", "Enable child collections": "启用子表", diff --git a/packages/core/client/src/locale/ko_KR.json b/packages/core/client/src/locale/ko_KR.json index f3c00c4e8..c0b8cbd38 100644 --- a/packages/core/client/src/locale/ko_KR.json +++ b/packages/core/client/src/locale/ko_KR.json @@ -60,6 +60,9 @@ "Insert right": "오른쪽에 삽입", "Insert inner": "내부에 삽입", "Delete": "삭제", + "Disassociate": "연결 해제", + "Disassociate record": "레코드 연결 해제", + "Are you sure you want to disassociate it?": "정말로 연결을 해제하시겠습니까?", "UI editor": "UI 편집기", "Collection": "컬렉션", "Collection selector": "컬렉션 선택기", diff --git a/packages/core/client/src/locale/pt_BR.json b/packages/core/client/src/locale/pt_BR.json index 642e79221..693a8250e 100644 --- a/packages/core/client/src/locale/pt_BR.json +++ b/packages/core/client/src/locale/pt_BR.json @@ -32,6 +32,9 @@ "Insert right": "Inserir à direita", "Insert inner": "Inserir interno", "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", "Collection": "Coleção", "Collections & Fields": "Coleções e campos", diff --git a/packages/core/client/src/locale/ru_RU.json b/packages/core/client/src/locale/ru_RU.json index 3411341e1..99f45d8ad 100644 --- a/packages/core/client/src/locale/ru_RU.json +++ b/packages/core/client/src/locale/ru_RU.json @@ -52,6 +52,9 @@ "Insert right": "Вставить справа", "Insert inner": "Вставить внутрь", "Delete": "Удалить", + "Disassociate": "Разъединить", + "Disassociate record": "Разъединить запись", + "Are you sure you want to disassociate it?": "Вы уверены, что хотите разъединить это?", "UI editor": "UI редактор", "Collection": "Коллекция", "Collections & Fields": "Коллекции & Поля", diff --git a/packages/core/client/src/locale/tr_TR.json b/packages/core/client/src/locale/tr_TR.json index ec2c67ee5..0cccd69d4 100644 --- a/packages/core/client/src/locale/tr_TR.json +++ b/packages/core/client/src/locale/tr_TR.json @@ -52,6 +52,9 @@ "Insert right": "Sağa yerleştir", "Insert inner": "İçine yerleştir", "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", "Collection": "Koleksiyonlar", "Collections & Fields": "Koleksiyonlar & Alanlar", diff --git a/packages/core/client/src/locale/uk_UA.json b/packages/core/client/src/locale/uk_UA.json index da860d5da..a530f6cfb 100644 --- a/packages/core/client/src/locale/uk_UA.json +++ b/packages/core/client/src/locale/uk_UA.json @@ -52,6 +52,9 @@ "Insert right": "Вставити справа", "Insert inner": "Вставити всередину", "Delete": "Видалити", + "Disassociate": "Роз'єднати", + "Disassociate record": "Роз'єднати запис", + "Are you sure you want to disassociate it?": "Ви впевнені, що хочете роз'єднати це?", "UI editor": "Редактор UI", "Collection": "Колекція", "Collections & Fields": "Колекції та поля", diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index 06e9d54d1..e76cbb80f 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -60,6 +60,9 @@ "Insert right": "在右边插入", "Insert inner": "在里面插入", "Delete": "删除", + "Disassociate": "解除关联", + "Disassociate record": "解除关联记录", + "Are you sure you want to disassociate it?": "你确定要解除关联吗?", "UI editor": "界面配置", "Collection": "数据表", "Collection selector": "数据表选择器", diff --git a/packages/core/client/src/locale/zh-TW.json b/packages/core/client/src/locale/zh-TW.json index 4f8c1727a..510910d3e 100644 --- a/packages/core/client/src/locale/zh-TW.json +++ b/packages/core/client/src/locale/zh-TW.json @@ -60,6 +60,9 @@ "Insert right": "從右邊插入", "Insert inner": "從裡面插入", "Delete": "刪除", + "Disassociate": "解除關聯", + "Disassociate record": "解除關聯記錄", + "Are you sure you want to disassociate it?": "你確定要解除關聯嗎?", "UI editor": "介面編輯", "Collection": "資料表", "Collection selector": "資料表選擇器", diff --git a/packages/core/client/src/modules/actions/disassociate/DisassociateActionInitializer.tsx b/packages/core/client/src/modules/actions/disassociate/DisassociateActionInitializer.tsx new file mode 100644 index 000000000..2065e4f6d --- /dev/null +++ b/packages/core/client/src/modules/actions/disassociate/DisassociateActionInitializer.tsx @@ -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 ; +}; diff --git a/packages/core/client/src/modules/actions/disassociate/__e2e__/disassociate.test.ts b/packages/core/client/src/modules/actions/disassociate/__e2e__/disassociate.test.ts new file mode 100644 index 000000000..51eb5753c --- /dev/null +++ b/packages/core/client/src/modules/actions/disassociate/__e2e__/disassociate.test.ts @@ -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(); +}); diff --git a/packages/core/client/src/modules/actions/disassociate/__e2e__/templatesOfPage.ts b/packages/core/client/src/modules/actions/disassociate/__e2e__/templatesOfPage.ts new file mode 100644 index 000000000..0ce1ffdd8 --- /dev/null +++ b/packages/core/client/src/modules/actions/disassociate/__e2e__/templatesOfPage.ts @@ -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, + }, +}; diff --git a/packages/core/client/src/modules/actions/disassociate/disassociateActionSettings.tsx b/packages/core/client/src/modules/actions/disassociate/disassociateActionSettings.tsx new file mode 100644 index 000000000..d11d7be30 --- /dev/null +++ b/packages/core/client/src/modules/actions/disassociate/disassociateActionSettings.tsx @@ -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', + }, + ], +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/TableActionColumnInitializers.tsx b/packages/core/client/src/modules/blocks/data-blocks/table/TableActionColumnInitializers.tsx index 0fe2fa090..3edb4f219 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/TableActionColumnInitializers.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/table/TableActionColumnInitializers.tsx @@ -4,13 +4,14 @@ import _ from 'lodash'; import React from 'react'; import { useTranslation } from 'react-i18next'; 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 { useDataBlockProps } from '../../../../data-source'; import { createDesignable, useDesignable } from '../../../../schema-component'; 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 = () => { const { t } = useTranslation(); @@ -65,11 +66,7 @@ export const Resizable = () => { ); }; -/** - * @deprecated - */ -export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({ - name: 'TableActionColumnInitializers', +const commonOptions = { insertPosition: 'beforeEnd', useInsert: function useInsert() { const { refresh } = useDesignable(); @@ -156,6 +153,27 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit 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', title: '{{t("Add child")}}', @@ -225,166 +243,20 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit Component: Resizable, }, ], +}; + +/** + * @deprecated + */ +export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({ + name: 'TableActionColumnInitializers', + ...commonOptions, }); export const tableActionColumnInitializers = new CompatibleSchemaInitializer( { name: 'table:configureItemActions', - insertPosition: 'beforeEnd', - 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 ( - - ); - }, - 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, - }, - ], + ...commonOptions, }, tableActionColumnInitializers_deprecated, ); diff --git a/packages/core/client/src/schema-initializer/index.ts b/packages/core/client/src/schema-initializer/index.ts index e8e9b2006..648cdb45f 100644 --- a/packages/core/client/src/schema-initializer/index.ts +++ b/packages/core/client/src/schema-initializer/index.ts @@ -12,6 +12,7 @@ import { } from '../modules/actions/add-record/customizeCreateFormBlockInitializers'; import { BulkDestroyActionInitializer } from '../modules/actions/bulk-destroy/BulkDestroyActionInitializer'; import { DestroyActionInitializer } from '../modules/actions/delete/DestroyActionInitializer'; +import { DisassociateActionInitializer } from '../modules/actions/disassociate/DisassociateActionInitializer'; import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer'; import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer'; import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer'; @@ -121,10 +122,10 @@ import * as items from './items'; export * from './buttons'; export * from './items'; export { + createDetailsBlockSchema, createFilterFormBlockSchema, createFormBlockSchema, createReadPrettyFormBlockSchema, - createDetailsBlockSchema, createTableBlockSchema, gridRowColWrap, itemsMerge, @@ -144,6 +145,7 @@ export class SchemaInitializerPlugin extends Plugin { this.app.addComponents({ ...initializerComponents, ...items, + DestroyActionInitializer, CreateFormBlockInitializer, FormBlockInitializer, RecordFormBlockInitializer, @@ -171,7 +173,7 @@ export class SchemaInitializerPlugin extends Plugin { UpdateSubmitActionInitializer, BulkDestroyActionInitializer, ExpandableActionInitializer, - DestroyActionInitializer, + DisassociateActionInitializer, FilterActionInitializer, RefreshActionInitializer, } as any); diff --git a/packages/core/client/src/schema-settings/SchemaSettingsPlugin.ts b/packages/core/client/src/schema-settings/SchemaSettingsPlugin.ts index 0e260900a..b88ec2cef 100644 --- a/packages/core/client/src/schema-settings/SchemaSettingsPlugin.ts +++ b/packages/core/client/src/schema-settings/SchemaSettingsPlugin.ts @@ -4,6 +4,7 @@ import { addNewActionSettings } from '../modules/actions/add-new/addNewActionSet import { customizeAddRecordActionSettings } from '../modules/actions/add-record/customizeAddRecordActionSettings'; import { bulkDeleteActionSettings } from '../modules/actions/bulk-destroy/bulkDeleteActionSettings'; import { deleteActionSettings } from '../modules/actions/delete/deleteActionSettings'; +import { disassociateActionSettings } from '../modules/actions/disassociate/disassociateActionSettings'; import { expendableActionSettings } from '../modules/actions/expand-collapse/expendableActionSettings'; import { filterActionSettings } from '../modules/actions/filter/filterActionSettings'; import { refreshActionSettings } from '../modules/actions/refresh/refreshActionSettings'; @@ -69,6 +70,7 @@ export class SchemaSettingsPlugin extends Plugin { this.schemaSettingsManager.add(viewActionSettings); this.schemaSettingsManager.add(editActionSettings); this.schemaSettingsManager.add(deleteActionSettings); + this.schemaSettingsManager.add(disassociateActionSettings); this.schemaSettingsManager.add(bulkDeleteActionSettings); this.schemaSettingsManager.add(customizeAddRecordActionSettings); this.schemaSettingsManager.add(customizePopupActionSettings); diff --git a/packages/core/create-nocobase-app/package.json b/packages/core/create-nocobase-app/package.json index 5b8ddf1d6..8707043ee 100755 --- a/packages/core/create-nocobase-app/package.json +++ b/packages/core/create-nocobase-app/package.json @@ -1,6 +1,6 @@ { "name": "create-nocobase-app", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "src/index.js", "license": "Apache-2.0", "dependencies": { diff --git a/packages/core/data-source-manager/package.json b/packages/core/data-source-manager/package.json index 20099feb6..7ec9fe5d3 100644 --- a/packages/core/data-source-manager/package.json +++ b/packages/core/data-source-manager/package.json @@ -1,16 +1,16 @@ { "name": "@nocobase/data-source-manager", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/actions": "0.20.0-alpha.14", - "@nocobase/cache": "0.20.0-alpha.14", - "@nocobase/database": "0.20.0-alpha.14", - "@nocobase/resourcer": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/actions": "0.20.0-alpha.15", + "@nocobase/cache": "0.20.0-alpha.15", + "@nocobase/database": "0.20.0-alpha.15", + "@nocobase/resourcer": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "@types/jsonwebtoken": "^8.5.8", "jsonwebtoken": "^8.5.1" }, diff --git a/packages/core/database/package.json b/packages/core/database/package.json index 02e3890d0..e5f461660 100644 --- a/packages/core/database/package.json +++ b/packages/core/database/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/database", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { - "@nocobase/logger": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/logger": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "async-mutex": "^0.3.2", "chalk": "^4.1.1", "cron-parser": "4.4.0", diff --git a/packages/core/database/src/__tests__/fields/uuid-field.test.ts b/packages/core/database/src/__tests__/fields/uuid-field.test.ts index bd6351c10..63fe69358 100644 --- a/packages/core/database/src/__tests__/fields/uuid-field.test.ts +++ b/packages/core/database/src/__tests__/fields/uuid-field.test.ts @@ -13,19 +13,20 @@ describe('string field', () => { await db.close(); }); - it('define', async () => { + it('should create uuid field', async () => { const Test = db.collection({ name: 'tests', - autoGenId: false, fields: [ { + name: 'uuid', type: 'uuid', - name: 'id', - primaryKey: true, }, ], }); + 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}$/); }); }); diff --git a/packages/core/database/src/fields/uuid-field.ts b/packages/core/database/src/fields/uuid-field.ts index f9af33703..53705c6b8 100644 --- a/packages/core/database/src/fields/uuid-field.ts +++ b/packages/core/database/src/fields/uuid-field.ts @@ -5,7 +5,7 @@ export class UuidField extends Field { constructor(options?: any, context?: FieldContext) { super( { - defaultValue: DataTypes.UUIDV4, + defaultValue: new DataTypes.UUIDV4(), ...options, }, context, diff --git a/packages/core/devtools/package.json b/packages/core/devtools/package.json index 366eb3b5e..8cb0a7c60 100644 --- a/packages/core/devtools/package.json +++ b/packages/core/devtools/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/devtools", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "Apache-2.0", "main": "./src/index.js", "dependencies": { - "@nocobase/build": "0.20.0-alpha.14", - "@nocobase/client": "0.20.0-alpha.14", - "@nocobase/test": "0.20.0-alpha.14", + "@nocobase/build": "0.20.0-alpha.15", + "@nocobase/client": "0.20.0-alpha.15", + "@nocobase/test": "0.20.0-alpha.15", "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.4", "@types/lodash": "^4.14.177", diff --git a/packages/core/evaluators/package.json b/packages/core/evaluators/package.json index 8eaed2cc1..bac1fc3ef 100644 --- a/packages/core/evaluators/package.json +++ b/packages/core/evaluators/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/evaluators", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { "@formulajs/formulajs": "4.2.0", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/utils": "0.20.0-alpha.15", "mathjs": "^10.6.0" }, "repository": { diff --git a/packages/core/logger/package.json b/packages/core/logger/package.json index 7fe0db5a5..663d1a98c 100644 --- a/packages/core/logger/package.json +++ b/packages/core/logger/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/logger", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "nocobase logging library", "license": "Apache-2.0", "main": "./lib/index.js", diff --git a/packages/core/logger/src/system-logger.ts b/packages/core/logger/src/system-logger.ts index 76ed33d2f..03ba4d7f4 100644 --- a/packages/core/logger/src/system-logger.ts +++ b/packages/core/logger/src/system-logger.ts @@ -49,13 +49,13 @@ class SystemLoggerTransport extends Transport { } 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 { module, submodule, method, ...meta } = args?.[0] || {}; logger.log({ level, - stack, message, + stack, meta, module: module || info['module'] || '', submodule: submodule || info['submodule'] || '', @@ -63,11 +63,51 @@ class SystemLoggerTransport extends Transport { app, reqId, }); + if (cause) { + logger.log({ + level, + message: cause.message, + stack: cause.stack, + app, + reqId, + }); + } callback(null, true); } } -export const createSystemLogger = (options: SystemLoggerOptions): SystemLogger => - winston.createLogger({ +function child(defaultRequestMetadata: any) { + 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)], }); + + // 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); + }, + }); +}; diff --git a/packages/core/resourcer/package.json b/packages/core/resourcer/package.json index b2396c032..e4d973c9d 100644 --- a/packages/core/resourcer/package.json +++ b/packages/core/resourcer/package.json @@ -1,12 +1,12 @@ { "name": "@nocobase/resourcer", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/utils": "0.20.0-alpha.15", "deepmerge": "^4.2.2", "koa-compose": "^4.1.0", "lodash": "^4.17.21", diff --git a/packages/core/sdk/package.json b/packages/core/sdk/package.json index aeaea7556..9a5cf25c5 100644 --- a/packages/core/sdk/package.json +++ b/packages/core/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/sdk", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "Apache-2.0", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/core/server/package.json b/packages/core/server/package.json index 91d564795..629736512 100644 --- a/packages/core/server/package.json +++ b/packages/core/server/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/server", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", @@ -10,18 +10,18 @@ "@koa/cors": "^3.1.0", "@koa/multer": "^3.0.2", "@koa/router": "^9.4.0", - "@nocobase/acl": "0.20.0-alpha.14", - "@nocobase/actions": "0.20.0-alpha.14", - "@nocobase/auth": "0.20.0-alpha.14", - "@nocobase/cache": "0.20.0-alpha.14", - "@nocobase/data-source-manager": "0.20.0-alpha.14", - "@nocobase/database": "0.20.0-alpha.14", - "@nocobase/evaluators": "0.20.0-alpha.14", - "@nocobase/logger": "0.20.0-alpha.14", - "@nocobase/resourcer": "0.20.0-alpha.14", - "@nocobase/sdk": "0.20.0-alpha.14", - "@nocobase/telemetry": "0.20.0-alpha.14", - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/acl": "0.20.0-alpha.15", + "@nocobase/actions": "0.20.0-alpha.15", + "@nocobase/auth": "0.20.0-alpha.15", + "@nocobase/cache": "0.20.0-alpha.15", + "@nocobase/data-source-manager": "0.20.0-alpha.15", + "@nocobase/database": "0.20.0-alpha.15", + "@nocobase/evaluators": "0.20.0-alpha.15", + "@nocobase/logger": "0.20.0-alpha.15", + "@nocobase/resourcer": "0.20.0-alpha.15", + "@nocobase/sdk": "0.20.0-alpha.15", + "@nocobase/telemetry": "0.20.0-alpha.15", + "@nocobase/utils": "0.20.0-alpha.15", "@types/decompress": "4.2.4", "@types/ini": "^1.3.31", "@types/koa-send": "^4.1.3", diff --git a/packages/core/server/src/acl/available-action.ts b/packages/core/server/src/acl/available-action.ts index 0277f2fd9..c34091428 100644 --- a/packages/core/server/src/acl/available-action.ts +++ b/packages/core/server/src/acl/available-action.ts @@ -34,6 +34,7 @@ const availableActions: { }, destroy: { displayName: '{{t("Delete")}}', + aliases: ['destroy', 'remove'], type: 'old-data', }, }; diff --git a/packages/core/telemetry/package.json b/packages/core/telemetry/package.json index d43103f31..c29edab05 100644 --- a/packages/core/telemetry/package.json +++ b/packages/core/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/telemetry", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "nocobase telemetry library", "license": "Apache-2.0", "main": "./lib/index.js", @@ -11,7 +11,7 @@ "directory": "packages/telemetry" }, "dependencies": { - "@nocobase/utils": "0.20.0-alpha.14", + "@nocobase/utils": "0.20.0-alpha.15", "@opentelemetry/api": "^1.7.0", "@opentelemetry/instrumentation": "^0.46.0", "@opentelemetry/resources": "^1.19.0", diff --git a/packages/core/test/package.json b/packages/core/test/package.json index ce6bb78fc..84c04dca8 100644 --- a/packages/core/test/package.json +++ b/packages/core/test/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/test", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "lib/index.js", "module": "./src/index.ts", "types": "./lib/index.d.ts", @@ -40,7 +40,7 @@ }, "dependencies": { "@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", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", diff --git a/packages/core/utils/package.json b/packages/core/utils/package.json index d92d2f6f1..8802917c6 100644 --- a/packages/core/utils/package.json +++ b/packages/core/utils/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/utils", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", diff --git a/packages/plugins/@nocobase/plugin-acl/package.json b/packages/plugins/@nocobase/plugin-acl/package.json index 901365e48..309714632 100644 --- a/packages/plugins/@nocobase/plugin-acl/package.json +++ b/packages/plugins/@nocobase/plugin-acl/package.json @@ -4,7 +4,7 @@ "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.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/acl", diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/RolesManagement.tsx b/packages/plugins/@nocobase/plugin-acl/src/client/RolesManagement.tsx index 49b164ad0..1b02749fc 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/client/RolesManagement.tsx +++ b/packages/plugins/@nocobase/plugin-acl/src/client/RolesManagement.tsx @@ -1,6 +1,13 @@ import React, { useState } from 'react'; 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 { RolesMenu } from './RolesMenu'; import { useACLTranslation } from './locale'; @@ -58,53 +65,55 @@ export const RolesManagement: React.FC = () => { children: item.Component ? React.createElement(item.Component, { active: activeKey === name }) : null, })); const [role, setRole] = useState(null); + const scCtx = useSchemaComponentContext(); return ( - - - - - + + + + + - - - - - - - - - - - setActiveKey(key)} - items={[ - { - key: 'permissions', - label: t('Permissions'), - children: , - }, - ...tabs, - ]} - /> - - - - + }} + > + + + + + + + + + + + setActiveKey(key)} + items={[ + { + key: 'permissions', + label: t('Permissions'), + children: , + }, + ...tabs, + ]} + /> + + + + + ); }; diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/RolesMenu.tsx b/packages/plugins/@nocobase/plugin-acl/src/client/RolesMenu.tsx index c1cb3b7c4..46ed56c2f 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/client/RolesMenu.tsx +++ b/packages/plugins/@nocobase/plugin-acl/src/client/RolesMenu.tsx @@ -5,55 +5,98 @@ import { useAPIClient, useResourceActionContext, } 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 React, { useContext, useEffect } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { useACLTranslation } from './locale'; import { Schema } from '@formily/react'; import { RolesManagerContext } from './RolesManagerProvider'; import { roleEditSchema } from './schemas/roles'; +import { useLoadMoreObserver } from './hooks/load-more-observer'; export const RolesMenu: React.FC & { Item: React.FC<{ item: any; onEdit: () => void }>; } = () => { const { t } = useACLTranslation(); - const { data } = useResourceActionContext(); - const [visible, setVisible] = React.useState(false); - const [record, setRecord] = React.useState(null); + const { data, run, loading } = useResourceActionContext(); + const [visible, setVisible] = useState(false); + const [record, setRecord] = useState(null); const { role, setRole } = useContext(RolesManagerContext); - const items = (data?.data || []).map((item: any) => ({ - key: item.name, - label: ( - { - setVisible(true); - setRecord(item); - }} - /> - ), - })); + const [roles, setRoles] = useState([]); + + const loadMore = useCallback(() => { + const meta = data?.meta; + if (!meta || meta.page >= meta.totalPage) { + return; + } + run({ + page: meta.page + 1, + }); + }, [data]); + const { lastItem, setLastItem } = useLoadMoreObserver({ loadMore }); const handleSelect = ({ key }) => { - setRole((data?.data || []).find((item: any) => item.name === key)); + setRole(roles.find((item: any) => item.name === key)); }; useEffect(() => { - if (!data?.data.length) { + if (!roles[0]) { return; } - setRole(data?.data[0]); - }, [data, setRole]); + setRole(roles[0]); + }, [roles, setRole]); + + useEffect(() => { + if (!data?.data?.length) { + return; + } + + const ref = React.createRef(); + 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 ? ( +
+ { + setVisible(true); + setRecord(item); + }} + /> +
+ ) : ( + { + setVisible(true); + setRecord(item); + }} + /> + ), + })), + [roles, lastItem], + ); return ( <> - {items.length ? ( - + {roles.length ? ( + <> + + {loading && } + ) : ( )} @@ -92,12 +135,15 @@ RolesMenu.Item = function DepartmentTreeItem({ item, onEdit }) { deleteDepartment(); } }; + const title = Schema.compile(item.title, { t }); return ( - {Schema.compile(item.title, { t })} + + {title} + diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/hooks/load-more-observer.ts b/packages/plugins/@nocobase/plugin-acl/src/client/hooks/load-more-observer.ts new file mode 100644 index 000000000..7bc5e5bbf --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/hooks/load-more-observer.ts @@ -0,0 +1,45 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; + +export const useLoadMoreObserver = ({ + loadMore, +}: { + loadMore: () => void; // callback +}) => { + const [lastItem, setLastItem] = useState>(null); + const observer = useRef(null); + const observeExposure = useCallback( + (lastItem: React.RefObject) => { + 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, + }; +}; diff --git a/packages/plugins/@nocobase/plugin-acl/src/server/server.ts b/packages/plugins/@nocobase/plugin-acl/src/server/server.ts index 98d33fa19..807773a0d 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-acl/src/server/server.ts @@ -398,11 +398,12 @@ export class PluginACL extends Plugin { }; // sync database role data to acl - this.app.on('afterLoad', async () => { + this.app.on('afterStart', async () => { await writeRolesToACL(this.app, { withOutResources: true, }); }); + // this.app.on('afterInstall', writeRolesToACL); this.app.on('afterInstallPlugin', async (plugin) => { diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json b/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json index 7308b704d..7ea3e71b0 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-bulk-edit", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-bulk-edit", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit", diff --git a/packages/plugins/@nocobase/plugin-action-bulk-update/package.json b/packages/plugins/@nocobase/plugin-action-bulk-update/package.json index 2c8d553f7..8d83ce095 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-update/package.json +++ b/packages/plugins/@nocobase/plugin-action-bulk-update/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-bulk-update", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-bulk-update", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update", diff --git a/packages/plugins/@nocobase/plugin-action-duplicate/package.json b/packages/plugins/@nocobase/plugin-action-duplicate/package.json index ae466348e..41dbaffb4 100644 --- a/packages/plugins/@nocobase/plugin-action-duplicate/package.json +++ b/packages/plugins/@nocobase/plugin-action-duplicate/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-duplicate", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-duplicate", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate", diff --git a/packages/plugins/@nocobase/plugin-action-print/package.json b/packages/plugins/@nocobase/plugin-action-print/package.json index 7228ed051..21b6d8421 100644 --- a/packages/plugins/@nocobase/plugin-action-print/package.json +++ b/packages/plugins/@nocobase/plugin-action-print/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-print", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-print", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print", diff --git a/packages/plugins/@nocobase/plugin-api-doc/package.json b/packages/plugins/@nocobase/plugin-api-doc/package.json index 7e987d6c5..0221c5b77 100644 --- a/packages/plugins/@nocobase/plugin-api-doc/package.json +++ b/packages/plugins/@nocobase/plugin-api-doc/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-api-doc", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "API documentation", "displayName.zh-CN": "API 文档", "description": "An OpenAPI documentation generator for NocoBase HTTP API.", diff --git a/packages/plugins/@nocobase/plugin-api-keys/package.json b/packages/plugins/@nocobase/plugin-api-keys/package.json index 9b1ad1d07..f10fe2ec5 100644 --- a/packages/plugins/@nocobase/plugin-api-keys/package.json +++ b/packages/plugins/@nocobase/plugin-api-keys/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:API 密钥", "description": "Allows users to use API key to access application's HTTP API", "description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/api-keys", diff --git a/packages/plugins/@nocobase/plugin-audit-logs/package.json b/packages/plugins/@nocobase/plugin-audit-logs/package.json index 5f9e0ae3e..ae328c717 100644 --- a/packages/plugins/@nocobase/plugin-audit-logs/package.json +++ b/packages/plugins/@nocobase/plugin-audit-logs/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-audit-logs", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "Audit logs (deprecated)", "displayName.zh-CN": "审计日志(废弃)", "description": "This plugin is deprecated. There will be a new audit log plugin in the future.", diff --git a/packages/plugins/@nocobase/plugin-auth/package.json b/packages/plugins/@nocobase/plugin-auth/package.json index fbe555537..055b1756b 100644 --- a/packages/plugins/@nocobase/plugin-auth/package.json +++ b/packages/plugins/@nocobase/plugin-auth/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-auth", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth", diff --git a/packages/plugins/@nocobase/plugin-backup-restore/package.json b/packages/plugins/@nocobase/plugin-backup-restore/package.json index b703acf9f..d664c020a 100644 --- a/packages/plugins/@nocobase/plugin-backup-restore/package.json +++ b/packages/plugins/@nocobase/plugin-backup-restore/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "应用的备份与还原", "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.", "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/backup-restore", diff --git a/packages/plugins/@nocobase/plugin-backup-restore/src/server/__tests__/dumper.test.ts b/packages/plugins/@nocobase/plugin-backup-restore/src/server/__tests__/dumper.test.ts index d06890bdb..4b3952ec2 100644 --- a/packages/plugins/@nocobase/plugin-backup-restore/src/server/__tests__/dumper.test.ts +++ b/packages/plugins/@nocobase/plugin-backup-restore/src/server/__tests__/dumper.test.ts @@ -85,6 +85,43 @@ describe('dumper', () => { 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', () => { let allGroups; diff --git a/packages/plugins/@nocobase/plugin-backup-restore/src/server/dumper.ts b/packages/plugins/@nocobase/plugin-backup-restore/src/server/dumper.ts index 32fa2a3ab..dbcfd373d 100644 --- a/packages/plugins/@nocobase/plugin-backup-restore/src/server/dumper.ts +++ b/packages/plugins/@nocobase/plugin-backup-restore/src/server/dumper.ts @@ -412,12 +412,18 @@ export class Dumper extends AppMigrator { if (collectionField) { // is a field - return { + const fieldAttributes: any = { field: attr.field, isCollectionField: true, type: collectionField.type, typeOptions: collectionField.options, }; + + if (fieldAttributes.typeOptions?.defaultValue?.constructor?.name === 'UUIDV4') { + delete fieldAttributes.typeOptions.defaultValue; + } + + return fieldAttributes; } return { diff --git a/packages/plugins/@nocobase/plugin-calendar/package.json b/packages/plugins/@nocobase/plugin-calendar/package.json index 49b018f76..27bc0ec19 100644 --- a/packages/plugins/@nocobase/plugin-calendar/package.json +++ b/packages/plugins/@nocobase/plugin-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-calendar", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "Calendar", "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.", diff --git a/packages/plugins/@nocobase/plugin-cas/package.json b/packages/plugins/@nocobase/plugin-cas/package.json index d8080330d..8788079f9 100644 --- a/packages/plugins/@nocobase/plugin-cas/package.json +++ b/packages/plugins/@nocobase/plugin-cas/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:CAS", "description": "CAS authentication.", "description.zh-CN": "通过 CAS 协议认证身份。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-cas", diff --git a/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts b/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts index 28db05de4..ae811ddb9 100644 --- a/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts +++ b/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts @@ -3,20 +3,25 @@ import { AppSupervisor } from '@nocobase/server'; import { CASAuth } from '../auth'; 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') { const appSupervisor = AppSupervisor.getInstance(); 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; + + if (prefix.endsWith('/')) { + prefix = prefix.slice(0, -1); + } + try { const { token } = await auth.signIn(); - ctx.redirect(`${prefix}${redirect}?authenticator=${authenticator}&token=${token}`); + ctx.redirect(`${prefix}${redirect || '/admin'}?authenticator=${authenticator}&token=${token}`); } catch (error) { ctx.redirect(`${prefix}/signin?authenticator=${authenticator}&error=${error.message}&redirect=${redirect}`); } diff --git a/packages/plugins/@nocobase/plugin-charts/package.json b/packages/plugins/@nocobase/plugin-charts/package.json index c5df2c17b..ae1b205de 100644 --- a/packages/plugins/@nocobase/plugin-charts/package.json +++ b/packages/plugins/@nocobase/plugin-charts/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "图表(废弃)", "description": "The plugin has been deprecated, please use the data visualization plugin instead.", "description.zh-CN": "已废弃插件,请使用数据可视化插件代替。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "license": "AGPL-3.0", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-china-region/package.json b/packages/plugins/@nocobase/plugin-china-region/package.json index aa1019b0f..34461a0f6 100644 --- a/packages/plugins/@nocobase/plugin-china-region/package.json +++ b/packages/plugins/@nocobase/plugin-china-region/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-china-region", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "Administrative divisions of China", "displayName.zh-CN": "中国行政区划", "description": "Provides data and field type for administrative divisions of China.", diff --git a/packages/plugins/@nocobase/plugin-client/package.json b/packages/plugins/@nocobase/plugin-client/package.json index 388f5ae3b..97128e546 100644 --- a/packages/plugins/@nocobase/plugin-client/package.json +++ b/packages/plugins/@nocobase/plugin-client/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "WEB 客户端", "description": "Provides a client interface for the NocoBase server", "description.zh-CN": "为 NocoBase 服务端提供客户端界面", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "license": "AGPL-3.0", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-collection-manager/package.json b/packages/plugins/@nocobase/plugin-collection-manager/package.json index df7335ec1..c65b2cd7e 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/package.json +++ b/packages/plugins/@nocobase/plugin-collection-manager/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数据源:主数据库", "description": "NocoBase main database, supports relational databases such as MySQL, PostgreSQL, SQLite and so on.", "description.zh-CN": "NocoBase 主数据库,支持 MySQL、PostgreSQL、SQLite 等关系型数据库。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/data-source-main", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main", diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/server/__tests__/fields/uuid.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/server/__tests__/fields/uuid.test.ts new file mode 100644 index 000000000..d17e4c7db --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/server/__tests__/fields/uuid.test.ts @@ -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}$/); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-custom-request/package.json b/packages/plugins/@nocobase/plugin-custom-request/package.json index 8aa459099..bbb63f529 100644 --- a/packages/plugins/@nocobase/plugin-custom-request/package.json +++ b/packages/plugins/@nocobase/plugin-custom-request/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-custom-request", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-custom-request", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request", diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/package.json b/packages/plugins/@nocobase/plugin-data-source-manager/package.json index 98dc169fc..8f0bb6449 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/package.json +++ b/packages/plugins/@nocobase/plugin-data-source-manager/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-data-source-manager", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "displayName": "Data source manager", "displayName.zh-CN": "数据源管理", diff --git a/packages/plugins/@nocobase/plugin-data-visualization/package.json b/packages/plugins/@nocobase/plugin-data-visualization/package.json index 2e0564f09..eb100dbd8 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/package.json +++ b/packages/plugins/@nocobase/plugin-data-visualization/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-data-visualization", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "Data visualization", "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.", diff --git a/packages/plugins/@nocobase/plugin-disable-pm-add/package.json b/packages/plugins/@nocobase/plugin-disable-pm-add/package.json index c422c51b9..25e097c88 100644 --- a/packages/plugins/@nocobase/plugin-disable-pm-add/package.json +++ b/packages/plugins/@nocobase/plugin-disable-pm-add/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-disable-pm-add", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "peerDependencies": { "@nocobase/client": "0.x", diff --git a/packages/plugins/@nocobase/plugin-error-handler/package.json b/packages/plugins/@nocobase/plugin-error-handler/package.json index 8c71dd3c8..e6d9d93c4 100644 --- a/packages/plugins/@nocobase/plugin-error-handler/package.json +++ b/packages/plugins/@nocobase/plugin-error-handler/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "错误处理器", "description": "Handling application errors and exceptions.", "description.zh-CN": "处理应用程序中的错误和异常。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-excel-formula-field/package.json b/packages/plugins/@nocobase/plugin-excel-formula-field/package.json index 2c9697df9..26b9438d4 100644 --- a/packages/plugins/@nocobase/plugin-excel-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-excel-formula-field/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-excel-formula-field", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "AGPL-3.0", "main": "./dist/server/index.js", diff --git a/packages/plugins/@nocobase/plugin-export/package.json b/packages/plugins/@nocobase/plugin-export/package.json index ce22a3c01..cddb09ce5 100644 --- a/packages/plugins/@nocobase/plugin-export/package.json +++ b/packages/plugins/@nocobase/plugin-export/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "操作:导出记录", "description": "Export filtered records to excel, you can configure which fields to export.", "description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-export", diff --git a/packages/plugins/@nocobase/plugin-file-manager/package.json b/packages/plugins/@nocobase/plugin-file-manager/package.json index 1fb81551a..189dc6ec5 100644 --- a/packages/plugins/@nocobase/plugin-file-manager/package.json +++ b/packages/plugins/@nocobase/plugin-file-manager/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-file-manager", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "File manager", "displayName.zh-CN": "文件管理器", "description": "Provides files storage services with files collection template and attachment field.", diff --git a/packages/plugins/@nocobase/plugin-file-manager/src/client/templates/file.ts b/packages/plugins/@nocobase/plugin-file-manager/src/client/templates/file.ts index 307c4cc66..a028c17f8 100644 --- a/packages/plugins/@nocobase/plugin-file-manager/src/client/templates/file.ts +++ b/packages/plugins/@nocobase/plugin-file-manager/src/client/templates/file.ts @@ -1,158 +1,6 @@ import { CollectionTemplate, getConfigurableProperties } from '@nocobase/client'; -// import { CollectionOptions } from '@nocobase/database'; 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 { name = 'file'; title = `{{t("File collection", { ns: "${NAMESPACE}" })}}`; @@ -236,7 +84,7 @@ export class FileCollectionTemplate extends CollectionTemplate { deletable: false, uiSchema: { type: 'string', - title: `{{t("Path")}}`, + title: `{{t("Path", { ns: "${NAMESPACE}" })}}`, 'x-component': 'Input', 'x-read-pretty': true, }, @@ -263,7 +111,7 @@ export class FileCollectionTemplate extends CollectionTemplate { deletable: false, uiSchema: { type: 'string', - title: `{{t("Preview")}}`, + title: `{{t("Preview", { ns: "${NAMESPACE}" })}}`, 'x-component': 'Preview', 'x-read-pretty': true, }, @@ -275,6 +123,12 @@ export class FileCollectionTemplate extends CollectionTemplate { target: 'storages', foreignKey: 'storageId', deletable: false, + uiSchema: { + type: 'string', + title: `{{t("Storage", { ns: "${NAMESPACE}" })}}`, + 'x-component': 'Input', + 'x-read-pretty': true, + }, }, // '其他文件信息(如图片的宽高)', { diff --git a/packages/plugins/@nocobase/plugin-formula-field/package.json b/packages/plugins/@nocobase/plugin-formula-field/package.json index 9173b5d0d..978fa62b5 100644 --- a/packages/plugins/@nocobase/plugin-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-formula-field/package.json @@ -4,7 +4,7 @@ "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.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-formula", diff --git a/packages/plugins/@nocobase/plugin-gantt/package.json b/packages/plugins/@nocobase/plugin-gantt/package.json index 78837c6ef..dc8e800d5 100644 --- a/packages/plugins/@nocobase/plugin-gantt/package.json +++ b/packages/plugins/@nocobase/plugin-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-gantt", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "displayName": "Block: Gantt", "displayName.zh-CN": "区块:甘特图", "description": "Provides Gantt block.", diff --git a/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json b/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json index 03ed8dea3..ee93f70fd 100644 --- a/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json +++ b/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "可视化数据表管理", "description": "An ER diagram-like tool. Currently only the Master database is supported.", "description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/graph-collection-manager", diff --git a/packages/plugins/@nocobase/plugin-iframe-block/package.json b/packages/plugins/@nocobase/plugin-iframe-block/package.json index 115192dad..f2c1c8109 100644 --- a/packages/plugins/@nocobase/plugin-iframe-block/package.json +++ b/packages/plugins/@nocobase/plugin-iframe-block/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "区块:iframe", "description": "Create an iframe block on the page to embed and display external web pages or content.", "description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/block-iframe", diff --git a/packages/plugins/@nocobase/plugin-import/package.json b/packages/plugins/@nocobase/plugin-import/package.json index 193a2a0cc..fc5cc1a6a 100644 --- a/packages/plugins/@nocobase/plugin-import/package.json +++ b/packages/plugins/@nocobase/plugin-import/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "操作:导入记录", "description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.", "description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-import", diff --git a/packages/plugins/@nocobase/plugin-kanban/package.json b/packages/plugins/@nocobase/plugin-kanban/package.json index 989f26f80..1652cdd14 100644 --- a/packages/plugins/@nocobase/plugin-kanban/package.json +++ b/packages/plugins/@nocobase/plugin-kanban/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-kanban", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/block-kanban", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban", diff --git a/packages/plugins/@nocobase/plugin-localization-management/package.json b/packages/plugins/@nocobase/plugin-localization-management/package.json index 14aeff38d..7f099e562 100644 --- a/packages/plugins/@nocobase/plugin-localization-management/package.json +++ b/packages/plugins/@nocobase/plugin-localization-management/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-localization-management", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/localization-management", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management", diff --git a/packages/plugins/@nocobase/plugin-logger/package.json b/packages/plugins/@nocobase/plugin-logger/package.json index a1db455ba..8e2c3e135 100644 --- a/packages/plugins/@nocobase/plugin-logger/package.json +++ b/packages/plugins/@nocobase/plugin-logger/package.json @@ -4,7 +4,7 @@ "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.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/logger", diff --git a/packages/plugins/@nocobase/plugin-map/package.json b/packages/plugins/@nocobase/plugin-map/package.json index 95598cc50..006de43b0 100644 --- a/packages/plugins/@nocobase/plugin-map/package.json +++ b/packages/plugins/@nocobase/plugin-map/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-map", "displayName": "Block: Map", "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.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。", "license": "AGPL-3.0", diff --git a/packages/plugins/@nocobase/plugin-math-formula-field/package.json b/packages/plugins/@nocobase/plugin-math-formula-field/package.json index 142a39875..22c507c21 100644 --- a/packages/plugins/@nocobase/plugin-math-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-math-formula-field/package.json @@ -4,7 +4,7 @@ "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.zh-CN": "一个功能强大的数学公式字段插件,旨在为数据库或数据管理系统提供灵活的数学计算和公式计算功能。它可以与各种数据库系统(如MySQL、PostgreSQL)无缝集成,并提供直观的用户界面来定义和执行数学公式字段。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-mobile-client/package.json b/packages/plugins/@nocobase/plugin-mobile-client/package.json index cb4e5a649..17cb41de5 100644 --- a/packages/plugins/@nocobase/plugin-mobile-client/package.json +++ b/packages/plugins/@nocobase/plugin-mobile-client/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-mobile-client", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/mobile-client", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client", diff --git a/packages/plugins/@nocobase/plugin-mock-collections/package.json b/packages/plugins/@nocobase/plugin-mock-collections/package.json index 58e5d27da..b81d45078 100644 --- a/packages/plugins/@nocobase/plugin-mock-collections/package.json +++ b/packages/plugins/@nocobase/plugin-mock-collections/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-mock-collections", "displayName": "mock-collections", "description": "mock-collections", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "license": "AGPL-3.0", "peerDependencies": { diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/package.json b/packages/plugins/@nocobase/plugin-multi-app-manager/package.json index 1c3501d02..e97d615dd 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/package.json +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "多应用管理器", "description": "Dynamically create multiple apps without separate deployments.", "description.zh-CN": "无需单独部署即可动态创建多个应用。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/multi-app-manager", diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/__tests__/multiple-apps.test.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/__tests__/multiple-apps.test.ts index 738714c88..d18ef82de 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/__tests__/multiple-apps.test.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/__tests__/multiple-apps.test.ts @@ -1,6 +1,6 @@ import { Database } from '@nocobase/database'; import { AppSupervisor, Gateway } from '@nocobase/server'; -import { MockServer, createMockServer } from '@nocobase/test'; +import { createMockServer, MockServer } from '@nocobase/test'; import { uid } from '@nocobase/utils'; import { vi } from 'vitest'; import { PluginMultiAppManager } from '../server'; @@ -22,6 +22,29 @@ describe('multiple apps', () => { 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 () => { const fn = vi.fn(); diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/models/application.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/models/application.ts index 48b1fe389..27dc4983b 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/models/application.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/models/application.ts @@ -1,6 +1,7 @@ import { Model, Transactionable } from '@nocobase/database'; import { Application } from '@nocobase/server'; import { AppOptionsFactory } from '../server'; +import { merge } from '@nocobase/utils'; export interface registerAppOptions extends Transactionable { skipInstall?: boolean; @@ -10,11 +11,12 @@ export interface registerAppOptions extends Transactionable { export class ApplicationModel extends Model { registerToSupervisor(mainApp: Application, options: registerAppOptions) { 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 = { - ...options.appOptionsFactory(appName, mainApp), - ...appOptions, + ...(merge(appOptions, appModelOptions) as object), name: appName, }; diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts index cd1c5675e..3aa6e3299 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts @@ -1,6 +1,5 @@ import { Database, IDatabaseOptions, Transactionable } from '@nocobase/database'; import Application, { AppSupervisor, Gateway, Plugin } from '@nocobase/server'; -import { Mutex } from 'async-mutex'; import lodash from 'lodash'; import path from 'path'; import { ApplicationModel } from '../server'; @@ -125,8 +124,6 @@ export class PluginMultiAppManager extends Plugin { appOptionsFactory: AppOptionsFactory = defaultAppOptionsFactory; subAppUpgradeHandler: SubAppUpgradeHandler = defaultSubAppUpgradeHandle; - private beforeGetApplicationMutex = new Mutex(); - static getDatabaseConfig(app: Application): IDatabaseOptions { let oldConfig = app.options.database instanceof Database @@ -136,6 +133,7 @@ export class PluginMultiAppManager extends Plugin { if (!oldConfig && app.db) { oldConfig = app.db.options; } + return lodash.cloneDeep(lodash.omit(oldConfig, ['migrator'])); } diff --git a/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json b/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json index 00dfc64ae..e40f50911 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json +++ b/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "多应用数据表共享", "description": "", "description.zh-CN": "", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "devDependencies": { "@formily/react": "2.x", diff --git a/packages/plugins/@nocobase/plugin-notifications/package.json b/packages/plugins/@nocobase/plugin-notifications/package.json index 27ecbbf05..9151dc886 100644 --- a/packages/plugins/@nocobase/plugin-notifications/package.json +++ b/packages/plugins/@nocobase/plugin-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-notifications", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "description": "", "license": "AGPL-3.0", "main": "./dist/server/index.js", diff --git a/packages/plugins/@nocobase/plugin-oidc/package.json b/packages/plugins/@nocobase/plugin-oidc/package.json index a35b9c73d..a1d3ea038 100644 --- a/packages/plugins/@nocobase/plugin-oidc/package.json +++ b/packages/plugins/@nocobase/plugin-oidc/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:OIDC", "description": "OIDC (OpenID Connect) authentication.", "description.zh-CN": "通过 OIDC (OpenID Connect) 协议认证身份。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-oidc", diff --git a/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts b/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts index 7cdadd839..40eb78767 100644 --- a/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts +++ b/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts @@ -10,14 +10,17 @@ export const redirect = async (ctx: Context, next: Next) => { const authenticator = search.get('name'); const appName = search.get('app'); const redirect = search.get('redirect') || '/admin'; - let prefix = ''; + let prefix = process.env.APP_PUBLIC_PATH || ''; if (appName && appName !== 'main') { const appSupervisor = AppSupervisor.getInstance(); 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 OIDCAuth; + if (prefix.endsWith('/')) { + prefix = prefix.slice(0, -1); + } try { const { token } = await auth.signIn(); ctx.redirect(`${prefix}${redirect}?authenticator=${authenticator}&token=${token}`); diff --git a/packages/plugins/@nocobase/plugin-saml/package.json b/packages/plugins/@nocobase/plugin-saml/package.json index 39ddb3fd2..ea7c40be2 100644 --- a/packages/plugins/@nocobase/plugin-saml/package.json +++ b/packages/plugins/@nocobase/plugin-saml/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:SAML 2.0", "description": "SAML 2.0 authentication.", "description.zh-CN": "通过 SAML 2.0 协议认证身份。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-saml", diff --git a/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts b/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts index 21f225947..8a1573b15 100644 --- a/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts +++ b/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts @@ -4,18 +4,21 @@ import { SAMLAuth } from '../saml-auth'; export const redirect = async (ctx: Context, next: Next) => { const { authenticator, __appName: appName } = ctx.action.params || {}; - const { RelayState: redirect = '/admin' } = ctx.action.params.values || {}; - let prefix = ''; + const { RelayState: redirect } = ctx.action.params.values || {}; + let prefix = process.env.APP_PUBLIC_PATH || ''; if (appName && appName !== 'main') { const appSupervisor = AppSupervisor.getInstance(); 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 SAMLAuth; + if (prefix.endsWith('/')) { + prefix = prefix.slice(0, -1); + } try { const { token } = await auth.signIn(); - ctx.redirect(`${prefix}${redirect}?authenticator=${authenticator}&token=${token}`); + ctx.redirect(`${prefix}${redirect || '/admin'}?authenticator=${authenticator}&token=${token}`); } catch (error) { ctx.redirect(`${prefix}/signin?authenticator=${authenticator}&error=${error.message}&redirect=${redirect}`); } diff --git a/packages/plugins/@nocobase/plugin-sample-hello/package.json b/packages/plugins/@nocobase/plugin-sample-hello/package.json index 2746508c5..cd30e46bb 100644 --- a/packages/plugins/@nocobase/plugin-sample-hello/package.json +++ b/packages/plugins/@nocobase/plugin-sample-hello/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-sample-hello", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "displayName": "Hello", "displayName.zh-CN": "Hello", diff --git a/packages/plugins/@nocobase/plugin-sequence-field/package.json b/packages/plugins/@nocobase/plugin-sequence-field/package.json index dfb179dc8..0f5ef69da 100644 --- a/packages/plugins/@nocobase/plugin-sequence-field/package.json +++ b/packages/plugins/@nocobase/plugin-sequence-field/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数据表字段:自动编码", "description": "Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.", "description.zh-CN": "根据配置的规则自动生成编码,支持日期、数字、文本的组合。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-sequence", diff --git a/packages/plugins/@nocobase/plugin-sms-auth/package.json b/packages/plugins/@nocobase/plugin-sms-auth/package.json index 766aa4cd2..e11b97201 100644 --- a/packages/plugins/@nocobase/plugin-sms-auth/package.json +++ b/packages/plugins/@nocobase/plugin-sms-auth/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:短信", "description": "SMS authentication.", "description.zh-CN": "通过短信验证码认证身份。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-sms", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms", diff --git a/packages/plugins/@nocobase/plugin-snapshot-field/package.json b/packages/plugins/@nocobase/plugin-snapshot-field/package.json index 70eeb5775..9ddc00e30 100644 --- a/packages/plugins/@nocobase/plugin-snapshot-field/package.json +++ b/packages/plugins/@nocobase/plugin-snapshot-field/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数据表字段:关系快照", "description": "When adding a new record, create a snapshot for its relational record and save in the new record. The snapshot will not be updated when the relational record is updated.", "description.zh-CN": "在添加数据时,为它的关系数据创建快照,并保存在当前的数据中。关系数据更新时,快照不会更新。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-snapshot", diff --git a/packages/plugins/@nocobase/plugin-system-settings/package.json b/packages/plugins/@nocobase/plugin-system-settings/package.json index 7d2acf875..a460762fa 100644 --- a/packages/plugins/@nocobase/plugin-system-settings/package.json +++ b/packages/plugins/@nocobase/plugin-system-settings/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "系统设置", "description": "Used to adjust the system title, logo, language, etc.", "description.zh-CN": "用于调整系统的标题、LOGO、语言等。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/system-settings", diff --git a/packages/plugins/@nocobase/plugin-theme-editor/package.json b/packages/plugins/@nocobase/plugin-theme-editor/package.json index 1d203ec70..d7db8ca29 100644 --- a/packages/plugins/@nocobase/plugin-theme-editor/package.json +++ b/packages/plugins/@nocobase/plugin-theme-editor/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-theme-editor", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/theme-editor", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/theme-editor", diff --git a/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json b/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json index 1ea50b1eb..af11e2790 100644 --- a/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json +++ b/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "路由管理", "description": "manage the routes of nocobase", "description.zh-CN": "管理页面路由。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json b/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json index 0dc856b97..11eb89dae 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "UI schema 存储服务", "description": "Provides centralized UI schema storage service.", "description.zh-CN": "提供中心化的 UI schema 存储服务。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/ui-schema-storage", diff --git a/packages/plugins/@nocobase/plugin-users/package.json b/packages/plugins/@nocobase/plugin-users/package.json index 29820721c..c543155f8 100644 --- a/packages/plugins/@nocobase/plugin-users/package.json +++ b/packages/plugins/@nocobase/plugin-users/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "用户", "description": "Provides basic user model, as well as created by and updated by fields.", "description.zh-CN": "提供了基础的用户模型,以及创建人和最后更新人字段。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/users", diff --git a/packages/plugins/@nocobase/plugin-users/src/server/__tests__/model.test.ts b/packages/plugins/@nocobase/plugin-users/src/server/__tests__/model.test.ts new file mode 100644 index 000000000..fb7317af9 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-users/src/server/__tests__/model.test.ts @@ -0,0 +1,27 @@ +import Database from '@nocobase/database'; +import { createMockServer, MockServer } from '@nocobase/test'; +import { UserModel } from '../models/UserModel'; + +describe('models', () => { + let app: MockServer; + let db: Database; + + beforeEach(async () => { + app = await createMockServer({ + plugins: ['auth', 'users'], + }); + db = app.db; + }); + + afterEach(async () => { + await app.destroy(); + }); + + it('model registeration', async () => { + const model = db.getModel('users'); + const u1 = model.build({ nickname: 'test', password: '123' }); + expect(u1).toBeInstanceOf(UserModel); + const n = u1.desensitize(); + expect(n.password).toBeUndefined(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-users/src/server/__tests__/role-users.test.ts b/packages/plugins/@nocobase/plugin-users/src/server/__tests__/role-users.test.ts new file mode 100644 index 000000000..5bb0589ab --- /dev/null +++ b/packages/plugins/@nocobase/plugin-users/src/server/__tests__/role-users.test.ts @@ -0,0 +1,56 @@ +import { Database, Repository } from '@nocobase/database'; +import { MockServer, createMockServer } from '@nocobase/test'; + +describe('actions', () => { + let app: MockServer; + let db: Database; + let repo: Repository; + let agent: any; + + beforeAll(async () => { + app = await createMockServer({ + plugins: ['acl', 'users', 'data-source-manager'], + }); + db = app.db; + repo = db.getRepository('users'); + agent = app.agent(); + }); + + afterAll(async () => { + await app.destroy(); + }); + + it('should list users exclude role', async () => { + const res = await agent.resource('users').listExcludeRole({ + roleName: ['admin'], + }); + expect(res.status).toBe(200); + expect(res.body.data.length).toBe(0); + }); + + it('should list users exclude role with filter', async () => { + let res = await agent.resource('users').listExcludeRole({ + roleName: ['test'], + }); + expect(res.status).toBe(200); + expect(res.body.data.length).toBe(1); + + res = await agent.resource('users').listExcludeRole({ + roleName: ['test'], + filter: { + id: 1, + }, + }); + expect(res.status).toBe(200); + expect(res.body.data.length).toBe(1); + + res = await agent.resource('users').listExcludeRole({ + roleName: ['test'], + filter: { + id: 2, + }, + }); + expect(res.status).toBe(200); + expect(res.body.data.length).toBe(0); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts b/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts index fa1aadc7b..a843ce57c 100644 --- a/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts +++ b/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts @@ -25,19 +25,21 @@ export const listExcludeRole = async (ctx: Context, next: Next) => { }, }); const userIds = users.map((user: { id: number }) => user.id); + if (userIds.length) { + ctx.action.mergeParams({ + filter: { + id: { + $notIn: userIds, + }, + }, + }); + } + const { filter } = ctx.action.params; const [rows, count] = await repo.findAndCount({ context: ctx, offset: (page - 1) * pageSize, limit: pageSize, - // Ensure memberIds is not empty to resolve strange issue: - // notIn: [] will be translated to "WHERE id IS NULL" - filter: userIds.length - ? { - id: { - $notIn: userIds, - }, - } - : {}, + filter, }); ctx.body = { count, diff --git a/packages/plugins/@nocobase/plugin-users/src/server/models/UserModel.ts b/packages/plugins/@nocobase/plugin-users/src/server/models/UserModel.ts new file mode 100644 index 000000000..93575c9dc --- /dev/null +++ b/packages/plugins/@nocobase/plugin-users/src/server/models/UserModel.ts @@ -0,0 +1,15 @@ +import { Model } from '@nocobase/database'; + +export class UserModel extends Model { + desensitize() { + const { fields } = (this.constructor as typeof UserModel).collection; + const result = (this.constructor as typeof UserModel).build({}, { isNewRecord: this.isNewRecord }); + for (const [name, value] of Object.entries(this.get())) { + const field = fields.get(name); + if (field && !field.options.hidden) { + result.set(name, value); + } + } + return result; + } +} diff --git a/packages/plugins/@nocobase/plugin-users/src/server/server.ts b/packages/plugins/@nocobase/plugin-users/src/server/server.ts index 359caef6e..402bfa288 100644 --- a/packages/plugins/@nocobase/plugin-users/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-users/src/server/server.ts @@ -5,9 +5,13 @@ import { resolve } from 'path'; import * as actions from './actions/users'; import { Cache } from '@nocobase/cache'; +import { UserModel } from './models/UserModel'; export default class PluginUsersServer extends Plugin { async beforeLoad() { + this.db.registerModels({ + UserModel, + }); this.db.registerOperators({ $isCurrentUser(_, ctx) { return { @@ -116,7 +120,6 @@ export default class PluginUsersServer extends Plugin { async load() { await this.importCollections(resolve(__dirname, 'collections')); - this.db.addMigrations({ namespace: 'users', directory: resolve(__dirname, 'migrations'), diff --git a/packages/plugins/@nocobase/plugin-verification/package.json b/packages/plugins/@nocobase/plugin-verification/package.json index 2244dfb1e..5cec9c45d 100644 --- a/packages/plugins/@nocobase/plugin-verification/package.json +++ b/packages/plugins/@nocobase/plugin-verification/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "验证码", "description": "verification setting.", "description.zh-CN": "验证码配置。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/verification", diff --git a/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json b/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json index 34afa5183..22265bc85 100644 --- a/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:数据操作触发器", "description": "Bind action buttons to trigger workflow events when clicked.", "description.zh-CN": "可对数据操作按钮绑定,在点击后触发对应的工作流事件。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/plugins/workflow-action-trigger", diff --git a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts index d05b49876..b113924b0 100644 --- a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts +++ b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts @@ -57,8 +57,9 @@ export default class extends Trigger { const { triggerWorkflows = '', values } = context.action.params; const { currentUser, currentRole } = context.state; + const { model: UserModel } = this.workflow.db.getCollection('users'); const userInfo = { - user: toJSON(currentUser), + user: UserModel.build(currentUser).desensitize(), roleName: currentRole, }; diff --git a/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json b/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json index 863b14613..aab70255c 100644 --- a/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:聚合查询节点", "description": "Used to aggregate data against the database in workflow, such as: statistics, sum, average, etc.", "description.zh-CN": "可用于在工作流中对数据库进行聚合查询,如:统计数量、求和、平均值等。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-aggregate", diff --git a/packages/plugins/@nocobase/plugin-workflow-delay/package.json b/packages/plugins/@nocobase/plugin-workflow-delay/package.json index bcd0286f4..53bb4333d 100644 --- a/packages/plugins/@nocobase/plugin-workflow-delay/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-delay/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:延时节点", "description": "Could be used in workflow parallel branch for waiting other branches.", "description.zh-CN": "可用于工作流并行分支中等待其他分支执行完成。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-delay", diff --git a/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json b/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json index 154153ac2..17f3a90c0 100644 --- a/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:动态表达式计算节点", "description": "Useful plugin for doing dynamic calculation based on expression collection records in workflow.", "description.zh-CN": "用于在工作流中进行基于数据行的动态表达式计算。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-dynamic-calculation", diff --git a/packages/plugins/@nocobase/plugin-workflow-loop/package.json b/packages/plugins/@nocobase/plugin-workflow-loop/package.json index 80422aa30..3b3440a32 100644 --- a/packages/plugins/@nocobase/plugin-workflow-loop/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-loop/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:循环节点", "description": "Used to repeat the sub-process processing of each value in an array, and can also be used for fixed times of sub-process processing.", "description.zh-CN": "用于对一个数组中的每个值进行重复的子流程处理,也可用于固定次数的重复子流程处理。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-loop", diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/package.json b/packages/plugins/@nocobase/plugin-workflow-manual/package.json index 2143afb72..3b1ebbb51 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-manual/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:人工处理节点", "description": "Could be used for workflows which some of decisions are made by users.", "description.zh-CN": "用于人工控制部分决策的流程。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-manual", diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/package.json b/packages/plugins/@nocobase/plugin-workflow-parallel/package.json index 36929071f..3834ab9e8 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:并行分支节点", "description": "Could be used for parallel execution of branch processes in the workflow.", "description.zh-CN": "用于在工作流中需要并行执行的分支流程。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-parallel", diff --git a/packages/plugins/@nocobase/plugin-workflow-request/package.json b/packages/plugins/@nocobase/plugin-workflow-request/package.json index 9e685d7f4..c2e60f30b 100644 --- a/packages/plugins/@nocobase/plugin-workflow-request/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-request/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:HTTP 请求节点", "description": "Send HTTP requests to any HTTP service for data interaction in workflow.", "description.zh-CN": "可用于在工作流中向任意 HTTP 服务发送请求,进行数据交互。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-request", diff --git a/packages/plugins/@nocobase/plugin-workflow-sql/package.json b/packages/plugins/@nocobase/plugin-workflow-sql/package.json index 8991725ae..466a83d89 100644 --- a/packages/plugins/@nocobase/plugin-workflow-sql/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-sql/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:SQL 节点", "description": "Execute SQL statements in workflow.", "description.zh-CN": "可用于在工作流中对数据库执行任意 SQL 语句。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-sql", diff --git a/packages/plugins/@nocobase/plugin-workflow-test/package.json b/packages/plugins/@nocobase/plugin-workflow-test/package.json index 679f97005..da4ddf5df 100644 --- a/packages/plugins/@nocobase/plugin-workflow-test/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-test/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-workflow-test", "displayName": "Workflow: test kit", "displayName.zh-CN": "工作流:测试工具包", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "dist/server/index.js", "types": "./dist/server/index.d.ts", diff --git a/packages/plugins/@nocobase/plugin-workflow/package.json b/packages/plugins/@nocobase/plugin-workflow/package.json index 341cd4ac1..437d230b8 100644 --- a/packages/plugins/@nocobase/plugin-workflow/package.json +++ b/packages/plugins/@nocobase/plugin-workflow/package.json @@ -4,13 +4,13 @@ "displayName.zh-CN": "工作流", "description": "A powerful BPM tool that provides foundational support for business automation, with the capability to extend unlimited triggers and nodes.", "description.zh-CN": "一个强大的 BPM 工具,为业务自动化提供基础支持,并且可任意扩展更多的触发器和节点。", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/workflow", "dependencies": { - "@nocobase/plugin-workflow-test": "0.20.0-alpha.14" + "@nocobase/plugin-workflow-test": "0.20.0-alpha.15" }, "devDependencies": { "@ant-design/icons": "5.x", diff --git a/packages/presets/nocobase/package.json b/packages/presets/nocobase/package.json index 50aed5af1..29ace686b 100644 --- a/packages/presets/nocobase/package.json +++ b/packages/presets/nocobase/package.json @@ -1,66 +1,66 @@ { "name": "@nocobase/preset-nocobase", - "version": "0.20.0-alpha.14", + "version": "0.20.0-alpha.15", "license": "AGPL-3.0", "main": "./lib/server/index.js", "dependencies": { "@formily/json-schema": "2.x", - "@nocobase/plugin-acl": "0.20.0-alpha.14", - "@nocobase/plugin-action-bulk-edit": "0.20.0-alpha.14", - "@nocobase/plugin-action-bulk-update": "0.20.0-alpha.14", - "@nocobase/plugin-action-duplicate": "0.20.0-alpha.14", - "@nocobase/plugin-action-print": "0.20.0-alpha.14", - "@nocobase/plugin-api-doc": "0.20.0-alpha.14", - "@nocobase/plugin-api-keys": "0.20.0-alpha.14", - "@nocobase/plugin-audit-logs": "0.20.0-alpha.14", - "@nocobase/plugin-auth": "0.20.0-alpha.14", - "@nocobase/plugin-backup-restore": "0.20.0-alpha.14", - "@nocobase/plugin-calendar": "0.20.0-alpha.14", - "@nocobase/plugin-cas": "0.20.0-alpha.14", - "@nocobase/plugin-charts": "0.20.0-alpha.14", - "@nocobase/plugin-china-region": "0.20.0-alpha.14", - "@nocobase/plugin-client": "0.20.0-alpha.14", - "@nocobase/plugin-collection-manager": "0.20.0-alpha.14", - "@nocobase/plugin-custom-request": "0.20.0-alpha.14", - "@nocobase/plugin-data-source-manager": "0.20.0-alpha.14", - "@nocobase/plugin-data-visualization": "0.20.0-alpha.14", - "@nocobase/plugin-error-handler": "0.20.0-alpha.14", - "@nocobase/plugin-export": "0.20.0-alpha.14", - "@nocobase/plugin-file-manager": "0.20.0-alpha.14", - "@nocobase/plugin-formula-field": "0.20.0-alpha.14", - "@nocobase/plugin-gantt": "0.20.0-alpha.14", - "@nocobase/plugin-graph-collection-manager": "0.20.0-alpha.14", - "@nocobase/plugin-iframe-block": "0.20.0-alpha.14", - "@nocobase/plugin-import": "0.20.0-alpha.14", - "@nocobase/plugin-kanban": "0.20.0-alpha.14", - "@nocobase/plugin-localization-management": "0.20.0-alpha.14", - "@nocobase/plugin-logger": "0.20.0-alpha.14", - "@nocobase/plugin-map": "0.20.0-alpha.14", - "@nocobase/plugin-mobile-client": "0.20.0-alpha.14", - "@nocobase/plugin-mock-collections": "0.20.0-alpha.14", - "@nocobase/plugin-multi-app-manager": "0.20.0-alpha.14", - "@nocobase/plugin-multi-app-share-collection": "0.20.0-alpha.14", - "@nocobase/plugin-oidc": "0.20.0-alpha.14", - "@nocobase/plugin-saml": "0.20.0-alpha.14", - "@nocobase/plugin-sequence-field": "0.20.0-alpha.14", - "@nocobase/plugin-sms-auth": "0.20.0-alpha.14", - "@nocobase/plugin-snapshot-field": "0.20.0-alpha.14", - "@nocobase/plugin-system-settings": "0.20.0-alpha.14", - "@nocobase/plugin-theme-editor": "0.20.0-alpha.14", - "@nocobase/plugin-ui-schema-storage": "0.20.0-alpha.14", - "@nocobase/plugin-users": "0.20.0-alpha.14", - "@nocobase/plugin-verification": "0.20.0-alpha.14", - "@nocobase/plugin-workflow": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-action-trigger": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-aggregate": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-delay": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-dynamic-calculation": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-loop": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-manual": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-parallel": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-request": "0.20.0-alpha.14", - "@nocobase/plugin-workflow-sql": "0.20.0-alpha.14", - "@nocobase/server": "0.20.0-alpha.14", + "@nocobase/plugin-acl": "0.20.0-alpha.15", + "@nocobase/plugin-action-bulk-edit": "0.20.0-alpha.15", + "@nocobase/plugin-action-bulk-update": "0.20.0-alpha.15", + "@nocobase/plugin-action-duplicate": "0.20.0-alpha.15", + "@nocobase/plugin-action-print": "0.20.0-alpha.15", + "@nocobase/plugin-api-doc": "0.20.0-alpha.15", + "@nocobase/plugin-api-keys": "0.20.0-alpha.15", + "@nocobase/plugin-audit-logs": "0.20.0-alpha.15", + "@nocobase/plugin-auth": "0.20.0-alpha.15", + "@nocobase/plugin-backup-restore": "0.20.0-alpha.15", + "@nocobase/plugin-calendar": "0.20.0-alpha.15", + "@nocobase/plugin-cas": "0.20.0-alpha.15", + "@nocobase/plugin-charts": "0.20.0-alpha.15", + "@nocobase/plugin-china-region": "0.20.0-alpha.15", + "@nocobase/plugin-client": "0.20.0-alpha.15", + "@nocobase/plugin-collection-manager": "0.20.0-alpha.15", + "@nocobase/plugin-custom-request": "0.20.0-alpha.15", + "@nocobase/plugin-data-source-manager": "0.20.0-alpha.15", + "@nocobase/plugin-data-visualization": "0.20.0-alpha.15", + "@nocobase/plugin-error-handler": "0.20.0-alpha.15", + "@nocobase/plugin-export": "0.20.0-alpha.15", + "@nocobase/plugin-file-manager": "0.20.0-alpha.15", + "@nocobase/plugin-formula-field": "0.20.0-alpha.15", + "@nocobase/plugin-gantt": "0.20.0-alpha.15", + "@nocobase/plugin-graph-collection-manager": "0.20.0-alpha.15", + "@nocobase/plugin-iframe-block": "0.20.0-alpha.15", + "@nocobase/plugin-import": "0.20.0-alpha.15", + "@nocobase/plugin-kanban": "0.20.0-alpha.15", + "@nocobase/plugin-localization-management": "0.20.0-alpha.15", + "@nocobase/plugin-logger": "0.20.0-alpha.15", + "@nocobase/plugin-map": "0.20.0-alpha.15", + "@nocobase/plugin-mobile-client": "0.20.0-alpha.15", + "@nocobase/plugin-mock-collections": "0.20.0-alpha.15", + "@nocobase/plugin-multi-app-manager": "0.20.0-alpha.15", + "@nocobase/plugin-multi-app-share-collection": "0.20.0-alpha.15", + "@nocobase/plugin-oidc": "0.20.0-alpha.15", + "@nocobase/plugin-saml": "0.20.0-alpha.15", + "@nocobase/plugin-sequence-field": "0.20.0-alpha.15", + "@nocobase/plugin-sms-auth": "0.20.0-alpha.15", + "@nocobase/plugin-snapshot-field": "0.20.0-alpha.15", + "@nocobase/plugin-system-settings": "0.20.0-alpha.15", + "@nocobase/plugin-theme-editor": "0.20.0-alpha.15", + "@nocobase/plugin-ui-schema-storage": "0.20.0-alpha.15", + "@nocobase/plugin-users": "0.20.0-alpha.15", + "@nocobase/plugin-verification": "0.20.0-alpha.15", + "@nocobase/plugin-workflow": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-action-trigger": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-aggregate": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-delay": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-dynamic-calculation": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-loop": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-manual": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-parallel": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-request": "0.20.0-alpha.15", + "@nocobase/plugin-workflow-sql": "0.20.0-alpha.15", + "@nocobase/server": "0.20.0-alpha.15", "cronstrue": "^2.11.0" }, "repository": {