V4.14.5.1 dev (#6290)

* chore: cherry pick some commits from v4.14.6-dev (#6287)

* fix: custom domain limitation (#6265)

* fix: system secret (#6259)

* fix: system secret

* chore: update docs

* chore: docs

* fix password variable & datetime picker (#6276)

* fix password variable & datetime picker

* doc

* chore: cherry pick some commits from v4.14.6-dev (#6287)

* fix: custom domain limitation (#6265)

* fix: system secret (#6259)

* fix: system secret

* chore: update docs

* chore: docs

* doc

* chore: docs

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: Finley Ge <finleyge@fastgpt.io>

* perf: extname computed (#6285)

* perf: extname computed

* chore: handle hash or query flags

---------

Co-authored-by: Finley Ge <finleyge@fastgpt.io>

* chore: docs (#6291)

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: Archer <545436317@qq.com>
This commit is contained in:
Finley Ge
2026-01-19 19:10:54 +08:00
committed by GitHub
parent b7a10bff2b
commit 8450a44d35
15 changed files with 464 additions and 64 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "app",
"version": "4.14.5",
"version": "4.14.5.1",
"private": false,
"scripts": {
"dev": "npm run build:workers && next dev",

View File

@@ -66,14 +66,17 @@ const LabelAndFormRender = ({
rules={{
validate: (value) => {
if (typeof value === 'number' || typeof value === 'boolean') return true;
if (inputType === InputTypeEnum.password && props.minLength) {
if (!value || typeof value !== 'object' || !value.value) return false;
if (value.value.length < props.minLength) {
if (!required) return true;
// 密码类型特殊处理:已加密的密码格式为 { value: '', secret: 'xxx' }
if (inputType === InputTypeEnum.password) {
const hasValue = value && typeof value === 'object' && (value.value || value.secret);
if (!hasValue) return false;
// 有 minLength 要求且正在输入新值时,检查长度
if (props.minLength && value.value && value.value.length < props.minLength) {
return t(`common:min_length`, { minLenth: props.minLength });
}
return true;
}
if (!required) return true;
if (inputType === InputTypeEnum.fileSelect) {
if (!value || !Array.isArray(value) || value.length === 0) {

View File

@@ -485,7 +485,7 @@ const InputTypeConfig = ({
setValue('timeRangeStart', date);
}}
popPosition="top"
timeGranularity={timeGranularity}
timeGranularity={timeGranularity || 'day'}
maxDate={timeRangeEnd ? new Date(timeRangeEnd) : undefined}
/>
</Box>
@@ -499,7 +499,7 @@ const InputTypeConfig = ({
setValue('timeRangeEnd', date);
}}
popPosition="top"
timeGranularity={timeGranularity}
timeGranularity={timeGranularity || 'day'}
minDate={timeRangeStart ? new Date(timeRangeStart) : undefined}
/>
</Box>
@@ -623,7 +623,7 @@ const InputTypeConfig = ({
setValue('defaultValue', date);
}}
popPosition="top"
timeGranularity={timeGranularity}
timeGranularity={timeGranularity || 'day'}
minDate={timeRangeStart ? new Date(timeRangeStart) : undefined}
maxDate={timeRangeEnd ? new Date(timeRangeEnd) : undefined}
/>
@@ -640,7 +640,7 @@ const InputTypeConfig = ({
setValue('defaultValue', [date, timeRangeEndDefault]);
}}
popPosition="top"
timeGranularity={timeGranularity}
timeGranularity={timeGranularity || 'day'}
minDate={timeRangeStart ? new Date(timeRangeStart) : undefined}
maxDate={
timeRangeEndDefault && timeRangeEnd
@@ -668,7 +668,7 @@ const InputTypeConfig = ({
setValue('defaultValue', [timeRangeStartDefault, date]);
}}
popPosition="top"
timeGranularity={timeGranularity}
timeGranularity={timeGranularity || 'day'}
minDate={
timeRangeStartDefault && timeRangeStart
? new Date(

View File

@@ -237,7 +237,7 @@ const Reference = ({
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
isDisabled: isEmptyItem,
minW: '240px',
w: '240px',
_hover: {
borderColor: 'blue.300'
}

View File

@@ -74,11 +74,11 @@ const CustomDomain = () => {
const [editDomain, setEditDomain] = useState<CustomDomainType | undefined>(undefined);
// 检查用户是否有 advanced 套餐
const isAdvancedPlan = useMemo(() => {
const isSupportCustomDomain = useMemo(() => {
const plan = teamPlanStatus?.standard;
if (!plan) return false;
return plan.customDomain && plan.customDomain > 0;
return !!(plan.customDomain && plan.customDomain > 0);
}, [teamPlanStatus?.standard]);
return (
@@ -100,7 +100,7 @@ const CustomDomain = () => {
<Button
variant="whitePrimaryOutline"
onClick={onOpenCreateModal}
isDisabled={!isAdvancedPlan}
isDisabled={isSupportCustomDomain}
>
{t('common:Add')}
</Button>
@@ -185,7 +185,7 @@ const CustomDomain = () => {
>
<EmptyTip
text={
!isAdvancedPlan && (
isSupportCustomDomain && (
<Flex flexDir="column" alignItems="center">
<Box>{t('account:upgrade_to_use_custom_domain')}</Box>
<Button

View File

@@ -0,0 +1,101 @@
import { NextAPI } from '@/service/middleware/entry';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoSystemTool } from '@fastgpt/service/core/plugin/tool/systemToolSchema';
import type { AnyBulkWriteOperation } from '@fastgpt/service/common/mongo';
import type { SystemPluginToolCollectionType } from '@fastgpt/global/core/plugin/tool/type';
export type ResponseType = {
message: string;
};
/**
* 4.14.5.1 版本数据初始化脚本
* 1. 迁移 system tool 数据:如果工具集配置了系统密钥,则需要给其子工具都写入 InputListVal 字段
*/
const migrateSystemSecret = async () => {
// 1. find all system tools
const tools = await MongoSystemTool.find(
{
pluginId: {
$regex: /systemTool-/
}
},
{
pluginId: 1,
inputListVal: 1
}
).lean();
// 2. 构建工具集和子工具的映射关系
const toolSetMap = new Map<string, (typeof tools)[0]>(); // 工具集 ID -> 工具集对象
const childToolsMap = new Map<string, typeof tools>(); // 工具集 ID -> 子工具列表
for (const tool of tools) {
if (tool.pluginId.includes('/')) {
// 这是一个子工具
const toolSetId = tool.pluginId.split('/')[0];
if (!childToolsMap.has(toolSetId)) {
childToolsMap.set(toolSetId, []);
}
childToolsMap.get(toolSetId)!.push(tool);
} else {
// 这是一个工具集
toolSetMap.set(tool.pluginId, tool);
}
}
// 3. 构建批量更新操作
const ops: AnyBulkWriteOperation<SystemPluginToolCollectionType>[] = [];
for (const [toolSetId, toolSet] of toolSetMap.entries()) {
// 只处理配置了系统密钥的工具集
if (toolSet.inputListVal) {
const childTools = childToolsMap.get(toolSetId) || [];
// 为每个子工具添加更新操作
for (const childTool of childTools) {
ops.push({
updateOne: {
filter: {
_id: childTool._id
},
update: {
$set: {
inputListVal: toolSet.inputListVal
}
}
}
});
}
}
}
// 4. 执行批量更新
if (ops.length > 0) {
await MongoSystemTool.bulkWrite(ops);
console.log(`Updated ${ops.length} child tools with system secrets`);
}
return ops.length;
};
/**
* 主处理函数
*/
async function handler(
req: ApiRequestProps,
_res: ApiResponseType<ResponseType>
): Promise<ResponseType> {
await authCert({ req, authRoot: true });
// 执行系统工具密钥迁移
const updatedCount = await migrateSystemSecret();
return {
message: `Completed v4.14.6 initialization: Updated ${updatedCount} child tools with system secrets`
};
}
export default NextAPI(handler);

View File

@@ -68,7 +68,8 @@ async function handler(
{ pluginId: tool.pluginId },
{
pluginId: tool.pluginId,
systemKeyCost: tool.systemKeyCost
systemKeyCost: tool.systemKeyCost,
inputListVal: updateFields.inputListVal
},
{ upsert: true, session }
);