Skip to content

Commit

Permalink
Feat: App folder and permission (#1726)
Browse files Browse the repository at this point in the history
* app folder

* feat: app foldere

* fix: run app param error

* perf: select app ux

* perf: folder rerender

* fix: ts

* fix: parentId

* fix: permission

* perf: loading ux

* perf: per select ux

* perf: clb context

* perf: query extension tip

* fix: ts

* perf: app detail per

* perf: default per
  • Loading branch information
c121914yu authored Jun 11, 2024
1 parent b20d075 commit bc6864c
Show file tree
Hide file tree
Showing 89 changed files with 2,494 additions and 694 deletions.
6 changes: 4 additions & 2 deletions .vscode/nextapi.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@
"scope": "typescriptreact",
"prefix": "context",
"body": [
"import { ReactNode } from 'react';",
"import React, { ReactNode } from 'react';",
"import { createContext } from 'use-context-selector';",
"",
"type ContextType = {$1};",
"",
"export const Context = createContext<ContextType>({});",
"",
"export const ContextProvider = ({ children }: { children: ReactNode }) => {",
"const ContextProvider = ({ children }: { children: ReactNode }) => {",
" const contextValue: ContextType = {};",
" return <Context.Provider value={contextValue}>{children}</Context.Provider>;",
"};",
"",
"export default ContextProvider"
],
"description": "FastGPT usecontext template"
}
Expand Down
10 changes: 6 additions & 4 deletions docSite/content/zh-cn/docs/development/upgrading/484.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ weight: 821
## V4.8.4 更新说明

1. 新增 - 应用使用新权限系统。
2. 优化 - 文本分割增加连续换行、制表符清除,避免大文本性能问题。
3. 修复 - Debug 模式下,相同 source 和 target 内容,导致连线显示异常。
4. 修复 - 定时执行初始化错误。
5. 调整组件库全局theme。
2. 新增 - 应用支持文件夹。
3. 优化 - 文本分割增加连续换行、制表符清除,避免大文本性能问题。
4. 修复 - Debug 模式下,相同 source 和 target 内容,导致连线显示异常。
5. 修复 - 定时执行初始化错误。
6. 修复 - 应用调用传参异常。
7. 调整组件库全局theme。
14 changes: 14 additions & 0 deletions packages/global/common/parentFolder/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,17 @@ export type ParentTreePathItemType = {
parentId: string;
parentName: string;
};
export type ParentIdType = string | null | undefined;

export type GetResourceFolderListProps = {
parentId: ParentIdType;
};
export type GetResourceFolderListItemResponse = {
name: string;
id: string;
};

export type GetResourceListItemResponse = GetResourceFolderListItemResponse & {
avatar: string;
isFolder: boolean;
};
17 changes: 17 additions & 0 deletions packages/global/common/parentFolder/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ParentIdType } from './type';

export const parseParentIdInMongo = (parentId: ParentIdType) => {
if (parentId === undefined) return {};

if (parentId === null || parentId === '')
return {
parentId: null
};

const pattern = /^[0-9a-fA-F]{24}$/;
if (pattern.test(parentId))
return {
parentId
};
return {};
};
4 changes: 4 additions & 0 deletions packages/global/core/app/constants.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { AppTTSConfigType, AppWhisperConfigType } from './type';

export enum AppTypeEnum {
folder = 'folder',
simple = 'simple',
advanced = 'advanced'
}
export const AppTypeMap = {
[AppTypeEnum.folder]: {
label: 'folder'
},
[AppTypeEnum.simple]: {
label: 'simple'
},
Expand Down
9 changes: 6 additions & 3 deletions packages/global/core/app/type.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type';

import { AppTypeEnum } from './constants';
import { PermissionTypeEnum } from '../../support/permission/constant';
import { VariableInputEnum } from '../workflow/constants';
Expand All @@ -9,14 +8,17 @@ import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/use
import { StoreEdgeItemType } from '../workflow/type/edge';
import { PermissionValueType } from '../../support/permission/type';
import { AppPermission } from '../../support/permission/app/controller';
import { ParentIdType } from '../../common/parentFolder/type';

export type AppSchema = {
_id: string;
parentId?: ParentIdType;
teamId: string;
tmbId: string;
name: string;
type: `${AppTypeEnum}`;
type: AppTypeEnum;
version?: 'v1' | 'v2';

name: string;
avatar: string;
intro: string;
updateTime: number;
Expand All @@ -39,6 +41,7 @@ export type AppListItemType = {
name: string;
avatar: string;
intro: string;
type: AppTypeEnum;
defaultPermission: PermissionValueType;
permission: AppPermission;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/global/core/app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const getDefaultAppForm = (): AppSimpleEditFormType => ({
limit: 1500,
searchMode: DatasetSearchModeEnum.embedding,
usingReRank: false,
datasetSearchUsingExtensionQuery: true,
datasetSearchUsingExtensionQuery: false,
datasetSearchExtensionBg: ''
},
selectedTools: [],
Expand Down
5 changes: 4 additions & 1 deletion packages/global/core/workflow/template/system/runApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export const RunAppModule: FlowNodeTemplateType = {
required: true
},
Input_Template_History,
Input_Template_UserChatInput
{
...Input_Template_UserChatInput,
toolDescription: '用户问题'
}
],
outputs: [
{
Expand Down
4 changes: 2 additions & 2 deletions packages/global/core/workflow/type/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ export type NodeSourceNodeItemType = {
/* --------------- function type -------------------- */
export type SelectAppItemType = {
id: string;
name: string;
logo: string;
// name: string;
// logo?: string;
};

/* agent */
Expand Down
2 changes: 1 addition & 1 deletion packages/global/support/permission/app/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ export const AppPermissionList: PermissionListType = {
}
};

export const AppDefaultPermission = NullPermission;
export const AppDefaultPermissionVal = NullPermission;
6 changes: 3 additions & 3 deletions packages/global/support/permission/app/controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { PerConstructPros, Permission } from '../controller';
import { AppDefaultPermission } from './constant';
import { AppDefaultPermissionVal } from './constant';

export class AppPermission extends Permission {
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: AppDefaultPermission
per: AppDefaultPermissionVal
};
} else if (!props?.per) {
props.per = AppDefaultPermission;
props.per = AppDefaultPermissionVal;
}
super(props);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/global/support/permission/collaborator.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Permission } from './controller';
import { PermissionValueType } from './type';

export type CollaboratorItemType = {
teamId: string;
tmbId: string;
permission: PermissionValueType;
permission: Permission;
name: string;
avatar: string;
};
2 changes: 1 addition & 1 deletion packages/global/support/permission/user/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const TeamPermissionList = {
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '可邀请, 删除成员'
description: '可创建资源、邀请、删除成员'
}
};

Expand Down
38 changes: 38 additions & 0 deletions packages/service/core/app/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { getLLMModel } from '../ai/model';
import { MongoAppVersion } from './version/schema';
import { MongoApp } from './schema';

export const beforeUpdateAppFormat = <T extends AppSchema['modules'] | undefined>({
nodes
Expand Down Expand Up @@ -65,3 +66,40 @@ export const getAppLatestVersion = async (appId: string, app?: AppSchema) => {
chatConfig: app?.chatConfig || {}
};
};

/* Get apps */
export async function findAppAndAllChildren({
teamId,
appId,
fields
}: {
teamId: string;
appId: string;
fields?: string;
}): Promise<AppSchema[]> {
const find = async (id: string) => {
const children = await MongoApp.find(
{
teamId,
parentId: id
},
fields
).lean();

let apps = children;

for (const child of children) {
const grandChildrenIds = await find(child._id);
apps = apps.concat(grandChildrenIds);
}

return apps;
};
const [app, childDatasets] = await Promise.all([MongoApp.findById(appId, fields), find(appId)]);

if (!app) {
return Promise.reject('Dataset not found');
}

return [app, ...childDatasets];
}
17 changes: 11 additions & 6 deletions packages/service/core/app/schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppTypeMap } from '@fastgpt/global/core/app/constants';
import { AppTypeEnum, AppTypeMap } from '@fastgpt/global/core/app/constants';
import { connectionMongo, type Model } from '../../common/mongo';
const { Schema, model, models } = connectionMongo;
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
Expand All @@ -7,7 +7,7 @@ import {
TeamCollectionName,
TeamMemberCollectionName
} from '@fastgpt/global/support/user/team/constant';
import { AppDefaultPermission } from '@fastgpt/global/support/permission/app/constant';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';

export const AppCollectionName = 'apps';

Expand All @@ -22,6 +22,11 @@ export const chatConfigType = {
};

const AppSchema = new Schema({
parentId: {
type: Schema.Types.ObjectId,
ref: AppCollectionName,
default: null
},
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName,
Expand All @@ -38,8 +43,8 @@ const AppSchema = new Schema({
},
type: {
type: String,
default: 'advanced',
enum: Object.keys(AppTypeMap)
default: AppTypeEnum.advanced,
enum: Object.values(AppTypeEnum)
},
version: {
type: String,
Expand Down Expand Up @@ -104,13 +109,13 @@ const AppSchema = new Schema({
// the default permission of a app
defaultPermission: {
type: Number,
default: AppDefaultPermission
default: AppDefaultPermissionVal
}
});

try {
AppSchema.index({ updateTime: -1 });
AppSchema.index({ teamId: 1 });
AppSchema.index({ teamId: 1, type: 1 });
AppSchema.index({ scheduledTriggerConfig: 1, intervalNextTime: -1 });
} catch (error) {
console.log(error);
Expand Down
27 changes: 14 additions & 13 deletions packages/service/core/workflow/dispatch/tools/runApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
import { getHistories } from '../utils';
import { chatValue2RuntimePrompt, runtimePrompt2ChatsValue } from '@fastgpt/global/core/chat/adapt';
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
import { authAppByTmbId } from '../../../../support/permission/app/auth';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';

type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.userChatInput]: string;
Expand All @@ -32,27 +34,25 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
const {
res,
teamId,
tmbId,
stream,
detail,
histories,
query,
params: { userChatInput, history, app }
} = props;
let start = Date.now();

if (!userChatInput) {
return Promise.reject('Input is empty');
}

const appData = await MongoApp.findOne({
_id: app.id,
teamId
const { app: appData } = await authAppByTmbId({
appId: app.id,
teamId,
tmbId,
per: ReadPermissionVal
});

if (!appData) {
return Promise.reject('App not found');
}

if (res && stream) {
responseWrite({
res,
Expand All @@ -64,18 +64,19 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
}

const chatHistories = getHistories(history, histories);
const { files } = chatValue2RuntimePrompt(query);

const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
...props,
appId: app.id,
runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)),
runtimeEdges: initWorkflowEdgeStatus(appData.edges),
histories: chatHistories,
query,
variables: {
...props.variables,
userChatInput
}
query: runtimePrompt2ChatsValue({
files,
text: userChatInput
}),
variables: props.variables
});

const completeMessages = chatHistories.concat([
Expand Down
3 changes: 2 additions & 1 deletion packages/service/support/permission/teamLimit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MongoDataset } from '../../core/dataset/schema';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { SystemErrEnum } from '@fastgpt/global/common/error/code/system';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';

export const checkDatasetLimit = async ({
teamId,
Expand Down Expand Up @@ -66,7 +67,7 @@ export const checkTeamDatasetLimit = async (teamId: string) => {
export const checkTeamAppLimit = async (teamId: string) => {
const [{ standardConstants }, appCount] = await Promise.all([
getTeamStandPlan({ teamId }),
MongoApp.count({ teamId })
MongoApp.count({ teamId, type: { $in: [AppTypeEnum.advanced, AppTypeEnum.simple] } })
]);

if (standardConstants && appCount >= standardConstants.maxAppAmount) {
Expand Down
Loading

0 comments on commit bc6864c

Please sign in to comment.