This commit is contained in:
Archer
2024-06-12 15:17:21 +08:00
committed by GitHub
parent bc6864c3dc
commit d0085a23e6
61 changed files with 558 additions and 348 deletions

View File

@@ -11,7 +11,7 @@ weight: 708
**开发环境下**,你需要将示例配置文件 `config.json` 复制成 `config.local.json` 文件才会生效。 **开发环境下**,你需要将示例配置文件 `config.json` 复制成 `config.local.json` 文件才会生效。
这个配置文件中包含了系统参数和各个模型配置`使用时务必去掉注释!!!!!!!!!!!!!!` 这个配置文件中包含了系统参数和各个模型配置
## 4.6.8+ 版本新配置文件 ## 4.6.8+ 版本新配置文件
@@ -158,7 +158,7 @@ llm模型全部合并
1. [部署 ReRank 模型](/docs/development/custom-models/bge-rerank/) 1. [部署 ReRank 模型](/docs/development/custom-models/bge-rerank/)
1. 找到 FastGPT 的配置文件中的 `reRankModels` 4.6.6 以前是 `ReRankModels` 1. 找到 FastGPT 的配置文件中的 `reRankModels` 4.6.6 以前是 `ReRankModels`
2. 修改对应的值:(记得去掉注释) 2. 修改对应的值:
```json ```json
{ {

View File

@@ -4,14 +4,26 @@ description: 'FastGPT V4.8.4 更新说明'
icon: 'upgrade' icon: 'upgrade'
draft: false draft: false
toc: true toc: true
weight: 821 weight: 820
--- ---
<!-- ## 升级指南 ## 升级指南
### 1. 修改镜像
- fastgpt 镜像 tag 修改成 v4.8.4 - fastgpt 镜像 tag 修改成 v4.8.4
- fastgpt-sandbox 镜像 tag 修改成 v4.8.4 (选择性,无变更) - fastgpt-sandbox 镜像 tag 修改成 v4.8.4 (选择性,无变更)
- 商业版镜像 tag 修改成 v4.8.4 --> - 商业版镜像 tag 修改成 v4.8.4
### 2. 商业版用户执行初始化
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 商业版的域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/init/484' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
## V4.8.4 更新说明 ## V4.8.4 更新说明

View File

@@ -154,6 +154,8 @@ services:
- MILVUS_TOKEN=none - MILVUS_TOKEN=none
# sandbox 地址 # sandbox 地址
- SANDBOX_URL=http://sandbox:3000 - SANDBOX_URL=http://sandbox:3000
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
volumes: volumes:
- ./config.json:/app/data/config.json - ./config.json:/app/data/config.json

View File

@@ -111,6 +111,8 @@ services:
- PG_URL=postgresql://username:password@pg:5432/postgres - PG_URL=postgresql://username:password@pg:5432/postgres
# sandbox 地址 # sandbox 地址
- SANDBOX_URL=http://sandbox:3000 - SANDBOX_URL=http://sandbox:3000
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
volumes: volumes:
- ./config.json:/app/data/config.json - ./config.json:/app/data/config.json

View File

@@ -92,6 +92,8 @@ services:
- MILVUS_TOKEN=zilliz_cloud_token - MILVUS_TOKEN=zilliz_cloud_token
# sandbox 地址 # sandbox 地址
- SANDBOX_URL=http://sandbox:3000 - SANDBOX_URL=http://sandbox:3000
# 日志等级: debug, info, warn, error
- LOG_LEVEL=info
volumes: volumes:
- ./config.json:/app/data/config.json - ./config.json:/app/data/config.json

View File

@@ -1,9 +1,8 @@
import { UpdateClbPermissionProps } from '../../support/permission/collaborator';
import { PermissionValueType } from '../../support/permission/type'; import { PermissionValueType } from '../../support/permission/type';
export type UpdateAppCollaboratorBody = { export type UpdateAppCollaboratorBody = UpdateClbPermissionProps & {
appId: string; appId: string;
tmbIds: string[];
permission: PermissionValueType;
}; };
export type AppCollaboratorDeleteParams = { export type AppCollaboratorDeleteParams = {

View File

@@ -20,6 +20,7 @@ import { RuntimeNodeItemType } from '../runtime/type';
import { PluginTypeEnum } from '../../plugin/constants'; import { PluginTypeEnum } from '../../plugin/constants';
import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge'; import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge';
import { NextApiResponse } from 'next'; import { NextApiResponse } from 'next';
import { AppDetailType, AppSchema } from '../../app/type';
export type FlowNodeCommonType = { export type FlowNodeCommonType = {
flowNodeType: FlowNodeTypeEnum; // render node card flowNodeType: FlowNodeTypeEnum; // render node card
@@ -131,7 +132,7 @@ export type ChatDispatchProps = {
teamId: string; teamId: string;
tmbId: string; tmbId: string;
user: UserModelSchema; user: UserModelSchema;
appId?: string; app: AppDetailType | AppSchema;
chatId?: string; chatId?: string;
responseChatItemId?: string; responseChatItemId?: string;
histories: ChatItemType[]; histories: ChatItemType[];

View File

@@ -8,3 +8,8 @@ export type CollaboratorItemType = {
name: string; name: string;
avatar: string; avatar: string;
}; };
export type UpdateClbPermissionProps = {
tmbIds: string[];
permission: PermissionValueType;
};

View File

@@ -11,7 +11,10 @@ export enum AuthUserTypeEnum {
export enum PermissionTypeEnum { export enum PermissionTypeEnum {
'private' = 'private', 'private' = 'private',
'public' = 'public' 'public' = 'public',
clbPrivate = 'clbPrivate',
publicRead = 'publicRead',
publicWrite = 'publicWrite'
} }
export const PermissionTypeMap = { export const PermissionTypeMap = {
[PermissionTypeEnum.private]: { [PermissionTypeEnum.private]: {
@@ -21,6 +24,18 @@ export const PermissionTypeMap = {
[PermissionTypeEnum.public]: { [PermissionTypeEnum.public]: {
iconLight: 'support/permission/publicLight', iconLight: 'support/permission/publicLight',
label: 'permission.Public' label: 'permission.Public'
},
[PermissionTypeEnum.publicRead]: {
iconLight: 'support/permission/publicLight',
label: '团队可访问'
},
[PermissionTypeEnum.publicWrite]: {
iconLight: 'support/permission/publicLight',
label: '团队可编辑'
},
[PermissionTypeEnum.clbPrivate]: {
iconLight: 'support/permission/privateLight',
label: '仅协作者'
} }
}; };

View File

@@ -1,11 +1,14 @@
import { PermissionKeyEnum, PermissionList, ReadPermissionVal } from '../constant'; import { PermissionKeyEnum, PermissionList, ReadPermissionVal } from '../constant';
import { PermissionListType } from '../type';
export const TeamPermissionList = { export const TeamPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: { [PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read] ...PermissionList[PermissionKeyEnum.read],
description: '成员仅可阅读相关资源,无法新建资源'
}, },
[PermissionKeyEnum.write]: { [PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write] ...PermissionList[PermissionKeyEnum.write],
description: '除了可读资源外,还可以新建新的资源'
}, },
[PermissionKeyEnum.manage]: { [PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage], ...PermissionList[PermissionKeyEnum.manage],

View File

@@ -22,7 +22,7 @@ export type UpdateTeamProps = {
/* ------------- member ----------- */ /* ------------- member ----------- */
export type DelMemberProps = { export type DelMemberProps = {
memberId: string; tmbId: string;
}; };
export type UpdateTeamMemberProps = { export type UpdateTeamMemberProps = {
teamId: string; teamId: string;
@@ -33,7 +33,7 @@ export type UpdateTeamMemberProps = {
export type InviteMemberProps = { export type InviteMemberProps = {
teamId: string; teamId: string;
usernames: string[]; usernames: string[];
role: `${TeamMemberRoleEnum}`; permission: PermissionValueType;
}; };
export type UpdateInviteProps = { export type UpdateInviteProps = {
tmbId: string; tmbId: string;
@@ -43,8 +43,3 @@ export type InviteMemberResponse = Record<
'invite' | 'inValid' | 'inTeam', 'invite' | 'inValid' | 'inTeam',
{ username: string; userId: string }[] { username: string; userId: string }[]
>; >;
export type UpdateTeamMemberPermissionProps = {
memberIds: string[];
permission: PermissionValueType;
};

View File

@@ -70,7 +70,7 @@ export const countGptMessagesTokens = (
callbackMap[id] = (data) => { callbackMap[id] = (data) => {
// 检测是否有内存泄漏 // 检测是否有内存泄漏
addLog.info(`Count token time: ${Date.now() - start}, token: ${data}`); addLog.debug(`Count token time: ${Date.now() - start}, token: ${data}`);
// console.log(process.memoryUsage()); // console.log(process.memoryUsage());
resolve(data); resolve(data);

View File

@@ -1,11 +1,12 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import chalk from 'chalk'; import chalk from 'chalk';
import { isProduction } from './constants';
enum LogLevelEnum { enum LogLevelEnum {
debug = 'debug', debug = 0,
info = 'info', info = 1,
warn = 'warn', warn = 2,
error = 'error' error = 3
} }
const logMap = { const logMap = {
[LogLevelEnum.debug]: { [LogLevelEnum.debug]: {
@@ -21,20 +22,35 @@ const logMap = {
levelLog: chalk.red('[Error]') levelLog: chalk.red('[Error]')
} }
}; };
const envLogLevelMap: Record<string, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
const logLevel = (() => {
if (!isProduction) return LogLevelEnum.debug;
const envLogLevel = (process.env.LOG_LEVEL || 'info').toLocaleLowerCase();
if (!envLogLevel || envLogLevelMap[envLogLevel] === undefined) return LogLevelEnum.info;
return envLogLevelMap[envLogLevel];
})();
/* add logger */ /* add logger */
export const addLog = { export const addLog = {
log(level: LogLevelEnum, msg: string, obj: Record<string, any> = {}) { log(level: LogLevelEnum, msg: string, obj: Record<string, any> = {}) {
if (level < logLevel) return;
const stringifyObj = JSON.stringify(obj); const stringifyObj = JSON.stringify(obj);
const isEmpty = Object.keys(obj).length === 0; const isEmpty = Object.keys(obj).length === 0;
console.log( console.log(
`${logMap[level].levelLog} ${dayjs().format('YYYY-MM-DD HH:mm:ss')} ${msg} ${ `${logMap[level].levelLog} ${dayjs().format('YYYY-MM-DD HH:mm:ss')} ${msg} ${
level !== 'error' && !isEmpty ? stringifyObj : '' level !== LogLevelEnum.error && !isEmpty ? stringifyObj : ''
}` }`
); );
level === 'error' && console.error(obj); level === LogLevelEnum.error && console.error(obj);
const lokiUrl = process.env.LOKI_LOG_URL as string; const lokiUrl = process.env.LOKI_LOG_URL as string;
if (!lokiUrl) return; if (!lokiUrl) return;

View File

@@ -142,17 +142,17 @@ export const delCollectionRelatedSource = async ({
.map((item) => item?.metadata?.relatedImgId || '') .map((item) => item?.metadata?.relatedImgId || '')
.filter(Boolean); .filter(Boolean);
// delete files
await delFileByFileIdList({
bucketName: BucketNameEnum.dataset,
fileIdList
});
// delete images // delete images
await delImgByRelatedId({ await delImgByRelatedId({
teamId, teamId,
relateIds: relatedImageIds, relateIds: relatedImageIds,
session session
}); });
// delete files
await delFileByFileIdList({
bucketName: BucketNameEnum.dataset,
fileIdList
});
}; };
/** /**
* delete collection and it related data * delete collection and it related data
@@ -182,14 +182,16 @@ export async function delCollectionAndRelatedSources({
); );
const collectionIds = collections.map((item) => String(item._id)); const collectionIds = collections.map((item) => String(item._id));
await delCollectionRelatedSource({ collections, session });
// delete training data // delete training data
await MongoDatasetTraining.deleteMany({ await MongoDatasetTraining.deleteMany({
teamId, teamId,
datasetIds: { $in: datasetIds }, datasetIds: { $in: datasetIds },
collectionId: { $in: collectionIds } collectionId: { $in: collectionIds }
}); });
/* file and imgs */
await delCollectionRelatedSource({ collections, session });
// delete dataset.datas // delete dataset.datas
await MongoDatasetData.deleteMany( await MongoDatasetData.deleteMany(
{ teamId, datasetIds: { $in: datasetIds }, collectionId: { $in: collectionIds } }, { teamId, datasetIds: { $in: datasetIds }, collectionId: { $in: collectionIds } },
@@ -199,6 +201,7 @@ export async function delCollectionAndRelatedSources({
// delete collections // delete collections
await MongoDatasetCollection.deleteMany( await MongoDatasetCollection.deleteMany(
{ {
teamId,
_id: { $in: collectionIds } _id: { $in: collectionIds }
}, },
{ session } { session }

View File

@@ -42,7 +42,7 @@ export async function findCollectionAndChild({
return collections; return collections;
} }
const [collection, childCollections] = await Promise.all([ const [collection, childCollections] = await Promise.all([
MongoDatasetCollection.findById(collectionId, fields), MongoDatasetCollection.findById(collectionId, fields).lean(),
find(collectionId) find(collectionId)
]); ]);

View File

@@ -82,17 +82,18 @@ export async function delDatasetRelevantData({
teamId, teamId,
datasetId: { $in: datasetIds } datasetId: { $in: datasetIds }
}, },
'_id teamId fileId metadata' '_id teamId datasetId fileId metadata'
).lean(); ).lean();
// image and file
await delCollectionRelatedSource({ collections, session });
// delete training data // delete training data
await MongoDatasetTraining.deleteMany({ await MongoDatasetTraining.deleteMany({
teamId, teamId,
datasetId: { $in: datasetIds } datasetId: { $in: datasetIds }
}); });
// image and file
await delCollectionRelatedSource({ collections, session });
// delete dataset.datas // delete dataset.datas
await MongoDatasetData.deleteMany({ teamId, datasetId: { $in: datasetIds } }, { session }); await MongoDatasetData.deleteMany({ teamId, datasetId: { $in: datasetIds } }, { session });

View File

@@ -407,13 +407,13 @@ export function responseStatus({
/* get system variable */ /* get system variable */
export function getSystemVariable({ export function getSystemVariable({
user, user,
appId, app,
chatId, chatId,
responseChatItemId, responseChatItemId,
histories = [] histories = []
}: Props) { }: Props) {
return { return {
appId, appId: String(app._id),
chatId, chatId,
responseChatItemId, responseChatItemId,
histories, histories,

View File

@@ -43,7 +43,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
let { let {
res, res,
detail, detail,
appId, app: { _id: appId },
chatId, chatId,
stream, stream,
responseChatItemId, responseChatItemId,

View File

@@ -33,8 +33,7 @@ type Response = DispatchNodeResultType<{
export const dispatchAppRequest = async (props: Props): Promise<Response> => { export const dispatchAppRequest = async (props: Props): Promise<Response> => {
const { const {
res, res,
teamId, app: workflowApp,
tmbId,
stream, stream,
detail, detail,
histories, histories,
@@ -46,10 +45,11 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
return Promise.reject('Input is empty'); return Promise.reject('Input is empty');
} }
// 检查该工作流的tmb是否有调用该app的权限不是校验对话的人是否有权限
const { app: appData } = await authAppByTmbId({ const { app: appData } = await authAppByTmbId({
appId: app.id, appId: app.id,
teamId, teamId: workflowApp.teamId,
tmbId, tmbId: workflowApp.tmbId,
per: ReadPermissionVal per: ReadPermissionVal
}); });
@@ -68,7 +68,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({ const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
...props, ...props,
appId: app.id, app: appData,
runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)), runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)),
runtimeEdges: initWorkflowEdgeStatus(appData.edges), runtimeEdges: initWorkflowEdgeStatus(appData.edges),
histories: chatHistories, histories: chatHistories,

View File

@@ -21,7 +21,7 @@ const UNDEFINED_SIGN = 'UNDEFINED_SIGN';
export const dispatchLafRequest = async (props: LafRequestProps): Promise<LafResponse> => { export const dispatchLafRequest = async (props: LafRequestProps): Promise<LafResponse> => {
let { let {
appId, app: { _id: appId },
chatId, chatId,
responseChatItemId, responseChatItemId,
variables, variables,

View File

@@ -7,8 +7,6 @@ import { AuthUserTypeEnum, PerResourceTypeEnum } from '@fastgpt/global/support/p
import { authOpenApiKey } from '../openapi/auth'; import { authOpenApiKey } from '../openapi/auth';
import { FileTokenQuery } from '@fastgpt/global/common/file/type'; import { FileTokenQuery } from '@fastgpt/global/common/file/type';
import { MongoResourcePermission } from './schema'; import { MongoResourcePermission } from './schema';
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { mongoSessionRun } from '../../common/mongo/sessionRun';
export const getResourcePermission = async ({ export const getResourcePermission = async ({
resourceType, resourceType,
@@ -36,41 +34,6 @@ export const getResourcePermission = async ({
export const delResourcePermissionById = (id: string) => { export const delResourcePermissionById = (id: string) => {
return MongoResourcePermission.findByIdAndRemove(id); return MongoResourcePermission.findByIdAndRemove(id);
}; };
export const updateResourcePermission = async ({
resourceId,
resourceType,
teamId,
tmbIdList,
permission
}: {
resourceId?: string;
resourceType: PerResourceTypeEnum;
teamId: string;
tmbIdList: string[];
permission: PermissionValueType;
}) => {
await mongoSessionRun((session) => {
return Promise.all(
tmbIdList.map((tmbId) =>
MongoResourcePermission.findOneAndUpdate(
{
resourceType,
teamId,
tmbId,
resourceId
},
{
permission
},
{
session,
upsert: true
}
)
)
);
});
};
/* 下面代码等迁移 */ /* 下面代码等迁移 */
/* create token */ /* create token */

View File

@@ -45,6 +45,11 @@ try {
unique: true unique: true
} }
); );
ResourcePermissionSchema.index({
resourceType: 1,
teamId: 1,
resourceId: 1
});
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@@ -9,10 +9,7 @@ import { MongoTeamMember } from './teamMemberSchema';
import { MongoTeam } from './teamSchema'; import { MongoTeam } from './teamSchema';
import { UpdateTeamProps } from '@fastgpt/global/support/user/team/controller'; import { UpdateTeamProps } from '@fastgpt/global/support/user/team/controller';
import { getResourcePermission } from '../../permission/controller'; import { getResourcePermission } from '../../permission/controller';
import { import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
PerResourceTypeEnum,
ReadPermissionVal
} from '@fastgpt/global/support/permission/constant';
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller'; import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemType> { async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemType> {

View File

@@ -21,6 +21,7 @@ export type SelectProps = ButtonProps & {
list: { list: {
alias?: string; alias?: string;
label: string | React.ReactNode; label: string | React.ReactNode;
description?: string;
value: string | number; value: string | number;
}[]; }[];
isLoading?: boolean; isLoading?: boolean;
@@ -125,10 +126,12 @@ const MySelect = (
{...menuItemStyles} {...menuItemStyles}
{...(value === item.value {...(value === item.value
? { ? {
color: 'primary.500', color: 'primary.600',
bg: 'myWhite.300' bg: 'myGray.100'
} }
: {})} : {
color: 'myGray.900'
})}
onClick={() => { onClick={() => {
if (onchange && value !== item.value) { if (onchange && value !== item.value) {
onchange(item.value); onchange(item.value);
@@ -136,8 +139,14 @@ const MySelect = (
}} }}
whiteSpace={'pre-wrap'} whiteSpace={'pre-wrap'}
fontSize={'sm'} fontSize={'sm'}
display={'block'}
> >
{item.label} <Box>{item.label}</Box>
{item.description && (
<Box color={'myGray.500'} fontSize={'xs'}>
{item.description}
</Box>
)}
</MenuItem> </MenuItem>
))} ))}
</MenuList> </MenuList>

3
pnpm-lock.yaml generated
View File

@@ -422,6 +422,9 @@ importers:
js-yaml: js-yaml:
specifier: ^4.1.0 specifier: ^4.1.0
version: 4.1.0 version: 4.1.0
json5:
specifier: ^2.2.3
version: 2.2.3
jsonwebtoken: jsonwebtoken:
specifier: ^9.0.2 specifier: ^9.0.2
version: 9.0.2 version: 9.0.2

View File

@@ -32,5 +32,7 @@ SANDBOX_URL=http://localhost:3001
PRO_URL= PRO_URL=
# 首页路径 # 首页路径
HOME_URL=/ HOME_URL=/
# 日志等级: debug, info, warn, error
LOG_LEVEL=info
# Loki Log Path # Loki Log Path
# LOKI_LOG_URL= # LOKI_LOG_URL=

View File

@@ -1,37 +1,36 @@
// 已使用 json5 进行解析,会自动去掉注释,无需手动去除
{ {
"feConfigs": { "feConfigs": {
"lafEnv": "https://laf.dev" "lafEnv": "https://laf.dev" // laf环境。 https://laf.run (杭州阿里云) ,或者私有化的laf环境。如果使用 Laf openapi 功能,需要最新版的 laf 。
}, },
"systemEnv": { "systemEnv": {
"openapiPrefix": "fastgpt",
"vectorMaxProcess": 15, "vectorMaxProcess": 15,
"qaMaxProcess": 15, "qaMaxProcess": 15,
"pgHNSWEfSearch": 100, "pgHNSWEfSearch": 100 // 向量搜索参数。越大搜索越精确但是速度越慢。设置为100有99%+精度。
"tokenWorkers": 20
}, },
"llmModels": [ "llmModels": [
{ {
"model": "gpt-3.5-turbo", "model": "gpt-3.5-turbo", // 模型名(对应OneAPI中渠道的模型名)
"name": "gpt-3.5-turbo", "name": "gpt-3.5-turbo", // 模型别名
"maxContext": 16000, "avatar": "/imgs/model/openai.svg", // 模型的logo
"avatar": "/imgs/model/openai.svg", "maxContext": 16000, // 最大上下文
"maxResponse": 4000, "maxResponse": 4000, // 最大回复
"quoteMaxToken": 13000, "quoteMaxToken": 13000, // 最大引用内容
"maxTemperature": 1.2, "maxTemperature": 1.2, // 最大温度
"charsPointsPrice": 0, "charsPointsPrice": 0, // n积分/1k token商业版
"censor": false, "censor": false, // 是否开启敏感校验(商业版)
"vision": false, "vision": false, // 是否支持图片输入
"datasetProcess": true, "datasetProcess": true, // 是否设置为知识库处理模型QA务必保证至少有一个为true否则知识库会报错
"usedInClassify": true, "usedInClassify": true, // 是否用于问题分类务必保证至少有一个为true
"usedInExtractFields": true, "usedInExtractFields": true, // 是否用于内容提取务必保证至少有一个为true
"usedInToolCall": true, "usedInToolCall": true, // 是否用于工具调用务必保证至少有一个为true
"usedInQueryExtension": true, "usedInQueryExtension": true, // 是否用于问题优化务必保证至少有一个为true
"toolChoice": true, "toolChoice": true, // 是否支持工具选择分类内容提取工具调用会用到。目前只有gpt支持
"functionCall": true, "functionCall": false, // 是否支持函数调用(分类,内容提取,工具调用会用到。会优先使用 toolChoice如果为false则使用 functionCall如果仍为 false则使用提示词模式
"customCQPrompt": "", "customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
"customExtractPrompt": "", "customExtractPrompt": "", // 自定义内容提取提示词
"defaultSystemChatPrompt": "", "defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
"defaultConfig": {} "defaultConfig": {} // 请求API时挟带一些默认配置比如 GLM4 的 top_p
}, },
{ {
"model": "gpt-4-0125-preview", "model": "gpt-4-0125-preview",
@@ -82,40 +81,16 @@
], ],
"vectorModels": [ "vectorModels": [
{ {
"model": "text-embedding-3-large", "model": "text-embedding-ada-002", // 模型名与OneAPI对应
"name": "Embedding-3-large", "name": "Embedding-2", // 模型展示名
"avatar": "/imgs/model/openai.svg", "avatar": "/imgs/model/openai.svg", // logo
"charsPointsPrice": 0, "charsPointsPrice": 0, // n积分/1k token
"defaultToken": 512, "defaultToken": 700, // 默认文本分割时候的 token
"maxToken": 3000, "maxToken": 3000, // 最大 token
"weight": 100, "weight": 100, // 优先训练权重
"dbConfig": {}, "defaultConfig": {}, // 自定义额外参数。例如,如果希望使用 embedding3-large 的话,可以传入 dimensions:1024来返回1024维度的向量。目前必须小于1536维度
"queryConfig": {}, "dbConfig": {}, // 存储时的额外参数(非对称向量模型时候需要用到)
"defaultConfig": { "queryConfig": {} // 参训时的额外参数
"dimensions": 1024
}
},
{
"model": "text-embedding-3-small",
"name": "Embedding-3-small",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {}
},
{
"model": "text-embedding-ada-002",
"name": "text-embedding-ada-002",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {}
} }
], ],
"reRankModels": [], "reRankModels": [],
@@ -125,36 +100,12 @@
"name": "OpenAI TTS1", "name": "OpenAI TTS1",
"charsPointsPrice": 0, "charsPointsPrice": 0,
"voices": [ "voices": [
{ { "label": "Alloy", "value": "alloy", "bufferId": "openai-Alloy" },
"label": "Alloy", { "label": "Echo", "value": "echo", "bufferId": "openai-Echo" },
"value": "alloy", { "label": "Fable", "value": "fable", "bufferId": "openai-Fable" },
"bufferId": "openai-Alloy" { "label": "Onyx", "value": "onyx", "bufferId": "openai-Onyx" },
}, { "label": "Nova", "value": "nova", "bufferId": "openai-Nova" },
{ { "label": "Shimmer", "value": "shimmer", "bufferId": "openai-Shimmer" }
"label": "Echo",
"value": "echo",
"bufferId": "openai-Echo"
},
{
"label": "Fable",
"value": "fable",
"bufferId": "openai-Fable"
},
{
"label": "Onyx",
"value": "onyx",
"bufferId": "openai-Onyx"
},
{
"label": "Nova",
"value": "nova",
"bufferId": "openai-Nova"
},
{
"label": "Shimmer",
"value": "shimmer",
"bufferId": "openai-Shimmer"
}
] ]
} }
], ],

View File

@@ -1223,6 +1223,7 @@
"Default permission": "Default permission", "Default permission": "Default permission",
"Manage": "Manage", "Manage": "Manage",
"Not collaborator": "Not collaborator", "Not collaborator": "Not collaborator",
"Owner": "Owner",
"Permission": "Permission", "Permission": "Permission",
"Permission config": "Permission config", "Permission config": "Permission config",
"Private": "Private", "Private": "Private",
@@ -1571,9 +1572,6 @@
"Invite Member Success Tip": "Invitation completed\nSuccess: {{success}}\nInvalid usernames: {{inValid}}\nAlready in team: {{inTeam}}", "Invite Member Success Tip": "Invitation completed\nSuccess: {{success}}\nInvalid usernames: {{inValid}}\nAlready in team: {{inTeam}}",
"Invite Member Tips": "The invitee can access or use other resources within the team", "Invite Member Tips": "The invitee can access or use other resources within the team",
"Invite Role Admin Alias": "Invite Admin", "Invite Role Admin Alias": "Invite Admin",
"Invite Role Admin Tip": "Admin\nCan create, edit, and use team resources",
"Invite Role Visitor Alias": "Invite Visitor",
"Invite Role Visitor Tip": "Visitor\nCan only use resources, no creation or editing rights",
"Leave Team": "Leave Team", "Leave Team": "Leave Team",
"Leave Team Failed": "Failed to leave team", "Leave Team Failed": "Failed to leave team",
"Manage": "Team Management", "Manage": "Team Management",

View File

@@ -1,5 +1,21 @@
{ {
"permission": {
"Set read permission": "Read permission",
"Set write permission": "Write permission"
},
"team": { "team": {
"Add manager": "Add manager" "Add manager": "Add manager"
},
"user": {
"team": {
"permission": {
"Manage": "Admin",
"Manage tip": "Team administrator with full permissions",
"Read": "Read",
"Read desc": "Members can only read related resources and cannot create new resources",
"Write": "Write",
"Write tip": "In addition to readable resources, you can create new resources"
}
}
} }
} }

View File

@@ -1231,6 +1231,7 @@
"Default permission": "默认权限", "Default permission": "默认权限",
"Manage": "管理", "Manage": "管理",
"Not collaborator": "暂无协作者", "Not collaborator": "暂无协作者",
"Owner": "创建者",
"Permission": "权限", "Permission": "权限",
"Permission config": "权限配置", "Permission config": "权限配置",
"Private": "私有", "Private": "私有",
@@ -1579,9 +1580,6 @@
"Invite Member Success Tip": "邀请成员完成\n成功: {{success}}人\n用户名无效: {{inValid}}\n已在团队中:{{inTeam}}", "Invite Member Success Tip": "邀请成员完成\n成功: {{success}}人\n用户名无效: {{inValid}}\n已在团队中:{{inTeam}}",
"Invite Member Tips": "对方可查阅或使用团队内的其他资源", "Invite Member Tips": "对方可查阅或使用团队内的其他资源",
"Invite Role Admin Alias": "邀请管理员加入", "Invite Role Admin Alias": "邀请管理员加入",
"Invite Role Admin Tip": "管理员\n可创建、编辑和使用团队资源",
"Invite Role Visitor Alias": "邀请访客加入",
"Invite Role Visitor Tip": "访客\n仅可使用资源无创建编辑权限",
"Leave Team": "离开团队", "Leave Team": "离开团队",
"Leave Team Failed": "离开团队异常", "Leave Team Failed": "离开团队异常",
"Manage": "团队管理", "Manage": "团队管理",

View File

@@ -1,4 +1,14 @@
{ {
"permission": {
"Manage": "管理员",
"Manage tip": "团队管理员,拥有全部权限",
"Read": "仅读",
"Read desc": "成员仅可阅读相关资源,无法新建资源",
"Set read permission": "设为仅读",
"Set write permission": "设为可写",
"Write": "可写",
"Write tip": "除了可读资源外,还可以新建新的资源"
},
"team": { "team": {
"Add manager": "添加管理员" "Add manager": "添加管理员"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "app", "name": "app",
"version": "4.8.3", "version": "4.8.4",
"private": false, "private": false,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@@ -43,6 +43,7 @@
"mermaid": "^10.2.3", "mermaid": "^10.2.3",
"nanoid": "^4.0.1", "nanoid": "^4.0.1",
"next": "14.2.3", "next": "14.2.3",
"json5": "^2.2.3",
"next-i18next": "15.2.0", "next-i18next": "15.2.0",
"nextjs-node-loader": "^1.1.5", "nextjs-node-loader": "^1.1.5",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",

View File

@@ -8,13 +8,13 @@ import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { PermissionValueType } from '@fastgpt/global/support/permission/type'; import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import DefaultPermissionList from '@/components/support/permission/DefaultPerList'; import DefaultPermissionList from '@/components/support/permission/DefaultPerList';
import { import CollaboratorContextProvider, {
CollaboratorContextProvider,
MemberManagerInputPropsType MemberManagerInputPropsType
} from '../../support/permission/MemberManager/context'; } from '../../support/permission/MemberManager/context';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
const FolderSlideCard = ({ const FolderSlideCard = ({
refreshDeps,
name, name,
intro, intro,
onEdit, onEdit,
@@ -25,6 +25,7 @@ const FolderSlideCard = ({
defaultPer, defaultPer,
managePer managePer
}: { }: {
refreshDeps?: any[];
name: string; name: string;
intro?: string; intro?: string;
onEdit: () => void; onEdit: () => void;
@@ -86,22 +87,24 @@ const FolderSlideCard = ({
> >
{t('common.Move')} {t('common.Move')}
</Button> </Button>
<Button {managePer.permission.isOwner && (
variant={'transparentDanger'} <Button
pl={1} variant={'transparentDanger'}
leftIcon={<MyIcon name={'delete'} w={'1rem'} />} pl={1}
transform={'none !important'} leftIcon={<MyIcon name={'delete'} w={'1rem'} />}
w={'100%'} transform={'none !important'}
justifyContent={'flex-start'} w={'100%'}
size={'sm'} justifyContent={'flex-start'}
fontSize={'mini'} size={'sm'}
mt={3} fontSize={'mini'}
onClick={() => { mt={3}
openConfirm(onDelete)(); onClick={() => {
}} openConfirm(onDelete)();
> }}
{t('common.Delete folder')} >
</Button> {t('common.Delete folder')}
</Button>
)}
</Box> </Box>
</> </>
)} )}
@@ -125,7 +128,7 @@ const FolderSlideCard = ({
</Box> </Box>
)} )}
<Box mt={6}> <Box mt={6}>
<CollaboratorContextProvider {...managePer}> <CollaboratorContextProvider {...managePer} refreshDeps={refreshDeps}>
{({ MemberListCard, onOpenManageModal, onOpenAddMember }) => { {({ MemberListCard, onOpenManageModal, onOpenAddMember }) => {
return ( return (
<> <>

View File

@@ -2,7 +2,7 @@ import React from 'react';
import MyModal from '@fastgpt/web/components/common/MyModal'; import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { PermissionValueType } from '@fastgpt/global/support/permission/type'; import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { MemberManagerInputPropsType, CollaboratorContextProvider } from '../MemberManager/context'; import CollaboratorContextProvider, { MemberManagerInputPropsType } from '../MemberManager/context';
import { Box, Button, Flex, HStack, ModalBody } from '@chakra-ui/react'; import { Box, Button, Flex, HStack, ModalBody } from '@chakra-ui/react';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import DefaultPermissionList from '../DefaultPerList'; import DefaultPermissionList from '../DefaultPerList';

View File

@@ -20,8 +20,11 @@ const PermissionIconText = ({
const per = useMemo(() => { const per = useMemo(() => {
if (permission) return permission; if (permission) return permission;
if (defaultPermission) { if (defaultPermission !== undefined) {
return new Permission({ per: defaultPermission }).hasReadPer ? 'public' : 'private'; const Per = new Permission({ per: defaultPermission });
if (Per.hasWritePer) return PermissionTypeEnum.publicWrite;
if (Per.hasReadPer) return PermissionTypeEnum.publicRead;
return PermissionTypeEnum.clbPrivate;
} }
return 'private'; return 'private';
}, [defaultPermission, permission]); }, [defaultPermission, permission]);

View File

@@ -26,12 +26,14 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import { ChevronDownIcon } from '@chakra-ui/icons'; import { ChevronDownIcon } from '@chakra-ui/icons';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next';
export type AddModalPropsType = { export type AddModalPropsType = {
onClose: () => void; onClose: () => void;
}; };
function AddMemberModal({ onClose }: AddModalPropsType) { function AddMemberModal({ onClose }: AddModalPropsType) {
const { t } = useTranslation();
const { userInfo } = useUserStore(); const { userInfo } = useUserStore();
const { permissionList, collaboratorList, onUpdateCollaborators, getPerLabelList } = const { permissionList, collaboratorList, onUpdateCollaborators, getPerLabelList } =
@@ -63,9 +65,12 @@ function AddMemberModal({ onClose }: AddModalPropsType) {
const { mutate: onConfirm, isLoading: isUpdating } = useRequest({ const { mutate: onConfirm, isLoading: isUpdating } = useRequest({
mutationFn: () => { mutationFn: () => {
return onUpdateCollaborators(selectedMemberIdList, selectedPermission); return onUpdateCollaborators({
tmbIds: selectedMemberIdList,
permission: selectedPermission
});
}, },
successToast: '添加成功', successToast: t('common.Add Success'),
errorToast: 'Error', errorToast: 'Error',
onSuccess() { onSuccess() {
onClose(); onClose();

View File

@@ -39,7 +39,10 @@ function ManageModal({ onClose }: ManageModalProps) {
const { mutate: onUpdate, isLoading: isUpdating } = useRequest({ const { mutate: onUpdate, isLoading: isUpdating } = useRequest({
mutationFn: ({ tmbId, per }: { tmbId: string; per: PermissionValueType }) => { mutationFn: ({ tmbId, per }: { tmbId: string; per: PermissionValueType }) => {
return onUpdateCollaborators([tmbId], per); return onUpdateCollaborators({
tmbIds: [tmbId],
permission: per
});
}, },
successToast: '更新成功', successToast: '更新成功',
errorToast: 'Error' errorToast: 'Error'

View File

@@ -6,7 +6,8 @@ import {
MenuList, MenuList,
Box, Box,
Radio, Radio,
useOutsideClick useOutsideClick,
HStack
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React, { useMemo, useRef, useState } from 'react'; import React, { useMemo, useRef, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -142,9 +143,15 @@ function PermissionSelect({
bottom={0} bottom={0}
left={0} left={0}
/> />
<Box position={'relative'} cursor={'pointer'} userSelect={'none'}> <Flex
alignItems={'center'}
justifyContent={'center'}
position={'relative'}
cursor={'pointer'}
userSelect={'none'}
>
{Button} {Button}
</Box> </Flex>
</Box> </Box>
<MenuList <MenuList
minW={isOpen ? `${width}px !important` : 0} minW={isOpen ? `${width}px !important` : 0}
@@ -182,7 +189,7 @@ function PermissionSelect({
<Box ml={4}> <Box ml={4}>
<Box>{item.name}</Box> <Box>{item.name}</Box>
<Box color={'myGray.500'} fontSize={'mini'}> <Box color={'myGray.500'} fontSize={'mini'}>
{item.description} {t(item.description)}
</Box> </Box>
</Box> </Box>
</Flex> </Flex>
@@ -236,7 +243,7 @@ function PermissionSelect({
{onDelete && ( {onDelete && (
<> <>
<MyDivider my={2} h={'2px'} borderColor={'myGray.200'} /> <MyDivider my={2} h={'2px'} borderColor={'myGray.200'} />
<Flex <HStack
{...MenuStyle} {...MenuStyle}
onClick={() => { onClick={() => {
onDelete(); onDelete();
@@ -244,8 +251,8 @@ function PermissionSelect({
}} }}
> >
<MyIcon name="delete" w="20px" color="red.600" /> <MyIcon name="delete" w="20px" color="red.600" />
<Box color="red.600">{t('common.Delete')}</Box> <Box color="red.600">{t('common.Remove')}</Box>
</Flex> </HStack>
</> </>
)} )}
</MenuList> </MenuList>

View File

@@ -1,5 +1,8 @@
import { BoxProps, useDisclosure } from '@chakra-ui/react'; import { BoxProps, useDisclosure } from '@chakra-ui/react';
import { CollaboratorItemType } from '@fastgpt/global/support/permission/collaborator'; import {
CollaboratorItemType,
UpdateClbPermissionProps
} from '@fastgpt/global/support/permission/collaborator';
import { PermissionList } from '@fastgpt/global/support/permission/constant'; import { PermissionList } from '@fastgpt/global/support/permission/constant';
import { Permission } from '@fastgpt/global/support/permission/controller'; import { Permission } from '@fastgpt/global/support/permission/controller';
import { PermissionListType, PermissionValueType } from '@fastgpt/global/support/permission/type'; import { PermissionListType, PermissionValueType } from '@fastgpt/global/support/permission/type';
@@ -9,6 +12,7 @@ import { createContext } from 'use-context-selector';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import MemberListCard, { MemberListCardProps } from './MemberListCard'; import MemberListCard, { MemberListCardProps } from './MemberListCard';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
const AddMemberModal = dynamic(() => import('./AddMemberModal')); const AddMemberModal = dynamic(() => import('./AddMemberModal'));
const ManageModal = dynamic(() => import('./ManageModal')); const ManageModal = dynamic(() => import('./ManageModal'));
@@ -16,8 +20,9 @@ export type MemberManagerInputPropsType = {
permission: Permission; permission: Permission;
onGetCollaboratorList: () => Promise<CollaboratorItemType[]>; onGetCollaboratorList: () => Promise<CollaboratorItemType[]>;
permissionList: PermissionListType; permissionList: PermissionListType;
onUpdateCollaborators: (tmbIds: string[], permission: PermissionValueType) => any; onUpdateCollaborators: (props: UpdateClbPermissionProps) => any;
onDelOneCollaborator: (tmbId: string) => any; onDelOneCollaborator: (tmbId: string) => any;
refreshDeps?: any[];
}; };
export type MemberManagerPropsType = MemberManagerInputPropsType & { export type MemberManagerPropsType = MemberManagerInputPropsType & {
collaboratorList: CollaboratorItemType[]; collaboratorList: CollaboratorItemType[];
@@ -55,24 +60,28 @@ export const CollaboratorContext = createContext<CollaboratorContextType>({
permission: new Permission() permission: new Permission()
}); });
export const CollaboratorContextProvider = ({ const CollaboratorContextProvider = ({
permission, permission,
onGetCollaboratorList, onGetCollaboratorList,
permissionList, permissionList,
onUpdateCollaborators, onUpdateCollaborators,
onDelOneCollaborator, onDelOneCollaborator,
refreshDeps = [],
children children
}: MemberManagerInputPropsType & { }: MemberManagerInputPropsType & {
children: (props: ChildrenProps) => ReactNode; children: (props: ChildrenProps) => ReactNode;
}) => { }) => {
const { const {
data: collaboratorList = [], data: collaboratorList = [],
refetch: refetchCollaboratorList, runAsync: refetchCollaboratorList,
isLoading: isFetchingCollaborator loading: isFetchingCollaborator
} = useQuery(['collaboratorList'], onGetCollaboratorList); } = useRequest2(onGetCollaboratorList, {
manual: false,
refreshDeps
});
const onUpdateCollaboratorsThen = async (tmbIds: string[], permission: PermissionValueType) => { const onUpdateCollaboratorsThen = async (props: UpdateClbPermissionProps) => {
await onUpdateCollaborators(tmbIds, permission); await onUpdateCollaborators(props);
refetchCollaboratorList(); refetchCollaboratorList();
}; };
const onDelOneCollaboratorThen = async (tmbId: string) => { const onDelOneCollaboratorThen = async (tmbId: string) => {
@@ -136,3 +145,5 @@ export const CollaboratorContextProvider = ({
</CollaboratorContext.Provider> </CollaboratorContext.Provider>
); );
}; };
export default CollaboratorContextProvider;

View File

@@ -0,0 +1,66 @@
import React, { useMemo } from 'react';
import { Permission } from '@fastgpt/global/support/permission/controller';
import { PermissionListType } from '@fastgpt/global/support/permission/type';
import { PermissionList } from '@fastgpt/global/support/permission/constant';
import MyTag from '@fastgpt/web/components/common/Tag/index';
import { HStack } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
const PermissionTag = ({
permission,
permissionList
}: {
permission: Permission;
permissionList: PermissionListType;
}) => {
const { t } = useTranslation();
const { commonLabel, otherLabels } = useMemo(() => {
const Per = new Permission({ per: permission.value });
const commonLabel = (() => {
if (permission.isOwner) return t('permission.Owner');
if (permission.hasManagePer) return PermissionList['manage'].name;
if (permission.hasWritePer) return PermissionList['write'].name;
if (permission.hasReadPer) return PermissionList['read'].name;
return;
})();
const otherLabels: string[] = [];
Object.values(permissionList).forEach((item) => {
if (item.checkBoxType === 'multiple') {
if (Per.checkPer(item.value)) {
otherLabels.push(item.name);
}
}
});
return {
commonLabel,
otherLabels
};
}, [
permission.hasManagePer,
permission.hasReadPer,
permission.hasWritePer,
permission.value,
permissionList
]);
return (
<HStack>
{commonLabel && (
<MyTag type="fill" colorSchema="blue">
{commonLabel}
</MyTag>
)}
{otherLabels.map((tag, i) => (
<MyTag key={i} type="fill" colorSchema="purple">
{tag}
</MyTag>
))}
</HStack>
);
};
export default PermissionTag;

View File

@@ -3,12 +3,18 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { ModalCloseButton, ModalBody, Box, ModalFooter, Button } from '@chakra-ui/react'; import { ModalCloseButton, ModalBody, Box, ModalFooter, Button } from '@chakra-ui/react';
import TagTextarea from '@/components/common/Textarea/TagTextarea'; import TagTextarea from '@/components/common/Textarea/TagTextarea';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { postInviteTeamMember } from '@/web/support/user/team/api'; import { postInviteTeamMember } from '@/web/support/user/team/api';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import type { InviteMemberResponse } from '@fastgpt/global/support/user/team/controller.d'; import type { InviteMemberResponse } from '@fastgpt/global/support/user/team/controller.d';
import MySelect from '@fastgpt/web/components/common/MySelect'; import MySelect from '@fastgpt/web/components/common/MySelect';
import {
ManagePermissionVal,
ReadPermissionVal,
WritePermissionVal
} from '@fastgpt/global/support/permission/constant';
import { useI18n } from '@/web/context/I18n';
import { useUserStore } from '@/web/support/user/useUserStore';
const InviteModal = ({ const InviteModal = ({
teamId, teamId,
@@ -20,25 +26,37 @@ const InviteModal = ({
onSuccess: () => void; onSuccess: () => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { userT } = useI18n();
const { ConfirmModal, openConfirm } = useConfirm({ const { ConfirmModal, openConfirm } = useConfirm({
title: t('user.team.Invite Member Result Tip'), title: t('user.team.Invite Member Result Tip'),
showCancel: false showCancel: false
}); });
const { userInfo } = useUserStore();
const [inviteUsernames, setInviteUsernames] = useState<string[]>([]); const [inviteUsernames, setInviteUsernames] = useState<string[]>([]);
const inviteTypes = useMemo( const inviteTypes = useMemo(
() => [ () => [
{ {
alias: t('user.team.Invite Role Visitor Alias'), label: userT('permission.Read'),
label: t('user.team.Invite Role Visitor Tip'), description: userT('permission.Read desc'),
value: TeamMemberRoleEnum.visitor value: ReadPermissionVal
}, },
{ {
alias: t('user.team.Invite Role Admin Alias'), label: userT('permission.Write'),
label: t('user.team.Invite Role Admin Tip'), description: userT('permission.Write tip'),
value: TeamMemberRoleEnum.admin value: WritePermissionVal
} },
...(userInfo?.team?.permission.isOwner
? [
{
label: userT('permission.Manage'),
description: userT('permission.Manage tip'),
value: ManagePermissionVal
}
]
: [])
], ],
[t] [userInfo?.team?.permission.isOwner, userT]
); );
const [selectedInviteType, setSelectInviteType] = useState(inviteTypes[0].value); const [selectedInviteType, setSelectInviteType] = useState(inviteTypes[0].value);
@@ -47,7 +65,7 @@ const InviteModal = ({
return postInviteTeamMember({ return postInviteTeamMember({
teamId, teamId,
usernames: inviteUsernames, usernames: inviteUsernames,
role: selectedInviteType permission: selectedInviteType
}); });
}, },
onSuccess(res: InviteMemberResponse) { onSuccess(res: InviteMemberResponse) {

View File

@@ -1,47 +1,51 @@
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box, MenuButton, Table, TableContainer, Tbody, Td, Th, Thead, Tr } from '@chakra-ui/react'; import {
Box,
HStack,
MenuButton,
Table,
TableContainer,
Tbody,
Td,
Th,
Thead,
Tr
} from '@chakra-ui/react';
import { import {
TeamMemberRoleEnum, TeamMemberRoleEnum,
TeamMemberRoleMap,
TeamMemberStatusMap TeamMemberStatusMap
} from '@fastgpt/global/support/user/team/constant'; } from '@fastgpt/global/support/user/team/constant';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamModalContext } from '../context'; import { TeamModalContext } from '../context';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { delRemoveMember } from '@/web/support/user/team/api';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import PermissionTags from '@/components/support/permission/PermissionTags';
import { TeamPermissionList } from '@fastgpt/global/support/permission/user/constant';
import PermissionSelect from '@/components/support/permission/MemberManager/PermissionSelect';
import { CollaboratorContext } from '@/components/support/permission/MemberManager/context';
import { delRemoveMember } from '@/web/support/user/team/api';
function MemberTable() { function MemberTable() {
const { userInfo } = useUserStore(); const { userInfo } = useUserStore();
const { t } = useTranslation(); const { t } = useTranslation();
const { members, refetchMembers } = useContextSelector(TeamModalContext, (v) => v); const { members, refetchMembers } = useContextSelector(TeamModalContext, (v) => v);
const { onUpdateCollaborators } = useContextSelector(CollaboratorContext, (v) => v);
const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({ const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm({
type: 'delete' type: 'delete'
}); });
const { mutate: onRemoveMember, isLoading: isRemovingMember } = useRequest({
mutationFn: delRemoveMember,
onSuccess() {
refetchMembers();
},
successToast: t('user.team.Remove Member Success'),
errorToast: t('user.team.Remove Member Failed')
});
return ( return (
<MyBox isLoading={isRemovingMember}> <MyBox>
<TableContainer overflow={'unset'} fontSize={'sm'}> <TableContainer overflow={'unset'} fontSize={'sm'}>
<Table overflow={'unset'}> <Table overflow={'unset'}>
<Thead bg={'myWhite.400'}> <Thead bg={'myWhite.400'}>
<Tr> <Tr>
<Th borderRadius={'none !important'}>{t('common.Username')}</Th> <Th borderRadius={'none !important'}>{t('common.Username')}</Th>
<Th>{t('user.team.Role')}</Th> <Th>{t('common.Permission')}</Th>
<Th>{t('common.Status')}</Th> <Th>{t('common.Status')}</Th>
<Th borderRadius={'none !important'}>{t('common.Action')}</Th> <Th borderRadius={'none !important'}>{t('common.Action')}</Th>
</Tr> </Tr>
@@ -49,13 +53,20 @@ function MemberTable() {
<Tbody> <Tbody>
{members.map((item) => ( {members.map((item) => (
<Tr key={item.userId} overflow={'unset'}> <Tr key={item.userId} overflow={'unset'}>
<Td display={'flex'} alignItems={'center'}> <Td>
<Avatar src={item.avatar} w={['18px', '22px']} /> <HStack>
<Box flex={'1 0 0'} w={0} ml={1} className={'textEllipsis'}> <Avatar src={item.avatar} w={['18px', '22px']} />
{item.memberName} <Box maxW={'150px'} className={'textEllipsis'}>
</Box> {item.memberName}
</Box>
</HStack>
</Td>
<Td>
<PermissionTags
permission={item.permission}
permissionList={TeamPermissionList}
/>
</Td> </Td>
<Td>{t(TeamMemberRoleMap[item.role]?.label || '')}</Td>
<Td color={TeamMemberStatusMap[item.status].color}> <Td color={TeamMemberStatusMap[item.status].color}>
{t(TeamMemberStatusMap[item.status]?.label || '')} {t(TeamMemberStatusMap[item.status]?.label || '')}
</Td> </Td>
@@ -63,9 +74,8 @@ function MemberTable() {
{userInfo?.team.permission.hasManagePer && {userInfo?.team.permission.hasManagePer &&
item.role !== TeamMemberRoleEnum.owner && item.role !== TeamMemberRoleEnum.owner &&
item.tmbId !== userInfo?.team.tmbId && ( item.tmbId !== userInfo?.team.tmbId && (
<MyMenu <PermissionSelect
width={20} value={item.permission.value}
trigger="hover"
Button={ Button={
<MenuButton <MenuButton
_hover={{ _hover={{
@@ -79,27 +89,21 @@ function MemberTable() {
<MyIcon name={'edit'} cursor={'pointer'} w="1rem" /> <MyIcon name={'edit'} cursor={'pointer'} w="1rem" />
</MenuButton> </MenuButton>
} }
menuList={[ onChange={(permission) => {
{ onUpdateCollaborators({
children: [ tmbIds: [item.tmbId],
{ permission
label: t('user.team.Remove Member Tip'), });
onClick: () => }}
openRemoveMember( onDelete={() => {
() => openRemoveMember(
onRemoveMember({ () => delRemoveMember(item.tmbId).then(refetchMembers),
teamId: item.teamId, undefined,
memberId: item.tmbId t('user.team.Remove Member Confirm Tip', {
}), username: item.memberName
undefined, })
t('user.team.Remove Member Confirm Tip', { )();
username: item.memberName }}
})
)()
}
]
}
]}
/> />
)} )}
</Td> </Td>

View File

@@ -38,7 +38,7 @@ function AddManagerModal({ onClose, onSuccess }: { onClose: () => void; onSucces
mutationFn: async () => { mutationFn: async () => {
return updateMemberPermission({ return updateMemberPermission({
permission: ManagePermissionVal, permission: ManagePermissionVal,
memberIds: selected.map((item) => { tmbIds: selected.map((item) => {
return item.tmbId; return item.tmbId;
}) })
}); });

View File

@@ -1,14 +1,26 @@
import React, { ReactNode, useState } from 'react'; import React, { ReactNode, useCallback, useState } from 'react';
import { createContext } from 'use-context-selector'; import { createContext } from 'use-context-selector';
import type { EditTeamFormDataType } from './components/EditInfoModal'; import type { EditTeamFormDataType } from './components/EditInfoModal';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { getTeamList, getTeamMembers, putSwitchTeam } from '@/web/support/user/team/api'; import {
delMemberPermission,
getTeamList,
getTeamMembers,
putSwitchTeam,
updateMemberPermission
} from '@/web/support/user/team/api';
import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant'; import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import type { TeamTmbItemType, TeamMemberItemType } from '@fastgpt/global/support/user/team/type'; import type { TeamTmbItemType, TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import CollaboratorContextProvider from '@/components/support/permission/MemberManager/context';
import { TeamPermissionList } from '@fastgpt/global/support/permission/user/constant';
import {
CollaboratorItemType,
UpdateClbPermissionProps
} from '@fastgpt/global/support/permission/collaborator';
const EditInfoModal = dynamic(() => import('./components/EditInfoModal')); const EditInfoModal = dynamic(() => import('./components/EditInfoModal'));
@@ -55,12 +67,35 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
// member action // member action
const { const {
data: members = [], data: members = [],
refetch: refetchMembers, runAsync: refetchMembers,
isLoading: loadingMembers loading: loadingMembers
} = useQuery(['getMembers', userInfo?.team?.teamId], () => { } = useRequest2(
if (!userInfo?.team?.teamId) return []; () => {
return getTeamMembers(); if (!userInfo?.team?.teamId) return Promise.resolve([]);
}); return getTeamMembers();
},
{
manual: false,
refreshDeps: [userInfo?.team?.teamId]
}
);
const onGetClbList = useCallback(() => {
return refetchMembers().then((res) =>
res.map<CollaboratorItemType>((member) => ({
teamId: member.teamId,
tmbId: member.tmbId,
permission: member.permission,
name: member.memberName,
avatar: member.avatar
}))
);
}, [refetchMembers]);
const { runAsync: onUpdatePer, loading: isUpdatingPer } = useRequest2(
(props: UpdateClbPermissionProps) => {
return updateMemberPermission(props);
}
);
const { mutate: onSwitchTeam, isLoading: isSwitchingTeam } = useRequest({ const { mutate: onSwitchTeam, isLoading: isSwitchingTeam } = useRequest({
mutationFn: async (teamId: string) => { mutationFn: async (teamId: string) => {
@@ -70,7 +105,7 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
errorToast: t('user.team.Switch Team Failed') errorToast: t('user.team.Switch Team Failed')
}); });
const isLoading = isLoadingTeams || isSwitchingTeam || loadingMembers; const isLoading = isLoadingTeams || isSwitchingTeam || loadingMembers || isUpdatingPer;
const contextValue = { const contextValue = {
myTeams, myTeams,
@@ -86,16 +121,30 @@ export const TeamModalContextProvider = ({ children }: { children: ReactNode })
return ( return (
<TeamModalContext.Provider value={contextValue}> <TeamModalContext.Provider value={contextValue}>
{children} {userInfo?.team?.permission && (
{!!editTeamData && ( <CollaboratorContextProvider
<EditInfoModal permission={userInfo?.team?.permission}
defaultData={editTeamData} permissionList={TeamPermissionList}
onClose={() => setEditTeamData(undefined)} onGetCollaboratorList={onGetClbList}
onSuccess={() => { onUpdateCollaborators={onUpdatePer}
refetchTeams(); onDelOneCollaborator={delMemberPermission}
initUserInfo(); >
}} {() => (
/> <>
{children}
{!!editTeamData && (
<EditInfoModal
defaultData={editTeamData}
onClose={() => setEditTeamData(undefined)}
onSuccess={() => {
refetchTeams();
initUserInfo();
}}
/>
)}
</>
)}
</CollaboratorContextProvider>
)} )}
</TeamModalContext.Provider> </TeamModalContext.Provider>
); );

View File

@@ -12,6 +12,7 @@ import { readConfigData } from '@/service/common/system';
import { exit } from 'process'; import { exit } from 'process';
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants'; import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
import { initFastGPTConfig } from '@fastgpt/service/common/system/tools'; import { initFastGPTConfig } from '@fastgpt/service/common/system/tools';
import json5 from 'json5';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await getInitConfig(); await getInitConfig();
@@ -88,7 +89,7 @@ export async function initSystemConfig() {
getFastGPTConfigFromDB(), getFastGPTConfigFromDB(),
readConfigData('config.json') readConfigData('config.json')
]); ]);
const fileRes = JSON.parse(fileConfig) as FastGPTConfigFileType; const fileRes = json5.parse(fileConfig) as FastGPTConfigFileType;
// get config from database // get config from database
const config: FastGPTConfigFileType = { const config: FastGPTConfigFileType = {
@@ -131,7 +132,7 @@ export function getSystemVersion() {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
global.systemVersion = process.env.npm_package_version || '0.0.0'; global.systemVersion = process.env.npm_package_version || '0.0.0';
} else { } else {
const packageJson = JSON.parse(readFileSync('/app/package.json', 'utf-8')); const packageJson = json5.parse(readFileSync('/app/package.json', 'utf-8'));
global.systemVersion = packageJson?.version; global.systemVersion = packageJson?.version;
} }
@@ -157,7 +158,7 @@ function getSystemPlugin() {
const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => { const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => {
const content = readFileSync(`${basePath}/${filename}`, 'utf-8'); const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
return { return {
...JSON.parse(content), ...json5.parse(content),
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`, id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`,
source: PluginSourceEnum.community source: PluginSourceEnum.community
}; };

View File

@@ -8,8 +8,12 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema'; import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema'; import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant'; import {
OwnerPermissionVal,
PerResourceTypeEnum
} from '@fastgpt/global/support/permission/constant';
import { findAppAndAllChildren } from '@fastgpt/service/core/app/controller'; import { findAppAndAllChildren } from '@fastgpt/service/core/app/controller';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) { async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string }; const { appId } = req.query as { appId: string };
@@ -27,8 +31,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
fields: '_id' fields: '_id'
}); });
console.log(apps);
await mongoSessionRun(async (session) => { await mongoSessionRun(async (session) => {
for await (const app of apps) { for await (const app of apps) {
const appId = app._id; const appId = app._id;
@@ -65,6 +67,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
}, },
{ session } { session }
); );
await MongoResourcePermission.deleteMany(
{
resourceType: PerResourceTypeEnum.app,
teamId,
resourceId: appId
},
{ session }
);
// delete app // delete app
await MongoApp.deleteOne( await MongoApp.deleteOne(
{ {

View File

@@ -14,7 +14,6 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch'; import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import { authCert } from '@fastgpt/service/support/permission/auth/common'; import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team'; import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge'; import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type'; import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils'; import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils';
@@ -61,7 +60,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
} }
/* user auth */ /* user auth */
const [_, { teamId, tmbId }] = await Promise.all([ const [{ app }, { teamId, tmbId }] = await Promise.all([
authApp({ req, authToken: true, appId, per: ReadPermissionVal }), authApp({ req, authToken: true, appId, per: ReadPermissionVal }),
authCert({ authCert({
req, req,
@@ -79,7 +78,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
teamId, teamId,
tmbId, tmbId,
user, user,
appId, app,
runtimeNodes: nodes, runtimeNodes: nodes,
runtimeEdges: edges, runtimeEdges: edges,
variables, variables,

View File

@@ -9,6 +9,7 @@ import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin'; import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { defaultApp } from '@/web/core/app/constants';
async function handler( async function handler(
req: NextApiRequest, req: NextApiRequest,
@@ -45,6 +46,12 @@ async function handler(
// auth balance // auth balance
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId); const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const app = {
...defaultApp,
teamId,
tmbId
};
/* start process */ /* start process */
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({ const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
res, res,
@@ -52,7 +59,7 @@ async function handler(
teamId, teamId,
tmbId, tmbId,
user, user,
appId, app,
runtimeNodes: nodes, runtimeNodes: nodes,
runtimeEdges: edges, runtimeEdges: edges,
variables, variables,

View File

@@ -13,6 +13,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
if (!requestPath) { if (!requestPath) {
throw new Error('url is empty'); throw new Error('url is empty');
} }
if (!FastGPTProUrl) {
throw new Error('未配置商业版链接');
}
const parsedUrl = new URL(FastGPTProUrl); const parsedUrl = new URL(FastGPTProUrl);
delete req.headers?.rootkey; delete req.headers?.rootkey;

View File

@@ -191,7 +191,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
user, user,
teamId: String(teamId), teamId: String(teamId),
tmbId: String(tmbId), tmbId: String(tmbId),
appId: String(app._id), app,
chatId, chatId,
responseChatItemId, responseChatItemId,
runtimeNodes: storeNodes2RuntimeNodes(nodes, getDefaultEntryNodeIds(nodes)), runtimeNodes: storeNodes2RuntimeNodes(nodes, getDefaultEntryNodeIds(nodes)),

View File

@@ -20,7 +20,7 @@ import Avatar from '@/components/Avatar';
import MyModal from '@fastgpt/web/components/common/MyModal'; import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import { CollaboratorContextProvider } from '@/components/support/permission/MemberManager/context'; import CollaboratorContextProvider from '@/components/support/permission/MemberManager/context';
import { import {
postUpdateAppCollaborators, postUpdateAppCollaborators,
deleteAppCollaborators, deleteAppCollaborators,
@@ -35,6 +35,7 @@ import {
import { PermissionValueType } from '@fastgpt/global/support/permission/type'; import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import DefaultPermissionList from '@/components/support/permission/DefaultPerList'; import DefaultPermissionList from '@/components/support/permission/DefaultPerList';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import { UpdateClbPermissionProps } from '@fastgpt/global/support/permission/collaborator';
const InfoModal = ({ onClose }: { onClose: () => void }) => { const InfoModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -123,7 +124,7 @@ const InfoModal = ({ onClose }: { onClose: () => void }) => {
[setValue, t, toast] [setValue, t, toast]
); );
const onUpdateCollaborators = async (tmbIds: string[], permission: PermissionValueType) => { const onUpdateCollaborators = async ({ tmbIds, permission }: UpdateClbPermissionProps) => {
await postUpdateAppCollaborators({ await postUpdateAppCollaborators({
tmbIds, tmbIds,
permission, permission,

View File

@@ -108,7 +108,7 @@ const Logs = ({ appId }: { appId: string }) => {
<Th>{appT('Mark Count')}</Th> <Th>{appT('Mark Count')}</Th>
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody fontSize={'xs'}>
{logs.map((item) => ( {logs.map((item) => (
<Tr <Tr
key={item._id} key={item._id}

View File

@@ -89,10 +89,23 @@ const EditForm = ({
const { setValue, getValues, handleSubmit, control, watch } = editForm; const { setValue, getValues, handleSubmit, control, watch } = editForm;
const { fields: datasets, replace: replaceKbList } = useFieldArray({ const { fields: datasets, replace: replaceDatasetList } = useFieldArray({
control, control,
name: 'dataset.datasets' name: 'dataset.datasets'
}); });
const selectDatasets = useMemo(
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
[allDatasets, datasets]
);
useEffect(() => {
if (selectDatasets.length !== datasets.length) {
replaceDatasetList(
selectDatasets.map((item) => ({
datasetId: item._id
}))
);
}
}, [datasets, replaceDatasetList, selectDatasets]);
const { const {
isOpen: isOpenDatasetSelect, isOpen: isOpenDatasetSelect,
@@ -131,11 +144,6 @@ const EditForm = ({
const scheduledTriggerConfig = watch('chatConfig.scheduledTriggerConfig'); const scheduledTriggerConfig = watch('chatConfig.scheduledTriggerConfig');
const searchMode = watch('dataset.searchMode'); const searchMode = watch('dataset.searchMode');
const selectDatasets = useMemo(
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
[allDatasets, datasets]
);
const tokenLimit = useMemo(() => { const tokenLimit = useMemo(() => {
return llmModelList.find((item) => item.model === selectLLMModel)?.quoteMaxToken || 3000; return llmModelList.find((item) => item.model === selectLLMModel)?.quoteMaxToken || 3000;
}, [selectLLMModel, llmModelList]); }, [selectLLMModel, llmModelList]);
@@ -475,7 +483,7 @@ const EditForm = ({
vectorModel: item.vectorModel vectorModel: item.vectorModel
}))} }))}
onClose={onCloseKbSelect} onClose={onCloseKbSelect}
onChange={replaceKbList} onChange={replaceDatasetList}
/> />
)} )}
{isOpenDatasetParams && ( {isOpenDatasetParams && (

View File

@@ -271,7 +271,13 @@ const ListItem = () => {
permission: editPerApp.permission, permission: editPerApp.permission,
onGetCollaboratorList: () => getCollaboratorList(editPerApp._id), onGetCollaboratorList: () => getCollaboratorList(editPerApp._id),
permissionList: AppPermissionList, permissionList: AppPermissionList,
onUpdateCollaborators: (tmbIds: string[], permission: number) => { onUpdateCollaborators: ({
tmbIds,
permission
}: {
tmbIds: string[];
permission: number;
}) => {
return postUpdateAppCollaborators({ return postUpdateAppCollaborators({
tmbIds, tmbIds,
permission, permission,

View File

@@ -140,6 +140,7 @@ const MyApps = () => {
{!!folderDetail && isPc && ( {!!folderDetail && isPc && (
<Box pt={[4, 6]}> <Box pt={[4, 6]}>
<FolderSlideCard <FolderSlideCard
refreshDeps={[folderDetail._id]}
name={folderDetail.name} name={folderDetail.name}
intro={folderDetail.intro} intro={folderDetail.intro}
onEdit={() => { onEdit={() => {
@@ -163,7 +164,13 @@ const MyApps = () => {
permission: folderDetail.permission, permission: folderDetail.permission,
onGetCollaboratorList: () => getCollaboratorList(folderDetail._id), onGetCollaboratorList: () => getCollaboratorList(folderDetail._id),
permissionList: AppPermissionList, permissionList: AppPermissionList,
onUpdateCollaborators: (tmbIds: string[], permission: number) => { onUpdateCollaborators: ({
tmbIds,
permission
}: {
tmbIds: string[];
permission: number;
}) => {
return postUpdateAppCollaborators({ return postUpdateAppCollaborators({
tmbIds, tmbIds,
permission, permission,

View File

@@ -374,7 +374,6 @@ const DataCard = () => {
e.stopPropagation(); e.stopPropagation();
openConfirm(async () => { openConfirm(async () => {
try { try {
setIsLoading(true);
await delOneDatasetDataById(item._id); await delOneDatasetDataById(item._id);
getData(pageNum); getData(pageNum);
} catch (error) { } catch (error) {
@@ -383,7 +382,6 @@ const DataCard = () => {
status: 'error' status: 'error'
}); });
} }
setIsLoading(false);
})(); })();
}} }}
/> />
@@ -411,14 +409,8 @@ const DataCard = () => {
</DrawerHeader> </DrawerHeader>
<DrawerBody> <DrawerBody>
{metadataList.map((item) => ( {metadataList.map((item, i) => (
<Flex <Flex key={i} alignItems={'center'} mb={5} wordBreak={'break-all'} fontSize={'sm'}>
key={item.label}
alignItems={'center'}
mb={5}
wordBreak={'break-all'}
fontSize={'sm'}
>
<Box color={'myGray.500'} flex={'0 0 100px'}> <Box color={'myGray.500'} flex={'0 0 100px'}>
{item.label} {item.label}
</Box> </Box>

View File

@@ -41,7 +41,7 @@ const Slider = ({ currentTab }: { currentTab: TabEnum }) => {
icon: 'common/overviewLight' icon: 'common/overviewLight'
}, },
{ label: t('core.dataset.test.Search Test'), id: TabEnum.test, icon: 'kbTest' }, { label: t('core.dataset.test.Search Test'), id: TabEnum.test, icon: 'kbTest' },
...(userInfo?.team.permission.hasWritePer && datasetDetail.isOwner ...(userInfo?.team.permission.hasManagePer || datasetDetail.isOwner
? [{ label: t('common.Config'), id: TabEnum.info, icon: 'common/settingLight' }] ? [{ label: t('common.Config'), id: TabEnum.info, icon: 'common/settingLight' }]
: []) : [])
]; ];

View File

@@ -34,7 +34,7 @@ export const getScheduleTriggerApp = async () => {
mode: 'chat', mode: 'chat',
teamId: String(app.teamId), teamId: String(app.teamId),
tmbId: String(app.tmbId), tmbId: String(app.tmbId),
appId: String(app._id), app,
runtimeNodes: storeNodes2RuntimeNodes(app.modules, getDefaultEntryNodeIds(app.modules)), runtimeNodes: storeNodes2RuntimeNodes(app.modules, getDefaultEntryNodeIds(app.modules)),
runtimeEdges: initWorkflowEdgeStatus(app.edges), runtimeEdges: initWorkflowEdgeStatus(app.edges),
variables: {}, variables: {},

View File

@@ -1,12 +1,10 @@
import { GET, POST, PUT, DELETE } from '@/web/common/api/request'; import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
import { UpdateClbPermissionProps } from '@fastgpt/global/support/permission/collaborator';
import { import {
CreateTeamProps, CreateTeamProps,
DelMemberProps,
InviteMemberProps, InviteMemberProps,
InviteMemberResponse, InviteMemberResponse,
UpdateInviteProps, UpdateInviteProps,
UpdateTeamMemberPermissionProps,
UpdateTeamMemberProps,
UpdateTeamProps UpdateTeamProps
} from '@fastgpt/global/support/user/team/controller.d'; } from '@fastgpt/global/support/user/team/controller.d';
import type { TeamTagItemType, TeamTagSchema } from '@fastgpt/global/support/user/team/type'; import type { TeamTagItemType, TeamTagSchema } from '@fastgpt/global/support/user/team/type';
@@ -33,15 +31,15 @@ export const postInviteTeamMember = (data: InviteMemberProps) =>
POST<InviteMemberResponse>(`/proApi/support/user/team/member/invite`, data); POST<InviteMemberResponse>(`/proApi/support/user/team/member/invite`, data);
export const putUpdateMemberName = (name: string) => export const putUpdateMemberName = (name: string) =>
PUT(`/proApi/support/user/team/member/updateName`, { name }); PUT(`/proApi/support/user/team/member/updateName`, { name });
export const delRemoveMember = (props: DelMemberProps) => export const delRemoveMember = (tmbId: string) =>
DELETE(`/proApi/support/user/team/member/delete`, props); DELETE(`/proApi/support/user/team/member/delete`, { tmbId });
export const updateInviteResult = (data: UpdateInviteProps) => export const updateInviteResult = (data: UpdateInviteProps) =>
PUT('/proApi/support/user/team/member/updateInvite', data); PUT('/proApi/support/user/team/member/updateInvite', data);
export const delLeaveTeam = (teamId: string) => export const delLeaveTeam = (teamId: string) =>
DELETE('/proApi/support/user/team/member/leave', { teamId }); DELETE('/proApi/support/user/team/member/leave', { teamId });
/* -------------- team collaborator -------------------- */ /* -------------- team collaborator -------------------- */
export const updateMemberPermission = (data: UpdateTeamMemberPermissionProps) => export const updateMemberPermission = (data: UpdateClbPermissionProps) =>
PUT('/proApi/support/user/team/collaborator/update', data); PUT('/proApi/support/user/team/collaborator/update', data);
export const delMemberPermission = (tmbId: string) => export const delMemberPermission = (tmbId: string) =>
DELETE('/proApi/support/user/team/collaborator/delete', { tmbId }); DELETE('/proApi/support/user/team/collaborator/delete', { tmbId });