Merge branch 'next' into develop

This commit is contained in:
katherinehhh
2025-10-28 09:24:38 +08:00
8 changed files with 151 additions and 69 deletions
+35
View File
@@ -5,6 +5,41 @@ 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/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.8.32](https://github.com/nocobase/nocobase/compare/v1.8.31...v1.8.32) - 2025-10-27
### 🚀 Improvements
- **[server]** Optimize the method for loading l10n resources to prevent blocking event loop ([#7653](https://github.com/nocobase/nocobase/pull/7653)) by @2013xile
- **[cache]** Avoid performance overhead caused by cloning Bloom filters ([#7652](https://github.com/nocobase/nocobase/pull/7652)) by @2013xile
- **[Action: Import records]** Improved error messaging when table headers are missing ([#7656](https://github.com/nocobase/nocobase/pull/7656)) by @mytharcher
### 🐛 Bug Fixes
- **[client]**
- fix error when clearing date field in filter block ([#7632](https://github.com/nocobase/nocobase/pull/7632)) by @katherinehhh
- prevent label word breaking in formItem label ([#7647](https://github.com/nocobase/nocobase/pull/7647)) by @katherinehhh
- fix subtable default value not working in edit form drawer ([#7631](https://github.com/nocobase/nocobase/pull/7631)) by @katherinehhh
- **[Collection field: administrative divisions of China]** Data import fails when the city and area have the same name ([#7673](https://github.com/nocobase/nocobase/pull/7673)) by @2013xile
- **[Workflow]**
- Fix the issue where, after deleting a node that starts branching, the key of the first node retained within the branch was incorrectly changed to a new value ([#7665](https://github.com/nocobase/nocobase/pull/7665)) by @mytharcher
- Fix logger error thrown when application stop ([#7639](https://github.com/nocobase/nocobase/pull/7639)) by @mytharcher
- **[File manager]** Fix the issue of `.msg` file can not be uploaded properly ([#7662](https://github.com/nocobase/nocobase/pull/7662)) by @mytharcher
- **[Data source: Main]** Fix the issue where metadata was not synchronized across multiple nodes after creating a reverse association field ([#7628](https://github.com/nocobase/nocobase/pull/7628)) by @mytharcher
- **[Workflow: Approval]**
- Fix the translation issue of the status text in approval completion notifications, using the systems default language for translation when the user has not set a language preference by @mytharcher
- Fix the issue where task count not updated after added assignee by @mytharcher
## [v1.8.31](https://github.com/nocobase/nocobase/compare/v1.8.30...v1.8.31) - 2025-10-17
### 🐛 Bug Fixes
+35
View File
@@ -5,6 +5,41 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
## [v1.8.32](https://github.com/nocobase/nocobase/compare/v1.8.31...v1.8.32) - 2025-10-27
### 🚀 优化
- **[server]** 优化加载本地化资源的方法,避免阻塞事件循环 ([#7653](https://github.com/nocobase/nocobase/pull/7653)) by @2013xile
- **[cache]** 避免因 clone 布隆过滤器造成的性能损耗 ([#7652](https://github.com/nocobase/nocobase/pull/7652)) by @2013xile
- **[操作:导入记录]** 改进了在未找到表头时的错误提示信息 ([#7656](https://github.com/nocobase/nocobase/pull/7656)) by @mytharcher
### 🐛 修复
- **[client]**
- 修复筛选区块中日期字段清除时报错的问题 ([#7632](https://github.com/nocobase/nocobase/pull/7632)) by @katherinehhh
- 修复字段标题换行截断单词的问题 ([#7647](https://github.com/nocobase/nocobase/pull/7647)) by @katherinehhh
- 修复编辑弹窗中子表格默认值失效的问题 ([#7631](https://github.com/nocobase/nocobase/pull/7631)) by @katherinehhh
- **[数据表字段:中国行政区划]** 城市和县区相同时,无法导入数据 ([#7673](https://github.com/nocobase/nocobase/pull/7673)) by @2013xile
- **[工作流]**
- 修复开启分支的节点删除后,保留的分支内部第一个节点的 key 被改为新值的问题 ([#7665](https://github.com/nocobase/nocobase/pull/7665)) by @mytharcher
- 修复应用停止时日志报错的问题 ([#7639](https://github.com/nocobase/nocobase/pull/7639)) by @mytharcher
- **[文件管理器]** 修复 `.msg` 文件无法正常上传的问题 ([#7662](https://github.com/nocobase/nocobase/pull/7662)) by @mytharcher
- **[数据源:主数据库]** 修复创建反向关系字段后,多节点未同步元数据的问题 ([#7628](https://github.com/nocobase/nocobase/pull/7628)) by @mytharcher
- **[工作流:审批]**
- 修复审批完成通知中的状态文本的翻译问题,当用户未设置语言偏好时使用系统配置的默认语言进行翻译 by @mytharcher
- 修复加签后待办数字未更新的问题 by @mytharcher
## [v1.8.31](https://github.com/nocobase/nocobase/compare/v1.8.30...v1.8.31) - 2025-10-17
### 🐛 修复
@@ -279,15 +279,15 @@ export function useBeforeUpload(rules) {
const error = validate(proxiedFile, rules);
if (error) {
proxiedFile.status = 'error';
proxiedFile.response = t(error);
file.status = 'error';
file.response = t(error);
} else {
if (proxiedFile.status === 'error') {
if (file.status === 'error') {
delete proxiedFile.status;
delete proxiedFile.response;
}
}
return error ? false : proxiedFile;
return error ? false : Promise.resolve(proxiedFile);
},
[rules],
);
@@ -25,7 +25,7 @@ export class ChinaRegionInterface extends BaseInterface {
});
for (let i = 0; i < items.length; i++) {
const instance = instances.find((item) => item.name === items[i]);
const instance = instances.find((item) => item.name === items[i] && item.level === i + 1);
if (!instance) {
throw new Error(`china region "${items[i]}" does not exist`);
}
@@ -10,13 +10,14 @@
import { PlusOutlined, DownOutlined } from '@ant-design/icons';
import { uid } from '@formily/shared';
import { ActionContext, i18n, SchemaComponent, useCompile, usePlugin, useRecord } from '@nocobase/client';
import { Button, Card, Dropdown } from 'antd';
import { Button, Card, Dropdown, message } from 'antd';
import _ from 'lodash';
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import FileManagerPlugin from '.';
import { storageSchema } from './schemas/storage';
import { storageTypes } from './schemas/storageTypes';
import { NAMESPACE, useFmTranslation } from './locale';
export const CreateStorage = () => {
const [schema, setSchema] = useState({});
@@ -98,66 +99,75 @@ export const EditStorage = () => {
const compile = useCompile();
const [visible, setVisible] = useState(false);
const { t } = useTranslation();
return (
<div>
<ActionContext.Provider value={{ visible, setVisible }}>
<a
onClick={() => {
setVisible(true);
const storageType = plugin.storageTypes.get(record.type);
if (storageType.fieldset['default']) {
storageType.fieldset['default']['x-reactions'] = (field) => {
if (field.initialValue) {
field.disabled = true;
} else {
field.disabled = false;
}
};
}
setSchema({
type: 'object',
const [messageApi, contextHolder] = message.useMessage();
const onEdit = useCallback(() => {
const storageType = plugin.storageTypes.get(record.type);
if (!storageType) {
messageApi.error(
t('Storage type {{type}} is not registered, please check if related plugin is enabled.', {
ns: NAMESPACE,
type: record.type,
}),
);
return;
}
setVisible(true);
if (storageType.fieldset['default']) {
storageType.fieldset['default']['x-reactions'] = (field) => {
if (field.initialValue) {
field.disabled = true;
} else {
field.disabled = false;
}
};
}
setSchema({
type: 'object',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
'x-decorator-props': {
initialValue: {
...record,
},
},
title: compile("{{t('Edit')}}") + ' - ' + compile(storageType.title),
properties: {
..._.cloneDeep(storageType.fieldset),
footer: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
'x-decorator-props': {
initialValue: {
...record,
},
cancel: {
title: '{{t("Cancel")}}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ cm.useCancelAction }}',
},
title: compile("{{t('Edit')}}") + ' - ' + compile(storageType.title),
properties: {
..._.cloneDeep(storageType.fieldset),
footer: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
cancel: {
title: '{{t("Cancel")}}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ cm.useCancelAction }}',
},
},
submit: {
title: '{{t("Submit")}}',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ cm.useUpdateAction }}',
},
},
},
},
},
submit: {
title: '{{t("Submit")}}',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ cm.useUpdateAction }}',
},
},
},
});
}}
>
{t('Edit')}
</a>
},
},
},
},
});
}, [compile, plugin.storageTypes, record]);
return (
<div>
{contextHolder}
<ActionContext.Provider value={{ visible, setVisible }}>
<a onClick={onEdit}>{t('Edit')}</a>
<SchemaComponent scope={{ createOnly: false }} schema={schema} />
</ActionContext.Provider>
</div>
@@ -40,5 +40,5 @@
"Aliyun OSS region part of the bucket. For example: \"oss-cn-beijing\".": "阿里云 OSS 存储桶所在区域。例如:\"oss-cn-beijing\"。",
"Timeout": "超时时间",
"Upload timeout for a single file in milliseconds. Default is 600000.": "上传单个文件的超时时间,单位为毫秒。默认为 600000。",
"Storage configuration not found. Please configure a storage provider first.": "存储配置未找到。请先配置存储提供程序。"
"Storage type {{type}} is not registered, please check if related plugin is enabled.": "{{type}} 类型的存储引擎未被注册,请检查相关插件是否已启用。"
}
@@ -288,7 +288,7 @@ describe('workflow > actions > nodes', () => {
filterByTk: n1.id,
});
const nodes = await workflow.getNodes();
const nodes = await workflow.getNodes({ order: [['id', 'ASC']] });
expect(nodes.length).toBe(0);
});
@@ -316,7 +316,7 @@ describe('workflow > actions > nodes', () => {
filterByTk: n1.id,
});
const nodes = await workflow.getNodes();
const nodes = await workflow.getNodes({ order: [['id', 'ASC']] });
expect(nodes.length).toBe(0);
});
@@ -357,7 +357,7 @@ describe('workflow > actions > nodes', () => {
keepBranch: 0,
});
const nodes = await workflow.getNodes();
const nodes = await workflow.getNodes({ order: [['id', 'ASC']] });
expect(nodes.length).toBe(1);
expect(nodes[0].id).toBe(n2.id);
});
@@ -393,9 +393,11 @@ describe('workflow > actions > nodes', () => {
keepBranch: 0,
});
const nodes = await workflow.getNodes();
const nodes = await workflow.getNodes({ order: [['id', 'ASC']] });
expect(nodes.length).toBe(1);
expect(nodes[0].id).toBe(n2.id);
// NOTE: ensure key is not updated to new value
expect(nodes[0].key).toBe(n2.key);
});
it('target has no upstream, 2 branches, no downstream, `keepBranch` as branch 2', async () => {
@@ -429,7 +431,7 @@ describe('workflow > actions > nodes', () => {
keepBranch: 1,
});
const nodes = await workflow.getNodes();
const nodes = await workflow.getNodes({ order: [['id', 'ASC']] });
expect(nodes.length).toBe(1);
expect(nodes[0].id).toBe(n3.id);
});
@@ -145,7 +145,7 @@ export async function destroy(context: Context, next) {
const { filterByTk, keepBranch } = context.action.params;
const keepBranchIndex = keepBranch == null || keepBranch === '' ? null : Number.parseInt(keepBranch, 10);
const fields = ['id', 'upstreamId', 'downstreamId', 'branchIndex'];
const fields = ['id', 'upstreamId', 'downstreamId', 'branchIndex', 'key'];
const instance = await repository.findOne({
filterByTk,
fields: [...fields, 'workflowId'],