fix: merge main and fix conflict

This commit is contained in:
aaaaaajie 2025-04-24 13:05:07 +08:00
commit 8f7da2e5cb
125 changed files with 2704 additions and 641 deletions

View File

@ -5,6 +5,73 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.6.23](https://github.com/nocobase/nocobase/compare/v1.6.22...v1.6.23) - 2025-04-23
### 🚀 Improvements
- **[cli]** Optimize internal logic of the `nocobase upgrade` command ([#6754](https://github.com/nocobase/nocobase/pull/6754)) by @chenos
- **[Template print]** Replaced datasource action control with client role-based access control. by @sheldon66
### 🐛 Bug Fixes
- **[cli]** Auto-update package.json on upgrade ([#6747](https://github.com/nocobase/nocobase/pull/6747)) by @chenos
- **[client]**
- missing filter for already associated data when adding association data ([#6750](https://github.com/nocobase/nocobase/pull/6750)) by @katherinehhh
- tree table 'Add Child' button linkage rule missing 'current record' ([#6752](https://github.com/nocobase/nocobase/pull/6752)) by @katherinehhh
- **[Action: Import records]** Fix the import and export exceptions that occur when setting field permissions. ([#6677](https://github.com/nocobase/nocobase/pull/6677)) by @aaaaaajie
- **[Block: Gantt]** gantt chart block overlapping months in calendar header for month view ([#6753](https://github.com/nocobase/nocobase/pull/6753)) by @katherinehhh
- **[Action: Export records Pro]**
- pro export button losing filter parameters after sorting table column by @katherinehhh
- Fix the import and export exceptions that occur when setting field permissions. by @aaaaaajie
- **[File storage: S3(Pro)]** Fix response data of uploaded file by @mytharcher
- **[Workflow: Approval]** Fix preload association fields for records by @mytharcher
## [v1.6.22](https://github.com/nocobase/nocobase/compare/v1.6.21...v1.6.22) - 2025-04-22
### 🚀 Improvements
- **[create-nocobase-app]** Upgrade dependencies and remove SQLite support ([#6708](https://github.com/nocobase/nocobase/pull/6708)) by @chenos
- **[File manager]** Expose utils API ([#6705](https://github.com/nocobase/nocobase/pull/6705)) by @mytharcher
- **[Workflow]** Add date types to variable types set ([#6717](https://github.com/nocobase/nocobase/pull/6717)) by @mytharcher
### 🐛 Bug Fixes
- **[client]**
- The problem of mobile top navigation bar icons being difficult to delete ([#6734](https://github.com/nocobase/nocobase/pull/6734)) by @zhangzhonghe
- After connecting through a foreign key, clicking to trigger filtering results in empty filter conditions ([#6634](https://github.com/nocobase/nocobase/pull/6634)) by @zhangzhonghe
- picker switching issue in date field of filter button ([#6695](https://github.com/nocobase/nocobase/pull/6695)) by @katherinehhh
- The issue of the collapse button in the left menu being obscured by the workflow pop-up window ([#6733](https://github.com/nocobase/nocobase/pull/6733)) by @zhangzhonghe
- missing action option constraints when reopening linkage rules ([#6723](https://github.com/nocobase/nocobase/pull/6723)) by @katherinehhh
- export button shown without export permission ([#6689](https://github.com/nocobase/nocobase/pull/6689)) by @katherinehhh
- Required fields hidden by linkage rules should not affect form submission ([#6709](https://github.com/nocobase/nocobase/pull/6709)) by @zhangzhonghe
- **[server]** appVersion incorrectly generated by create-migration ([#6740](https://github.com/nocobase/nocobase/pull/6740)) by @chenos
- **[build]** Fix error thrown in tar command ([#6722](https://github.com/nocobase/nocobase/pull/6722)) by @mytharcher
- **[Workflow]** Fix error thrown when execute schedule event in subflow ([#6721](https://github.com/nocobase/nocobase/pull/6721)) by @mytharcher
- **[Workflow: Custom action event]** Support to execute in multiple records mode by @mytharcher
- **[File storage: S3(Pro)]** Add multer make logic for server-side upload by @mytharcher
## [v1.6.21](https://github.com/nocobase/nocobase/compare/v1.6.20...v1.6.21) - 2025-04-17 ## [v1.6.21](https://github.com/nocobase/nocobase/compare/v1.6.20...v1.6.21) - 2025-04-17
### 🚀 Improvements ### 🚀 Improvements

View File

@ -5,6 +5,73 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。 并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
## [v1.6.23](https://github.com/nocobase/nocobase/compare/v1.6.22...v1.6.23) - 2025-04-23
### 🚀 优化
- **[cli]** 优化 `nocobase upgrade` 命令的内部实现逻辑 ([#6754](https://github.com/nocobase/nocobase/pull/6754)) by @chenos
- **[模板打印]** 用客户端角色访问控制替换了数据源操作权限控制。 by @sheldon66
### 🐛 修复
- **[cli]** 升级时自动更新项目的 package.json ([#6747](https://github.com/nocobase/nocobase/pull/6747)) by @chenos
- **[client]**
- 添加关联表格时未过滤已关联的数据 ([#6750](https://github.com/nocobase/nocobase/pull/6750)) by @katherinehhh
- 树表格中添加子记录按钮的联动规则缺失「当前记录」变量 ([#6752](https://github.com/nocobase/nocobase/pull/6752)) by @katherinehhh
- **[操作:导入记录]** 修复设置字段权限时出现的导入导出异常。 ([#6677](https://github.com/nocobase/nocobase/pull/6677)) by @aaaaaajie
- **[区块:甘特图]** 甘特图区块设置月份视图时,日历头部月份重叠 ([#6753](https://github.com/nocobase/nocobase/pull/6753)) by @katherinehhh
- **[操作:导出记录 Pro]**
- pro导出按钮在点击表格排序后丢失过滤参数 by @katherinehhh
- 修复设置字段权限时出现的导入导出异常。 by @aaaaaajie
- **[文件存储S3 (Pro)]** 修复已上传文件的响应数据 by @mytharcher
- **[工作流:审批]** 修复预加载审批记录数据的关系字段 by @mytharcher
## [v1.6.22](https://github.com/nocobase/nocobase/compare/v1.6.21...v1.6.22) - 2025-04-22
### 🚀 优化
- **[create-nocobase-app]** 更新依赖,移除 SQLite 支持 ([#6708](https://github.com/nocobase/nocobase/pull/6708)) by @chenos
- **[文件管理器]** 暴露公共包 API ([#6705](https://github.com/nocobase/nocobase/pull/6705)) by @mytharcher
- **[工作流]** 为变量的类型集合增加日期相关类型 ([#6717](https://github.com/nocobase/nocobase/pull/6717)) by @mytharcher
### 🐛 修复
- **[client]**
- 移动端顶部的导航栏图标很难被删除的问题 ([#6734](https://github.com/nocobase/nocobase/pull/6734)) by @zhangzhonghe
- 通过外键连接后,点击触发筛选,筛选条件为空 ([#6634](https://github.com/nocobase/nocobase/pull/6634)) by @zhangzhonghe
- 筛选按钮中日期字段切换picker 异常 ([#6695](https://github.com/nocobase/nocobase/pull/6695)) by @katherinehhh
- 左侧菜单的收起按钮会被绑定工作流弹窗遮挡的问题 ([#6733](https://github.com/nocobase/nocobase/pull/6733)) by @zhangzhonghe
- 重新打开联动规则时缺少操作选项约束 ([#6723](https://github.com/nocobase/nocobase/pull/6723)) by @katherinehhh
- 未设置导出权限时仍显示导出按钮 ([#6689](https://github.com/nocobase/nocobase/pull/6689)) by @katherinehhh
- 被联动规则隐藏的必填字段,不应该影响表单的提交 ([#6709](https://github.com/nocobase/nocobase/pull/6709)) by @zhangzhonghe
- **[server]** create-migration 命令生成的 appVersion 不准确 ([#6740](https://github.com/nocobase/nocobase/pull/6740)) by @chenos
- **[build]** 修复 tar 命令报错的问题 ([#6722](https://github.com/nocobase/nocobase/pull/6722)) by @mytharcher
- **[工作流]** 修复子流程执行定时任务报错的问题 ([#6721](https://github.com/nocobase/nocobase/pull/6721)) by @mytharcher
- **[工作流:自定义操作事件]** 支持多行记录模式的手动执行 by @mytharcher
- **[文件存储S3 (Pro)]** 增加 multer 逻辑用于服务端上传 by @mytharcher
## [v1.6.21](https://github.com/nocobase/nocobase/compare/v1.6.20...v1.6.21) - 2025-04-17 ## [v1.6.21](https://github.com/nocobase/nocobase/compare/v1.6.20...v1.6.21) - 2025-04-17
### 🚀 优化 ### 🚀 优化

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.21", "version": "1.6.23",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"npmClientArgs": ["--ignore-engines"], "npmClientArgs": ["--ignore-engines"],

View File

@ -1,13 +1,13 @@
{ {
"name": "@nocobase/acl", "name": "@nocobase/acl",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"dependencies": { "dependencies": {
"@nocobase/resourcer": "1.6.21", "@nocobase/resourcer": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"minimatch": "^5.1.1" "minimatch": "^5.1.1"
}, },
"repository": { "repository": {

View File

@ -1,14 +1,14 @@
{ {
"name": "@nocobase/actions", "name": "@nocobase/actions",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"dependencies": { "dependencies": {
"@nocobase/cache": "1.6.21", "@nocobase/cache": "1.6.23",
"@nocobase/database": "1.6.21", "@nocobase/database": "1.6.23",
"@nocobase/resourcer": "1.6.21" "@nocobase/resourcer": "1.6.23"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -1,17 +1,17 @@
{ {
"name": "@nocobase/app", "name": "@nocobase/app",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"dependencies": { "dependencies": {
"@nocobase/database": "1.6.21", "@nocobase/database": "1.6.23",
"@nocobase/preset-nocobase": "1.6.21", "@nocobase/preset-nocobase": "1.6.23",
"@nocobase/server": "1.6.21" "@nocobase/server": "1.6.23"
}, },
"devDependencies": { "devDependencies": {
"@nocobase/client": "1.6.21" "@nocobase/client": "1.6.23"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -1,16 +1,16 @@
{ {
"name": "@nocobase/auth", "name": "@nocobase/auth",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"dependencies": { "dependencies": {
"@nocobase/actions": "1.6.21", "@nocobase/actions": "1.6.23",
"@nocobase/cache": "1.6.21", "@nocobase/cache": "1.6.23",
"@nocobase/database": "1.6.21", "@nocobase/database": "1.6.23",
"@nocobase/resourcer": "1.6.21", "@nocobase/resourcer": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"@types/jsonwebtoken": "^9.0.9", "@types/jsonwebtoken": "^9.0.9",
"jsonwebtoken": "^9.0.2" "jsonwebtoken": "^9.0.2"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/build", "name": "@nocobase/build",
"version": "1.6.21", "version": "1.6.23",
"description": "Library build tool based on rollup.", "description": "Library build tool based on rollup.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/cache", "name": "@nocobase/cache",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/cli", "name": "@nocobase/cli",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./src/index.js", "main": "./src/index.js",
@ -8,23 +8,25 @@
"nocobase": "./bin/index.js" "nocobase": "./bin/index.js"
}, },
"dependencies": { "dependencies": {
"@nocobase/app": "1.6.21", "@nocobase/app": "1.6.23",
"@types/fs-extra": "^11.0.1", "@types/fs-extra": "^11.0.1",
"@umijs/utils": "3.5.20", "@umijs/utils": "3.5.20",
"chalk": "^4.1.1", "chalk": "^4.1.1",
"commander": "^9.2.0", "commander": "^9.2.0",
"deepmerge": "^4.3.1",
"dotenv": "^16.0.0", "dotenv": "^16.0.0",
"execa": "^5.1.1", "execa": "^5.1.1",
"fast-glob": "^3.3.1", "fast-glob": "^3.3.1",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"p-all": "3.0.0", "p-all": "3.0.0",
"pm2": "^6.0.5",
"portfinder": "^1.0.28", "portfinder": "^1.0.28",
"tree-kill": "^1.2.2",
"tar": "^7.4.3", "tar": "^7.4.3",
"tree-kill": "^1.2.2",
"tsx": "^4.19.0" "tsx": "^4.19.0"
}, },
"devDependencies": { "devDependencies": {
"@nocobase/devtools": "1.6.21" "@nocobase/devtools": "1.6.23"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -30,6 +30,7 @@ module.exports = (cli) => {
require('./test')(cli); require('./test')(cli);
require('./test-coverage')(cli); require('./test-coverage')(cli);
require('./umi')(cli); require('./umi')(cli);
require('./update-deps')(cli);
require('./upgrade')(cli); require('./upgrade')(cli);
require('./postinstall')(cli); require('./postinstall')(cli);
require('./pkg')(cli); require('./pkg')(cli);

View File

@ -0,0 +1,71 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
const chalk = require('chalk');
const { Command } = require('commander');
const { resolve } = require('path');
const { run, promptForTs, runAppCommand, hasCorePackages, downloadPro, hasTsNode, checkDBDialect } = require('../util');
const { existsSync, rmSync } = require('fs');
const { readJSON, writeJSON } = require('fs-extra');
const deepmerge = require('deepmerge');
const rmAppDir = () => {
// If ts-node is not installed, do not do the following
const appDevDir = resolve(process.cwd(), './storage/.app-dev');
if (existsSync(appDevDir)) {
rmSync(appDevDir, { recursive: true, force: true });
}
};
/**
*
* @param {Command} cli
*/
module.exports = (cli) => {
cli
.command('update-deps')
.option('--force')
.allowUnknownOption()
.action(async (options) => {
if (hasCorePackages() || !hasTsNode()) {
await downloadPro();
return;
}
const pkg = require('../../package.json');
let distTag = 'latest';
if (pkg.version.includes('alpha')) {
distTag = 'alpha';
} else if (pkg.version.includes('beta')) {
distTag = 'beta';
}
const { stdout } = await run('npm', ['info', `@nocobase/cli@${distTag}`, 'version'], {
stdio: 'pipe',
});
if (!options.force && pkg.version === stdout) {
await downloadPro();
rmAppDir();
return;
}
const descPath = resolve(process.cwd(), 'package.json');
const descJson = await readJSON(descPath, 'utf8');
const sourcePath = resolve(__dirname, '../../templates/create-app-package.json');
const sourceJson = await readJSON(sourcePath, 'utf8');
if (descJson['dependencies']?.['@nocobase/cli']) {
descJson['dependencies']['@nocobase/cli'] = stdout;
}
if (descJson['devDependencies']?.['@nocobase/devtools']) {
descJson['devDependencies']['@nocobase/devtools'] = stdout;
}
const json = deepmerge(descJson, sourceJson);
await writeJSON(descPath, json, { spaces: 2, encoding: 'utf8' });
await run('yarn', ['install']);
await downloadPro();
rmAppDir();
});
};

View File

@ -12,13 +12,23 @@ const { Command } = require('commander');
const { resolve } = require('path'); const { resolve } = require('path');
const { run, promptForTs, runAppCommand, hasCorePackages, downloadPro, hasTsNode, checkDBDialect } = require('../util'); const { run, promptForTs, runAppCommand, hasCorePackages, downloadPro, hasTsNode, checkDBDialect } = require('../util');
const { existsSync, rmSync } = require('fs'); const { existsSync, rmSync } = require('fs');
const { readJSON, writeJSON } = require('fs-extra');
const deepmerge = require('deepmerge');
async function updatePackage() {
const sourcePath = resolve(__dirname, '../../templates/create-app-package.json');
const descPath = resolve(process.cwd(), 'package.json');
const sourceJson = await readJSON(sourcePath, 'utf8');
const descJson = await readJSON(descPath, 'utf8');
const json = deepmerge(descJson, sourceJson);
await writeJSON(descPath, json, { spaces: 2, encoding: 'utf8' });
}
/** /**
* *
* @param {Command} cli * @param {Command} cli
*/ */
module.exports = (cli) => { module.exports = (cli) => {
const { APP_PACKAGE_ROOT } = process.env;
cli cli
.command('upgrade') .command('upgrade')
.allowUnknownOption() .allowUnknownOption()
@ -27,52 +37,11 @@ module.exports = (cli) => {
.option('-S|--skip-code-update') .option('-S|--skip-code-update')
.action(async (options) => { .action(async (options) => {
checkDBDialect(); checkDBDialect();
if (hasTsNode()) promptForTs();
if (hasCorePackages()) {
// await run('yarn', ['install']);
await downloadPro();
await runAppCommand('upgrade');
return;
}
if (options.skipCodeUpdate) { if (options.skipCodeUpdate) {
await downloadPro();
await runAppCommand('upgrade'); await runAppCommand('upgrade');
return; } else {
await run('nocobase', ['update-deps']);
await run('nocobase', ['upgrade', '--skip-code-update']);
} }
// await runAppCommand('upgrade');
if (!hasTsNode()) {
await downloadPro();
await runAppCommand('upgrade');
return;
}
const rmAppDir = () => {
// If ts-node is not installed, do not do the following
const appDevDir = resolve(process.cwd(), './storage/.app-dev');
if (existsSync(appDevDir)) {
rmSync(appDevDir, { recursive: true, force: true });
}
};
const pkg = require('../../package.json');
let distTag = 'latest';
if (pkg.version.includes('alpha')) {
distTag = 'alpha';
} else if (pkg.version.includes('beta')) {
distTag = 'beta';
}
// get latest version
const { stdout } = await run('npm', ['info', `@nocobase/cli@${distTag}`, 'version'], {
stdio: 'pipe',
});
if (pkg.version === stdout) {
await downloadPro();
await runAppCommand('upgrade');
await rmAppDir();
return;
}
await run('yarn', ['add', `@nocobase/cli@${distTag}`, `@nocobase/devtools@${distTag}`, '-W']);
await run('yarn', ['install']);
await downloadPro();
await runAppCommand('upgrade');
await rmAppDir();
}); });
}; };

View File

@ -0,0 +1,39 @@
{
"private": true,
"workspaces": ["packages/*/*", "packages/*/*/*"],
"engines": {
"node": ">=18"
},
"scripts": {
"nocobase": "nocobase",
"pm": "nocobase pm",
"pm2": "nocobase pm2",
"dev": "nocobase dev",
"start": "nocobase start",
"clean": "nocobase clean",
"build": "nocobase build",
"test": "nocobase test",
"e2e": "nocobase e2e",
"tar": "nocobase tar",
"postinstall": "nocobase postinstall",
"lint": "eslint ."
},
"resolutions": {
"cytoscape": "3.28.0",
"@types/react": "18.3.18",
"@types/react-dom": "^18.0.0",
"react-router-dom": "6.28.1",
"react-router": "6.28.1",
"async": "^3.2.6",
"antd": "5.12.8",
"rollup": "4.24.0",
"semver": "^7.7.1"
},
"dependencies": {
"pm2": "^6.0.5",
"mysql2": "^3.14.0",
"mariadb": "^3.4.1",
"pg": "^8.14.1",
"pg-hstore": "^2.3.4"
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/client", "name": "@nocobase/client",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.mjs", "module": "es/index.mjs",
@ -27,9 +27,9 @@
"@formily/reactive-react": "^2.2.27", "@formily/reactive-react": "^2.2.27",
"@formily/shared": "^2.2.27", "@formily/shared": "^2.2.27",
"@formily/validator": "^2.2.27", "@formily/validator": "^2.2.27",
"@nocobase/evaluators": "1.6.21", "@nocobase/evaluators": "1.6.23",
"@nocobase/sdk": "1.6.21", "@nocobase/sdk": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"ahooks": "^3.7.2", "ahooks": "^3.7.2",
"antd": "5.12.8", "antd": "5.12.8",
"antd-style": "3.7.1", "antd-style": "3.7.1",

View File

@ -97,6 +97,30 @@ const filterValue = (value) => {
return obj; return obj;
}; };
function getFilteredFormValues(form) {
const values = _.cloneDeep(form.values);
const allFields = [];
form.query('*').forEach((field) => {
if (field) {
allFields.push(field);
}
});
const readonlyPaths = allFields
.filter((field) => field?.componentProps?.readOnlySubmit)
.map((field) => {
const segments = field.path?.segments || [];
if (segments.length <= 1) {
return segments.join('.');
}
return segments.slice(0, -1).join('.');
});
for (const path of readonlyPaths) {
_.unset(values, path);
}
return values;
}
export function getFormValues({ export function getFormValues({
filterByTk, filterByTk,
field, field,
@ -124,7 +148,7 @@ export function getFormValues({
} }
} }
return form.values; return getFilteredFormValues(form);
} }
export function useCollectValuesToSubmit() { export function useCollectValuesToSubmit() {

View File

@ -7,7 +7,7 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import React, { useState, useContext } from 'react'; import React, { useState, useContext, useEffect } from 'react';
import { RecordPickerProvider, RecordPickerContext } from '../../../schema-component/antd/record-picker'; import { RecordPickerProvider, RecordPickerContext } from '../../../schema-component/antd/record-picker';
import { import {
SchemaComponentOptions, SchemaComponentOptions,
@ -41,9 +41,16 @@ const useTableSelectorProps = () => {
export const AssociateActionProvider = (props) => { export const AssociateActionProvider = (props) => {
const [selectedRows, setSelectedRows] = useState([]); const [selectedRows, setSelectedRows] = useState([]);
const collection = useCollection(); const collection = useCollection();
const { resource, service, block, __parent } = useBlockRequestContext(); const { resource, block, __parent } = useBlockRequestContext();
const actionCtx = useActionContext(); const actionCtx = useActionContext();
const { isMobile } = useOpenModeContext() || {}; const { isMobile } = useOpenModeContext() || {};
const [associationData, setAssociationData] = useState([]);
useEffect(() => {
resource?.list?.().then((res) => {
setAssociationData(res.data?.data || []);
});
}, [resource]);
const pickerProps = { const pickerProps = {
size: 'small', size: 'small',
onChange: props?.onChange, onChange: props?.onChange,
@ -73,8 +80,8 @@ export const AssociateActionProvider = (props) => {
}; };
const getFilter = () => { const getFilter = () => {
const targetKey = collection?.filterTargetKey || 'id'; const targetKey = collection?.filterTargetKey || 'id';
if (service.data?.data) { if (associationData) {
const list = service.data?.data.map((option) => option[targetKey]).filter(Boolean); const list = associationData.map((option) => option[targetKey]).filter(Boolean);
const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {}; const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {};
return filter; return filter;
} }

View File

@ -321,11 +321,7 @@ const InternalAction: React.FC<InternalActionProps> = observer(function Com(prop
} }
if (addChild) { if (addChild) {
return wrapSSR( return wrapSSR(<TreeRecordProvider parent={recordData}>{result}</TreeRecordProvider>) as React.ReactElement;
<RecordProvider record={null} parent={parentRecordData}>
<TreeRecordProvider parent={recordData}>{result}</TreeRecordProvider>
</RecordProvider>,
) as React.ReactElement;
} }
return wrapSSR(result) as React.ReactElement; return wrapSSR(result) as React.ReactElement;

View File

@ -34,7 +34,7 @@ import useServiceOptions, { useAssociationFieldContext } from './hooks';
const removeIfKeyEmpty = (obj, filterTargetKey) => { const removeIfKeyEmpty = (obj, filterTargetKey) => {
if (!obj || typeof obj !== 'object' || !filterTargetKey || Array.isArray(obj)) return obj; if (!obj || typeof obj !== 'object' || !filterTargetKey || Array.isArray(obj)) return obj;
return !obj[filterTargetKey] ? null : obj; return !obj[filterTargetKey] ? undefined : obj;
}; };
export const AssociationFieldAddNewer = (props) => { export const AssociationFieldAddNewer = (props) => {
@ -106,8 +106,13 @@ const InternalAssociationSelect = observer(
useEffect(() => { useEffect(() => {
const initValue = isVariable(field.value) ? undefined : field.value; const initValue = isVariable(field.value) ? undefined : field.value;
const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue; const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue;
setInnerValue(value); const result = removeIfKeyEmpty(value, filterTargetKey);
}, [field.value]); setInnerValue(result);
if (!isEqual(field.value, result)) {
field.value = result;
}
}, [field.value, filterTargetKey]);
useEffect(() => { useEffect(() => {
const id = uid(); const id = uid();
form.addEffects(id, () => { form.addEffects(id, () => {

View File

@ -101,6 +101,10 @@ const useLazyLoadDisplayAssociationFieldsOfForm = () => {
field.value = null; field.value = null;
} else { } else {
field.value = result; field.value = result;
field.componentProps = {
...field.componentProps,
readOnlySubmit: true,
}; // 让它不参与提交
} }
}); });
}) })

View File

@ -131,7 +131,7 @@ export const ValueDynamicComponent = (props: ValueDynamicComponentProps) => {
<span style={{ marginLeft: '.25em' }} className={'ant-formily-item-extra'}> <span style={{ marginLeft: '.25em' }} className={'ant-formily-item-extra'}>
{t('Syntax references')}: {t('Syntax references')}:
</span> </span>
<a href="https://formulajs.info/functions/" target="_blank" rel="noreferrer"> <a href="https://docs.nocobase.com/handbook/calculation-engines/formula" target="_blank" rel="noreferrer">
Formula.js Formula.js
</a> </a>
</> </>

View File

@ -1,6 +1,6 @@
{ {
"name": "create-nocobase-app", "name": "create-nocobase-app",
"version": "1.6.21", "version": "1.6.23",
"main": "src/index.js", "main": "src/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

View File

@ -21,7 +21,7 @@ cli
.option('--quickstart', 'quickstart app creation') .option('--quickstart', 'quickstart app creation')
.option('--skip-dev-dependencies') .option('--skip-dev-dependencies')
.option('-a, --all-db-dialect', 'install all database dialect dependencies') .option('-a, --all-db-dialect', 'install all database dialect dependencies')
.option('-d, --db-dialect <dbDialect>', 'database dialect, current support mysql/postgres', 'postgres') .option('-d, --db-dialect [dbDialect]', 'database dialect, current support postgres, mysql, mariadb, kingbase')
.option('-e, --env <env>', 'environment variables write into .env file', concat, []) .option('-e, --env <env>', 'environment variables write into .env file', concat, [])
.description('create a new application') .description('create a new application')
.action(async (name, options) => { .action(async (name, options) => {

View File

@ -37,21 +37,6 @@ class AppGenerator extends Generator {
return items; return items;
} }
checkDbEnv() {
const dialect = this.args.dbDialect;
const env = this.env;
if (dialect === 'sqlite') {
return;
}
if (!env.DB_DATABASE || !env.DB_USER || !env.DB_PASSWORD) {
console.log(
chalk.red(
`Please set DB_HOST, DB_PORT, DB_DATABASE, DB_USER, DB_PASSWORD in .env file to complete database settings`,
),
);
}
}
checkProjectPath() { checkProjectPath() {
if (existsSync(this.cwd)) { if (existsSync(this.cwd)) {
console.log(chalk.red('Project directory already exists')); console.log(chalk.red('Project directory already exists'));
@ -59,19 +44,6 @@ class AppGenerator extends Generator {
} }
} }
checkDialect() {
const dialect = this.args.dbDialect;
const supportDialects = ['mysql', 'mariadb', 'postgres'];
if (!supportDialects.includes(dialect)) {
console.log(
`dialect ${chalk.red(dialect)} is not supported, currently supported dialects are ${chalk.green(
supportDialects.join(','),
)}.`,
);
process.exit(1);
}
}
getContext() { getContext() {
const env = this.env; const env = this.env;
const envs = []; const envs = [];
@ -158,28 +130,33 @@ class AppGenerator extends Generator {
async writing() { async writing() {
this.checkProjectPath(); this.checkProjectPath();
this.checkDialect();
const { name } = this.context; const { name } = this.context;
console.log(`Creating a new NocoBase application at ${chalk.green(name)}`); console.log(`Creating a new NocoBase application at ${chalk.green(name)}`);
console.log('Creating files'); console.log('Creating files');
const context = this.getContext();
this.copyDirectory({ this.copyDirectory({
context: this.getContext(), context,
path: join(__dirname, '../templates/app'), path: join(__dirname, '../templates/app'),
target: this.cwd, target: this.cwd,
}); });
this.checkDbEnv(); const json = {
name: context.name,
...(await fs.readJSON(join(this.cwd, 'package.json'), 'utf8')),
};
const skipDevDependencies = this.args.skipDevDependencies; json['dependencies']['@nocobase/cli'] = context.version;
if (skipDevDependencies) {
const json = await fs.readJSON(join(this.cwd, 'package.json'), 'utf8'); if (!this.args.skipDevDependencies) {
delete json['devDependencies']; json['devDependencies'] = json['devDependencies'] || {};
await fs.writeJSON(join(this.cwd, 'package.json'), json, { encoding: 'utf8', spaces: 2 }); json['devDependencies']['@nocobase/devtools'] = context.version;
} }
await fs.writeJSON(join(this.cwd, 'package.json'), json, { encoding: 'utf8', spaces: 2 });
console.log(''); console.log('');
console.log(chalk.green(`$ cd ${name}`)); console.log(chalk.green(`$ cd ${name}`));
console.log(chalk.green(`$ yarn install`)); console.log(chalk.green(`$ yarn install`));

View File

@ -1,5 +1,4 @@
{ {
"name": "{{{name}}}",
"private": true, "private": true,
"workspaces": [ "workspaces": [
"packages/*/*", "packages/*/*",
@ -34,11 +33,10 @@
"semver": "^7.7.1" "semver": "^7.7.1"
}, },
"dependencies": { "dependencies": {
"@nocobase/cli": "{{{version}}}",
"pm2": "^6.0.5", "pm2": "^6.0.5",
{{{dependencies}}} "mysql2": "^3.14.0",
}, "mariadb": "^3.4.1",
"devDependencies": { "pg": "^8.14.1",
"@nocobase/devtools": "{{{version}}}" "pg-hstore": "^2.3.4"
} }
} }

View File

@ -1,16 +1,16 @@
{ {
"name": "@nocobase/data-source-manager", "name": "@nocobase/data-source-manager",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"dependencies": { "dependencies": {
"@nocobase/actions": "1.6.21", "@nocobase/actions": "1.6.23",
"@nocobase/cache": "1.6.21", "@nocobase/cache": "1.6.23",
"@nocobase/database": "1.6.21", "@nocobase/database": "1.6.23",
"@nocobase/resourcer": "1.6.21", "@nocobase/resourcer": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"@types/jsonwebtoken": "^9.0.9", "@types/jsonwebtoken": "^9.0.9",
"jsonwebtoken": "^9.0.2" "jsonwebtoken": "^9.0.2"
}, },

View File

@ -1,13 +1,13 @@
{ {
"name": "@nocobase/database", "name": "@nocobase/database",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@nocobase/logger": "1.6.21", "@nocobase/logger": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"async-mutex": "^0.3.2", "async-mutex": "^0.3.2",
"chalk": "^4.1.1", "chalk": "^4.1.1",
"cron-parser": "4.4.0", "cron-parser": "4.4.0",

View File

@ -1,13 +1,13 @@
{ {
"name": "@nocobase/devtools", "name": "@nocobase/devtools",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./src/index.js", "main": "./src/index.js",
"dependencies": { "dependencies": {
"@nocobase/build": "1.6.21", "@nocobase/build": "1.6.23",
"@nocobase/client": "1.6.21", "@nocobase/client": "1.6.23",
"@nocobase/test": "1.6.21", "@nocobase/test": "1.6.23",
"@types/koa": "^2.15.0", "@types/koa": "^2.15.0",
"@types/koa-bodyparser": "^4.3.4", "@types/koa-bodyparser": "^4.3.4",
"@types/lodash": "^4.14.177", "@types/lodash": "^4.14.177",

View File

@ -1,13 +1,13 @@
{ {
"name": "@nocobase/evaluators", "name": "@nocobase/evaluators",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@formulajs/formulajs": "4.4.9", "@formulajs/formulajs": "4.4.9",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"mathjs": "^10.6.0" "mathjs": "^10.6.0"
}, },
"repository": { "repository": {

View File

@ -1,10 +1,10 @@
{ {
"name": "@nocobase/lock-manager", "name": "@nocobase/lock-manager",
"version": "1.6.21", "version": "1.6.23",
"main": "lib/index.js", "main": "lib/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"devDependencies": { "devDependencies": {
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"async-mutex": "^0.5.0" "async-mutex": "^0.5.0"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/logger", "name": "@nocobase/logger",
"version": "1.6.21", "version": "1.6.23",
"description": "nocobase logging library", "description": "nocobase logging library",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",

View File

@ -1,12 +1,12 @@
{ {
"name": "@nocobase/resourcer", "name": "@nocobase/resourcer",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"koa-compose": "^4.1.0", "koa-compose": "^4.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/sdk", "name": "@nocobase/sdk",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/server", "name": "@nocobase/server",
"version": "1.6.21", "version": "1.6.23",
"main": "lib/index.js", "main": "lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"license": "AGPL-3.0", "license": "AGPL-3.0",
@ -10,19 +10,19 @@
"@koa/cors": "^5.0.0", "@koa/cors": "^5.0.0",
"@koa/multer": "^3.1.0", "@koa/multer": "^3.1.0",
"@koa/router": "^13.1.0", "@koa/router": "^13.1.0",
"@nocobase/acl": "1.6.21", "@nocobase/acl": "1.6.23",
"@nocobase/actions": "1.6.21", "@nocobase/actions": "1.6.23",
"@nocobase/auth": "1.6.21", "@nocobase/auth": "1.6.23",
"@nocobase/cache": "1.6.21", "@nocobase/cache": "1.6.23",
"@nocobase/data-source-manager": "1.6.21", "@nocobase/data-source-manager": "1.6.23",
"@nocobase/database": "1.6.21", "@nocobase/database": "1.6.23",
"@nocobase/evaluators": "1.6.21", "@nocobase/evaluators": "1.6.23",
"@nocobase/lock-manager": "1.6.21", "@nocobase/lock-manager": "1.6.23",
"@nocobase/logger": "1.6.21", "@nocobase/logger": "1.6.23",
"@nocobase/resourcer": "1.6.21", "@nocobase/resourcer": "1.6.23",
"@nocobase/sdk": "1.6.21", "@nocobase/sdk": "1.6.23",
"@nocobase/telemetry": "1.6.21", "@nocobase/telemetry": "1.6.23",
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"@types/decompress": "4.2.7", "@types/decompress": "4.2.7",
"@types/ini": "^1.3.31", "@types/ini": "^1.3.31",
"@types/koa-send": "^4.1.3", "@types/koa-send": "^4.1.3",

View File

@ -29,14 +29,13 @@ export default (app: Application) => {
'migrations', 'migrations',
`${dayjs().format('YYYYMMDDHHmmss')}-${name}.ts`, `${dayjs().format('YYYYMMDDHHmmss')}-${name}.ts`,
); );
const version = app.getVersion(); const version = app.getPackageVersion();
// 匹配主版本号、次版本号、小版本号和后缀的正则表达式
const regex = /(\d+)\.(\d+)\.(\d+)(-[\w.]+)?/; const regex = /(\d+)\.(\d+)\.(\d+)(-[\w.]+)?/;
const nextVersion = version.replace(regex, (match, major, minor, patch, suffix) => { const nextVersion = version.replace(regex, (match, major, minor, patch, suffix) => {
// 将小版本号转换为整数并加1 if (version.includes('beta') || version.includes('alpha')) {
const newPatch = parseInt(patch) + 1; return `${major}.${minor}.${patch}`;
// 返回新的版本号 }
return `${major}.${minor}.${newPatch}${suffix || ''}`; return `${major}.${1 + 1 * minor}.0`;
}); });
const from = pkg === '@nocobase/server' ? `../migration` : '@nocobase/server'; const from = pkg === '@nocobase/server' ? `../migration` : '@nocobase/server';
const data = `import { Migration } from '${from}'; const data = `import { Migration } from '${from}';

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/telemetry", "name": "@nocobase/telemetry",
"version": "1.6.21", "version": "1.6.23",
"description": "nocobase telemetry library", "description": "nocobase telemetry library",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./lib/index.js", "main": "./lib/index.js",
@ -11,7 +11,7 @@
"directory": "packages/telemetry" "directory": "packages/telemetry"
}, },
"dependencies": { "dependencies": {
"@nocobase/utils": "1.6.21", "@nocobase/utils": "1.6.23",
"@opentelemetry/api": "^1.7.0", "@opentelemetry/api": "^1.7.0",
"@opentelemetry/instrumentation": "^0.46.0", "@opentelemetry/instrumentation": "^0.46.0",
"@opentelemetry/resources": "^1.19.0", "@opentelemetry/resources": "^1.19.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/test", "name": "@nocobase/test",
"version": "1.6.21", "version": "1.6.23",
"main": "lib/index.js", "main": "lib/index.js",
"module": "./src/index.ts", "module": "./src/index.ts",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
@ -51,7 +51,7 @@
}, },
"dependencies": { "dependencies": {
"@faker-js/faker": "8.1.0", "@faker-js/faker": "8.1.0",
"@nocobase/server": "1.6.21", "@nocobase/server": "1.6.23",
"@playwright/test": "^1.45.3", "@playwright/test": "^1.45.3",
"@testing-library/jest-dom": "^6.4.2", "@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.0.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/utils", "name": "@nocobase/utils",
"version": "1.6.21", "version": "1.6.23",
"main": "lib/index.js", "main": "lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"license": "AGPL-3.0", "license": "AGPL-3.0",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "权限控制", "displayName.zh-CN": "权限控制",
"description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.", "description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
"description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。", "description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/acl", "homepage": "https://docs.nocobase.com/handbook/acl",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-action-bulk-edit", "name": "@nocobase/plugin-action-bulk-edit",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-bulk-edit", "homepage": "https://docs.nocobase.com/handbook/action-bulk-edit",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-action-bulk-update", "name": "@nocobase/plugin-action-bulk-update",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-bulk-update", "homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-action-custom-request", "name": "@nocobase/plugin-action-custom-request",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-custom-request", "homepage": "https://docs.nocobase.com/handbook/action-custom-request",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-action-duplicate", "name": "@nocobase/plugin-action-duplicate",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-duplicate", "homepage": "https://docs.nocobase.com/handbook/action-duplicate",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "操作:导出记录", "displayName.zh-CN": "操作:导出记录",
"description": "Export filtered records to excel, you can configure which fields to export.", "description": "Export filtered records to excel, you can configure which fields to export.",
"description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。", "description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-export", "homepage": "https://docs.nocobase.com/handbook/action-export",

View File

@ -21,6 +21,7 @@ import { deepGet } from '../utils/deep-get';
import path from 'path'; import path from 'path';
import os from 'os'; import os from 'os';
import { Logger } from '@nocobase/logger'; import { Logger } from '@nocobase/logger';
import _ from 'lodash';
export type ExportOptions = { export type ExportOptions = {
collectionManager: ICollectionManager; collectionManager: ICollectionManager;
@ -68,7 +69,7 @@ abstract class BaseExporter<T extends ExportOptions = ExportOptions> extends Eve
const { collection, chunkSize, repository } = this.options; const { collection, chunkSize, repository } = this.options;
const repo = repository || collection.repository; const repo = repository || collection.repository;
const total = (await repo.count(this.getFindOptions())) as number; const total = (await repo.count(this.getFindOptions(ctx))) as number;
this.logger?.info(`Found ${total} records to export from collection [${collection.name}]`); this.logger?.info(`Found ${total} records to export from collection [${collection.name}]`);
const totalCountStartTime = process.hrtime(); const totalCountStartTime = process.hrtime();
let current = 0; let current = 0;
@ -76,7 +77,7 @@ abstract class BaseExporter<T extends ExportOptions = ExportOptions> extends Eve
// gt 200000, offset + limit will be slow,so use cursor // gt 200000, offset + limit will be slow,so use cursor
const chunkHandle = (total > 200000 ? repo.chunkWithCursor : repo.chunk).bind(repo); const chunkHandle = (total > 200000 ? repo.chunkWithCursor : repo.chunk).bind(repo);
const findOptions = { const findOptions = {
...this.getFindOptions(), ...this.getFindOptions(ctx),
chunkSize: chunkSize || 200, chunkSize: chunkSize || 200,
beforeFind: async (options) => { beforeFind: async (options) => {
this._batchQueryStartTime = process.hrtime(); this._batchQueryStartTime = process.hrtime();
@ -129,31 +130,34 @@ abstract class BaseExporter<T extends ExportOptions = ExportOptions> extends Eve
} }
} }
protected getAppendOptionsFromFields() { protected getAppendOptionsFromFields(ctx?) {
return this.options.fields const fields = this.options.fields.map((x) => x[0]);
const hasPermissionFields = _.isEmpty(ctx?.permission?.can?.params)
? fields
: _.intersection(ctx?.permission?.can?.params?.appends || [], fields);
return hasPermissionFields
.map((field) => { .map((field) => {
const fieldInstance = this.options.collection.getField(field[0]); const fieldInstance = this.options.collection.getField(field);
if (!fieldInstance) { if (!fieldInstance) {
throw new Error(`Field "${field[0]}" not found: , please check the fields configuration.`); throw new Error(`Field "${field}" not found: , please check the fields configuration.`);
} }
if (fieldInstance.isRelationField()) { if (fieldInstance.isRelationField()) {
return field.join('.'); return field;
} }
return null; return null;
}) })
.filter(Boolean); .filter(Boolean);
} }
protected getFindOptions(ctx?) {
protected getFindOptions() {
const { findOptions = {} } = this.options; const { findOptions = {} } = this.options;
if (this.limit) { if (this.limit) {
findOptions.limit = this.limit; findOptions.limit = this.limit;
} }
const appendOptions = this.getAppendOptionsFromFields(); const appendOptions = this.getAppendOptionsFromFields(ctx);
if (appendOptions.length) { if (appendOptions.length) {
return { return {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "操作:导入记录", "displayName.zh-CN": "操作:导入记录",
"description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.", "description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
"description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。", "description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-import", "homepage": "https://docs.nocobase.com/handbook/action-import",

View File

@ -2156,6 +2156,76 @@ describe('xlsx importer', () => {
expect(await Post.repository.count()).toBe(1); expect(await Post.repository.count()).toBe(1);
}); });
it('should filter no permission columns', async () => {
const User = app.db.collection({
name: 'users',
fields: [
{
type: 'string',
name: 'name',
},
{
type: 'string',
name: 'email',
},
],
});
await app.db.sync();
const templateCreator = new TemplateCreator({
collection: User,
explain: 'test',
columns: [
{
dataIndex: ['name'],
defaultTitle: '姓名',
},
{
dataIndex: ['email'],
defaultTitle: '邮箱',
},
],
});
const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook;
const worksheet = template.Sheets[template.SheetNames[0]];
XLSX.utils.sheet_add_aoa(worksheet, [['User1', 'test@test.com']], {
origin: 'A3',
});
const importer = new XlsxImporter({
collectionManager: app.mainDataSource.collectionManager,
collection: User,
explain: 'test',
columns: [
{
dataIndex: ['name'],
defaultTitle: '姓名',
},
{
dataIndex: ['email'],
defaultTitle: '邮箱',
},
],
workbook: template,
});
await importer.run({
context: {
permission: {
can: { params: { fields: ['name'] } },
},
},
});
expect(await User.repository.count()).toBe(1);
const user = await User.repository.findOne();
expect(user.get('name')).toBe('User1');
expect(user.get('email')).not.exist;
});
it('should import time field successfully', async () => { it('should import time field successfully', async () => {
const TimeCollection = app.db.collection({ const TimeCollection = app.db.collection({
name: 'time_tests', name: 'time_tests',

View File

@ -14,6 +14,8 @@ import { Collection as DBCollection, Database } from '@nocobase/database';
import { Transaction } from 'sequelize'; import { Transaction } from 'sequelize';
import EventEmitter from 'events'; import EventEmitter from 'events';
import { ImportValidationError, ImportError } from '../errors'; import { ImportValidationError, ImportError } from '../errors';
import { Context } from '@nocobase/actions';
import _ from 'lodash';
export type ImportColumn = { export type ImportColumn = {
dataIndex: Array<string>; dataIndex: Array<string>;
@ -54,8 +56,9 @@ export class XlsxImporter extends EventEmitter {
this.repository = options.repository ? options.repository : options.collection.repository; this.repository = options.repository ? options.repository : options.collection.repository;
} }
async validate() { async validate(ctx?: Context) {
if (this.options.columns.length == 0) { const columns = this.getColumnsByPermission(ctx);
if (columns.length == 0) {
throw new ImportValidationError('Columns configuration is empty'); throw new ImportValidationError('Columns configuration is empty');
} }
@ -66,7 +69,7 @@ export class XlsxImporter extends EventEmitter {
} }
} }
const data = await this.getData(); const data = await this.getData(ctx);
return data; return data;
} }
@ -80,7 +83,7 @@ export class XlsxImporter extends EventEmitter {
} }
try { try {
await this.validate(); await this.validate(options.context);
const imported = await this.performImport(options); const imported = await this.performImport(options);
// @ts-ignore // @ts-ignore
@ -111,7 +114,7 @@ export class XlsxImporter extends EventEmitter {
} }
let hasImportedAutoIncrementPrimary = false; let hasImportedAutoIncrementPrimary = false;
for (const importedDataIndex of this.options.columns) { for (const importedDataIndex of this.getColumnsByPermission(options?.context)) {
if (importedDataIndex.dataIndex[0] === autoIncrementAttribute) { if (importedDataIndex.dataIndex[0] === autoIncrementAttribute) {
hasImportedAutoIncrementPrimary = true; hasImportedAutoIncrementPrimary = true;
break; break;
@ -150,9 +153,18 @@ export class XlsxImporter extends EventEmitter {
this.emit('seqReset', { maxVal, seqName: autoIncrInfo.seqName }); this.emit('seqReset', { maxVal, seqName: autoIncrInfo.seqName });
} }
private getColumnsByPermission(ctx: Context): ImportColumn[] {
const columns = this.options.columns;
return columns.filter((x) =>
_.isEmpty(ctx?.permission?.can?.params)
? true
: _.includes(ctx?.permission?.can?.params?.fields || [], x.dataIndex[0]),
);
}
async performImport(options?: RunOptions): Promise<any> { async performImport(options?: RunOptions): Promise<any> {
const transaction = options?.transaction; const transaction = options?.transaction;
const data = await this.getData(); const data = await this.getData(options?.context);
const chunks = lodash.chunk(data.slice(1), this.options.chunkSize || 200); const chunks = lodash.chunk(data.slice(1), this.options.chunkSize || 200);
let handingRowIndex = 1; let handingRowIndex = 1;
@ -271,25 +283,26 @@ export class XlsxImporter extends EventEmitter {
return str; return str;
} }
private getExpectedHeaders(): string[] { private getExpectedHeaders(ctx?: Context): string[] {
return this.options.columns.map((col) => col.title || col.defaultTitle); const columns = this.getColumnsByPermission(ctx);
return columns.map((col) => col.title || col.defaultTitle);
} }
async getData() { async getData(ctx?: Context) {
const workbook = this.options.workbook; const workbook = this.options.workbook;
const worksheet = workbook.Sheets[workbook.SheetNames[0]]; const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const data = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null }) as string[][]; let data = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: null }) as string[][];
// Find and validate header row // Find and validate header row
const expectedHeaders = this.getExpectedHeaders(); const expectedHeaders = this.getExpectedHeaders(ctx);
const { headerRowIndex, headers } = this.findAndValidateHeaders(data); const { headerRowIndex, headers } = this.findAndValidateHeaders({ data, expectedHeaders });
if (headerRowIndex === -1) { if (headerRowIndex === -1) {
throw new ImportValidationError('Headers not found. Expected headers: {{headers}}', { throw new ImportValidationError('Headers not found. Expected headers: {{headers}}', {
headers: expectedHeaders.join(', '), headers: expectedHeaders.join(', '),
}); });
} }
data = this.alignWithHeaders({ data, expectedHeaders, headers });
// Extract data rows // Extract data rows
const rows = data.slice(headerRowIndex + 1); const rows = data.slice(headerRowIndex + 1);
@ -301,8 +314,18 @@ export class XlsxImporter extends EventEmitter {
return [headers, ...rows]; return [headers, ...rows];
} }
private findAndValidateHeaders(data: string[][]): { headerRowIndex: number; headers: string[] } { private alignWithHeaders(params: { headers: string[]; expectedHeaders: string[]; data: string[][] }): string[][] {
const expectedHeaders = this.getExpectedHeaders(); const { expectedHeaders, headers, data } = params;
const keepCols = headers.map((x, i) => (expectedHeaders.includes(x) ? i : -1)).filter((i) => i > -1);
return data.map((row) => keepCols.map((i) => row[i]));
}
private findAndValidateHeaders(options: { expectedHeaders: string[]; data: string[][] }): {
headerRowIndex: number;
headers: string[];
} {
const { data, expectedHeaders } = options;
// Find header row and validate // Find header row and validate
for (let rowIndex = 0; rowIndex < data.length; rowIndex++) { for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
@ -310,31 +333,11 @@ export class XlsxImporter extends EventEmitter {
const actualHeaders = row.filter((cell) => cell !== null && cell !== ''); const actualHeaders = row.filter((cell) => cell !== null && cell !== '');
const allHeadersFound = expectedHeaders.every((header) => actualHeaders.includes(header)); const allHeadersFound = expectedHeaders.every((header) => actualHeaders.includes(header));
const noExtraHeaders = actualHeaders.length === expectedHeaders.length;
if (allHeadersFound && noExtraHeaders) { if (allHeadersFound) {
const mismatchIndex = expectedHeaders.findIndex((title, index) => actualHeaders[index] !== title); const orderedHeaders = expectedHeaders.filter((h) => actualHeaders.includes(h));
return { headerRowIndex: rowIndex, headers: orderedHeaders };
if (mismatchIndex === -1) {
// All headers match
return { headerRowIndex: rowIndex, headers: actualHeaders };
} else {
// Found potential header row but with mismatch
throw new ImportValidationError(
'Header mismatch at column {{column}}: expected "{{expected}}", but got "{{actual}}"',
{
column: mismatchIndex + 1,
expected: expectedHeaders[mismatchIndex],
actual: actualHeaders[mismatchIndex] || 'empty',
},
);
} }
} }
} }
// No row with matching headers found
throw new ImportValidationError('Headers not found. Expected headers: {{headers}}', {
headers: expectedHeaders.join(', '),
});
}
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-action-print", "name": "@nocobase/plugin-action-print",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-print", "homepage": "https://docs.nocobase.com/handbook/action-print",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "AI 集成", "displayName.zh-CN": "AI 集成",
"description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.", "description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.",
"description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。", "description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"peerDependencies": { "peerDependencies": {
"@nocobase/client": "1.x", "@nocobase/client": "1.x",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-api-doc", "name": "@nocobase/plugin-api-doc",
"version": "1.6.21", "version": "1.6.23",
"displayName": "API documentation", "displayName": "API documentation",
"displayName.zh-CN": "API 文档", "displayName.zh-CN": "API 文档",
"description": "An OpenAPI documentation generator for NocoBase HTTP API.", "description": "An OpenAPI documentation generator for NocoBase HTTP API.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "认证API 密钥", "displayName.zh-CN": "认证API 密钥",
"description": "Allows users to use API key to access application's HTTP API", "description": "Allows users to use API key to access application's HTTP API",
"description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API", "description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/api-keys", "homepage": "https://docs.nocobase.com/handbook/api-keys",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "异步任务管理器", "displayName.zh-CN": "异步任务管理器",
"description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.", "description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
"description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。", "description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"peerDependencies": { "peerDependencies": {
"@nocobase/client": "1.x", "@nocobase/client": "1.x",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-audit-logs", "name": "@nocobase/plugin-audit-logs",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Audit logs (deprecated)", "displayName": "Audit logs (deprecated)",
"displayName.zh-CN": "审计日志(废弃)", "displayName.zh-CN": "审计日志(废弃)",
"description": "This plugin is deprecated. There will be a new audit log plugin in the future.", "description": "This plugin is deprecated. There will be a new audit log plugin in the future.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "认证:短信", "displayName.zh-CN": "认证:短信",
"description": "SMS authentication.", "description": "SMS authentication.",
"description.zh-CN": "通过短信验证码认证身份。", "description.zh-CN": "通过短信验证码认证身份。",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/auth-sms", "homepage": "https://docs.nocobase.com/handbook/auth-sms",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-auth", "name": "@nocobase/plugin-auth",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/auth", "homepage": "https://docs.nocobase.com/handbook/auth",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "应用的备份与还原(废弃)", "displayName.zh-CN": "应用的备份与还原(废弃)",
"description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.", "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。", "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/backup-restore", "homepage": "https://docs.nocobase.com/handbook/backup-restore",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "区块iframe", "displayName.zh-CN": "区块iframe",
"description": "Create an iframe block on the page to embed and display external web pages or content.", "description": "Create an iframe block on the page to embed and display external web pages or content.",
"description.zh-CN": "在页面上创建和管理iframe用于嵌入和展示外部网页或内容。", "description.zh-CN": "在页面上创建和管理iframe用于嵌入和展示外部网页或内容。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/block-iframe", "homepage": "https://docs.nocobase.com/handbook/block-iframe",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-block-workbench", "name": "@nocobase/plugin-block-workbench",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Block: Action panel", "displayName": "Block: Action panel",
"displayName.zh-CN": "区块:操作面板", "displayName.zh-CN": "区块:操作面板",
"description": "Centrally manages and displays various actions, allowing users to efficiently perform tasks. It supports extensibility, with current action types including pop-ups, links, scanning, and custom requests.", "description": "Centrally manages and displays various actions, allowing users to efficiently perform tasks. It supports extensibility, with current action types including pop-ups, links, scanning, and custom requests.",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-calendar", "name": "@nocobase/plugin-calendar",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Calendar", "displayName": "Calendar",
"displayName.zh-CN": "日历", "displayName.zh-CN": "日历",
"description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.", "description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "图表(废弃)", "displayName.zh-CN": "图表(废弃)",
"description": "The plugin has been deprecated, please use the data visualization plugin instead.", "description": "The plugin has been deprecated, please use the data visualization plugin instead.",
"description.zh-CN": "已废弃插件,请使用数据可视化插件代替。", "description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"devDependencies": { "devDependencies": {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "WEB 客户端", "displayName.zh-CN": "WEB 客户端",
"description": "Provides a client interface for the NocoBase server", "description": "Provides a client interface for the NocoBase server",
"description.zh-CN": "为 NocoBase 服务端提供客户端界面", "description.zh-CN": "为 NocoBase 服务端提供客户端界面",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"devDependencies": { "devDependencies": {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表: SQL", "displayName.zh-CN": "数据表: SQL",
"description": "Provides SQL collection template", "description": "Provides SQL collection template",
"description.zh-CN": "提供 SQL 数据表模板", "description.zh-CN": "提供 SQL 数据表模板",
"version": "1.6.21", "version": "1.6.23",
"homepage": "https://docs-cn.nocobase.com/handbook/collection-sql", "homepage": "https://docs-cn.nocobase.com/handbook/collection-sql",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql",
"main": "dist/server/index.js", "main": "dist/server/index.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-collection-tree", "name": "@nocobase/plugin-collection-tree",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Collection: Tree", "displayName": "Collection: Tree",
"displayName.zh-CN": "数据表:树", "displayName.zh-CN": "数据表:树",
"description": "Provides tree collection template", "description": "Provides tree collection template",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据源:主数据库", "displayName.zh-CN": "数据源:主数据库",
"description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.", "description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.",
"description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。", "description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/data-source-main", "homepage": "https://docs.nocobase.com/handbook/data-source-main",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-data-source-manager", "name": "@nocobase/plugin-data-source-manager",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"displayName": "Data source manager", "displayName": "Data source manager",
"displayName.zh-CN": "数据源管理", "displayName.zh-CN": "数据源管理",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-data-visualization", "name": "@nocobase/plugin-data-visualization",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Data visualization", "displayName": "Data visualization",
"displayName.zh-CN": "数据可视化", "displayName.zh-CN": "数据可视化",
"description": "Provides data visualization feature, including chart block and chart filter block, support line charts, area charts, bar charts and more than a dozen kinds of charts, you can also extend more chart types.", "description": "Provides data visualization feature, including chart block and chart filter block, support line charts, area charts, bar charts and more than a dozen kinds of charts, you can also extend more chart types.",

View File

@ -4,10 +4,10 @@
"displayName.zh-CN": "部门", "displayName.zh-CN": "部门",
"description": "Organize users by departments, set hierarchical relationships, link roles to control permissions, and use departments as variables in workflows and expressions.", "description": "Organize users by departments, set hierarchical relationships, link roles to control permissions, and use departments as variables in workflows and expressions.",
"description.zh-CN": "以部门来组织用户,设定上下级关系,绑定角色控制权限,并支持作为变量用于工作流和表达式。", "description.zh-CN": "以部门来组织用户,设定上下级关系,绑定角色控制权限,并支持作为变量用于工作流和表达式。",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"devDependencies": { "devDependencies": {
"@nocobase/plugin-user-data-sync": "1.6.21" "@nocobase/plugin-user-data-sync": "1.6.23"
}, },
"peerDependencies": { "peerDependencies": {
"@nocobase/actions": "1.x", "@nocobase/actions": "1.x",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-disable-pm-add", "name": "@nocobase/plugin-disable-pm-add",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"peerDependencies": { "peerDependencies": {
"@nocobase/client": "1.x", "@nocobase/client": "1.x",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-environment-variables", "name": "@nocobase/plugin-environment-variables",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"peerDependencies": { "peerDependencies": {
"@nocobase/client": "1.x", "@nocobase/client": "1.x",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "错误处理器", "displayName.zh-CN": "错误处理器",
"description": "Handling application errors and exceptions.", "description": "Handling application errors and exceptions.",
"description.zh-CN": "处理应用程序中的错误和异常。", "description.zh-CN": "处理应用程序中的错误和异常。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"devDependencies": { "devDependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-field-attachment-url", "name": "@nocobase/plugin-field-attachment-url",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"displayName": "Collection field: Attachment(URL)", "displayName": "Collection field: Attachment(URL)",
"displayName.zh-CN": "数据表字段附件URL", "displayName.zh-CN": "数据表字段附件URL",
@ -12,7 +12,7 @@
"@nocobase/test": "1.x" "@nocobase/test": "1.x"
}, },
"devDependencies": { "devDependencies": {
"@nocobase/plugin-file-manager": "1.6.21" "@nocobase/plugin-file-manager": "1.6.23"
}, },
"keywords": [ "keywords": [
"Collection fields" "Collection fields"

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-field-china-region", "name": "@nocobase/plugin-field-china-region",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Collection field: administrative divisions of China", "displayName": "Collection field: administrative divisions of China",
"displayName.zh-CN": "数据表字段:中国行政区划", "displayName.zh-CN": "数据表字段:中国行政区划",
"description": "Provides data and field type for administrative divisions of China.", "description": "Provides data and field type for administrative divisions of China.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:公式", "displayName.zh-CN": "数据表字段:公式",
"description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.", "description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.",
"description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎", "description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-formula", "homepage": "https://docs.nocobase.com/handbook/field-formula",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:多对多 (数组)", "displayName.zh-CN": "数据表字段:多对多 (数组)",
"description": "Allows to create many to many relationships between two models by storing an array of unique keys of the target model.", "description": "Allows to create many to many relationships between two models by storing an array of unique keys of the target model.",
"description.zh-CN": "支持通过在数组中存储目标表唯一键的方式建立多对多关系。", "description.zh-CN": "支持通过在数组中存储目标表唯一键的方式建立多对多关系。",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"peerDependencies": { "peerDependencies": {
"@nocobase/client": "1.x", "@nocobase/client": "1.x",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段Markdown(Vditor)", "displayName.zh-CN": "数据表字段Markdown(Vditor)",
"description": "Used to store Markdown and render it using Vditor editor, supports common Markdown syntax such as list, code, quote, etc., and supports uploading images, recordings, etc.It also allows for instant rendering, where what you see is what you get.", "description": "Used to store Markdown and render it using Vditor editor, supports common Markdown syntax such as list, code, quote, etc., and supports uploading images, recordings, etc.It also allows for instant rendering, where what you see is what you get.",
"description.zh-CN": "用于存储 Markdown并使用 Vditor 编辑器渲染,支持常见 Markdown 语法,如列表,代码,引用等,并支持上传图片,录音等。同时可以做到即时渲染,所见即所得。", "description.zh-CN": "用于存储 Markdown并使用 Vditor 编辑器渲染,支持常见 Markdown 语法,如列表,代码,引用等,并支持上传图片,录音等。同时可以做到即时渲染,所见即所得。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-markdown-vditor", "homepage": "https://docs.nocobase.com/handbook/field-markdown-vditor",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:自动编码", "displayName.zh-CN": "数据表字段:自动编码",
"description": "Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.", "description": "Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.",
"description.zh-CN": "根据配置的规则自动生成编码,支持日期、数字、文本的组合。", "description.zh-CN": "根据配置的规则自动生成编码,支持日期、数字、文本的组合。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-sequence", "homepage": "https://docs.nocobase.com/handbook/field-sequence",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-field-sort", "name": "@nocobase/plugin-field-sort",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"displayName": "Collection field: Sort", "displayName": "Collection field: Sort",
"displayName.zh-CN": "数据表字段:排序", "displayName.zh-CN": "数据表字段:排序",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-file-manager", "name": "@nocobase/plugin-file-manager",
"version": "1.6.21", "version": "1.6.23",
"displayName": "File manager", "displayName": "File manager",
"displayName.zh-CN": "文件管理器", "displayName.zh-CN": "文件管理器",
"description": "Provides files storage services with files collection template and attachment field.", "description": "Provides files storage services with files collection template and attachment field.",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-gantt", "name": "@nocobase/plugin-gantt",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Block: Gantt", "displayName": "Block: Gantt",
"displayName.zh-CN": "区块:甘特图", "displayName.zh-CN": "区块:甘特图",
"description": "Provides Gantt block.", "description": "Provides Gantt block.",

View File

@ -52,12 +52,7 @@ export const Calendar: React.FC<CalendarProps> = ({
const date = dateSetup.dates[i]; const date = dateSetup.dates[i];
const bottomValue = date.getFullYear(); const bottomValue = date.getFullYear();
bottomValues.push( bottomValues.push(
<text <text key={date.getTime()} y={headerHeight * 0.8} x={columnWidth * i + columnWidth * 0.5}>
key={date.getTime()}
y={headerHeight * 0.8}
x={columnWidth * i + columnWidth * 0.5}
className={cx('calendarBottomText')}
>
{bottomValue} {bottomValue}
</text>, </text>,
); );
@ -98,7 +93,7 @@ export const Calendar: React.FC<CalendarProps> = ({
key={date.getTime()} key={date.getTime()}
y={headerHeight * 0.8} y={headerHeight * 0.8}
x={columnWidth * i + columnWidth * 0.5} x={columnWidth * i + columnWidth * 0.5}
className={cx('calendarBottomText')} className={styles.calendarBottomText}
> >
{quarter} {quarter}
</text>, </text>,
@ -118,7 +113,7 @@ export const Calendar: React.FC<CalendarProps> = ({
x1Line={columnWidth * i} x1Line={columnWidth * i}
y1Line={0} y1Line={0}
y2Line={topDefaultHeight} y2Line={topDefaultHeight}
xText={Math.abs(xText)} xText={Math.abs(xText) - 200}
yText={topDefaultHeight * 0.9} yText={topDefaultHeight * 0.9}
/>, />,
); );
@ -139,7 +134,7 @@ export const Calendar: React.FC<CalendarProps> = ({
key={bottomValue + date.getFullYear()} key={bottomValue + date.getFullYear()}
y={headerHeight * 0.8} y={headerHeight * 0.8}
x={columnWidth * i + columnWidth * 0.5} x={columnWidth * i + columnWidth * 0.5}
className={cx('calendarBottomText')} className={styles.calendarBottomText}
> >
{bottomValue} {bottomValue}
</text>, </text>,
@ -189,7 +184,7 @@ export const Calendar: React.FC<CalendarProps> = ({
key={date.getTime()} key={date.getTime()}
y={headerHeight * 0.8} y={headerHeight * 0.8}
x={columnWidth * (i + +rtl)} x={columnWidth * (i + +rtl)}
className={cx('calendarBottomText')} className={styles.calendarBottomText}
> >
{bottomValue} {bottomValue}
</text>, </text>,

View File

@ -23,6 +23,9 @@ const useStyles = createStyles(({ token, css }) => {
background: ${colorFillAlterSolid}; background: ${colorFillAlterSolid};
border-bottom: 1px solid ${token.colorBorderSecondary}; border-bottom: 1px solid ${token.colorBorderSecondary};
`, `,
calendarBottomText: css`
font-size: 11px;
`,
nbGanttCalendar: css` nbGanttCalendar: css`
.calendarbottomtext: { .calendarbottomtext: {
textanchor: middle; textanchor: middle;

View File

@ -47,7 +47,7 @@ import { TaskGantt } from './task-gantt';
import { TaskGanttContentProps } from './task-gantt-content'; import { TaskGanttContentProps } from './task-gantt-content';
const getColumnWidth = (dataSetLength: any, clientWidth: any) => { const getColumnWidth = (dataSetLength: any, clientWidth: any) => {
const columnWidth = clientWidth / dataSetLength > 50 ? Math.floor(clientWidth / dataSetLength) + 20 : 50; const columnWidth = clientWidth / dataSetLength > 50 ? Math.floor(clientWidth / dataSetLength) + 20 : 60;
return columnWidth; return columnWidth;
}; };

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "可视化数据表管理", "displayName.zh-CN": "可视化数据表管理",
"description": "An ER diagram-like tool. Currently only the Master database is supported.", "description": "An ER diagram-like tool. Currently only the Master database is supported.",
"description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。", "description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/graph-collection-manager", "homepage": "https://docs.nocobase.com/handbook/graph-collection-manager",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-kanban", "name": "@nocobase/plugin-kanban",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/block-kanban", "homepage": "https://docs.nocobase.com/handbook/block-kanban",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban",

View File

@ -2,7 +2,7 @@
"name": "@nocobase/plugin-locale-tester", "name": "@nocobase/plugin-locale-tester",
"displayName": "Locale tester", "displayName": "Locale tester",
"displayName.zh-CN": "翻译测试工具", "displayName.zh-CN": "翻译测试工具",
"version": "1.6.21", "version": "1.6.23",
"homepage": "https://github.com/nocobase/locales", "homepage": "https://github.com/nocobase/locales",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"peerDependencies": { "peerDependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-localization", "name": "@nocobase/plugin-localization",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/localization-management", "homepage": "https://docs.nocobase.com/handbook/localization-management",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "日志", "displayName.zh-CN": "日志",
"description": "Server-side logs, mainly including API request logs and system runtime logs, and allows to package and download log files.", "description": "Server-side logs, mainly including API request logs and system runtime logs, and allows to package and download log files.",
"description.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。", "description.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/logger", "homepage": "https://docs.nocobase.com/handbook/logger",

View File

@ -2,7 +2,7 @@
"name": "@nocobase/plugin-map", "name": "@nocobase/plugin-map",
"displayName": "Block: Map", "displayName": "Block: Map",
"displayName.zh-CN": "区块:地图", "displayName.zh-CN": "区块:地图",
"version": "1.6.21", "version": "1.6.23",
"description": "Map block, support Gaode map and Google map, you can also extend more map types.", "description": "Map block, support Gaode map and Google map, you can also extend more map types.",
"description.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。", "description.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。",
"license": "AGPL-3.0", "license": "AGPL-3.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-mobile-client", "name": "@nocobase/plugin-mobile-client",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/mobile-client", "homepage": "https://docs.nocobase.com/handbook/mobile-client",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-mobile", "name": "@nocobase/plugin-mobile",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/mobile", "homepage": "https://docs.nocobase.com/handbook/mobile",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile",

View File

@ -2,7 +2,7 @@
"name": "@nocobase/plugin-mock-collections", "name": "@nocobase/plugin-mock-collections",
"displayName": "mock-collections", "displayName": "mock-collections",
"description": "mock-collections", "description": "mock-collections",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"peerDependencies": { "peerDependencies": {

View File

@ -199,7 +199,7 @@ export default {
value: 'formula.js', value: 'formula.js',
label: 'Formula.js', label: 'Formula.js',
tooltip: '{{t("Formula.js supports most Microsoft Excel formula functions.")}}', tooltip: '{{t("Formula.js supports most Microsoft Excel formula functions.")}}',
link: 'https://formulajs.info/functions/', link: 'https://docs.nocobase.com/handbook/calculation-engines/formula',
}, },
], ],
default: 'formula.js', default: 'formula.js',

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "多应用管理器", "displayName.zh-CN": "多应用管理器",
"description": "Dynamically create multiple apps without separate deployments.", "description": "Dynamically create multiple apps without separate deployments.",
"description.zh-CN": "无需单独部署即可动态创建多个应用。", "description.zh-CN": "无需单独部署即可动态创建多个应用。",
"version": "1.6.21", "version": "1.6.23",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/multi-app-manager", "homepage": "https://docs.nocobase.com/handbook/multi-app-manager",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "多应用数据表共享", "displayName.zh-CN": "多应用数据表共享",
"description": "", "description": "",
"description.zh-CN": "", "description.zh-CN": "",
"version": "1.6.21", "version": "1.6.23",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",
"devDependencies": { "devDependencies": {
"@formily/react": "2.x", "@formily/react": "2.x",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-notification-email", "name": "@nocobase/plugin-notification-email",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Notification: Email", "displayName": "Notification: Email",
"displayName.zh-CN": "通知:电子邮件", "displayName.zh-CN": "通知:电子邮件",
"description": "Used for sending email notifications with built-in SMTP transport.", "description": "Used for sending email notifications with built-in SMTP transport.",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-notification-in-app-message", "name": "@nocobase/plugin-notification-in-app-message",
"version": "1.6.21", "version": "1.6.23",
"displayName": "Notification: In-app message", "displayName": "Notification: In-app message",
"displayName.zh-CN": "通知:站内信", "displayName.zh-CN": "通知:站内信",
"description": "It supports users in receiving real-time message notifications within the NocoBase application.", "description": "It supports users in receiving real-time message notifications within the NocoBase application.",

View File

@ -4,7 +4,7 @@
"description": "Provides a unified management service that includes channel configuration, logging, and other features, supporting the configuration of various notification channels, including in-app message and email.", "description": "Provides a unified management service that includes channel configuration, logging, and other features, supporting the configuration of various notification channels, including in-app message and email.",
"displayName.zh-CN": "通知管理", "displayName.zh-CN": "通知管理",
"description.zh-CN": "提供统一的管理服务,涵盖渠道配置、日志记录等功能,支持多种通知渠道的配置,包括站内信和电子邮件等。", "description.zh-CN": "提供统一的管理服务,涵盖渠道配置、日志记录等功能,支持多种通知渠道的配置,包括站内信和电子邮件等。",
"version": "1.6.21", "version": "1.6.23",
"homepage": "https://docs.nocobase.com/handbook/notification-manager", "homepage": "https://docs.nocobase.com/handbook/notification-manager",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/notification-manager", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/notification-manager",
"main": "dist/server/index.js", "main": "dist/server/index.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-notifications", "name": "@nocobase/plugin-notifications",
"version": "1.6.21", "version": "1.6.23",
"description": "", "description": "",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "./dist/server/index.js", "main": "./dist/server/index.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@nocobase/plugin-public-forms", "name": "@nocobase/plugin-public-forms",
"version": "1.6.21", "version": "1.6.23",
"main": "dist/server/index.js", "main": "dist/server/index.js",
"displayName": "Public forms", "displayName": "Public forms",
"displayName.zh-CN": "公开表单", "displayName.zh-CN": "公开表单",

Some files were not shown because too many files have changed in this diff Show More