4.8-preview fix (#1324)
* feishu app release (#85) * Revert "lafAccount add pat & re request when token invalid (#76)" (#77) This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be. * perf: workflow ux * system config * feat: feishu app release * chore: sovle the conflicts files; fix the feishu entry * fix: rename Feishu interface to FeishuType * fix: fix type problem in app.ts * fix: type problem * fix: style problem --------- Co-authored-by: Archer <545436317@qq.com> * perf: publish channel code * change system variable position (#94) * perf: workflow context * perf: variable select * hide publish * perf: simple edit auto refresh * perf: simple edit data refresh * fix: target handle --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
parent
5ca4049757
commit
a0c1320d47
@ -21,5 +21,7 @@ FastGPT workflow V2上线,支持更加简洁的工作流模式。
|
|||||||
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
||||||
3. 新增 - 定时执行应用。可轻松实现定时任务。
|
3. 新增 - 定时执行应用。可轻松实现定时任务。
|
||||||
4. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
4. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
||||||
5. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
6. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
||||||
6. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
7. 优化 - 工作流上下文传递,性能🚀。
|
||||||
|
8. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
|
||||||
|
9. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
||||||
@ -125,6 +125,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
|
|
||||||
defaultAppForm.selectedTools.push({
|
defaultAppForm.selectedTools.push({
|
||||||
id: node.pluginId,
|
id: node.pluginId,
|
||||||
|
pluginId: node.pluginId,
|
||||||
name: node.name,
|
name: node.name,
|
||||||
avatar: node.avatar,
|
avatar: node.avatar,
|
||||||
intro: node.intro || '',
|
intro: node.intro || '',
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
export enum OutLinkTypeEnum {
|
export enum PublishChannelEnum {
|
||||||
share = 'share',
|
share = 'share',
|
||||||
iframe = 'iframe',
|
iframe = 'iframe',
|
||||||
apikey = 'apikey'
|
apikey = 'apikey',
|
||||||
|
feishu = 'feishu'
|
||||||
}
|
}
|
||||||
|
|||||||
60
packages/global/support/outLink/type.d.ts
vendored
60
packages/global/support/outLink/type.d.ts
vendored
@ -1,31 +1,79 @@
|
|||||||
import { AppSchema } from 'core/app/type';
|
import { AppSchema } from 'core/app/type';
|
||||||
import { OutLinkTypeEnum } from './constant';
|
import { PublishChannelEnum } from './constant';
|
||||||
|
|
||||||
export type OutLinkSchema = {
|
// Feishu Config interface
|
||||||
|
export interface FeishuType {
|
||||||
|
appId: string;
|
||||||
|
appSecret: string;
|
||||||
|
// Encrypt config
|
||||||
|
// refer to: https://open.feishu.cn/document/server-docs/event-subscription-guide/event-subscription-configure-/configure-encrypt-key
|
||||||
|
encryptKey?: string; // no secret if null
|
||||||
|
// Token Verification
|
||||||
|
// refer to: https://open.feishu.cn/document/server-docs/event-subscription-guide/event-subscription-configure-/encrypt-key-encryption-configuration-case
|
||||||
|
verificationToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Unused
|
||||||
|
export interface WecomType {
|
||||||
|
ReplyLimit: Boolean;
|
||||||
|
defaultResponse: string;
|
||||||
|
immediateResponse: boolean;
|
||||||
|
WXWORK_TOKEN: string;
|
||||||
|
WXWORK_AESKEY: string;
|
||||||
|
WXWORK_SECRET: string;
|
||||||
|
WXWORD_ID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OutLinkSchema<T = void> = {
|
||||||
_id: string;
|
_id: string;
|
||||||
shareId: string;
|
shareId: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
|
// teamId: Schema.Types.ObjectId;
|
||||||
|
// tmbId: Schema.Types.ObjectId;
|
||||||
|
// appId: Schema.Types.ObjectId;
|
||||||
name: string;
|
name: string;
|
||||||
usagePoints: number;
|
usagePoints: number;
|
||||||
lastTime: Date;
|
lastTime: Date;
|
||||||
type: `${OutLinkTypeEnum}`;
|
type: PublishChannelEnum;
|
||||||
|
|
||||||
|
// whether the response content is detailed
|
||||||
responseDetail: boolean;
|
responseDetail: boolean;
|
||||||
|
|
||||||
|
// response when request
|
||||||
|
immediateResponse?: string;
|
||||||
|
// response when error or other situation
|
||||||
|
defaultResponse?: string;
|
||||||
|
|
||||||
limit?: {
|
limit?: {
|
||||||
expiredTime?: Date;
|
expiredTime?: Date;
|
||||||
|
// Questions per minute
|
||||||
QPM: number;
|
QPM: number;
|
||||||
maxUsagePoints: number;
|
maxUsagePoints: number;
|
||||||
|
// Verification message hook url
|
||||||
hookUrl?: string;
|
hookUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app?: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// to handle MongoDB querying
|
||||||
export type OutLinkWithAppType = Omit<OutLinkSchema, 'appId'> & {
|
export type OutLinkWithAppType = Omit<OutLinkSchema, 'appId'> & {
|
||||||
appId: AppSchema;
|
appId: AppSchema;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OutLinkEditType = {
|
// Edit the Outlink
|
||||||
|
export type OutLinkEditType<T = void> = {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
responseDetail: OutLinkSchema['responseDetail'];
|
responseDetail: OutLinkSchema<T>['responseDetail'];
|
||||||
limit: OutLinkSchema['limit'];
|
// response when request
|
||||||
|
immediateResponse?: string;
|
||||||
|
// response when error or other situation
|
||||||
|
defaultResponse?: string;
|
||||||
|
limit?: OutLinkSchema<T>['limit'];
|
||||||
|
|
||||||
|
// config for specific platform
|
||||||
|
app?: T;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { connectionMongo, type Model } from '../../common/mongo';
|
import { connectionMongo, type Model } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
|
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
|
||||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
|
||||||
import {
|
import {
|
||||||
TeamCollectionName,
|
TeamCollectionName,
|
||||||
TeamMemberCollectionName
|
TeamMemberCollectionName
|
||||||
@ -30,7 +29,7 @@ const OutLinkSchema = new Schema({
|
|||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: OutLinkTypeEnum.share
|
required: true
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -62,6 +61,26 @@ const OutLinkSchema = new Schema({
|
|||||||
hookUrl: {
|
hookUrl: {
|
||||||
type: String
|
type: String
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
app: {
|
||||||
|
appId: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
appSecret: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
encryptKey: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
verificationToken: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediateResponse: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
defaultResponse: {
|
||||||
|
type: String
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ export const iconPaths = {
|
|||||||
'core/app/headphones': () => import('./icons/core/app/headphones.svg'),
|
'core/app/headphones': () => import('./icons/core/app/headphones.svg'),
|
||||||
'core/app/logsLight': () => import('./icons/core/app/logsLight.svg'),
|
'core/app/logsLight': () => import('./icons/core/app/logsLight.svg'),
|
||||||
'core/app/markLight': () => import('./icons/core/app/markLight.svg'),
|
'core/app/markLight': () => import('./icons/core/app/markLight.svg'),
|
||||||
|
'core/app/publish/lark': () => import('./icons/core/app/publish/lark.svg'),
|
||||||
'core/app/questionGuide': () => import('./icons/core/app/questionGuide.svg'),
|
'core/app/questionGuide': () => import('./icons/core/app/questionGuide.svg'),
|
||||||
'core/app/schedulePlan': () => import('./icons/core/app/schedulePlan.svg'),
|
'core/app/schedulePlan': () => import('./icons/core/app/schedulePlan.svg'),
|
||||||
'core/app/simpleMode/ai': () => import('./icons/core/app/simpleMode/ai.svg'),
|
'core/app/simpleMode/ai': () => import('./icons/core/app/simpleMode/ai.svg'),
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
<svg t="1714285522209" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5343"
|
||||||
|
width="128" height="128">
|
||||||
|
<path
|
||||||
|
d="M891.318857 340.845714c4.900571 0 9.728 0.292571 14.628572 0.804572a409.965714 409.965714 0 0 1 108.836571 30.061714c10.093714 4.534857 12.580571 8.192 3.949714 17.334857-24.868571 26.624-45.494857 57.051429-61.001143 89.965714-16.822857 35.328-35.108571 69.851429-52.297142 105.033143a225.28 225.28 0 0 1-52.150858 69.412572c-53.613714 48.493714-116.150857 68.973714-187.538285 59.099428-81.92-11.337143-159.451429-38.985143-232.740572-75.483428a143.506286 143.506286 0 0 1-10.459428-5.485715 5.339429 5.339429 0 0 1 0.292571-9.216l5.12-2.706285c59.245714-31.670857 108.836571-75.849143 156.525714-122.294857 20.187429-19.529143 39.497143-40.009143 59.904-59.318858A345.014857 345.014857 0 0 1 804.571429 352.256c13.165714-3.218286 26.550857-5.778286 39.789714-8.630857h0.585143l28.233143-2.56"
|
||||||
|
fill="#133C9A" p-id="5344"></path>
|
||||||
|
<path
|
||||||
|
d="M317.659429 913.846857c-8.996571-0.512-31.158857-3.584-33.865143-3.949714a536.429714 536.429714 0 0 1-165.083429-48.274286c-30.208-14.116571-59.245714-30.72-88.356571-46.957714-19.163429-10.678857-27.794286-27.282286-27.648-49.883429 0.585143-83.382857 0.585143-166.765714 0-250.148571C2.413714 461.019429 0.731429 407.405714 0 353.718857c0-4.754286 0.731429-9.508571 2.194286-13.897143 3.291429-9.728 9.947429-10.24 16.530285-3.949714 7.606857 7.314286 13.677714 16.237714 21.211429 23.405714 67.291429 66.413714 138.752 127.195429 218.770286 177.225143 45.056 28.891429 91.940571 54.710857 140.434285 77.385143 77.750857 35.328 157.549714 66.486857 241.078858 86.235429 73.874286 17.481143 145.627429 6.436571 205.458285-40.374858 18.285714-15.652571 27.282286-27.062857 48.932572-55.881142a359.862857 359.862857 0 0 1-37.376 72.850285c-13.897143 21.942857-45.348571 51.2-69.193143 74.093715-36.278857 35.108571-83.748571 63.561143-128.292572 87.552-48.566857 26.185143-99.035429 47.104-152.941714 58.514285-27.648 6.948571-67.584 14.848-81.334857 15.579429-2.413714-0.146286-10.678857 1.682286-14.848 1.389714-35.547429 2.633143-57.490286 3.657143-92.891429 0z"
|
||||||
|
fill="#3370FF" p-id="5345"></path>
|
||||||
|
<path
|
||||||
|
d="M165.083429 110.518857a52.443429 52.443429 0 0 1 7.460571 0c152.649143 0 304.128 2.486857 456.630857 2.486857 0.292571 0 0.585143 0 0.731429 0.219429 14.189714 12.361143 27.282286 25.746286 39.277714 40.155428 34.450286 34.230857 60.123429 93.622857 77.677714 129.755429 8.777143 25.014857 21.942857 48.859429 28.16 76.8v0.438857c-15.579429 5.046857-30.72 11.190857-45.348571 18.505143-44.178286 22.381714-64.219429 38.765714-100.790857 74.752-19.968 19.529143-37.010286 37.083429-63.488 62.098286a563.346286 563.346286 0 0 1-29.769143 26.916571c-7.021714-12.434286-125.732571-244.589714-364.251429-427.300571"
|
||||||
|
fill="#00D6B9" p-id="5346"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
@ -1,5 +1,8 @@
|
|||||||
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
|
||||||
export type EditorVariablePickerType = {
|
export type EditorVariablePickerType = {
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
valueType?: WorkflowIOValueTypeEnum;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
"@chakra-ui/react": "2.8.1",
|
"@chakra-ui/react": "2.8.1",
|
||||||
"@chakra-ui/styled-system": "2.9.1",
|
"@chakra-ui/styled-system": "2.9.1",
|
||||||
"@chakra-ui/system": "2.6.1",
|
"@chakra-ui/system": "2.6.1",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "11.11.0",
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fingerprintjs/fingerprintjs": "^4.3.0",
|
"@fingerprintjs/fingerprintjs": "^4.3.0",
|
||||||
"@lexical/react": "0.12.6",
|
"@lexical/react": "0.12.6",
|
||||||
|
|||||||
31
pnpm-lock.yaml
generated
31
pnpm-lock.yaml
generated
@ -230,10 +230,10 @@ importers:
|
|||||||
specifier: 2.6.1
|
specifier: 2.6.1
|
||||||
version: 2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
version: 2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
||||||
'@emotion/react':
|
'@emotion/react':
|
||||||
specifier: ^11.11.1
|
specifier: 11.11.1
|
||||||
version: 11.11.1(@types/react@18.2.0)(react@18.2.0)
|
version: 11.11.1(@types/react@18.2.0)(react@18.2.0)
|
||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
specifier: ^11.11.0
|
specifier: 11.11.0
|
||||||
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.0)(react@18.2.0)
|
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.0)(react@18.2.0)
|
||||||
'@fastgpt/global':
|
'@fastgpt/global':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@ -336,10 +336,10 @@ importers:
|
|||||||
specifier: 2.6.1
|
specifier: 2.6.1
|
||||||
version: 2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
version: 2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
||||||
'@emotion/react':
|
'@emotion/react':
|
||||||
specifier: ^11.11.1
|
specifier: 11.11.1
|
||||||
version: 11.11.1(@types/react@18.2.0)(react@18.2.0)
|
version: 11.11.1(@types/react@18.2.0)(react@18.2.0)
|
||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
specifier: ^11.11.0
|
specifier: 11.11.0
|
||||||
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.0)(react@18.2.0)
|
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.0)(react@18.2.0)
|
||||||
'@fastgpt/global':
|
'@fastgpt/global':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@ -408,7 +408,7 @@ importers:
|
|||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
mermaid:
|
mermaid:
|
||||||
specifier: 10.2.3
|
specifier: ^10.2.3
|
||||||
version: 10.2.3
|
version: 10.2.3
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
@ -467,6 +467,9 @@ importers:
|
|||||||
sass:
|
sass:
|
||||||
specifier: ^1.58.3
|
specifier: ^1.58.3
|
||||||
version: 1.58.3
|
version: 1.58.3
|
||||||
|
use-context-selector:
|
||||||
|
specifier: ^1.4.4
|
||||||
|
version: 1.4.4(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0)
|
||||||
zustand:
|
zustand:
|
||||||
specifier: ^4.3.5
|
specifier: ^4.3.5
|
||||||
version: 4.3.5(immer@9.0.19)(react@18.2.0)
|
version: 4.3.5(immer@9.0.19)(react@18.2.0)
|
||||||
@ -12158,6 +12161,24 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/use-context-selector@1.4.4(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0):
|
||||||
|
resolution: {integrity: sha512-pS790zwGxxe59GoBha3QYOwk8AFGp4DN6DOtH+eoqVmgBBRXVx4IlPDhJmmMiNQAgUaLlP+58aqRC3A4rdaSjg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '*'
|
||||||
|
react-native: '*'
|
||||||
|
scheduler: '>=0.19.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
react-native:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
scheduler: 0.23.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/use-sidecar@1.1.2(@types/react@18.2.0)(react@18.2.0):
|
/use-sidecar@1.1.2(@types/react@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|||||||
@ -76,7 +76,7 @@ const nextConfig = {
|
|||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
transpilePackages: ['@fastgpt/*'],
|
transpilePackages: ['@fastgpt/*', 'ahooks'],
|
||||||
experimental: {
|
experimental: {
|
||||||
// 外部包独立打包
|
// 外部包独立打包
|
||||||
serverComponentsExternalPackages: ['mongoose', 'pg'],
|
serverComponentsExternalPackages: ['mongoose', 'pg'],
|
||||||
|
|||||||
@ -16,13 +16,14 @@
|
|||||||
"@chakra-ui/react": "2.8.1",
|
"@chakra-ui/react": "2.8.1",
|
||||||
"@chakra-ui/styled-system": "2.9.1",
|
"@chakra-ui/styled-system": "2.9.1",
|
||||||
"@chakra-ui/system": "2.6.1",
|
"@chakra-ui/system": "2.6.1",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "11.11.0",
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fastgpt/plugins": "workspace:*",
|
"@fastgpt/plugins": "workspace:*",
|
||||||
"@fastgpt/service": "workspace:*",
|
"@fastgpt/service": "workspace:*",
|
||||||
"@fastgpt/web": "workspace:*",
|
"@fastgpt/web": "workspace:*",
|
||||||
"@fortaine/fetch-event-source": "^3.0.6",
|
"@fortaine/fetch-event-source": "^3.0.6",
|
||||||
|
"@node-rs/jieba": "1.10.0",
|
||||||
"@tanstack/react-query": "^4.24.10",
|
"@tanstack/react-query": "^4.24.10",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"ahooks": "^3.7.11",
|
"ahooks": "^3.7.11",
|
||||||
@ -39,10 +40,11 @@
|
|||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mermaid": "10.2.3",
|
"mermaid": "^10.2.3",
|
||||||
"nanoid": "^4.0.1",
|
"nanoid": "^4.0.1",
|
||||||
"next": "13.5.2",
|
"next": "13.5.2",
|
||||||
"next-i18next": "15.2.0",
|
"next-i18next": "15.2.0",
|
||||||
|
"nextjs-node-loader": "^1.1.5",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
@ -58,9 +60,8 @@
|
|||||||
"remark-math": "^5.1.1",
|
"remark-math": "^5.1.1",
|
||||||
"request-ip": "^3.3.0",
|
"request-ip": "^3.3.0",
|
||||||
"sass": "^1.58.3",
|
"sass": "^1.58.3",
|
||||||
"zustand": "^4.3.5",
|
"use-context-selector": "^1.4.4",
|
||||||
"nextjs-node-loader": "^1.1.5",
|
"zustand": "^4.3.5"
|
||||||
"@node-rs/jieba": "1.10.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/webpack": "^6.5.1",
|
"@svgr/webpack": "^6.5.1",
|
||||||
@ -76,6 +77,7 @@
|
|||||||
"@types/request-ip": "^0.0.37",
|
"@types/request-ip": "^0.0.37",
|
||||||
"eslint": "8.34.0",
|
"eslint": "8.34.0",
|
||||||
"eslint-config-next": "13.1.6",
|
"eslint-config-next": "13.1.6",
|
||||||
|
"nextjs-node-loader": "^1.1.5",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,6 +153,7 @@
|
|||||||
"Submit failed": "Submit failed",
|
"Submit failed": "Submit failed",
|
||||||
"Submit success": "Update Success",
|
"Submit success": "Update Success",
|
||||||
"Sync success": "",
|
"Sync success": "",
|
||||||
|
"System Output": "System Output",
|
||||||
"System version": "System version",
|
"System version": "System version",
|
||||||
"Team": "Team",
|
"Team": "Team",
|
||||||
"Team Tags Set": "Team Tags",
|
"Team Tags Set": "Team Tags",
|
||||||
@ -280,6 +281,7 @@
|
|||||||
"App intro": "App intro",
|
"App intro": "App intro",
|
||||||
"App params config": "App Config",
|
"App params config": "App Config",
|
||||||
"Auto Save time": "Auto-saved: {{time}}",
|
"Auto Save time": "Auto-saved: {{time}}",
|
||||||
|
"Change to simple mode": "Switch easy mode",
|
||||||
"Chat Variable": "",
|
"Chat Variable": "",
|
||||||
"Config schedule plan": "Config schedule config",
|
"Config schedule plan": "Config schedule config",
|
||||||
"Config whisper": "Config whisper",
|
"Config whisper": "Config whisper",
|
||||||
@ -374,6 +376,11 @@
|
|||||||
"Show History": "Show History",
|
"Show History": "Show History",
|
||||||
"Web Link": "Web Link"
|
"Web Link": "Web Link"
|
||||||
},
|
},
|
||||||
|
"publish": {
|
||||||
|
"Fei Shu Bot Desc": "Access the Lark robot",
|
||||||
|
"Fei shu bot": "Lark",
|
||||||
|
"Fei shu bot publish": "Posted to Lark Robot"
|
||||||
|
},
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"Default prompt": "Default prompt",
|
"Default prompt": "Default prompt",
|
||||||
"Default prompt placeholder": "Default problem when executing the application",
|
"Default prompt placeholder": "Default problem when executing the application",
|
||||||
@ -957,6 +964,7 @@
|
|||||||
"anyInput": "Any input",
|
"anyInput": "Any input",
|
||||||
"chat history": "chat history",
|
"chat history": "chat history",
|
||||||
"switch": "Trigger",
|
"switch": "Trigger",
|
||||||
|
"system params": "System params",
|
||||||
"textEditor textarea": "Text edit",
|
"textEditor textarea": "Text edit",
|
||||||
"user question": "User question"
|
"user question": "User question"
|
||||||
},
|
},
|
||||||
@ -1108,6 +1116,7 @@
|
|||||||
"Stop debug": "Stop",
|
"Stop debug": "Stop",
|
||||||
"Success": "Running success",
|
"Success": "Running success",
|
||||||
"Value type": "Type",
|
"Value type": "Type",
|
||||||
|
"Variable outputs": "Variables",
|
||||||
"chat": {
|
"chat": {
|
||||||
"Quote prompt": "Quote prompt"
|
"Quote prompt": "Quote prompt"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -153,6 +153,7 @@
|
|||||||
"Submit failed": "提交失败",
|
"Submit failed": "提交失败",
|
||||||
"Submit success": "提交成功",
|
"Submit success": "提交成功",
|
||||||
"Sync success": "同步成功",
|
"Sync success": "同步成功",
|
||||||
|
"System Output": "系统输出",
|
||||||
"System version": "系统版本",
|
"System version": "系统版本",
|
||||||
"Team": "团队",
|
"Team": "团队",
|
||||||
"Team Tags Set": "标签",
|
"Team Tags Set": "标签",
|
||||||
@ -280,6 +281,7 @@
|
|||||||
"App intro": "应用介绍",
|
"App intro": "应用介绍",
|
||||||
"App params config": "应用配置",
|
"App params config": "应用配置",
|
||||||
"Auto Save time": "自动保存: {{time}}",
|
"Auto Save time": "自动保存: {{time}}",
|
||||||
|
"Change to simple mode": "切换简易模式",
|
||||||
"Chat Variable": "对话框变量",
|
"Chat Variable": "对话框变量",
|
||||||
"Config schedule plan": "配置定时执行",
|
"Config schedule plan": "配置定时执行",
|
||||||
"Config whisper": "配置语音输入",
|
"Config whisper": "配置语音输入",
|
||||||
@ -374,6 +376,11 @@
|
|||||||
"Show History": "展示历史对话",
|
"Show History": "展示历史对话",
|
||||||
"Web Link": "网络链接"
|
"Web Link": "网络链接"
|
||||||
},
|
},
|
||||||
|
"publish": {
|
||||||
|
"Fei Shu Bot Desc": "接入到飞书机器人中",
|
||||||
|
"Fei shu bot": "飞书",
|
||||||
|
"Fei shu bot publish": "发布到飞书机器人"
|
||||||
|
},
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"Default prompt": "默认问题",
|
"Default prompt": "默认问题",
|
||||||
"Default prompt placeholder": "执行应用时的默认问题",
|
"Default prompt placeholder": "执行应用时的默认问题",
|
||||||
@ -638,7 +645,8 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {}
|
"training": {
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@ -958,6 +966,7 @@
|
|||||||
"anyInput": "",
|
"anyInput": "",
|
||||||
"chat history": "聊天记录",
|
"chat history": "聊天记录",
|
||||||
"switch": "触发器",
|
"switch": "触发器",
|
||||||
|
"system params": "系统参数",
|
||||||
"textEditor textarea": "文本编辑",
|
"textEditor textarea": "文本编辑",
|
||||||
"user question": "用户问题"
|
"user question": "用户问题"
|
||||||
},
|
},
|
||||||
@ -1109,6 +1118,7 @@
|
|||||||
"Stop debug": "停止调试",
|
"Stop debug": "停止调试",
|
||||||
"Success": "运行成功",
|
"Success": "运行成功",
|
||||||
"Value type": "数据类型",
|
"Value type": "数据类型",
|
||||||
|
"Variable outputs": "全局变量",
|
||||||
"chat": {
|
"chat": {
|
||||||
"Quote prompt": "引用提示词"
|
"Quote prompt": "引用提示词"
|
||||||
},
|
},
|
||||||
|
|||||||
20
projects/app/src/components/common/HiddenInput/index.tsx
Normal file
20
projects/app/src/components/common/HiddenInput/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Button, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
|
||||||
|
import { ViewOffIcon, ViewIcon } from '@chakra-ui/icons';
|
||||||
|
function HiddenInput(props: any) {
|
||||||
|
const [show, setShow] = React.useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputGroup>
|
||||||
|
<Input {...props} type={show ? 'text' : 'password'} />
|
||||||
|
<InputRightElement width="4.5rem">
|
||||||
|
<Button h="1.75rem" size="sm" onClick={() => setShow(!show)}>
|
||||||
|
{show ? <ViewOffIcon /> : <ViewIcon />}
|
||||||
|
</Button>
|
||||||
|
</InputRightElement>
|
||||||
|
</InputGroup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HiddenInput;
|
||||||
@ -13,7 +13,6 @@ import {
|
|||||||
Switch,
|
Switch,
|
||||||
Input,
|
Input,
|
||||||
FormControl,
|
FormControl,
|
||||||
Image,
|
|
||||||
Table,
|
Table,
|
||||||
Thead,
|
Thead,
|
||||||
Tbody,
|
Tbody,
|
||||||
@ -21,7 +20,6 @@ import {
|
|||||||
Th,
|
Th,
|
||||||
Td,
|
Td,
|
||||||
TableContainer,
|
TableContainer,
|
||||||
BoxProps,
|
|
||||||
useDisclosure
|
useDisclosure
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||||
|
|||||||
@ -3,7 +3,8 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/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 { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useFlowProviderStore } from './FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../context';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@ -12,7 +13,8 @@ type Props = {
|
|||||||
const ImportSettings = ({ onClose }: Props) => {
|
const ImportSettings = ({ onClose }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { setNodes, setEdges, initData } = useFlowProviderStore();
|
|
||||||
|
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,14 +1,5 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import {
|
import { Box, Flex, IconButton, Input, InputGroup, InputLeftElement, css } from '@chakra-ui/react';
|
||||||
Box,
|
|
||||||
Card,
|
|
||||||
Flex,
|
|
||||||
IconButton,
|
|
||||||
Input,
|
|
||||||
InputGroup,
|
|
||||||
InputLeftElement,
|
|
||||||
css
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import type {
|
import type {
|
||||||
FlowNodeTemplateType,
|
FlowNodeTemplateType,
|
||||||
nodeTemplateListType
|
nodeTemplateListType
|
||||||
@ -16,8 +7,6 @@ import type {
|
|||||||
import { useViewport, XYPosition } from 'reactflow';
|
import { useViewport, XYPosition } from 'reactflow';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import { useFlowProviderStore } from './FlowProvider';
|
|
||||||
import { customAlphabet } from 'nanoid';
|
|
||||||
import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils';
|
import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||||
@ -36,6 +25,9 @@ import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../context';
|
||||||
|
import { useCreation } from 'ahooks';
|
||||||
|
|
||||||
type ModuleTemplateListProps = {
|
type ModuleTemplateListProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -62,7 +54,9 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
const [currentParent, setCurrentParent] = useState<RenderListProps['currentParent']>();
|
const [currentParent, setCurrentParent] = useState<RenderListProps['currentParent']>();
|
||||||
const [searchKey, setSearchKey] = useState('');
|
const [searchKey, setSearchKey] = useState('');
|
||||||
const { feConfigs } = useSystemStore();
|
const { feConfigs } = useSystemStore();
|
||||||
const { nodes, basicNodeTemplates, hasToolNode } = useFlowProviderStore();
|
const basicNodeTemplates = useContextSelector(WorkflowContext, (v) => v.basicNodeTemplates);
|
||||||
|
const hasToolNode = useContextSelector(WorkflowContext, (v) => v.hasToolNode);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
systemNodeTemplates,
|
systemNodeTemplates,
|
||||||
@ -72,12 +66,12 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
} = useWorkflowStore();
|
} = useWorkflowStore();
|
||||||
const [templateType, setTemplateType] = useState(TemplateTypeEnum.basic);
|
const [templateType, setTemplateType] = useState(TemplateTypeEnum.basic);
|
||||||
|
|
||||||
const templatesString = useMemo(() => {
|
const templates = useCreation(() => {
|
||||||
const map = {
|
const map = {
|
||||||
[TemplateTypeEnum.basic]: basicNodeTemplates.filter((item) => {
|
[TemplateTypeEnum.basic]: basicNodeTemplates.filter((item) => {
|
||||||
// unique node filter
|
// unique node filter
|
||||||
if (item.unique) {
|
if (item.unique) {
|
||||||
const nodeExist = nodes.some((node) => node.data.flowNodeType === item.flowNodeType);
|
const nodeExist = nodeList.some((node) => node.flowNodeType === item.flowNodeType);
|
||||||
if (nodeExist) {
|
if (nodeExist) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -97,12 +91,12 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
searchKey ? item.pluginType !== PluginTypeEnum.folder : true
|
searchKey ? item.pluginType !== PluginTypeEnum.folder : true
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
return JSON.stringify(map[templateType]);
|
return map[templateType];
|
||||||
}, [
|
}, [
|
||||||
basicNodeTemplates,
|
basicNodeTemplates,
|
||||||
feConfigs.lafEnv,
|
feConfigs.lafEnv,
|
||||||
hasToolNode,
|
hasToolNode,
|
||||||
nodes,
|
nodeList,
|
||||||
searchKey,
|
searchKey,
|
||||||
systemNodeTemplates,
|
systemNodeTemplates,
|
||||||
teamPluginNodeTemplates,
|
teamPluginNodeTemplates,
|
||||||
@ -132,8 +126,6 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
|
||||||
const parseTemplates = JSON.parse(templatesString) as FlowNodeTemplateType[];
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
@ -240,7 +232,7 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<RenderList
|
<RenderList
|
||||||
templates={parseTemplates}
|
templates={templates}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
currentParent={currentParent}
|
currentParent={currentParent}
|
||||||
setCurrentParent={setCurrentParent}
|
setCurrentParent={setCurrentParent}
|
||||||
@ -248,19 +240,6 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, [
|
|
||||||
currentParent,
|
|
||||||
isOpen,
|
|
||||||
onChangeTab,
|
|
||||||
onClose,
|
|
||||||
router,
|
|
||||||
searchKey,
|
|
||||||
t,
|
|
||||||
templateType,
|
|
||||||
templatesString
|
|
||||||
]);
|
|
||||||
|
|
||||||
return Render;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(NodeTemplatesModal);
|
export default React.memo(NodeTemplatesModal);
|
||||||
@ -276,7 +255,8 @@ const RenderList = React.memo(function RenderList({
|
|||||||
const { x, y, zoom } = useViewport();
|
const { x, y, zoom } = useViewport();
|
||||||
const { setLoading } = useSystemStore();
|
const { setLoading } = useSystemStore();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { reactFlowWrapper, setNodes } = useFlowProviderStore();
|
const reactFlowWrapper = useContextSelector(WorkflowContext, (v) => v.reactFlowWrapper);
|
||||||
|
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||||
|
|
||||||
const formatTemplates = useMemo<nodeTemplateListType>(() => {
|
const formatTemplates = useMemo<nodeTemplateListType>(() => {
|
||||||
const copy: nodeTemplateListType = JSON.parse(JSON.stringify(moduleTemplatesList));
|
const copy: nodeTemplateListType = JSON.parse(JSON.stringify(moduleTemplatesList));
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
|
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const ButtonEdge = (props: EdgeProps) => {
|
const ButtonEdge = (props: EdgeProps) => {
|
||||||
const { nodes, setEdges, workflowDebugData } = useFlowProviderStore();
|
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||||
|
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||||
|
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
sourceX,
|
sourceX,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { storeNodes2RuntimeNodes } from '@fastgpt/global/core/workflow/runtime/u
|
|||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
|
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { getWorkflowStore, useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { checkWorkflowNodeAndConnection } from '@/web/core/workflow/utils';
|
import { checkWorkflowNodeAndConnection } from '@/web/core/workflow/utils';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
@ -25,6 +24,8 @@ import {
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { checkInputIsReference } from '@fastgpt/global/core/workflow/utils';
|
import { checkInputIsReference } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext, getWorkflowStore } from '../../context';
|
||||||
|
|
||||||
const MyRightDrawer = dynamic(
|
const MyRightDrawer = dynamic(
|
||||||
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
||||||
@ -35,7 +36,10 @@ export const useDebug = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const { edges, setNodes, onStartNodeDebug, onUpdateNodeError } = useFlowProviderStore();
|
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||||
|
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
const onStartNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStartNodeDebug);
|
||||||
|
|
||||||
const [runtimeNodeId, setRuntimeNodeId] = useState<string>();
|
const [runtimeNodeId, setRuntimeNodeId] = useState<string>();
|
||||||
const [runtimeNodes, setRuntimeNodes] = useState<RuntimeNodeItemType[]>();
|
const [runtimeNodes, setRuntimeNodes] = useState<RuntimeNodeItemType[]>();
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { getWorkflowStore, useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Node } from 'reactflow';
|
import { Node } from 'reactflow';
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext, getWorkflowStore } from '../../context';
|
||||||
|
|
||||||
export const useKeyboard = () => {
|
export const useKeyboard = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { setNodes } = useFlowProviderStore();
|
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||||
const { copyData } = useCopyData();
|
const { copyData } = useCopyData();
|
||||||
|
|
||||||
const [isDowningCtrl, setIsDowningCtrl] = useState(false);
|
const [isDowningCtrl, setIsDowningCtrl] = useState(false);
|
||||||
@ -29,6 +30,7 @@ export const useKeyboard = () => {
|
|||||||
const onCopy = useCallback(async () => {
|
const onCopy = useCallback(async () => {
|
||||||
if (hasInputtingElement()) return;
|
if (hasInputtingElement()) return;
|
||||||
const { nodes } = await getWorkflowStore();
|
const { nodes } = await getWorkflowStore();
|
||||||
|
|
||||||
const selectedNodes = nodes.filter(
|
const selectedNodes = nodes.filter(
|
||||||
(node) => node.selected && !node.data?.isError && node.data?.unique !== true
|
(node) => node.selected && !node.data?.isError && node.data?.unique !== true
|
||||||
);
|
);
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import dynamic from 'next/dynamic';
|
|||||||
|
|
||||||
import ButtonEdge from './components/ButtonEdge';
|
import ButtonEdge from './components/ButtonEdge';
|
||||||
import NodeTemplatesModal from './NodeTemplatesModal';
|
import NodeTemplatesModal from './NodeTemplatesModal';
|
||||||
import { useFlowProviderStore } from './FlowProvider';
|
|
||||||
|
|
||||||
import 'reactflow/dist/style.css';
|
import 'reactflow/dist/style.css';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
@ -32,6 +31,8 @@ import MyTooltip from '@/components/MyTooltip';
|
|||||||
import { connectionLineStyle, defaultEdgeOptions } from '../constants';
|
import { connectionLineStyle, defaultEdgeOptions } from '../constants';
|
||||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||||
import { useKeyboard } from './hooks/useKeyboard';
|
import { useKeyboard } from './hooks/useKeyboard';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../context';
|
||||||
|
|
||||||
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
||||||
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||||
@ -71,16 +72,13 @@ const Container = React.memo(function Container() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { isDowningCtrl } = useKeyboard();
|
const { isDowningCtrl } = useKeyboard();
|
||||||
|
const setConnectingEdge = useContextSelector(WorkflowContext, (v) => v.setConnectingEdge);
|
||||||
const {
|
const reactFlowWrapper = useContextSelector(WorkflowContext, (v) => v.reactFlowWrapper);
|
||||||
reactFlowWrapper,
|
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||||
nodes,
|
const onNodesChange = useContextSelector(WorkflowContext, (v) => v.onNodesChange);
|
||||||
onNodesChange,
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
edges,
|
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||||
setEdges,
|
const onEdgesChange = useContextSelector(WorkflowContext, (v) => v.onEdgesChange);
|
||||||
onEdgesChange,
|
|
||||||
setConnectingEdge
|
|
||||||
} = useFlowProviderStore();
|
|
||||||
|
|
||||||
/* node */
|
/* node */
|
||||||
const handleNodesChange = useCallback(
|
const handleNodesChange = useCallback(
|
||||||
|
|||||||
@ -4,15 +4,16 @@ import NodeCard from './render/NodeCard';
|
|||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import Container from '../components/Container';
|
import Container from '../components/Container';
|
||||||
import RenderInput from './render/RenderInput';
|
import RenderInput from './render/RenderInput';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import RenderToolInput from './render/RenderToolInput';
|
import RenderToolInput from './render/RenderToolInput';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const NodeAnswer = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeAnswer = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs } = data;
|
||||||
const { splitToolInputs } = useFlowProviderStore();
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -11,16 +11,16 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { SourceHandle } from './render/Handle';
|
import { SourceHandle } from './render/Handle';
|
||||||
import IOTitle from '../components/IOTitle';
|
|
||||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const NodeCQNode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeCQNode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs } = data;
|
const { nodeId, inputs } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const CustomComponent = useMemo(
|
const CustomComponent = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@ -9,19 +9,21 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { getOneQuoteInputTemplate } from '@fastgpt/global/core/workflow/template/system/datasetConcat';
|
import { getOneQuoteInputTemplate } from '@fastgpt/global/core/workflow/template/system/datasetConcat';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import MySlider from '@/components/Slider';
|
import MySlider from '@/components/Slider';
|
||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||||
import RenderOutput from './render/RenderOutput';
|
import RenderOutput from './render/RenderOutput';
|
||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { llmModelList } = useSystemStore();
|
const { llmModelList } = useSystemStore();
|
||||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const quotes = useMemo(
|
const quotes = useMemo(
|
||||||
() => inputs.filter((item) => item.valueType === WorkflowIOValueTypeEnum.datasetQuote),
|
() => inputs.filter((item) => item.valueType === WorkflowIOValueTypeEnum.datasetQuote),
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import ExtractFieldModal, { defaultField } from './ExtractFieldModal';
|
|||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useFlowProviderStore } from '../../FlowProvider';
|
|
||||||
import RenderToolInput from '../render/RenderToolInput';
|
import RenderToolInput from '../render/RenderToolInput';
|
||||||
import {
|
import {
|
||||||
FlowNodeInputItemType,
|
FlowNodeInputItemType,
|
||||||
@ -34,12 +33,17 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/type/io.d';
|
} from '@fastgpt/global/core/workflow/type/io.d';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import IOTitle from '../../components/IOTitle';
|
import IOTitle from '../../components/IOTitle';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
|
||||||
const NodeExtract = ({ data }: NodeProps<FlowNodeItemType>) => {
|
const NodeExtract = ({ data }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { inputs, outputs, nodeId } = data;
|
const { inputs, outputs, nodeId } = data;
|
||||||
const { splitToolInputs, onChangeNode } = useFlowProviderStore();
|
|
||||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
|
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||||
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
||||||
|
|
||||||
const CustomComponent = useMemo(
|
const CustomComponent = useMemo(
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
|||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import parse from '@bany/curl-to-json';
|
import parse from '@bany/curl-to-json';
|
||||||
import { useFlowProviderStore } from '../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
|
||||||
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
||||||
const methodMap: { [K in RequestMethod]: string } = {
|
const methodMap: { [K in RequestMethod]: string } = {
|
||||||
@ -28,7 +29,8 @@ const CurlImportModal = ({
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const { register, handleSubmit } = useForm({
|
const { register, handleSubmit } = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
curlContent: ''
|
curlContent: ''
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import {
|
|||||||
useDisclosure
|
useDisclosure
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useFlowProviderStore } from '../../FlowProvider';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import Tabs from '@/components/Tabs';
|
import Tabs from '@/components/Tabs';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
@ -41,6 +40,9 @@ import MySelect from '@fastgpt/web/components/common/MySelect';
|
|||||||
import RenderToolInput from '../render/RenderToolInput';
|
import RenderToolInput from '../render/RenderToolInput';
|
||||||
import IOTitle from '../../components/IOTitle';
|
import IOTitle from '../../components/IOTitle';
|
||||||
import { getSystemVariables } from '@/web/core/app/utils';
|
import { getSystemVariables } from '@/web/core/app/utils';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
const CurlImportModal = dynamic(() => import('./CurlImportModal'));
|
const CurlImportModal = dynamic(() => import('./CurlImportModal'));
|
||||||
|
|
||||||
export const HttpHeaders = [
|
export const HttpHeaders = [
|
||||||
@ -105,7 +107,7 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [_, startSts] = useTransition();
|
const [_, startSts] = useTransition();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const { isOpen: isOpenCurl, onOpen: onOpenCurl, onClose: onCloseCurl } = useDisclosure();
|
const { isOpen: isOpenCurl, onOpen: onOpenCurl, onClose: onCloseCurl } = useDisclosure();
|
||||||
|
|
||||||
@ -277,7 +279,7 @@ export function RenderHttpProps({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedTab, setSelectedTab] = useState(TabEnum.params);
|
const [selectedTab, setSelectedTab] = useState(TabEnum.params);
|
||||||
const { nodeList } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const requestMethods = inputs.find((item) => item.key === NodeInputKeyEnum.httpMethod)?.value;
|
const requestMethods = inputs.find((item) => item.key === NodeInputKeyEnum.httpMethod)?.value;
|
||||||
const params = inputs.find((item) => item.key === NodeInputKeyEnum.httpParams);
|
const params = inputs.find((item) => item.key === NodeInputKeyEnum.httpParams);
|
||||||
@ -289,11 +291,7 @@ export function RenderHttpProps({
|
|||||||
|
|
||||||
// get variable
|
// get variable
|
||||||
const variables = useMemo(() => {
|
const variables = useMemo(() => {
|
||||||
const globalVariables = formatEditorVariablePickerIcon(
|
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
|
||||||
);
|
|
||||||
|
|
||||||
const systemVariables = getSystemVariables(t);
|
|
||||||
|
|
||||||
const moduleVariables = formatEditorVariablePickerIcon(
|
const moduleVariables = formatEditorVariablePickerIcon(
|
||||||
inputs
|
inputs
|
||||||
@ -304,7 +302,7 @@ export function RenderHttpProps({
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...moduleVariables, ...globalVariables, ...systemVariables];
|
return [...moduleVariables, ...globalVariables];
|
||||||
}, [inputs, nodeList, t]);
|
}, [inputs, nodeList, t]);
|
||||||
|
|
||||||
const variableText = useMemo(() => {
|
const variableText = useMemo(() => {
|
||||||
@ -407,7 +405,7 @@ const RenderForm = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const [list, setList] = useState<PropsArrType[]>(input.value || []);
|
const [list, setList] = useState<PropsArrType[]>(input.value || []);
|
||||||
const [updateTrigger, setUpdateTrigger] = useState(false);
|
const [updateTrigger, setUpdateTrigger] = useState(false);
|
||||||
@ -601,7 +599,7 @@ const RenderJson = ({
|
|||||||
variables: EditorVariablePickerType[];
|
variables: EditorVariablePickerType[];
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const [_, startSts] = useTransition();
|
const [_, startSts] = useTransition();
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
@ -650,7 +648,7 @@ const RenderPropsItem = ({ text, num }: { text: string; num: number }) => {
|
|||||||
const NodeHttp = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeHttp = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
const { splitToolInputs } = useFlowProviderStore();
|
const splitToolInputs = useContextSelector(WorkflowContext, (v) => v.splitToolInputs);
|
||||||
const { toolInputs, commonInputs, isTool } = splitToolInputs(inputs, nodeId);
|
const { toolInputs, commonInputs, isTool } = splitToolInputs(inputs, nodeId);
|
||||||
|
|
||||||
const CustomComponents = useMemo(
|
const CustomComponents = useMemo(
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import NodeCard from './render/NodeCard';
|
import NodeCard from './render/NodeCard';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { Box, Button, Flex, background } from '@chakra-ui/react';
|
import { Box, Button, Flex, background } from '@chakra-ui/react';
|
||||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
@ -25,11 +24,13 @@ import {
|
|||||||
import { stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
import { stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
import MyInput from '@/components/MyInput';
|
import MyInput from '@/components/MyInput';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs = [], outputs } = data;
|
const { nodeId, inputs = [], outputs } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const condition = useMemo(
|
const condition = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -274,7 +275,7 @@ const ConditionSelect = ({
|
|||||||
variable?: ReferenceValueProps;
|
variable?: ReferenceValueProps;
|
||||||
onSelect: (e: VariableConditionEnum) => void;
|
onSelect: (e: VariableConditionEnum) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { nodeList } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
// get condition type
|
// get condition type
|
||||||
const valueType = useMemo(() => {
|
const valueType = useMemo(() => {
|
||||||
@ -337,7 +338,7 @@ const ConditionValueInput = ({
|
|||||||
condition?: VariableConditionEnum;
|
condition?: VariableConditionEnum;
|
||||||
onChange: (e: string) => void;
|
onChange: (e: string) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { nodeList } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
// get value type
|
// get value type
|
||||||
const valueType = useMemo(() => {
|
const valueType = useMemo(() => {
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
|||||||
import Container from '../components/Container';
|
import Container from '../components/Container';
|
||||||
import { Box, Button, Center, Flex, useDisclosure } from '@chakra-ui/react';
|
import { Box, Button, Center, Flex, useDisclosure } from '@chakra-ui/react';
|
||||||
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { getLafAppDetail } from '@/web/support/laf/api';
|
import { getLafAppDetail } from '@/web/support/laf/api';
|
||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
@ -32,6 +31,8 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/type/io';
|
} from '@fastgpt/global/core/workflow/type/io';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
const { data, selected } = props;
|
const { data, selected } = props;
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
|
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
||||||
|
|
||||||
@ -293,7 +294,7 @@ const ConfigLaf = () => {
|
|||||||
const RenderIO = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const RenderIO = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
const { splitToolInputs } = useFlowProviderStore();
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
const { commonInputs, toolInputs, isTool } = splitToolInputs(inputs, nodeId);
|
const { commonInputs, toolInputs, isTool } = splitToolInputs(inputs, nodeId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import React, { useMemo, useState } from 'react';
|
|||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import NodeCard from './render/NodeCard';
|
import NodeCard from './render/NodeCard';
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { Box, Button, Flex } from '@chakra-ui/react';
|
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import {
|
import {
|
||||||
@ -17,7 +16,6 @@ import type {
|
|||||||
EditNodeFieldType
|
EditNodeFieldType
|
||||||
} from '@fastgpt/global/core/workflow/node/type.d';
|
} from '@fastgpt/global/core/workflow/node/type.d';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import {
|
import {
|
||||||
FlowNodeInputMap,
|
FlowNodeInputMap,
|
||||||
@ -26,6 +24,8 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/node/constant';
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||||
import VariableTable from '../nodes/render/VariableTable';
|
import VariableTable from '../nodes/render/VariableTable';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const defaultCreateField: EditNodeFieldType = {
|
const defaultCreateField: EditNodeFieldType = {
|
||||||
label: '',
|
label: '',
|
||||||
@ -50,7 +50,7 @@ const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
|
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
||||||
const [editField, setEditField] = useState<EditNodeFieldType>();
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|||||||
@ -11,8 +11,9 @@ import { EditInputFieldMapType, EditNodeFieldType } from '@fastgpt/global/core/w
|
|||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import RenderInput from './render/RenderInput';
|
import RenderInput from './render/RenderInput';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const FieldEditModal = dynamic(() => import('./render/FieldEditModal'));
|
const FieldEditModal = dynamic(() => import('./render/FieldEditModal'));
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ const createEditField: EditInputFieldMapType = {
|
|||||||
const NodePluginOutput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodePluginOutput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs } = data;
|
const { nodeId, inputs } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,10 @@ import RenderInput from './render/RenderInput';
|
|||||||
import RenderOutput from './render/RenderOutput';
|
import RenderOutput from './render/RenderOutput';
|
||||||
import RenderToolInput from './render/RenderToolInput';
|
import RenderToolInput from './render/RenderToolInput';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
|
||||||
const NodeSimple = ({
|
const NodeSimple = ({
|
||||||
data,
|
data,
|
||||||
@ -18,7 +19,7 @@ const NodeSimple = ({
|
|||||||
maxW
|
maxW
|
||||||
}: NodeProps<FlowNodeItemType> & { minW?: string | number; maxW?: string | number }) => {
|
}: NodeProps<FlowNodeItemType> & { minW?: string | number; maxW?: string | number }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { splitToolInputs } = useFlowProviderStore();
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
const { nodeId, inputs, outputs } = data;
|
const { nodeId, inputs, outputs } = data;
|
||||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +1,31 @@
|
|||||||
import React, { useCallback, useMemo, useTransition } from 'react';
|
import React, { useMemo, useTransition } from 'react';
|
||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import { Box, Flex, Textarea, useTheme } from '@chakra-ui/react';
|
import { Box, Flex, Textarea, useTheme } from '@chakra-ui/react';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { welcomeTextTip } from '@fastgpt/global/core/workflow/template/tip';
|
import { welcomeTextTip } from '@fastgpt/global/core/workflow/template/tip';
|
||||||
|
|
||||||
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
|
||||||
import QGSwitch from '@/components/core/app/QGSwitch';
|
import QGSwitch from '@/components/core/app/QGSwitch';
|
||||||
import TTSSelect from '@/components/core/app/TTSSelect';
|
import TTSSelect from '@/components/core/app/TTSSelect';
|
||||||
import WhisperConfig from '@/components/core/app/WhisperConfig';
|
import WhisperConfig from '@/components/core/app/WhisperConfig';
|
||||||
import { splitGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { splitGuideModule } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { TTSTypeEnum } from '@/constants/app';
|
import { TTSTypeEnum } from '@/constants/app';
|
||||||
import { useFlowProviderStore } from '../FlowProvider';
|
|
||||||
import VariableEdit from '../../../app/VariableEdit';
|
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import NodeCard from './render/NodeCard';
|
import NodeCard from './render/NodeCard';
|
||||||
import ScheduledTriggerConfig from '@/components/core/app/ScheduledTriggerConfig';
|
import ScheduledTriggerConfig from '@/components/core/app/ScheduledTriggerConfig';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
import { VariableItemType } from '@fastgpt/global/core/app/type';
|
||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
import VariableEdit from '@/components/core/app/VariableEdit';
|
||||||
|
import {
|
||||||
|
FlowNodeOutputTypeEnum,
|
||||||
|
FlowNodeTypeEnum
|
||||||
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
import { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
|
|
||||||
const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -38,10 +45,10 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
>
|
>
|
||||||
<Box px={4} py={'10px'} position={'relative'} borderRadius={'md'} className="nodrag">
|
<Box px={4} py={'10px'} position={'relative'} borderRadius={'md'} className="nodrag">
|
||||||
<WelcomeText data={data} />
|
<WelcomeText data={data} />
|
||||||
<Box pt={4} pb={2}>
|
<Box pt={4}>
|
||||||
<ChatStartVariable data={data} />
|
<ChatStartVariable data={data} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box pt={3} borderTop={theme.borders.base}>
|
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||||
<TTSGuide data={data} />
|
<TTSGuide data={data} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||||
@ -65,7 +72,7 @@ function WelcomeText({ data }: { data: FlowNodeItemType }) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const [, startTst] = useTransition();
|
const [, startTst] = useTransition();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const welcomeText = inputs.find((item) => item.key === NodeInputKeyEnum.welcomeText);
|
const welcomeText = inputs.find((item) => item.key === NodeInputKeyEnum.welcomeText);
|
||||||
|
|
||||||
@ -108,7 +115,7 @@ function WelcomeText({ data }: { data: FlowNodeItemType }) {
|
|||||||
|
|
||||||
function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const variables = useMemo(
|
const variables = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -117,8 +124,8 @@ function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
|||||||
[inputs]
|
[inputs]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateVariables = useCallback(
|
const updateVariables = useMemoizedFn((value: VariableItemType[]) => {
|
||||||
(value: VariableItemType[]) => {
|
// update system config node
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId,
|
nodeId,
|
||||||
key: NodeInputKeyEnum.variables,
|
key: NodeInputKeyEnum.variables,
|
||||||
@ -128,16 +135,14 @@ function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
[inputs, nodeId, onChangeNode]
|
|
||||||
);
|
|
||||||
|
|
||||||
return <VariableEdit variables={variables} onChange={(e) => updateVariables(e)} />;
|
return <VariableEdit variables={variables} onChange={(e) => updateVariables(e)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function QuestionGuide({ data }: { data: FlowNodeItemType }) {
|
function QuestionGuide({ data }: { data: FlowNodeItemType }) {
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const questionGuide = useMemo(
|
const questionGuide = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -168,7 +173,7 @@ function QuestionGuide({ data }: { data: FlowNodeItemType }) {
|
|||||||
|
|
||||||
function TTSGuide({ data }: { data: FlowNodeItemType }) {
|
function TTSGuide({ data }: { data: FlowNodeItemType }) {
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const { ttsConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
const { ttsConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -191,7 +196,7 @@ function TTSGuide({ data }: { data: FlowNodeItemType }) {
|
|||||||
|
|
||||||
function WhisperGuide({ data }: { data: FlowNodeItemType }) {
|
function WhisperGuide({ data }: { data: FlowNodeItemType }) {
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const { ttsConfig, whisperConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
const { ttsConfig, whisperConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -215,7 +220,7 @@ function WhisperGuide({ data }: { data: FlowNodeItemType }) {
|
|||||||
|
|
||||||
function ScheduledTrigger({ data }: { data: FlowNodeItemType }) {
|
function ScheduledTrigger({ data }: { data: FlowNodeItemType }) {
|
||||||
const { inputs, nodeId } = data;
|
const { inputs, nodeId } = data;
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const { scheduledTriggerConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
const { scheduledTriggerConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import NodeCard from './render/NodeCard';
|
import NodeCard from './render/NodeCard';
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
@ -6,10 +6,30 @@ import Container from '../components/Container';
|
|||||||
import RenderOutput from './render/RenderOutput';
|
import RenderOutput from './render/RenderOutput';
|
||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../context';
|
||||||
|
import { useCreation } from 'ahooks';
|
||||||
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
|
import { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
|
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
|
||||||
const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, outputs } = data;
|
const { nodeId, outputs } = data;
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
|
const variablesOutputs = useCreation(() => {
|
||||||
|
const variables = getWorkflowGlobalVariables(nodeList, t);
|
||||||
|
|
||||||
|
return variables.map<FlowNodeOutputItemType>((item) => ({
|
||||||
|
id: item.key,
|
||||||
|
type: FlowNodeOutputTypeEnum.static,
|
||||||
|
key: item.key,
|
||||||
|
valueType: item.valueType || WorkflowIOValueTypeEnum.any,
|
||||||
|
label: item.label
|
||||||
|
}));
|
||||||
|
}, [nodeList, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeCard
|
<NodeCard
|
||||||
@ -26,6 +46,10 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
<IOTitle text={t('common.Output')} />
|
<IOTitle text={t('common.Output')} />
|
||||||
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
||||||
</Container>
|
</Container>
|
||||||
|
<Container>
|
||||||
|
<IOTitle text={t('core.module.Variable')} />
|
||||||
|
<RenderOutput nodeId={nodeId} flowOutputList={variablesOutputs} />
|
||||||
|
</Container>
|
||||||
</NodeCard>
|
</NodeCard>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Position } from 'reactflow';
|
import { Position } from 'reactflow';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
|
||||||
import { SourceHandle, TargetHandle } from '.';
|
import { SourceHandle, TargetHandle } from '.';
|
||||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||||
const { nodeList, edges, connectingEdge } = useFlowProviderStore();
|
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||||
|
|
||||||
@ -102,7 +105,8 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ConnectionTargetHandle = ({ nodeId }: { nodeId: string }) => {
|
export const ConnectionTargetHandle = ({ nodeId }: { nodeId: string }) => {
|
||||||
const { nodeList, connectingEdge } = useFlowProviderStore();
|
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
|
||||||
import { Box, BoxProps } from '@chakra-ui/react';
|
import { Box, BoxProps } from '@chakra-ui/react';
|
||||||
import {
|
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
WorkflowIOValueTypeEnum,
|
|
||||||
NodeOutputKeyEnum
|
|
||||||
} from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Connection, Handle, Position } from 'reactflow';
|
import { Connection, Handle, Position } from 'reactflow';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
const handleSize = '14px';
|
const handleSize = '14px';
|
||||||
|
|
||||||
type ToolHandleProps = BoxProps & {
|
type ToolHandleProps = BoxProps & {
|
||||||
@ -17,7 +14,9 @@ type ToolHandleProps = BoxProps & {
|
|||||||
};
|
};
|
||||||
export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { connectingEdge, edges } = useFlowProviderStore();
|
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
const handleId = NodeOutputKeyEnum.selectedTools;
|
const handleId = NodeOutputKeyEnum.selectedTools;
|
||||||
|
|
||||||
const connected = edges.some((edge) => edge.target === nodeId && edge.targetHandle === handleId);
|
const connected = edges.some((edge) => edge.target === nodeId && edge.targetHandle === handleId);
|
||||||
@ -62,7 +61,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
|||||||
|
|
||||||
export const ToolSourceHandle = ({ nodeId }: ToolHandleProps) => {
|
export const ToolSourceHandle = ({ nodeId }: ToolHandleProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { setEdges } = useFlowProviderStore();
|
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||||
|
|
||||||
/* onConnect edge, delete tool input and switch */
|
/* onConnect edge, delete tool input and switch */
|
||||||
const onConnect = useCallback(
|
const onConnect = useCallback(
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
|
||||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import { handleHighLightStyle, sourceCommonStyle, handleConnectedStyle, handleSize } from './style';
|
import { handleHighLightStyle, sourceCommonStyle, handleConnectedStyle, handleSize } from './style';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
@ -23,7 +24,11 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
|||||||
highlightStyle: Record<string, any>;
|
highlightStyle: Record<string, any>;
|
||||||
connectedStyle: Record<string, any>;
|
connectedStyle: Record<string, any>;
|
||||||
}) {
|
}) {
|
||||||
const { nodes, hoverNodeId, edges, connectingEdge } = useFlowProviderStore();
|
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
|
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||||
|
const hoverNodeId = useContextSelector(WorkflowContext, (v) => v.hoverNodeId);
|
||||||
|
|
||||||
const node = useMemo(() => nodes.find((node) => node.data.nodeId === nodeId), [nodes, nodeId]);
|
const node = useMemo(() => nodes.find((node) => node.data.nodeId === nodeId), [nodes, nodeId]);
|
||||||
const connected = edges.some((edge) => edge.sourceHandle === handleId);
|
const connected = edges.some((edge) => edge.sourceHandle === handleId);
|
||||||
@ -136,8 +141,10 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
|||||||
highlightStyle: Record<string, any>;
|
highlightStyle: Record<string, any>;
|
||||||
connectedStyle: Record<string, any>;
|
connectedStyle: Record<string, any>;
|
||||||
}) {
|
}) {
|
||||||
const { nodeList, edges, connectingEdge } = useFlowProviderStore();
|
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||||
const connected = edges.some((edge) => edge.targetHandle === handleId);
|
const connected = edges.some((edge) => edge.targetHandle === handleId);
|
||||||
const connectedEdges = edges.filter((edge) => edge.target === nodeId);
|
const connectedEdges = edges.filter((edge) => edge.target === nodeId);
|
||||||
@ -194,12 +201,13 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
||||||
// Same source node
|
|
||||||
|
|
||||||
if (connectedEdges.some((item) => item.sourceHandle === connectingEdge?.handleId)) return false;
|
// Same source node
|
||||||
|
if (connectedEdges.some((item) => item.target === nodeId && item.targetHandle !== handleId))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, [connectedEdges, connectingEdge?.handleId, edges, node, nodeId]);
|
}, [connectedEdges, connectingEdge?.handleId, edges, handleId, node, nodeId]);
|
||||||
|
|
||||||
const RenderHandle = useMemo(() => {
|
const RenderHandle = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.
|
|||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useFlowProviderStore } from '../../FlowProvider';
|
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||||
@ -21,6 +20,8 @@ import { getPreviewPluginModule } from '@/web/core/plugin/api';
|
|||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
|
||||||
type Props = FlowNodeItemType & {
|
type Props = FlowNodeItemType & {
|
||||||
children?: React.ReactNode | React.ReactNode[] | string;
|
children?: React.ReactNode | React.ReactNode[] | string;
|
||||||
@ -55,7 +56,9 @@ const NodeCard = (props: Props) => {
|
|||||||
pluginId
|
pluginId
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { nodeList, setHoverNodeId, onUpdateNodeError } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const setHoverNodeId = useContextSelector(WorkflowContext, (v) => v.setHoverNodeId);
|
||||||
|
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||||
|
|
||||||
const showToolHandle = useMemo(
|
const showToolHandle = useMemo(
|
||||||
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
|
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
|
||||||
@ -105,7 +108,6 @@ const NodeCard = (props: Props) => {
|
|||||||
intro
|
intro
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
minW={minW}
|
minW={minW}
|
||||||
@ -140,9 +142,6 @@ const NodeCard = (props: Props) => {
|
|||||||
<ConnectionTargetHandle nodeId={nodeId} />
|
<ConnectionTargetHandle nodeId={nodeId} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}, [Header, children, isError, maxW, minW, nodeId, onUpdateNodeError, selected, setHoverNodeId]);
|
|
||||||
|
|
||||||
return Render;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(NodeCard);
|
export default React.memo(NodeCard);
|
||||||
@ -180,7 +179,10 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
type: 'delete'
|
type: 'delete'
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setNodes, setEdges, onResetNode, onChangeNode } = useFlowProviderStore();
|
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||||
|
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
||||||
|
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const onCopyNode = useCallback(
|
const onCopyNode = useCallback(
|
||||||
(nodeId: string) => {
|
(nodeId: string) => {
|
||||||
@ -383,7 +385,8 @@ const NodeIntro = React.memo(function NodeIntro({
|
|||||||
intro?: string;
|
intro?: string;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode, splitToolInputs } = useFlowProviderStore();
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const moduleIsTool = useMemo(() => {
|
const moduleIsTool = useMemo(() => {
|
||||||
const { isTool } = splitToolInputs([], nodeId);
|
const { isTool } = splitToolInputs([], nodeId);
|
||||||
@ -442,8 +445,12 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
|||||||
debugResult: FlowNodeItemType['debugResult'];
|
debugResult: FlowNodeItemType['debugResult'];
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode, onStopNodeDebug, onNextNodeDebug, workflowDebugData } =
|
|
||||||
useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const onStopNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStopNodeDebug);
|
||||||
|
const onNextNodeDebug = useContextSelector(WorkflowContext, (v) => v.onNextNodeDebug);
|
||||||
|
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||||
|
|
||||||
const { openConfirm, ConfirmModal } = useConfirm({
|
const { openConfirm, ConfirmModal } = useConfirm({
|
||||||
content: t('core.workflow.Confirm stop debug')
|
content: t('core.workflow.Confirm stop debug')
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
|
||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
@ -13,17 +12,20 @@ import dynamic from 'next/dynamic';
|
|||||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import ValueTypeLabel from '../ValueTypeLabel';
|
import ValueTypeLabel from '../ValueTypeLabel';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
const FieldEditModal = dynamic(() => import('../FieldEditModal'));
|
const FieldEditModal = dynamic(() => import('../FieldEditModal'));
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
input: FlowNodeInputItemType;
|
input: FlowNodeInputItemType;
|
||||||
mode?: 'app' | 'plugin';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const InputLabel = ({ nodeId, input }: Props) => {
|
const InputLabel = ({ nodeId, input }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
description,
|
description,
|
||||||
toolDescription,
|
toolDescription,
|
||||||
|
|||||||
@ -5,18 +5,21 @@ import { SmallAddIcon } from '@chakra-ui/icons';
|
|||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
import Reference from './Reference';
|
import Reference from './Reference';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
|
const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
|
||||||
|
|
||||||
const AddInputParam = (props: RenderInputProps) => {
|
const AddInputParam = (props: RenderInputProps) => {
|
||||||
const { item, inputs, nodeId } = props;
|
const { item, inputs, nodeId } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode, mode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const mode = useContextSelector(WorkflowContext, (ctx) => ctx.mode);
|
||||||
|
|
||||||
const inputValue = useMemo(() => (item.value || []) as FlowNodeInputItemType[], [item.value]);
|
const inputValue = useMemo(() => (item.value || []) as FlowNodeInputItemType[], [item.value]);
|
||||||
|
|
||||||
const [editField, setEditField] = useState<EditNodeFieldType>();
|
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||||
import {
|
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
|
||||||
formatEditorVariablePickerIcon,
|
import { useContextSelector } from 'use-context-selector';
|
||||||
getGuideModule,
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
splitGuideModule
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
} from '@fastgpt/global/core/workflow/utils';
|
import { useCreation } from 'ahooks';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
const JsonEditor = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
const JsonEditor = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
const { t } = useTranslation();
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
// get variable
|
// get variable
|
||||||
const variables = useMemo(() => {
|
const variables = useCreation(() => {
|
||||||
const globalVariables = formatEditorVariablePickerIcon(
|
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
|
||||||
);
|
|
||||||
const moduleVariables = formatEditorVariablePickerIcon(
|
const moduleVariables = formatEditorVariablePickerIcon(
|
||||||
inputs
|
inputs
|
||||||
.filter((input) => input.canEdit)
|
.filter((input) => input.canEdit)
|
||||||
|
|||||||
@ -7,10 +7,11 @@ import {
|
|||||||
NumberInputField,
|
NumberInputField,
|
||||||
NumberInputStepper
|
NumberInputStepper
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
|
const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { Flex, Box, ButtonProps } from '@chakra-ui/react';
|
import { Flex, Box, ButtonProps } from '@chakra-ui/react';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { computedNodeInputReference } from '@/web/core/workflow/utils';
|
import { computedNodeInputReference } from '@/web/core/workflow/utils';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import {
|
import {
|
||||||
NodeOutputKeyEnum,
|
NodeOutputKeyEnum,
|
||||||
|
VARIABLE_NODE_ID,
|
||||||
WorkflowIOValueTypeEnum
|
WorkflowIOValueTypeEnum
|
||||||
} from '@fastgpt/global/core/workflow/constants';
|
} from '@fastgpt/global/core/workflow/constants';
|
||||||
import type { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
import type { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
|
||||||
const MultipleRowSelect = dynamic(
|
const MultipleRowSelect = dynamic(
|
||||||
() => import('@fastgpt/web/components/common/MySelect/MultipleRowSelect')
|
() => import('@fastgpt/web/components/common/MySelect/MultipleRowSelect')
|
||||||
@ -34,10 +37,25 @@ type SelectProps = {
|
|||||||
|
|
||||||
const Reference = ({ item, nodeId }: RenderInputProps) => {
|
const Reference = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const onSelect = useCallback(
|
const onSelect = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
|
const workflowStartNode = nodeList.find(
|
||||||
|
(node) => node.flowNodeType === FlowNodeTypeEnum.workflowStart
|
||||||
|
);
|
||||||
|
if (e[0] === workflowStartNode?.id && e[1] !== NodeOutputKeyEnum.userChatInput) {
|
||||||
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: item.key,
|
||||||
|
value: {
|
||||||
|
...item,
|
||||||
|
value: [VARIABLE_NODE_ID, e[1]]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId,
|
nodeId,
|
||||||
type: 'updateInput',
|
type: 'updateInput',
|
||||||
@ -47,8 +65,9 @@ const Reference = ({ item, nodeId }: RenderInputProps) => {
|
|||||||
value: e
|
value: e
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[item, nodeId, onChangeNode]
|
[item, nodeId, nodeList, onChangeNode]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { referenceList, formatValue } = useReference({
|
const { referenceList, formatValue } = useReference({
|
||||||
@ -79,13 +98,15 @@ export const useReference = ({
|
|||||||
value?: any;
|
value?: any;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeList, edges } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
const referenceList = useMemo(() => {
|
const referenceList = useMemo(() => {
|
||||||
const sourceNodes = computedNodeInputReference({
|
const sourceNodes = computedNodeInputReference({
|
||||||
nodeId,
|
nodeId,
|
||||||
nodes: nodeList,
|
nodes: nodeList,
|
||||||
edges: edges
|
edges: edges,
|
||||||
|
t
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!sourceNodes) return [];
|
if (!sourceNodes) return [];
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
|
||||||
const SelectRender = ({ item, nodeId }: RenderInputProps) => {
|
const SelectRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
|
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
import { SelectAppItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import SelectAppModal from '../../../../SelectAppModal';
|
import SelectAppModal from '../../../../SelectAppModal';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SelectAppRender = ({ item, nodeId }: RenderInputProps) => {
|
const SelectAppRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { filterAppIds, onChangeNode } = useFlowProviderStore();
|
const filterAppIds = useContextSelector(WorkflowContext, (ctx) => ctx.filterAppIds);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenSelectApp,
|
isOpen: isOpenSelectApp,
|
||||||
@ -20,7 +22,7 @@ const SelectAppRender = ({ item, nodeId }: RenderInputProps) => {
|
|||||||
|
|
||||||
const value = item.value as SelectAppItemType | undefined;
|
const value = item.value as SelectAppItemType | undefined;
|
||||||
|
|
||||||
const filterAppString = useMemo(() => filterAppIds.join(','), [filterAppIds]);
|
const filterAppString = useMemo(() => filterAppIds?.join(',') || '', [filterAppIds]);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import { Box, Button, Flex, Grid, useDisclosure, useTheme } from '@chakra-ui/react';
|
import { Box, Button, Flex, Grid, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||||
import { SelectedDatasetType } from '@fastgpt/global/core/workflow/api';
|
import { SelectedDatasetType } from '@fastgpt/global/core/workflow/api';
|
||||||
@ -8,19 +7,19 @@ import Avatar from '@/components/Avatar';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
||||||
|
|
||||||
const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const [data, setData] = useState({
|
const [data, setData] = useState({
|
||||||
searchMode: DatasetSearchModeEnum.embedding,
|
searchMode: DatasetSearchModeEnum.embedding,
|
||||||
limit: 5,
|
limit: 5,
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import { Box, Button, Flex, useDisclosure } from '@chakra-ui/react';
|
import { Box, Button, Flex, useDisclosure } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
@ -10,9 +9,13 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
|||||||
import DatasetParamsModal, { DatasetParamsProps } from '@/components/core/app/DatasetParamsModal';
|
import DatasetParamsModal, { DatasetParamsProps } from '@/components/core/app/DatasetParamsModal';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import SearchParamsTip from '@/components/core/dataset/SearchParamsTip';
|
import SearchParamsTip from '@/components/core/dataset/SearchParamsTip';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SelectDatasetParam = ({ inputs = [], nodeId }: RenderInputProps) => {
|
const SelectDatasetParam = ({ inputs = [], nodeId }: RenderInputProps) => {
|
||||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { llmModelList } = useSystemStore();
|
const { llmModelList } = useSystemStore();
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,12 @@ import type { RenderInputProps } from '../type';
|
|||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import { llmModelTypeFilterMap } from '@fastgpt/global/core/ai/constants';
|
import { llmModelTypeFilterMap } from '@fastgpt/global/core/ai/constants';
|
||||||
import AIModelSelector from '@/components/Select/AIModelSelector';
|
import AIModelSelector from '@/components/Select/AIModelSelector';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => {
|
const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { llmModelList } = useSystemStore();
|
const { llmModelList } = useSystemStore();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const modelList = useMemo(
|
const modelList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import type { SettingAIDataType } from '@fastgpt/global/core/app/type.d';
|
import type { SettingAIDataType } from '@fastgpt/global/core/app/type.d';
|
||||||
import SettingLLMModel from '@/components/core/ai/SettingLLMModel';
|
import SettingLLMModel from '@/components/core/ai/SettingLLMModel';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SelectAiModelRender = ({ item, inputs = [], nodeId }: RenderInputProps) => {
|
const SelectAiModelRender = ({ item, inputs = [], nodeId }: RenderInputProps) => {
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const onChangeModel = useCallback(
|
const onChangeModel = useCallback(
|
||||||
(e: SettingAIDataType) => {
|
(e: SettingAIDataType) => {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { Box, BoxProps, Button, Flex, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
import { Box, BoxProps, Button, Flex, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { PromptTemplateItem } from '@fastgpt/global/core/ai/type';
|
import { PromptTemplateItem } from '@fastgpt/global/core/ai/type';
|
||||||
@ -25,6 +24,10 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
|||||||
import Reference from './Reference';
|
import Reference from './Reference';
|
||||||
import { getSystemVariables } from '@/web/core/app/utils';
|
import { getSystemVariables } from '@/web/core/app/utils';
|
||||||
import ValueTypeLabel from '../../ValueTypeLabel';
|
import ValueTypeLabel from '../../ValueTypeLabel';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
|
import { useCreation } from 'ahooks';
|
||||||
|
|
||||||
const LabelStyles: BoxProps = {
|
const LabelStyles: BoxProps = {
|
||||||
fontSize: ['sm', 'md']
|
fontSize: ['sm', 'md']
|
||||||
@ -38,7 +41,9 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
|
|||||||
const { inputs = [], nodeId } = props;
|
const { inputs = [], nodeId } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
const { watch, setValue, handleSubmit } = useForm({
|
const { watch, setValue, handleSubmit } = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
quoteTemplate: inputs.find((input) => input.key === 'quoteTemplate')?.value || '',
|
quoteTemplate: inputs.find((input) => input.key === 'quoteTemplate')?.value || '',
|
||||||
@ -48,14 +53,10 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
|
|||||||
const aiChatQuoteTemplate = watch('quoteTemplate');
|
const aiChatQuoteTemplate = watch('quoteTemplate');
|
||||||
const aiChatQuotePrompt = watch('quotePrompt');
|
const aiChatQuotePrompt = watch('quotePrompt');
|
||||||
|
|
||||||
const variables = useMemo(() => {
|
const variables = useCreation(() => {
|
||||||
const globalVariables = formatEditorVariablePickerIcon(
|
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
|
||||||
);
|
|
||||||
|
|
||||||
const systemVariables = getSystemVariables(t);
|
return globalVariables;
|
||||||
|
|
||||||
return [...globalVariables, ...systemVariables];
|
|
||||||
}, [nodeList, t]);
|
}, [nodeList, t]);
|
||||||
|
|
||||||
const [selectTemplateData, setSelectTemplateData] = useState<{
|
const [selectTemplateData, setSelectTemplateData] = useState<{
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import MySlider from '@/components/Slider';
|
import MySlider from '@/components/Slider';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SliderRender = ({ item, nodeId }: RenderInputProps) => {
|
const SliderRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { Switch } from '@chakra-ui/react';
|
import { Switch } from '@chakra-ui/react';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const SwitchRender = ({ item, nodeId }: RenderInputProps) => {
|
const SwitchRender = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { Input } from '@chakra-ui/react';
|
import { Input } from '@chakra-ui/react';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const TextInput = ({ item, nodeId }: RenderInputProps) => {
|
const TextInput = ({ item, nodeId }: RenderInputProps) => {
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,24 +1,22 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||||
import {
|
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
|
||||||
formatEditorVariablePickerIcon,
|
import { useContextSelector } from 'use-context-selector';
|
||||||
getGuideModule,
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
splitGuideModule
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
} from '@fastgpt/global/core/workflow/utils';
|
import { useCreation } from 'ahooks';
|
||||||
import { getSystemVariables } from '@/web/core/app/utils';
|
|
||||||
|
|
||||||
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
// get variable
|
// get variable
|
||||||
const variables = useMemo(() => {
|
const variables = useCreation(() => {
|
||||||
const globalVariables = formatEditorVariablePickerIcon(
|
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
|
||||||
);
|
|
||||||
const moduleVariables = formatEditorVariablePickerIcon(
|
const moduleVariables = formatEditorVariablePickerIcon(
|
||||||
inputs
|
inputs
|
||||||
.filter((input) => input.canEdit)
|
.filter((input) => input.canEdit)
|
||||||
@ -28,9 +26,7 @@ const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
const systemVariables = getSystemVariables(t);
|
return [...globalVariables, ...moduleVariables];
|
||||||
|
|
||||||
return [...globalVariables, ...moduleVariables, ...systemVariables];
|
|
||||||
}, [nodeList, inputs, t]);
|
}, [nodeList, inputs, t]);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
|
|||||||
@ -11,7 +11,8 @@ import VariableTable from '../VariableTable';
|
|||||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const RenderList: {
|
const RenderList: {
|
||||||
types: `${FlowNodeOutputTypeEnum}`[];
|
types: `${FlowNodeOutputTypeEnum}`[];
|
||||||
@ -26,7 +27,7 @@ const RenderOutput = ({
|
|||||||
flowOutputList: FlowNodeOutputItemType[];
|
flowOutputList: FlowNodeOutputItemType[];
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const outputString = useMemo(() => JSON.stringify(flowOutputList), [flowOutputList]);
|
const outputString = useMemo(() => JSON.stringify(flowOutputList), [flowOutputList]);
|
||||||
const copyOutputs = useMemo(() => {
|
const copyOutputs = useMemo(() => {
|
||||||
|
|||||||
@ -17,8 +17,9 @@ import { defaultEditFormData } from './constants';
|
|||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
|
||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const EditFieldModal = ({
|
const EditFieldModal = ({
|
||||||
defaultValue = defaultEditFormData,
|
defaultValue = defaultEditFormData,
|
||||||
@ -27,7 +28,7 @@ const EditFieldModal = ({
|
|||||||
}: EditFieldModalProps) => {
|
}: EditFieldModalProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const { register, setValue, handleSubmit, watch } = useForm<FlowNodeInputItemType>({
|
const { register, setValue, handleSubmit, watch } = useForm<FlowNodeInputItemType>({
|
||||||
defaultValues: defaultValue
|
defaultValues: defaultValue
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import type {
|
import type {
|
||||||
FlowNodeInputItemType,
|
FlowNodeInputItemType,
|
||||||
FlowNodeOutputItemType
|
FlowNodeOutputItemType
|
||||||
@ -19,7 +19,8 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { defaultEditFormData } from './constants';
|
import { defaultEditFormData } from './constants';
|
||||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
const EditFieldModal = dynamic(() => import('./EditFieldModal'));
|
const EditFieldModal = dynamic(() => import('./EditFieldModal'));
|
||||||
|
|
||||||
const RenderToolInput = ({
|
const RenderToolInput = ({
|
||||||
@ -32,8 +33,9 @@ const RenderToolInput = ({
|
|||||||
canEdit?: boolean;
|
canEdit?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { onChangeNode } = useFlowProviderStore();
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const [editField, setEditField] = React.useState<FlowNodeInputItemType>();
|
|
||||||
|
const [editField, setEditField] = useState<FlowNodeInputItemType>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -1,58 +1,89 @@
|
|||||||
import {
|
|
||||||
type Node,
|
|
||||||
type NodeChange,
|
|
||||||
type Edge,
|
|
||||||
type EdgeChange,
|
|
||||||
useNodesState,
|
|
||||||
useEdgesState,
|
|
||||||
OnConnectStartParams
|
|
||||||
} from 'reactflow';
|
|
||||||
import type {
|
|
||||||
FlowNodeItemType,
|
|
||||||
FlowNodeTemplateType
|
|
||||||
} from '@fastgpt/global/core/workflow/type/index.d';
|
|
||||||
import type { FlowNodeChangeProps } from '@fastgpt/global/core/workflow/type/fe.d';
|
|
||||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
|
||||||
import React, {
|
|
||||||
type SetStateAction,
|
|
||||||
type Dispatch,
|
|
||||||
useContext,
|
|
||||||
useCallback,
|
|
||||||
createContext,
|
|
||||||
useRef,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
useEffect
|
|
||||||
} from 'react';
|
|
||||||
import { storeEdgesRenderEdge, storeNode2FlowNode } from '@/web/core/workflow/utils';
|
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
|
||||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
|
||||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
|
||||||
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
|
||||||
import { defaultRunningStatus } from '../constants';
|
|
||||||
import { postWorkflowDebug } from '@/web/core/workflow/api';
|
import { postWorkflowDebug } from '@/web/core/workflow/api';
|
||||||
|
import { storeEdgesRenderEdge, storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
import {
|
||||||
|
FlowNodeItemType,
|
||||||
|
FlowNodeTemplateType,
|
||||||
|
StoreNodeItemType
|
||||||
|
} from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
|
import { FlowNodeChangeProps } from '@fastgpt/global/core/workflow/type/fe';
|
||||||
|
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
import { useCreation, useMemoizedFn } from 'ahooks';
|
||||||
|
import React, {
|
||||||
|
Dispatch,
|
||||||
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
|
import {
|
||||||
|
Edge,
|
||||||
|
EdgeChange,
|
||||||
|
Node,
|
||||||
|
NodeChange,
|
||||||
|
OnConnectStartParams,
|
||||||
|
useEdgesState,
|
||||||
|
useNodesState
|
||||||
|
} from 'reactflow';
|
||||||
|
import { createContext } from 'use-context-selector';
|
||||||
|
import { defaultRunningStatus } from './constants';
|
||||||
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
||||||
import { delay } from '@fastgpt/global/common/system/utils';
|
|
||||||
|
|
||||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||||
|
|
||||||
export type useFlowProviderStoreType = {
|
type WorkflowContextType = {
|
||||||
// connect
|
|
||||||
connectingEdge: OnConnectStartParams | undefined;
|
|
||||||
setConnectingEdge: React.Dispatch<React.SetStateAction<OnConnectStartParams | undefined>>;
|
|
||||||
// nodes
|
|
||||||
basicNodeTemplates: FlowNodeTemplateType[];
|
|
||||||
reactFlowWrapper: null | React.RefObject<HTMLDivElement>;
|
|
||||||
mode: 'app' | 'plugin';
|
mode: 'app' | 'plugin';
|
||||||
filterAppIds: string[];
|
basicNodeTemplates: FlowNodeTemplateType[];
|
||||||
|
filterAppIds?: string[];
|
||||||
|
reactFlowWrapper: React.RefObject<HTMLDivElement> | null;
|
||||||
|
|
||||||
|
// nodes
|
||||||
nodes: Node<FlowNodeItemType, string | undefined>[];
|
nodes: Node<FlowNodeItemType, string | undefined>[];
|
||||||
nodeList: FlowNodeItemType[];
|
nodeList: FlowNodeItemType[];
|
||||||
setNodes: Dispatch<SetStateAction<Node<FlowNodeItemType, string | undefined>[]>>;
|
setNodes: Dispatch<SetStateAction<Node<FlowNodeItemType, string | undefined>[]>>;
|
||||||
onNodesChange: OnChange<NodeChange>;
|
onNodesChange: OnChange<NodeChange>;
|
||||||
|
hasToolNode: boolean;
|
||||||
|
hoverNodeId?: string;
|
||||||
|
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||||
|
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||||
|
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void;
|
||||||
|
onChangeNode: (e: FlowNodeChangeProps) => void;
|
||||||
|
|
||||||
|
// edges
|
||||||
|
edges: Edge<any>[];
|
||||||
|
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||||
|
onEdgesChange: OnChange<EdgeChange>;
|
||||||
|
onDelEdge: (e: {
|
||||||
|
nodeId: string;
|
||||||
|
sourceHandle?: string | undefined;
|
||||||
|
targetHandle?: string | undefined;
|
||||||
|
}) => void;
|
||||||
|
|
||||||
|
// connect
|
||||||
|
connectingEdge?: OnConnectStartParams;
|
||||||
|
setConnectingEdge: React.Dispatch<React.SetStateAction<OnConnectStartParams | undefined>>;
|
||||||
|
|
||||||
|
// common function
|
||||||
|
onFixView: () => void;
|
||||||
|
splitToolInputs: (
|
||||||
|
inputs: FlowNodeInputItemType[],
|
||||||
|
nodeId: string
|
||||||
|
) => {
|
||||||
|
isTool: boolean;
|
||||||
|
toolInputs: FlowNodeInputItemType[];
|
||||||
|
commonInputs: FlowNodeInputItemType[];
|
||||||
|
};
|
||||||
|
initData: (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => Promise<void>;
|
||||||
|
|
||||||
|
// debug
|
||||||
// debug
|
// debug
|
||||||
workflowDebugData:
|
workflowDebugData:
|
||||||
| {
|
| {
|
||||||
@ -72,67 +103,66 @@ export type useFlowProviderStoreType = {
|
|||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
onStopNodeDebug: () => void;
|
onStopNodeDebug: () => void;
|
||||||
|
|
||||||
edges: Edge<any>[];
|
|
||||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
|
||||||
onEdgesChange: OnChange<EdgeChange>;
|
|
||||||
onFixView: () => void;
|
|
||||||
onChangeNode: (e: FlowNodeChangeProps) => void;
|
|
||||||
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void;
|
|
||||||
onDelEdge: (e: {
|
|
||||||
nodeId: string;
|
|
||||||
sourceHandle?: string | undefined;
|
|
||||||
targetHandle?: string | undefined;
|
|
||||||
}) => void;
|
|
||||||
initData: (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => Promise<void>;
|
|
||||||
splitToolInputs: (
|
|
||||||
inputs: FlowNodeInputItemType[],
|
|
||||||
nodeId: string
|
|
||||||
) => {
|
|
||||||
isTool: boolean;
|
|
||||||
toolInputs: FlowNodeInputItemType[];
|
|
||||||
commonInputs: FlowNodeInputItemType[];
|
|
||||||
};
|
|
||||||
hasToolNode: boolean;
|
|
||||||
hoverNodeId: string | undefined;
|
|
||||||
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
||||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const StateContext = createContext<useFlowProviderStoreType>({
|
type ContextValueProps = Pick<
|
||||||
reactFlowWrapper: null,
|
WorkflowContextType,
|
||||||
|
'mode' | 'basicNodeTemplates' | 'filterAppIds'
|
||||||
|
> & {
|
||||||
|
appId?: string;
|
||||||
|
pluginId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DebugDataType = {
|
||||||
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
|
nextRunNodes: RuntimeNodeItemType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WorkflowContext = createContext<WorkflowContextType>({
|
||||||
mode: 'app',
|
mode: 'app',
|
||||||
filterAppIds: [],
|
setConnectingEdge: function (
|
||||||
|
value: React.SetStateAction<OnConnectStartParams | undefined>
|
||||||
|
): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
onFixView: function (): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
basicNodeTemplates: [],
|
||||||
|
reactFlowWrapper: null,
|
||||||
nodes: [],
|
nodes: [],
|
||||||
|
nodeList: [],
|
||||||
setNodes: function (
|
setNodes: function (
|
||||||
value: React.SetStateAction<Node<FlowNodeItemType, string | undefined>[]>
|
value: React.SetStateAction<Node<FlowNodeItemType, string | undefined>[]>
|
||||||
): void {
|
): void {
|
||||||
return;
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onNodesChange: function (changes: NodeChange[]): void {
|
onNodesChange: function (changes: NodeChange[]): void {
|
||||||
return;
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
hasToolNode: false,
|
||||||
|
setHoverNodeId: function (value: React.SetStateAction<string | undefined>): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
onUpdateNodeError: function (node: string, isError: Boolean): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
edges: [],
|
edges: [],
|
||||||
setEdges: function (value: React.SetStateAction<Edge<any>[]>): void {
|
setEdges: function (value: React.SetStateAction<Edge<any>[]>): void {
|
||||||
return;
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onEdgesChange: function (changes: EdgeChange[]): void {
|
onEdgesChange: function (changes: EdgeChange[]): void {
|
||||||
return;
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onFixView: function (): void {
|
onResetNode: function (e: { id: string; module: FlowNodeTemplateType }): void {
|
||||||
return;
|
throw new Error('Function not implemented.');
|
||||||
},
|
|
||||||
onChangeNode: function (e: FlowNodeChangeProps): void {
|
|
||||||
return;
|
|
||||||
},
|
},
|
||||||
onDelEdge: function (e: {
|
onDelEdge: function (e: {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
sourceHandle?: string | undefined;
|
sourceHandle?: string | undefined;
|
||||||
targetHandle?: string | undefined;
|
targetHandle?: string | undefined;
|
||||||
}): void {
|
}): void {
|
||||||
return;
|
|
||||||
},
|
|
||||||
onResetNode: function (e): void {
|
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
splitToolInputs: function (
|
splitToolInputs: function (
|
||||||
@ -145,23 +175,12 @@ const StateContext = createContext<useFlowProviderStoreType>({
|
|||||||
} {
|
} {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
hasToolNode: false,
|
|
||||||
connectingEdge: undefined,
|
|
||||||
basicNodeTemplates: [],
|
|
||||||
initData: function (e: {
|
initData: function (e: {
|
||||||
nodes: StoreNodeItemType[];
|
nodes: StoreNodeItemType[];
|
||||||
edges: StoreEdgeItemType[];
|
edges: StoreEdgeItemType[];
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
hoverNodeId: undefined,
|
|
||||||
setHoverNodeId: function (value: React.SetStateAction<string | undefined>): void {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
},
|
|
||||||
onUpdateNodeError: function (nodeId: string, isError: Boolean): void {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
},
|
|
||||||
nodeList: [],
|
|
||||||
workflowDebugData: undefined,
|
workflowDebugData: undefined,
|
||||||
onNextNodeDebug: function (): Promise<void> {
|
onNextNodeDebug: function (): Promise<void> {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
@ -180,55 +199,24 @@ const StateContext = createContext<useFlowProviderStoreType>({
|
|||||||
onStopNodeDebug: function (): void {
|
onStopNodeDebug: function (): void {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
setConnectingEdge: function (
|
onChangeNode: function (e: FlowNodeChangeProps): void {
|
||||||
value: React.SetStateAction<OnConnectStartParams | undefined>
|
|
||||||
): void {
|
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
export const useFlowProviderStore = () => useContext(StateContext);
|
|
||||||
|
|
||||||
export const FlowProvider = ({
|
const WorkflowContextProvider = ({
|
||||||
mode,
|
|
||||||
basicNodeTemplates = [],
|
|
||||||
filterAppIds = [],
|
|
||||||
children,
|
children,
|
||||||
appId,
|
value
|
||||||
pluginId
|
|
||||||
}: {
|
}: {
|
||||||
mode: useFlowProviderStoreType['mode'];
|
|
||||||
basicNodeTemplates: FlowNodeTemplateType[];
|
|
||||||
filterAppIds?: string[];
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
appId?: string;
|
value: ContextValueProps;
|
||||||
pluginId?: string;
|
|
||||||
}) => {
|
}) => {
|
||||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
const { appId, pluginId } = value;
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
||||||
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
|
||||||
const [connectingEdge, setConnectingEdge] = useState<OnConnectStartParams>();
|
|
||||||
|
|
||||||
const stringifyNodes = useMemo(() => JSON.stringify(nodes.map((node) => node.data)), [nodes]);
|
|
||||||
const nodeList = useMemo(
|
|
||||||
() => JSON.parse(stringifyNodes) as FlowNodeItemType[],
|
|
||||||
[stringifyNodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasToolNode = useMemo(() => {
|
|
||||||
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
|
||||||
}, [nodes]);
|
|
||||||
|
|
||||||
const onFixView = useCallback(() => {
|
|
||||||
const btn = document.querySelector('.custom-workflow-fix_view') as HTMLButtonElement;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
btn && btn.click();
|
|
||||||
}, 100);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/* edge */
|
/* edge */
|
||||||
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||||
const onDelEdge = useCallback(
|
const onDelEdge = useCallback(
|
||||||
({
|
({
|
||||||
nodeId,
|
nodeId,
|
||||||
@ -252,9 +240,34 @@ export const FlowProvider = ({
|
|||||||
[setEdges]
|
[setEdges]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* connect */
|
||||||
|
const [connectingEdge, setConnectingEdge] = useState<OnConnectStartParams>();
|
||||||
|
|
||||||
/* node */
|
/* node */
|
||||||
|
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
||||||
|
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
||||||
|
|
||||||
|
const nodeList = useCreation(() => nodes.map((node) => node.data), [nodes]);
|
||||||
|
|
||||||
|
const hasToolNode = useMemo(() => {
|
||||||
|
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
||||||
|
}, [nodes]);
|
||||||
|
|
||||||
|
const onUpdateNodeError = useMemoizedFn((nodeId: string, isError: Boolean) => {
|
||||||
|
setNodes((nodes) => {
|
||||||
|
return nodes.map((item) => {
|
||||||
|
if (item.data?.nodeId === nodeId) {
|
||||||
|
item.selected = true;
|
||||||
|
//@ts-ignore
|
||||||
|
item.data.isError = isError;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// reset a node data. delete edge and replace it
|
// reset a node data. delete edge and replace it
|
||||||
const onResetNode = useCallback(
|
const onResetNode = useMemoizedFn(
|
||||||
({ id, module }: { id: string; module: FlowNodeTemplateType }) => {
|
({ id, module }: { id: string; module: FlowNodeTemplateType }) => {
|
||||||
setNodes((state) =>
|
setNodes((state) =>
|
||||||
state.map((node) => {
|
state.map((node) => {
|
||||||
@ -277,11 +290,10 @@ export const FlowProvider = ({
|
|||||||
return node;
|
return node;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
[onDelEdge, setNodes]
|
|
||||||
);
|
);
|
||||||
const onChangeNode = useCallback(
|
|
||||||
(props: FlowNodeChangeProps) => {
|
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
|
||||||
const { nodeId, type } = props;
|
const { nodeId, type } = props;
|
||||||
setNodes((nodes) =>
|
setNodes((nodes) =>
|
||||||
nodes.map((node) => {
|
nodes.map((node) => {
|
||||||
@ -377,31 +389,43 @@ export const FlowProvider = ({
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
|
||||||
[onDelEdge, setNodes, toast]
|
|
||||||
);
|
|
||||||
const onUpdateNodeError = useCallback(
|
|
||||||
(nodeId: string, isError: Boolean) => {
|
|
||||||
setNodes((nodes) => {
|
|
||||||
return nodes.map((item) => {
|
|
||||||
if (item.data?.nodeId === nodeId) {
|
|
||||||
item.selected = true;
|
|
||||||
//@ts-ignore
|
|
||||||
item.data.isError = isError;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* function */
|
||||||
|
const onFixView = useMemoizedFn(() => {
|
||||||
|
const btn = document.querySelector('.custom-workflow-fix_view') as HTMLButtonElement;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
btn && btn.click();
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
[setNodes]
|
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
||||||
|
const splitToolInputs = useMemoizedFn((inputs: FlowNodeInputItemType[], nodeId: string) => {
|
||||||
|
const isTool = !!edges.find(
|
||||||
|
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Run workflow debug and get next runtime data */
|
return {
|
||||||
const [workflowDebugData, setWorkflowDebugData] = useState<{
|
isTool,
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
toolInputs: inputs.filter((item) => isTool && item.toolDescription),
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
commonInputs: inputs.filter((item) => {
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
if (!isTool) return true;
|
||||||
}>();
|
return !item.toolDescription;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const initData = useMemoizedFn(
|
||||||
|
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
||||||
|
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
||||||
|
|
||||||
|
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* debug */
|
||||||
|
const [workflowDebugData, setWorkflowDebugData] = useState<DebugDataType>();
|
||||||
const onNextNodeDebug = useCallback(
|
const onNextNodeDebug = useCallback(
|
||||||
async (debugData = workflowDebugData) => {
|
async (debugData = workflowDebugData) => {
|
||||||
if (!debugData) return;
|
if (!debugData) return;
|
||||||
@ -592,36 +616,6 @@ export const FlowProvider = ({
|
|||||||
[onNextNodeDebug, onStopNodeDebug]
|
[onNextNodeDebug, onStopNodeDebug]
|
||||||
);
|
);
|
||||||
|
|
||||||
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
|
||||||
const splitToolInputs = useCallback(
|
|
||||||
(inputs: FlowNodeInputItemType[], nodeId: string) => {
|
|
||||||
const isTool = !!edges.find(
|
|
||||||
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
isTool,
|
|
||||||
toolInputs: inputs.filter((item) => isTool && item.toolDescription),
|
|
||||||
commonInputs: inputs.filter((item) => {
|
|
||||||
if (!isTool) return true;
|
|
||||||
return !item.toolDescription;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[edges]
|
|
||||||
);
|
|
||||||
|
|
||||||
const initData = useCallback(
|
|
||||||
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
|
||||||
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
|
||||||
|
|
||||||
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
|
||||||
|
|
||||||
await delay(200);
|
|
||||||
},
|
|
||||||
[setEdges, setNodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
eventBus.on(EventNameEnum.requestWorkflowStore, () => {
|
eventBus.on(EventNameEnum.requestWorkflowStore, () => {
|
||||||
eventBus.emit(EventNameEnum.receiveWorkflowStore, {
|
eventBus.emit(EventNameEnum.receiveWorkflowStore, {
|
||||||
@ -633,43 +627,49 @@ export const FlowProvider = ({
|
|||||||
};
|
};
|
||||||
}, [nodes]);
|
}, [nodes]);
|
||||||
|
|
||||||
const value = {
|
return (
|
||||||
|
<WorkflowContext.Provider
|
||||||
|
value={{
|
||||||
reactFlowWrapper,
|
reactFlowWrapper,
|
||||||
mode,
|
...value,
|
||||||
filterAppIds,
|
// node
|
||||||
edges,
|
|
||||||
setEdges,
|
|
||||||
onEdgesChange,
|
|
||||||
// nodes
|
|
||||||
nodes,
|
nodes,
|
||||||
nodeList,
|
|
||||||
setNodes,
|
setNodes,
|
||||||
onNodesChange,
|
onNodesChange,
|
||||||
|
nodeList,
|
||||||
|
hasToolNode,
|
||||||
hoverNodeId,
|
hoverNodeId,
|
||||||
setHoverNodeId,
|
setHoverNodeId,
|
||||||
onUpdateNodeError,
|
onUpdateNodeError,
|
||||||
|
onResetNode,
|
||||||
|
onChangeNode,
|
||||||
|
|
||||||
|
// edge
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
onEdgesChange,
|
||||||
|
connectingEdge,
|
||||||
|
setConnectingEdge,
|
||||||
|
onDelEdge,
|
||||||
|
|
||||||
|
// function
|
||||||
|
onFixView,
|
||||||
|
splitToolInputs,
|
||||||
|
initData,
|
||||||
|
|
||||||
|
// debug
|
||||||
workflowDebugData,
|
workflowDebugData,
|
||||||
onNextNodeDebug,
|
onNextNodeDebug,
|
||||||
onStartNodeDebug,
|
onStartNodeDebug,
|
||||||
onStopNodeDebug,
|
onStopNodeDebug
|
||||||
|
}}
|
||||||
basicNodeTemplates,
|
>
|
||||||
// connect
|
{children}
|
||||||
connectingEdge,
|
</WorkflowContext.Provider>
|
||||||
setConnectingEdge,
|
);
|
||||||
onFixView,
|
|
||||||
onChangeNode,
|
|
||||||
onResetNode,
|
|
||||||
onDelEdge,
|
|
||||||
initData,
|
|
||||||
splitToolInputs,
|
|
||||||
hasToolNode
|
|
||||||
};
|
|
||||||
|
|
||||||
return <StateContext.Provider value={value}>{children}</StateContext.Provider>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(FlowProvider);
|
export default WorkflowContextProvider;
|
||||||
|
|
||||||
type GetWorkflowStoreResponse = {
|
type GetWorkflowStoreResponse = {
|
||||||
nodes: Node<FlowNodeItemType>[];
|
nodes: Node<FlowNodeItemType>[];
|
||||||
@ -108,7 +108,9 @@ const LafAccountModal = ({
|
|||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Link textDecoration={'underline'} href={`${feConfigs.lafEnv}/`} isExternal>
|
<Link textDecoration={'underline'} href={`${feConfigs.lafEnv}/`} isExternal>
|
||||||
{t('support.user.Go laf env', { env: feConfigs.lafEnv })}
|
{t('support.user.Go laf env', {
|
||||||
|
env: feConfigs.lafEnv?.split('//')[1]
|
||||||
|
})}
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { AppDetailType } from '@fastgpt/global/core/app/type.d';
|
import { AppDetailType } from '@fastgpt/global/core/app/type.d';
|
||||||
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
import type { FeishuType, OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
||||||
|
|
||||||
export const defaultApp: AppDetailType = {
|
export const defaultApp: AppDetailType = {
|
||||||
_id: '',
|
_id: '',
|
||||||
@ -28,6 +28,32 @@ export const defaultOutLinkForm: OutLinkEditType = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export const defaultWecomOutLinkForm: OutLinkConfigEditType = {
|
||||||
|
// name: '',
|
||||||
|
// wecomConfig: {
|
||||||
|
// ReplyLimit: false,
|
||||||
|
// defaultResponse: '',
|
||||||
|
// immediateResponse: false,
|
||||||
|
// WXWORK_TOKEN: '',
|
||||||
|
// WXWORK_AESKEY: '',
|
||||||
|
// WXWORK_SECRET: '',
|
||||||
|
// WXWORD_ID: ''
|
||||||
|
// },
|
||||||
|
// limit: {
|
||||||
|
// QPM: 100,
|
||||||
|
// maxUsagePoints: -1
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const defaultFeishuOutLinkForm: OutLinkEditType<FeishuType> = {
|
||||||
|
name: '',
|
||||||
|
limit: {
|
||||||
|
QPM: 100,
|
||||||
|
maxUsagePoints: -1
|
||||||
|
},
|
||||||
|
responseDetail: false
|
||||||
|
};
|
||||||
|
|
||||||
export enum TTSTypeEnum {
|
export enum TTSTypeEnum {
|
||||||
none = 'none',
|
none = 'none',
|
||||||
web = 'web',
|
web = 'web',
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { Box, Card, Flex, Select } from '@chakra-ui/react';
|
import { Box, Card, Flex } from '@chakra-ui/react';
|
||||||
import React, { useCallback, useRef } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { timezoneList } from '@fastgpt/global/common/time/timezone';
|
|
||||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||||
import { UserType } from '@fastgpt/global/support/user/type';
|
import { UserType } from '@fastgpt/global/support/user/type';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
|||||||
@ -28,10 +28,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
avatar: props.avatar,
|
avatar: props.avatar,
|
||||||
parentId: props.parentId,
|
parentId: props.parentId,
|
||||||
version: 'v2',
|
version: 'v2',
|
||||||
...(modules && {
|
...(modules?.length && {
|
||||||
modules: modules
|
modules: modules
|
||||||
}),
|
}),
|
||||||
...(edges && { edges }),
|
...(edges?.length && { edges }),
|
||||||
metadata: props.metadata
|
metadata: props.metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { request } from 'https';
|
import { request } from 'https';
|
||||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
|
||||||
import url from 'url';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
@ -25,7 +23,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
throw new Error('lafEnv is empty');
|
throw new Error('lafEnv is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedUrl = url.parse(lafEnv);
|
const parsedUrl = new URL(lafEnv);
|
||||||
delete req.headers?.cookie;
|
delete req.headers?.cookie;
|
||||||
delete req.headers?.host;
|
delete req.headers?.host;
|
||||||
delete req.headers?.origin;
|
delete req.headers?.origin;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
|||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { request } from 'http';
|
import { request } from 'http';
|
||||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||||
import url from 'url';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
@ -15,8 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
throw new Error('url is empty');
|
throw new Error('url is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedUrl = url.parse(FastGPTProUrl);
|
const parsedUrl = new URL(FastGPTProUrl);
|
||||||
|
|
||||||
delete req.headers?.rootkey;
|
delete req.headers?.rootkey;
|
||||||
|
|
||||||
const requestResult = request({
|
const requestResult = request({
|
||||||
@ -37,6 +35,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
response.statusCode && res.writeHead(response.statusCode);
|
response.statusCode && res.writeHead(response.statusCode);
|
||||||
response.pipe(res);
|
response.pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
requestResult.on('error', (e) => {
|
requestResult.on('error', (e) => {
|
||||||
res.send(e);
|
res.send(e);
|
||||||
res.end();
|
res.end();
|
||||||
|
|||||||
@ -5,16 +5,17 @@ import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
|
|||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
||||||
|
|
||||||
/* create a shareChat */
|
/* create a shareChat */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
const { appId, ...props } = req.body as OutLinkEditType & {
|
const { appId, ...props } = req.body as OutLinkEditType &
|
||||||
|
OutLinkEditType & {
|
||||||
appId: string;
|
appId: string;
|
||||||
type: `${OutLinkTypeEnum}`;
|
type: PublishChannelEnum;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { teamId, tmbId } = await authApp({ req, authToken: true, appId, per: 'w' });
|
const { teamId, tmbId } = await authApp({ req, authToken: true, appId, per: 'w' });
|
||||||
|
|||||||
@ -9,15 +9,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
try {
|
try {
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
const { appId } = req.query as {
|
const { appId, type } = req.query as {
|
||||||
appId: string;
|
appId: string;
|
||||||
|
type: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { teamId, tmbId, isOwner } = await authApp({ req, authToken: true, appId, per: 'w' });
|
const { teamId, tmbId, isOwner } = await authApp({ req, authToken: true, appId, per: 'w' });
|
||||||
|
|
||||||
const data = await MongoOutLink.find({
|
const data = await MongoOutLink.find({
|
||||||
appId,
|
appId,
|
||||||
...(isOwner ? { teamId } : { tmbId })
|
...(isOwner ? { teamId } : { tmbId }),
|
||||||
|
type: type
|
||||||
}).sort({
|
}).sort({
|
||||||
_id: -1
|
_id: -1
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,10 +9,6 @@ import dynamic from 'next/dynamic';
|
|||||||
|
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import ChatTest, { type ChatTestComponentRef } from '@/components/core/workflow/Flow/ChatTest';
|
import ChatTest, { type ChatTestComponentRef } from '@/components/core/workflow/Flow/ChatTest';
|
||||||
import {
|
|
||||||
getWorkflowStore,
|
|
||||||
useFlowProviderStore
|
|
||||||
} from '@/components/core/workflow/Flow/FlowProvider';
|
|
||||||
import { flowNode2StoreNodes } from '@/components/core/workflow/utils';
|
import { flowNode2StoreNodes } from '@/components/core/workflow/utils';
|
||||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
@ -28,6 +24,8 @@ import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
|
|||||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { formatTime2HM } from '@fastgpt/global/common/string/time';
|
import { formatTime2HM } from '@fastgpt/global/common/string/time';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
||||||
|
|
||||||
@ -59,9 +57,11 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
|||||||
});
|
});
|
||||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||||
const { publishApp, updateAppDetail } = useAppStore();
|
const { publishApp, updateAppDetail } = useAppStore();
|
||||||
const { edges, onUpdateNodeError } = useFlowProviderStore();
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [saveLabel, setSaveLabel] = useState(t('core.app.Onclick to save'));
|
const [saveLabel, setSaveLabel] = useState(t('core.app.Onclick to save'));
|
||||||
|
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||||
|
|
||||||
const flowData2StoreDataAndCheck = useCallback(async () => {
|
const flowData2StoreDataAndCheck = useCallback(async () => {
|
||||||
const { nodes } = await getWorkflowStore();
|
const { nodes } = await getWorkflowStore();
|
||||||
@ -101,13 +101,13 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
|||||||
time: formatTime2HM()
|
time: formatTime2HM()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ChatTestRef.current?.resetChatTest();
|
// ChatTestRef.current?.resetChatTest();
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}, [updateAppDetail, app._id, edges, ChatTestRef, t]);
|
}, [updateAppDetail, app._id, edges, t]);
|
||||||
|
|
||||||
const onclickPublish = useCallback(async () => {
|
const onclickPublish = useCallback(async () => {
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
|
|||||||
@ -2,10 +2,11 @@ import React, { useEffect, useMemo } from 'react';
|
|||||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import Flow from '@/components/core/workflow/Flow';
|
import Flow from '@/components/core/workflow/Flow';
|
||||||
import FlowProvider, { useFlowProviderStore } from '@/components/core/workflow/Flow/FlowProvider';
|
|
||||||
import { appSystemModuleTemplates } from '@fastgpt/global/core/workflow/template/constants';
|
import { appSystemModuleTemplates } from '@fastgpt/global/core/workflow/template/constants';
|
||||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||||
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
||||||
|
import WorkflowContextProvider, { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
|
||||||
type Props = { app: AppSchema; onClose: () => void };
|
type Props = { app: AppSchema; onClose: () => void };
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ const Render = ({ app, onClose }: Props) => {
|
|||||||
'检测到您的高级编排为旧版,系统将为您自动格式化成新版工作流。\n\n由于版本差异较大,会导致许多工作流无法正常排布,请重新手动连接工作流。如仍异常,可尝试删除对应节点后重新添加。\n\n你可以直接点击测试进行调试,无需点击保存,点击保存为新版工作流。'
|
'检测到您的高级编排为旧版,系统将为您自动格式化成新版工作流。\n\n由于版本差异较大,会导致许多工作流无法正常排布,请重新手动连接工作流。如仍异常,可尝试删除对应节点后重新添加。\n\n你可以直接点击测试进行调试,无需点击保存,点击保存为新版工作流。'
|
||||||
});
|
});
|
||||||
|
|
||||||
const { initData } = useFlowProviderStore();
|
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||||
|
|
||||||
const workflowStringData = JSON.stringify({
|
const workflowStringData = JSON.stringify({
|
||||||
nodes: app.modules || [],
|
nodes: app.modules || [],
|
||||||
@ -53,13 +54,15 @@ export default React.memo(function FlowEdit(props: Props) {
|
|||||||
const filterAppIds = useMemo(() => [props.app._id], [props.app._id]);
|
const filterAppIds = useMemo(() => [props.app._id], [props.app._id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlowProvider
|
<WorkflowContextProvider
|
||||||
appId={props.app._id}
|
value={{
|
||||||
mode={'app'}
|
appId: props.app._id,
|
||||||
filterAppIds={filterAppIds}
|
mode: 'app',
|
||||||
basicNodeTemplates={appSystemModuleTemplates}
|
filterAppIds,
|
||||||
|
basicNodeTemplates: appSystemModuleTemplates
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Render {...props} />
|
<Render {...props} />
|
||||||
</FlowProvider>
|
</WorkflowContextProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Box, useTheme } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
|
|
||||||
import MyRadio from '@/components/common/MyRadio';
|
|
||||||
import Share from './Share';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
const API = dynamic(() => import('./API'));
|
|
||||||
|
|
||||||
const OutLink = ({ appId }: { appId: string }) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const [linkType, setLinkType] = useState<`${OutLinkTypeEnum}`>(OutLinkTypeEnum.share);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box pt={[1, 5]}>
|
|
||||||
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2} px={[4, 8]}>
|
|
||||||
{t('core.app.navbar.Publish app')}
|
|
||||||
</Box>
|
|
||||||
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
|
||||||
<MyRadio
|
|
||||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(auto-fill, minmax(0, 400px))']}
|
|
||||||
iconSize={'20px'}
|
|
||||||
list={[
|
|
||||||
{
|
|
||||||
icon: '/imgs/modal/shareFill.svg',
|
|
||||||
title: t('core.app.Share link'),
|
|
||||||
desc: t('core.app.Share link desc'),
|
|
||||||
value: OutLinkTypeEnum.share
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'support/outlink/apikeyFill',
|
|
||||||
title: t('core.app.Api request'),
|
|
||||||
desc: t('core.app.Api request desc'),
|
|
||||||
value: OutLinkTypeEnum.apikey
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
// icon: 'support/outlink/iframeLight',
|
|
||||||
// title: '网页嵌入',
|
|
||||||
// desc: '嵌入到已有网页中,右下角会生成对话按键',
|
|
||||||
// value: OutLinkTypeEnum.iframe
|
|
||||||
// }
|
|
||||||
]}
|
|
||||||
value={linkType}
|
|
||||||
onChange={(e) => setLinkType(e as `${OutLinkTypeEnum}`)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{linkType === OutLinkTypeEnum.share && <Share appId={appId} />}
|
|
||||||
{linkType === OutLinkTypeEnum.apikey && <API appId={appId} />}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default OutLink;
|
|
||||||
@ -0,0 +1,211 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { Flex, Box, Button, ModalFooter, ModalBody, Input } from '@chakra-ui/react';
|
||||||
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
|
import type { FeishuType, OutLinkEditType } from '@fastgpt/global/support/outLink/type';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
|
||||||
|
|
||||||
|
const FeiShuEditModal = ({
|
||||||
|
appId,
|
||||||
|
defaultData,
|
||||||
|
onClose,
|
||||||
|
onCreate,
|
||||||
|
onEdit
|
||||||
|
}: {
|
||||||
|
appId: string;
|
||||||
|
defaultData: OutLinkEditType<FeishuType>;
|
||||||
|
onClose: () => void;
|
||||||
|
onCreate: (id: string) => void;
|
||||||
|
onEdit: () => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
setValue,
|
||||||
|
handleSubmit: submitShareChat
|
||||||
|
} = useForm({
|
||||||
|
defaultValues: defaultData
|
||||||
|
});
|
||||||
|
|
||||||
|
const isEdit = useMemo(() => !!defaultData?._id, [defaultData]);
|
||||||
|
|
||||||
|
const { mutate: onclickCreate, isLoading: creating } = useRequest({
|
||||||
|
mutationFn: async (e: OutLinkEditType<FeishuType>) => {
|
||||||
|
createShareChat({
|
||||||
|
...e,
|
||||||
|
appId,
|
||||||
|
type: PublishChannelEnum.feishu
|
||||||
|
});
|
||||||
|
},
|
||||||
|
errorToast: t('common.Create Failed'),
|
||||||
|
onSuccess: onCreate
|
||||||
|
});
|
||||||
|
const { mutate: onclickUpdate, isLoading: updating } = useRequest({
|
||||||
|
mutationFn: (e: OutLinkEditType<FeishuType>) => {
|
||||||
|
return updateShareChat(e);
|
||||||
|
},
|
||||||
|
errorToast: t('common.Update Failed'),
|
||||||
|
onSuccess: onEdit
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyModal
|
||||||
|
isOpen={true}
|
||||||
|
iconSrc="/imgs/modal/shareFill.svg"
|
||||||
|
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
|
||||||
|
>
|
||||||
|
<ModalBody>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 90px'}>{t('Name')}</Box>
|
||||||
|
<Input
|
||||||
|
placeholder={t('outlink.Feishu name') || 'Link Name'} // TODO: i18n
|
||||||
|
maxLength={20}
|
||||||
|
{...register('name', {
|
||||||
|
required: t('common.Name is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
QPM
|
||||||
|
<MyTooltip label={t('outlink.QPM Tips' || '')}>
|
||||||
|
<QuestionOutlineIcon ml={1} />
|
||||||
|
</MyTooltip>
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
max={1000}
|
||||||
|
{...register('limit.QPM', {
|
||||||
|
min: 0,
|
||||||
|
max: 1000,
|
||||||
|
valueAsNumber: true,
|
||||||
|
required: t('outlink.QPM is empty') || ''
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
{t('support.outlink.Max usage points')}
|
||||||
|
<MyTooltip label={t('support.outlink.Max usage points tip')}>
|
||||||
|
<QuestionOutlineIcon ml={1} />
|
||||||
|
</MyTooltip>
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
{...register('limit.maxUsagePoints', {
|
||||||
|
min: -1,
|
||||||
|
max: 10000000,
|
||||||
|
valueAsNumber: true,
|
||||||
|
required: true
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
{t('common.Expired Time')}
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
type="datetime-local"
|
||||||
|
defaultValue={
|
||||||
|
defaultData.limit?.expiredTime
|
||||||
|
? dayjs(defaultData.limit?.expiredTime).format('YYYY-MM-DDTHH:mm')
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
onChange={(e) => {
|
||||||
|
setValue('limit.expiredTime', new Date(e.target.value));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
默认回复
|
||||||
|
{/* TODO: i18n */}
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
placeholder={t('outlink.Default Response') || 'Link Name'}
|
||||||
|
maxLength={20}
|
||||||
|
{...register('defaultResponse', {
|
||||||
|
required: t('common.default Response is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
立即回复
|
||||||
|
{/* TODO: i18n */}
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
placeholder={t('outlink.Default Response') || 'Link Name'}
|
||||||
|
maxLength={20}
|
||||||
|
{...register('immediateResponse', {
|
||||||
|
required: t('common.default Response is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Box flex={'0 0 90px'}>{t('core.module.http.AppId')}</Box>
|
||||||
|
<Input
|
||||||
|
placeholder={t('core.module.http.appId') || 'Link Name'}
|
||||||
|
// maxLength={20}
|
||||||
|
{...register('app.appId', {
|
||||||
|
required: t('common.Name is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Box flex={'0 0 90px'}>{t('core.module.http.AppSecret')}</Box>
|
||||||
|
<Input
|
||||||
|
placeholder={t('outlink.AppSecret') || 'Link Name'}
|
||||||
|
// maxLength={20}
|
||||||
|
{...register('app.appSecret', {
|
||||||
|
required: t('common.Name is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Box flex={'0 0 90px'}>Encrypt Key</Box>
|
||||||
|
<Input
|
||||||
|
placeholder="Encrypt Key"
|
||||||
|
// maxLength={20}
|
||||||
|
{...register('app.encryptKey', {
|
||||||
|
required: t('common.Name is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Box flex={'0 0 90px'}>Verification Token</Box>
|
||||||
|
<Input
|
||||||
|
placeholder="Verification Token"
|
||||||
|
// maxLength={20}
|
||||||
|
{...register('app.verificationToken', {
|
||||||
|
required: t('common.Name is empty') || 'Name is empty'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
{/* <Flex alignItems={'center'} mt={4}> */}
|
||||||
|
{/* <Flex flex={'0 0 90px'} alignItems={'center'}> */}
|
||||||
|
{/* 限制回复 */}
|
||||||
|
{/* </Flex> */}
|
||||||
|
{/* <Switch {...register('wecomConfig.ReplyLimit')} size={'lg'} /> */}
|
||||||
|
{/* </Flex> */}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
|
||||||
|
{t('common.Close')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
isLoading={creating || updating}
|
||||||
|
onClick={submitShareChat((data) => (isEdit ? onclickUpdate(data) : onclickCreate(data)))}
|
||||||
|
>
|
||||||
|
{t('common.Confirm')}
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</MyModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FeiShuEditModal;
|
||||||
@ -0,0 +1,193 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Flex,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
TableContainer,
|
||||||
|
Table,
|
||||||
|
Thead,
|
||||||
|
Tr,
|
||||||
|
Th,
|
||||||
|
Td,
|
||||||
|
Tbody
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { getShareChatList, delShareChatById } from '@/web/support/outLink/api';
|
||||||
|
import { formatTimeToChatTime } from '@/utils/tools';
|
||||||
|
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||||
|
import { defaultFeishuOutLinkForm } from '@/constants/app';
|
||||||
|
import type { FeishuType, OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
||||||
|
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||||
|
|
||||||
|
const FeiShuEditModal = dynamic(() => import('./FeiShuEditModal'));
|
||||||
|
|
||||||
|
const FeiShu = ({ appId }: { appId: string }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { Loading, setIsLoading } = useLoading();
|
||||||
|
const { feConfigs } = useSystemStore();
|
||||||
|
const { copyData } = useCopyData();
|
||||||
|
const [editFeiShuLinkData, setEditFeiShuLinkData] = useState<OutLinkEditType<FeishuType>>();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const {
|
||||||
|
isFetching,
|
||||||
|
data: shareChatList = [],
|
||||||
|
refetch: refetchShareChatList
|
||||||
|
} = useQuery(['initShareChatList', appId], () =>
|
||||||
|
getShareChatList<FeishuType>({ appId, type: PublishChannelEnum.feishu })
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
|
||||||
|
<Flex justifyContent={'space-between'}>
|
||||||
|
<Box fontWeight={'bold'} fontSize={['md', 'xl']}>
|
||||||
|
{t('core.app.publish.Fei shu bot publish')}
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant={'whitePrimary'}
|
||||||
|
colorScheme={'blue'}
|
||||||
|
size={['sm', 'md']}
|
||||||
|
{...(shareChatList.length >= 10
|
||||||
|
? {
|
||||||
|
isDisabled: true,
|
||||||
|
title: t('core.app.share.Amount limit tip')
|
||||||
|
}
|
||||||
|
: {})}
|
||||||
|
onClick={() => setEditFeiShuLinkData(defaultFeishuOutLinkForm)}
|
||||||
|
>
|
||||||
|
{t('core.app.share.Create link')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
<TableContainer mt={3}>
|
||||||
|
<Table variant={'simple'} w={'100%'} overflowX={'auto'} fontSize={'sm'}>
|
||||||
|
<Thead>
|
||||||
|
<Tr>
|
||||||
|
<Th>{t('common.Name')}</Th>
|
||||||
|
<Th>{t('support.outlink.Usage points')}</Th>
|
||||||
|
{feConfigs?.isPlus && (
|
||||||
|
<>
|
||||||
|
<Th>{t('core.app.share.Ip limit title')}</Th>
|
||||||
|
<Th>{t('common.Expired Time')}</Th>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Th>{t('common.Last use time')}</Th>
|
||||||
|
<Th></Th>
|
||||||
|
</Tr>
|
||||||
|
</Thead>
|
||||||
|
<Tbody>
|
||||||
|
{shareChatList.map((item) => (
|
||||||
|
<Tr key={item._id}>
|
||||||
|
<Td>{item.name}</Td>
|
||||||
|
<Td>
|
||||||
|
{Math.round(item.usagePoints)}
|
||||||
|
{feConfigs?.isPlus
|
||||||
|
? `${
|
||||||
|
item.limit?.maxUsagePoints && item.limit.maxUsagePoints > -1
|
||||||
|
? ` / ${item.limit.maxUsagePoints}`
|
||||||
|
: ` / ${t('common.Unlimited')}`
|
||||||
|
}`
|
||||||
|
: ''}
|
||||||
|
</Td>
|
||||||
|
{feConfigs?.isPlus && (
|
||||||
|
<>
|
||||||
|
<Td>{item?.limit?.QPM || '-'}</Td>
|
||||||
|
<Td>
|
||||||
|
{item?.limit?.expiredTime
|
||||||
|
? dayjs(item.limit?.expiredTime).format('YYYY/MM/DD\nHH:mm')
|
||||||
|
: '-'}
|
||||||
|
</Td>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Td>
|
||||||
|
{item.lastTime ? t(formatTimeToChatTime(item.lastTime)) : t('common.Un used')}
|
||||||
|
</Td>
|
||||||
|
<Td display={'flex'} alignItems={'center'}>
|
||||||
|
<MyMenu
|
||||||
|
Button={
|
||||||
|
<MyIcon
|
||||||
|
name={'more'}
|
||||||
|
_hover={{ bg: 'myGray.100 ' }}
|
||||||
|
cursor={'pointer'}
|
||||||
|
borderRadius={'md'}
|
||||||
|
w={'14px'}
|
||||||
|
p={2}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
menuList={[
|
||||||
|
{
|
||||||
|
label: t('common.Edit'),
|
||||||
|
icon: 'edit',
|
||||||
|
onClick: () =>
|
||||||
|
setEditFeiShuLinkData({
|
||||||
|
_id: item._id,
|
||||||
|
name: item.name,
|
||||||
|
limit: item.limit,
|
||||||
|
app: item.app,
|
||||||
|
responseDetail: item.responseDetail,
|
||||||
|
defaultResponse: item.defaultResponse,
|
||||||
|
immediateResponse: item.immediateResponse
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('common.Delete'),
|
||||||
|
icon: 'delete',
|
||||||
|
onClick: async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
await delShareChatById(item._id);
|
||||||
|
refetchShareChatList();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Tbody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
{editFeiShuLinkData && (
|
||||||
|
<FeiShuEditModal
|
||||||
|
appId={appId}
|
||||||
|
// type={'feishu' as PublishChannelEnum}
|
||||||
|
defaultData={editFeiShuLinkData}
|
||||||
|
onCreate={(id) => {
|
||||||
|
refetchShareChatList();
|
||||||
|
setEditFeiShuLinkData(undefined);
|
||||||
|
}}
|
||||||
|
onEdit={() => {
|
||||||
|
toast({
|
||||||
|
status: 'success',
|
||||||
|
title: t('common.Update Successful')
|
||||||
|
});
|
||||||
|
refetchShareChatList();
|
||||||
|
setEditFeiShuLinkData(undefined);
|
||||||
|
}}
|
||||||
|
onClose={() => setEditFeiShuLinkData(undefined)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{shareChatList.length === 0 && !isFetching && (
|
||||||
|
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'10vh'}>
|
||||||
|
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||||
|
<Box mt={2} color={'myGray.500'}>
|
||||||
|
{t('core.app.share.Not share link')}
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
<Loading loading={isFetching} fixed={false} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(FeiShu);
|
||||||
@ -32,8 +32,8 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { defaultOutLinkForm } from '@/constants/app';
|
import { defaultOutLinkForm } from '@/constants/app';
|
||||||
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
|
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
|
||||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
@ -47,7 +47,7 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
|||||||
|
|
||||||
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
|
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
|
||||||
|
|
||||||
const Share = ({ appId }: { appId: string }) => {
|
const Share = ({ appId }: { appId: string; type: PublishChannelEnum }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Loading, setIsLoading } = useLoading();
|
const { Loading, setIsLoading } = useLoading();
|
||||||
const { feConfigs } = useSystemStore();
|
const { feConfigs } = useSystemStore();
|
||||||
@ -64,7 +64,9 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
isFetching,
|
isFetching,
|
||||||
data: shareChatList = [],
|
data: shareChatList = [],
|
||||||
refetch: refetchShareChatList
|
refetch: refetchShareChatList
|
||||||
} = useQuery(['initShareChatList', appId], () => getShareChatList(appId));
|
} = useQuery(['initShareChatList', appId], () =>
|
||||||
|
getShareChatList({ appId, type: PublishChannelEnum.share })
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
|
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
|
||||||
@ -95,12 +97,16 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>{t('common.Name')}</Th>
|
<Th>{t('common.Name')}</Th>
|
||||||
|
{feConfigs?.isPlus && (
|
||||||
|
<>
|
||||||
|
<Th>{t('common.Expired Time')}</Th>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Th>{t('support.outlink.Usage points')}</Th>
|
<Th>{t('support.outlink.Usage points')}</Th>
|
||||||
<Th>{t('core.app.share.Is response quote')}</Th>
|
<Th>{t('core.app.share.Is response quote')}</Th>
|
||||||
{feConfigs?.isPlus && (
|
{feConfigs?.isPlus && (
|
||||||
<>
|
<>
|
||||||
<Th>{t('core.app.share.Ip limit title')}</Th>
|
<Th>{t('core.app.share.Ip limit title')}</Th>
|
||||||
<Th>{t('common.Expired Time')}</Th>
|
|
||||||
<Th>{t('core.app.share.Role check')}</Th>
|
<Th>{t('core.app.share.Role check')}</Th>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -112,6 +118,15 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
{shareChatList.map((item) => (
|
{shareChatList.map((item) => (
|
||||||
<Tr key={item._id}>
|
<Tr key={item._id}>
|
||||||
<Td>{item.name}</Td>
|
<Td>{item.name}</Td>
|
||||||
|
{feConfigs?.isPlus && (
|
||||||
|
<>
|
||||||
|
<Td>
|
||||||
|
{item.limit?.expiredTime
|
||||||
|
? dayjs(item.limit.expiredTime).format('YYYY-MM-DD HH:mm')
|
||||||
|
: '-'}
|
||||||
|
</Td>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Td>
|
<Td>
|
||||||
{Math.round(item.usagePoints)}
|
{Math.round(item.usagePoints)}
|
||||||
{feConfigs?.isPlus
|
{feConfigs?.isPlus
|
||||||
@ -126,18 +141,14 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
{feConfigs?.isPlus && (
|
{feConfigs?.isPlus && (
|
||||||
<>
|
<>
|
||||||
<Td>{item?.limit?.QPM || '-'}</Td>
|
<Td>{item?.limit?.QPM || '-'}</Td>
|
||||||
<Td>
|
|
||||||
{item?.limit?.expiredTime
|
|
||||||
? dayjs(item.limit?.expiredTime).format('YYYY/MM/DD\nHH:mm')
|
|
||||||
: '-'}
|
|
||||||
</Td>
|
|
||||||
<Th>{item?.limit?.hookUrl ? '✔' : '✖'}</Th>
|
<Th>{item?.limit?.hookUrl ? '✔' : '✖'}</Th>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : t('common.Un used')}</Td>
|
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : t('common.Un used')}</Td>
|
||||||
<Td display={'flex'} alignItems={'center'}>
|
<Td display={'flex'} alignItems={'center'}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setSelectedLinkData(item)}
|
onClick={() => setSelectedLinkData(item as OutLinkSchema)}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
mr={3}
|
mr={3}
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
@ -201,7 +212,7 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
{!!editLinkData && (
|
{!!editLinkData && (
|
||||||
<EditLinkModal
|
<EditLinkModal
|
||||||
appId={appId}
|
appId={appId}
|
||||||
type={'share'}
|
type={PublishChannelEnum.share}
|
||||||
defaultData={editLinkData}
|
defaultData={editLinkData}
|
||||||
onCreate={(id) => {
|
onCreate={(id) => {
|
||||||
const url = `${location.origin}/chat/share?shareId=${id}`;
|
const url = `${location.origin}/chat/share?shareId=${id}`;
|
||||||
@ -242,7 +253,7 @@ function EditLinkModal({
|
|||||||
onEdit
|
onEdit
|
||||||
}: {
|
}: {
|
||||||
appId: string;
|
appId: string;
|
||||||
type: `${OutLinkTypeEnum}`;
|
type: PublishChannelEnum;
|
||||||
defaultData: OutLinkEditType;
|
defaultData: OutLinkEditType;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCreate: (id: string) => void;
|
onCreate: (id: string) => void;
|
||||||
@ -297,6 +308,22 @@ function EditLinkModal({
|
|||||||
</Flex>
|
</Flex>
|
||||||
{feConfigs?.isPlus && (
|
{feConfigs?.isPlus && (
|
||||||
<>
|
<>
|
||||||
|
<Flex alignItems={'center'} mt={4}>
|
||||||
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
|
{t('common.Expired Time')}
|
||||||
|
</Flex>
|
||||||
|
<Input
|
||||||
|
type="datetime-local"
|
||||||
|
defaultValue={
|
||||||
|
defaultData.limit?.expiredTime
|
||||||
|
? dayjs(defaultData.limit?.expiredTime).format('YYYY-MM-DDTHH:mm')
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
onChange={(e) => {
|
||||||
|
setValue('limit.expiredTime', new Date(e.target.value));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={4}>
|
<Flex alignItems={'center'} mt={4}>
|
||||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
QPM
|
QPM
|
||||||
@ -330,22 +357,7 @@ function EditLinkModal({
|
|||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={4}>
|
|
||||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
|
||||||
{t('common.Expired Time')}
|
|
||||||
</Flex>
|
|
||||||
<Input
|
|
||||||
type="datetime-local"
|
|
||||||
defaultValue={
|
|
||||||
defaultData.limit?.expiredTime
|
|
||||||
? dayjs(defaultData.limit?.expiredTime).format('YYYY-MM-DDTHH:mm')
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
onChange={(e) => {
|
|
||||||
setValue('limit.expiredTime', new Date(e.target.value));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
<Flex alignItems={'center'} mt={4}>
|
<Flex alignItems={'center'} mt={4}>
|
||||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||||
{t('outlink.token auth')}
|
{t('outlink.token auth')}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
import { Box, useTheme } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
import MyRadio from '@/components/common/MyRadio';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
|
import Link from './Link';
|
||||||
|
const API = dynamic(() => import('./API'));
|
||||||
|
const FeiShu = dynamic(() => import('./FeiShu'));
|
||||||
|
|
||||||
|
const OutLink = ({ appId }: { appId: string }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const theme = useTheme();
|
||||||
|
const publishList = useRef([
|
||||||
|
{
|
||||||
|
icon: '/imgs/modal/shareFill.svg',
|
||||||
|
title: t('core.app.Share link'),
|
||||||
|
desc: t('core.app.Share link desc'),
|
||||||
|
value: PublishChannelEnum.share
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'support/outlink/apikeyFill',
|
||||||
|
title: t('core.app.Api request'),
|
||||||
|
desc: t('core.app.Api request desc'),
|
||||||
|
value: PublishChannelEnum.apikey
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// icon: 'core/app/publish/lark',
|
||||||
|
// title: t('core.app.publish.Fei shu bot'),
|
||||||
|
// desc: t('core.app.publish.Fei Shu Bot Desc'),
|
||||||
|
// value: PublishChannelEnum.feishu
|
||||||
|
// }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [linkType, setLinkType] = useState<PublishChannelEnum>(PublishChannelEnum.share);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box pt={[1, 5]}>
|
||||||
|
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2} px={[4, 8]}>
|
||||||
|
{t('core.app.navbar.Publish app')}
|
||||||
|
</Box>
|
||||||
|
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
||||||
|
<MyRadio
|
||||||
|
gridTemplateColumns={['repeat(1,1fr)', 'repeat(auto-fill, minmax(0, 300px))']}
|
||||||
|
iconSize={'20px'}
|
||||||
|
list={publishList.current}
|
||||||
|
value={linkType}
|
||||||
|
onChange={(e) => setLinkType(e as PublishChannelEnum)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{linkType === PublishChannelEnum.share && (
|
||||||
|
<Link appId={appId} type={PublishChannelEnum.share} />
|
||||||
|
)}
|
||||||
|
{linkType === PublishChannelEnum.apikey && <API appId={appId} />}
|
||||||
|
{linkType === PublishChannelEnum.feishu && <FeiShu appId={appId} />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OutLink;
|
||||||
@ -1,11 +1,9 @@
|
|||||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
|
||||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||||
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
import ChatBox from '@/components/ChatBox';
|
import ChatBox from '@/components/ChatBox';
|
||||||
import type { ComponentRef, StartChatFnProps } from '@/components/ChatBox/type.d';
|
import type { ComponentRef, StartChatFnProps } from '@/components/ChatBox/type.d';
|
||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { streamFetch } from '@/web/common/api/fetch';
|
import { streamFetch } from '@/web/common/api/fetch';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
@ -13,27 +11,41 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
|||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
||||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
|
||||||
import {
|
import {
|
||||||
getDefaultEntryNodeIds,
|
getDefaultEntryNodeIds,
|
||||||
initWorkflowEdgeStatus,
|
initWorkflowEdgeStatus,
|
||||||
storeNodes2RuntimeNodes
|
storeNodes2RuntimeNodes
|
||||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
|
import { useCreation, useMemoizedFn, useSafeState } from 'ahooks';
|
||||||
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
|
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
|
||||||
|
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||||
|
import { form2AppWorkflow } from '@/web/core/app/utils';
|
||||||
|
|
||||||
const ChatTest = ({ appId }: { appId: string }) => {
|
const ChatTest = ({
|
||||||
|
editForm,
|
||||||
|
appId
|
||||||
|
}: {
|
||||||
|
editForm: UseFormReturn<AppSimpleEditFormType, any>;
|
||||||
|
appId: string;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
const { appDetail } = useAppStore();
|
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const [workflowData, setWorkflowData] = useState<{
|
const { appDetail } = useAppStore();
|
||||||
nodes: StoreNodeItemType[];
|
|
||||||
edges: StoreEdgeItemType[];
|
|
||||||
}>({
|
|
||||||
nodes: [],
|
|
||||||
edges: []
|
|
||||||
});
|
|
||||||
|
|
||||||
const startChat = useCallback(
|
const { watch } = editForm;
|
||||||
|
|
||||||
|
const [workflowData, setWorkflowData] = useSafeState({
|
||||||
|
nodes: appDetail.modules || [],
|
||||||
|
edges: appDetail.edges || []
|
||||||
|
});
|
||||||
|
const userGuideModule = useCreation(
|
||||||
|
() => getGuideModule(workflowData.nodes),
|
||||||
|
[workflowData.nodes]
|
||||||
|
);
|
||||||
|
|
||||||
|
const startChat = useMemoizedFn(
|
||||||
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||||
if (!workflowData) return Promise.reject('workflowData is empty');
|
if (!workflowData) return Promise.reject('workflowData is empty');
|
||||||
|
|
||||||
@ -72,8 +84,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return { responseText, responseData };
|
return { responseText, responseData };
|
||||||
},
|
}
|
||||||
[workflowData, appId, appDetail.name]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetChatBox = useCallback(() => {
|
const resetChatBox = useCallback(() => {
|
||||||
@ -82,12 +93,15 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resetChatBox();
|
const wat = watch((data) => {
|
||||||
setWorkflowData({
|
const { nodes, edges } = form2AppWorkflow(data as AppSimpleEditFormType);
|
||||||
nodes: appDetail.modules || [],
|
setWorkflowData({ nodes, edges });
|
||||||
edges: appDetail.edges || []
|
|
||||||
});
|
});
|
||||||
}, [appDetail, resetChatBox]);
|
|
||||||
|
return () => {
|
||||||
|
wat.unsubscribe();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@ -124,7 +138,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
appAvatar={appDetail.avatar}
|
appAvatar={appDetail.avatar}
|
||||||
userAvatar={userInfo?.avatar}
|
userAvatar={userInfo?.avatar}
|
||||||
showMarkIcon
|
showMarkIcon
|
||||||
userGuideModule={getGuideModule(workflowData.nodes)}
|
userGuideModule={userGuideModule}
|
||||||
showFileSelector={checkChatSupportSelectFileByModules(workflowData.nodes)}
|
showFileSelector={checkChatSupportSelectFileByModules(workflowData.nodes)}
|
||||||
onStartChat={startChat}
|
onStartChat={startChat}
|
||||||
onDelMessage={() => {}}
|
onDelMessage={() => {}}
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import React, { useMemo, useState, useTransition } from 'react';
|
import React, { useMemo, useTransition } from 'react';
|
||||||
import { Box, Flex, Grid, BoxProps, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
import { Box, Flex, Grid, BoxProps, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
import { AddIcon, QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
import { AddIcon, QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import { useForm, useFieldArray } from 'react-hook-form';
|
import { useFieldArray, UseFormReturn } from 'react-hook-form';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import { appWorkflow2Form, getDefaultAppForm } from '@fastgpt/global/core/app/utils';
|
|
||||||
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
|
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
|
||||||
import { welcomeTextTip } from '@fastgpt/global/core/workflow/template/tip';
|
import { welcomeTextTip } from '@fastgpt/global/core/workflow/template/tip';
|
||||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||||
@ -51,26 +49,24 @@ const LabelStyles: BoxProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const EditForm = ({
|
const EditForm = ({
|
||||||
|
editForm,
|
||||||
divRef,
|
divRef,
|
||||||
isSticky
|
isSticky
|
||||||
}: {
|
}: {
|
||||||
|
editForm: UseFormReturn<AppSimpleEditFormType, any>;
|
||||||
divRef: React.RefObject<HTMLDivElement>;
|
divRef: React.RefObject<HTMLDivElement>;
|
||||||
isSticky: boolean;
|
isSticky: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { appDetail, publishApp } = useAppStore();
|
const { publishApp, appDetail } = useAppStore();
|
||||||
|
|
||||||
const { loadAllDatasets, allDatasets } = useDatasetStore();
|
const { allDatasets } = useDatasetStore();
|
||||||
const { isPc, llmModelList } = useSystemStore();
|
const { llmModelList } = useSystemStore();
|
||||||
const [refresh, setRefresh] = useState(false);
|
|
||||||
const [, startTst] = useTransition();
|
const [, startTst] = useTransition();
|
||||||
|
|
||||||
const { setValue, getValues, reset, handleSubmit, control, watch } =
|
const { setValue, getValues, handleSubmit, control, watch } = editForm;
|
||||||
useForm<AppSimpleEditFormType>({
|
|
||||||
defaultValues: getDefaultAppForm()
|
|
||||||
});
|
|
||||||
|
|
||||||
const { fields: datasets, replace: replaceKbList } = useFieldArray({
|
const { fields: datasets, replace: replaceKbList } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
@ -107,6 +103,9 @@ const EditForm = ({
|
|||||||
[t, variables]
|
[t, variables]
|
||||||
);
|
);
|
||||||
const searchMode = watch('dataset.searchMode');
|
const searchMode = watch('dataset.searchMode');
|
||||||
|
const tts = getValues('userGuide.tts');
|
||||||
|
const whisperConfig = getValues('userGuide.whisper');
|
||||||
|
const postQuestionGuide = getValues('userGuide.questionGuide');
|
||||||
|
|
||||||
const selectDatasets = useMemo(
|
const selectDatasets = useMemo(
|
||||||
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
|
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
|
||||||
@ -118,7 +117,7 @@ const EditForm = ({
|
|||||||
}, [selectLLMModel, llmModelList]);
|
}, [selectLLMModel, llmModelList]);
|
||||||
|
|
||||||
/* on save app */
|
/* on save app */
|
||||||
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
|
const { mutate: onSubmitPublish, isLoading: isSaving } = useRequest({
|
||||||
mutationFn: async (data: AppSimpleEditFormType) => {
|
mutationFn: async (data: AppSimpleEditFormType) => {
|
||||||
const { nodes, edges } = form2AppWorkflow(data);
|
const { nodes, edges } = form2AppWorkflow(data);
|
||||||
|
|
||||||
@ -132,22 +131,6 @@ const EditForm = ({
|
|||||||
errorToast: t('common.Save Failed')
|
errorToast: t('common.Save Failed')
|
||||||
});
|
});
|
||||||
|
|
||||||
useQuery(
|
|
||||||
['init', appDetail],
|
|
||||||
() => {
|
|
||||||
const formatVal = appWorkflow2Form({
|
|
||||||
nodes: appDetail.modules
|
|
||||||
});
|
|
||||||
reset(formatVal);
|
|
||||||
setRefresh(!refresh);
|
|
||||||
return formatVal;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: !!appDetail._id
|
|
||||||
}
|
|
||||||
);
|
|
||||||
useQuery(['loadAllDatasets'], loadAllDatasets);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{/* title */}
|
{/* title */}
|
||||||
@ -177,16 +160,23 @@ const EditForm = ({
|
|||||||
<Button
|
<Button
|
||||||
isLoading={isSaving}
|
isLoading={isSaving}
|
||||||
size={['sm', 'md']}
|
size={['sm', 'md']}
|
||||||
|
leftIcon={
|
||||||
|
appDetail.type === AppTypeEnum.simple ? (
|
||||||
|
<MyIcon name={'common/publishFill'} w={['14px', '16px']} />
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
variant={appDetail.type === AppTypeEnum.simple ? 'primary' : 'whitePrimary'}
|
variant={appDetail.type === AppTypeEnum.simple ? 'primary' : 'whitePrimary'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (appDetail.type !== AppTypeEnum.simple) {
|
if (appDetail.type !== AppTypeEnum.simple) {
|
||||||
openConfirmSave(handleSubmit((data) => onSubmitSave(data)))();
|
openConfirmSave(handleSubmit((data) => onSubmitPublish(data)))();
|
||||||
} else {
|
} else {
|
||||||
handleSubmit((data) => onSubmitSave(data))();
|
handleSubmit((data) => onSubmitPublish(data))();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isPc ? t('core.app.Save and preview') : t('common.Save')}
|
{appDetail.type !== AppTypeEnum.simple
|
||||||
|
? t('core.app.Change to simple mode')
|
||||||
|
: t('core.app.Publish')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
@ -272,7 +262,7 @@ const EditForm = ({
|
|||||||
{t('common.Params')}
|
{t('common.Params')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{getValues('dataset.datasets').length > 0 && (
|
{datasetSearchSetting.datasets?.length > 0 && (
|
||||||
<Box my={3}>
|
<Box my={3}>
|
||||||
<SearchParamsTip
|
<SearchParamsTip
|
||||||
searchMode={searchMode}
|
searchMode={searchMode}
|
||||||
@ -382,7 +372,6 @@ const EditForm = ({
|
|||||||
variables={variables}
|
variables={variables}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setValue('userGuide.variables', e);
|
setValue('userGuide.variables', e);
|
||||||
setRefresh(!refresh);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -411,10 +400,9 @@ const EditForm = ({
|
|||||||
{/* tts */}
|
{/* tts */}
|
||||||
<Box {...BoxStyles}>
|
<Box {...BoxStyles}>
|
||||||
<TTSSelect
|
<TTSSelect
|
||||||
value={getValues('userGuide.tts')}
|
value={tts}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setValue('userGuide.tts', e);
|
setValue('userGuide.tts', e);
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -422,11 +410,10 @@ const EditForm = ({
|
|||||||
{/* whisper */}
|
{/* whisper */}
|
||||||
<Box {...BoxStyles}>
|
<Box {...BoxStyles}>
|
||||||
<WhisperConfig
|
<WhisperConfig
|
||||||
isOpenAudio={getValues('userGuide.tts').type !== TTSTypeEnum.none}
|
isOpenAudio={tts.type !== TTSTypeEnum.none}
|
||||||
value={getValues('userGuide.whisper')}
|
value={whisperConfig}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setValue('userGuide.whisper', e);
|
setValue('userGuide.whisper', e);
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -434,12 +421,10 @@ const EditForm = ({
|
|||||||
{/* question guide */}
|
{/* question guide */}
|
||||||
<Box {...BoxStyles} borderBottom={'none'}>
|
<Box {...BoxStyles} borderBottom={'none'}>
|
||||||
<QGSwitch
|
<QGSwitch
|
||||||
isChecked={getValues('userGuide.questionGuide')}
|
isChecked={postQuestionGuide}
|
||||||
size={'lg'}
|
size={'lg'}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target.checked;
|
setValue('userGuide.questionGuide', e.target.checked);
|
||||||
setValue('userGuide.questionGuide', value);
|
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -468,8 +453,6 @@ const EditForm = ({
|
|||||||
...getValues('dataset'),
|
...getValues('dataset'),
|
||||||
...e
|
...e
|
||||||
});
|
});
|
||||||
|
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,14 +2,33 @@ import React from 'react';
|
|||||||
import { Box, Grid } from '@chakra-ui/react';
|
import { Box, Grid } from '@chakra-ui/react';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import { useSticky } from '@/web/common/hooks/useSticky';
|
import { useSticky } from '@/web/common/hooks/useSticky';
|
||||||
|
import { useMount } from 'ahooks';
|
||||||
|
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||||
|
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { appWorkflow2Form } from '@fastgpt/global/core/app/utils';
|
||||||
|
|
||||||
import ChatTest from './ChatTest';
|
import ChatTest from './ChatTest';
|
||||||
import AppCard from './AppCard';
|
import AppCard from './AppCard';
|
||||||
import EditForm from './EditForm';
|
import EditForm from './EditForm';
|
||||||
|
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
|
||||||
|
|
||||||
const SimpleEdit = ({ appId }: { appId: string }) => {
|
const SimpleEdit = ({ appId }: { appId: string }) => {
|
||||||
const { isPc } = useSystemStore();
|
const { isPc } = useSystemStore();
|
||||||
const { parentRef, divRef, isSticky } = useSticky();
|
const { parentRef, divRef, isSticky } = useSticky();
|
||||||
|
const { loadAllDatasets } = useDatasetStore();
|
||||||
|
const { appDetail } = useAppStore();
|
||||||
|
|
||||||
|
const editForm = useForm<AppSimpleEditFormType>({
|
||||||
|
defaultValues: appWorkflow2Form({
|
||||||
|
nodes: appDetail.modules
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// show selected dataset
|
||||||
|
useMount(() => {
|
||||||
|
loadAllDatasets();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid gridTemplateColumns={['1fr', '560px 1fr']} h={'100%'}>
|
<Grid gridTemplateColumns={['1fr', '560px 1fr']} h={'100%'}>
|
||||||
@ -25,10 +44,10 @@ const SimpleEdit = ({ appId }: { appId: string }) => {
|
|||||||
<AppCard appId={appId} />
|
<AppCard appId={appId} />
|
||||||
|
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<EditForm divRef={divRef} isSticky={isSticky} />
|
<EditForm editForm={editForm} divRef={divRef} isSticky={isSticky} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{isPc && <ChatTest appId={appId} />}
|
{isPc && <ChatTest editForm={editForm} appId={appId} />}
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { useTranslation } from 'next-i18next';
|
|||||||
const FlowEdit = dynamic(() => import('./components/FlowEdit'), {
|
const FlowEdit = dynamic(() => import('./components/FlowEdit'), {
|
||||||
loading: () => <Loading />
|
loading: () => <Loading />
|
||||||
});
|
});
|
||||||
const OutLink = dynamic(() => import('./components/OutLink'), {});
|
const Publish = dynamic(() => import('./components/Publish'), {});
|
||||||
const Logs = dynamic(() => import('./components/Logs'), {});
|
const Logs = dynamic(() => import('./components/Logs'), {});
|
||||||
|
|
||||||
enum TabEnum {
|
enum TabEnum {
|
||||||
@ -39,7 +39,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
const { feConfigs } = useSystemStore();
|
const { feConfigs } = useSystemStore();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { appId } = router.query as { appId: string };
|
const { appId } = router.query as { appId: string };
|
||||||
const { appDetail, loadAppDetail, clearAppModules } = useAppStore();
|
const { appDetail, loadAppDetail } = useAppStore();
|
||||||
|
|
||||||
const setCurrentTab = useCallback(
|
const setCurrentTab = useCallback(
|
||||||
(tab: `${TabEnum}`) => {
|
(tab: `${TabEnum}`) => {
|
||||||
@ -82,7 +82,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
|
|
||||||
const onCloseFlowEdit = useCallback(() => setCurrentTab(TabEnum.simpleEdit), [setCurrentTab]);
|
const onCloseFlowEdit = useCallback(() => setCurrentTab(TabEnum.simpleEdit), [setCurrentTab]);
|
||||||
|
|
||||||
useQuery([appId], () => loadAppDetail(appId, true), {
|
const { isSuccess, isLoading } = useQuery([appId], () => loadAppDetail(appId, true), {
|
||||||
onError(err: any) {
|
onError(err: any) {
|
||||||
toast({
|
toast({
|
||||||
title: err?.message || t('core.app.error.Get app failed'),
|
title: err?.message || t('core.app.error.Get app failed'),
|
||||||
@ -100,7 +100,8 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{appDetail.name}</title>
|
<title>{appDetail.name}</title>
|
||||||
</Head>
|
</Head>
|
||||||
<PageContainer>
|
<PageContainer isLoading={isLoading}>
|
||||||
|
{isSuccess && (
|
||||||
<Flex flexDirection={['column', 'row']} h={'100%'}>
|
<Flex flexDirection={['column', 'row']} h={'100%'}>
|
||||||
{/* pc tab */}
|
{/* pc tab */}
|
||||||
<Box
|
<Box
|
||||||
@ -179,9 +180,10 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
<FlowEdit app={appDetail} onClose={onCloseFlowEdit} />
|
<FlowEdit app={appDetail} onClose={onCloseFlowEdit} />
|
||||||
)}
|
)}
|
||||||
{currentTab === TabEnum.logs && <Logs appId={appId} />}
|
{currentTab === TabEnum.logs && <Logs appId={appId} />}
|
||||||
{currentTab === TabEnum.publish && <OutLink appId={appId} />}
|
{currentTab === TabEnum.publish && <Publish appId={appId} />}
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
)}
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,14 +11,12 @@ import { flowNode2StoreNodes } from '@/components/core/workflow/utils';
|
|||||||
import { putUpdatePlugin } from '@/web/core/plugin/api';
|
import { putUpdatePlugin } from '@/web/core/plugin/api';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||||
import {
|
|
||||||
getWorkflowStore,
|
|
||||||
useFlowProviderStore
|
|
||||||
} from '@/components/core/workflow/Flow/FlowProvider';
|
|
||||||
import {
|
import {
|
||||||
checkWorkflowNodeAndConnection,
|
checkWorkflowNodeAndConnection,
|
||||||
filterSensitiveNodesData
|
filterSensitiveNodesData
|
||||||
} from '@/web/core/workflow/utils';
|
} from '@/web/core/workflow/utils';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
|
||||||
|
|
||||||
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
||||||
|
|
||||||
@ -29,11 +27,13 @@ const Header = ({ plugin, onClose }: Props) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { copyData } = useCopyData();
|
const { copyData } = useCopyData();
|
||||||
const { edges, onUpdateNodeError } = useFlowProviderStore();
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||||
|
|
||||||
const flowData2StoreDataAndCheck = useCallback(async () => {
|
const flowData2StoreDataAndCheck = useCallback(async () => {
|
||||||
const { nodes } = await getWorkflowStore();
|
const { nodes } = await getWorkflowStore();
|
||||||
|
|
||||||
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
||||||
if (!checkResults) {
|
if (!checkResults) {
|
||||||
const storeNodes = flowNode2StoreNodes({ nodes, edges });
|
const storeNodes = flowNode2StoreNodes({ nodes, edges });
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import Flow from '@/components/core/workflow/Flow';
|
import Flow from '@/components/core/workflow/Flow';
|
||||||
import FlowProvider, { useFlowProviderStore } from '@/components/core/workflow/Flow/FlowProvider';
|
|
||||||
import { pluginSystemModuleTemplates } from '@fastgpt/global/core/workflow/template/constants';
|
import { pluginSystemModuleTemplates } from '@fastgpt/global/core/workflow/template/constants';
|
||||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
@ -14,6 +13,8 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||||
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
||||||
import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
|
import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
|
||||||
|
import WorkflowContextProvider, { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
|
||||||
type Props = { pluginId: string };
|
type Props = { pluginId: string };
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ const Render = ({ pluginId }: Props) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { initData } = useFlowProviderStore();
|
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||||
|
|
||||||
const { data: pluginDetail } = useQuery(
|
const { data: pluginDetail } = useQuery(
|
||||||
['getOnePlugin', pluginId],
|
['getOnePlugin', pluginId],
|
||||||
@ -78,9 +79,11 @@ const Render = ({ pluginId }: Props) => {
|
|||||||
|
|
||||||
export default function FlowEdit(props: any) {
|
export default function FlowEdit(props: any) {
|
||||||
return (
|
return (
|
||||||
<FlowProvider mode={'plugin'} basicNodeTemplates={pluginSystemModuleTemplates}>
|
<WorkflowContextProvider
|
||||||
|
value={{ mode: 'plugin', basicNodeTemplates: pluginSystemModuleTemplates }}
|
||||||
|
>
|
||||||
<Render {...props} />
|
<Render {...props} />
|
||||||
</FlowProvider>
|
</WorkflowContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { TTSTypeEnum } from '@/constants/app';
|
|||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import type { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat.d';
|
import type { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat.d';
|
||||||
import { getToken } from '@/web/support/user/auth';
|
import { getToken } from '@/web/support/user/auth';
|
||||||
|
import { useMount } from 'ahooks';
|
||||||
|
|
||||||
const contentType = 'audio/mpeg';
|
const contentType = 'audio/mpeg';
|
||||||
const splitMarker = 'SPLIT_MARKER';
|
const splitMarker = 'SPLIT_MARKER';
|
||||||
@ -329,7 +330,7 @@ export const useAudioPlay = (props?: OutLinkChatAuthProps & { ttsConfig?: AppTTS
|
|||||||
);
|
);
|
||||||
|
|
||||||
// listen audio status
|
// listen audio status
|
||||||
useEffect(() => {
|
useMount(() => {
|
||||||
const audio = new Audio();
|
const audio = new Audio();
|
||||||
audioRef.current = audio;
|
audioRef.current = audio;
|
||||||
|
|
||||||
@ -357,7 +358,7 @@ export const useAudioPlay = (props?: OutLinkChatAuthProps & { ttsConfig?: AppTTS
|
|||||||
audio.remove();
|
audio.remove();
|
||||||
window.removeEventListener('beforeunload', listen);
|
window.removeEventListener('beforeunload', listen);
|
||||||
};
|
};
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
audio: audioRef.current,
|
audio: audioRef.current,
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { clientInitData } from '@/web/common/system/staticData';
|
import { clientInitData } from '@/web/common/system/staticData';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index.d';
|
import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index.d';
|
||||||
import { change2DefaultLng, setLngStore } from '@/web/common/utils/i18n';
|
import { change2DefaultLng, setLngStore } from '@/web/common/utils/i18n';
|
||||||
|
import { useMemoizedFn, useMount } from 'ahooks';
|
||||||
|
|
||||||
export const useInitApp = () => {
|
export const useInitApp = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -14,7 +15,7 @@ export const useInitApp = () => {
|
|||||||
const [scripts, setScripts] = useState<FastGPTFeConfigsType['scripts']>([]);
|
const [scripts, setScripts] = useState<FastGPTFeConfigsType['scripts']>([]);
|
||||||
const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI');
|
const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI');
|
||||||
|
|
||||||
const initFetch = useCallback(async () => {
|
const initFetch = useMemoizedFn(async () => {
|
||||||
const {
|
const {
|
||||||
feConfigs: { scripts, isPlus, show_git, systemTitle }
|
feConfigs: { scripts, isPlus, show_git, systemTitle }
|
||||||
} = await clientInitData();
|
} = await clientInitData();
|
||||||
@ -35,18 +36,18 @@ export const useInitApp = () => {
|
|||||||
|
|
||||||
setScripts(scripts || []);
|
setScripts(scripts || []);
|
||||||
setInitd();
|
setInitd();
|
||||||
}, [loadGitStar, setInitd]);
|
});
|
||||||
|
|
||||||
const initUserLanguage = useCallback(() => {
|
const initUserLanguage = useMemoizedFn(() => {
|
||||||
// get default language
|
// get default language
|
||||||
const targetLng = change2DefaultLng(i18n.language);
|
const targetLng = change2DefaultLng(i18n.language);
|
||||||
if (targetLng) {
|
if (targetLng) {
|
||||||
setLngStore(targetLng);
|
setLngStore(targetLng);
|
||||||
router.replace(router.asPath, undefined, { locale: targetLng });
|
router.replace(router.asPath, undefined, { locale: targetLng });
|
||||||
}
|
}
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useMount(() => {
|
||||||
initFetch();
|
initFetch();
|
||||||
initUserLanguage();
|
initUserLanguage();
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ export const useInitApp = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('error', errorTrack);
|
window.removeEventListener('error', errorTrack);
|
||||||
};
|
};
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
hiId && localStorage.setItem('inviterId', hiId);
|
hiId && localStorage.setItem('inviterId', hiId);
|
||||||
|
|||||||
@ -704,7 +704,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
|
|||||||
...pluginTool.map((tool) => tool.edges).flat()
|
...pluginTool.map((tool) => tool.edges).flat()
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
console.log(config);
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,23 +724,28 @@ export const getSystemVariables = (t: TFunction): EditorVariablePickerType[] =>
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: 'appId',
|
key: 'appId',
|
||||||
label: t('core.module.http.AppId')
|
label: t('core.module.http.AppId'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'chatId',
|
key: 'chatId',
|
||||||
label: t('core.module.http.ChatId')
|
label: t('core.module.http.ChatId'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'responseChatItemId',
|
key: 'responseChatItemId',
|
||||||
label: t('core.module.http.ResponseChatItemId')
|
label: t('core.module.http.ResponseChatItemId'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'histories',
|
key: 'histories',
|
||||||
label: t('core.module.http.Histories')
|
label: t('core.module.http.Histories'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.chatHistory
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'cTime',
|
key: 'cTime',
|
||||||
label: t('core.module.http.Current time')
|
label: t('core.module.http.Current time'),
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
StoreNodeItemType
|
StoreNodeItemType
|
||||||
} from '@fastgpt/global/core/workflow/type';
|
} from '@fastgpt/global/core/workflow/type';
|
||||||
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
|
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { getHandleId, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { LLMModelTypeEnum } from '@fastgpt/global/core/ai/constants';
|
import { LLMModelTypeEnum } from '@fastgpt/global/core/ai/constants';
|
||||||
import {
|
import {
|
||||||
@ -24,8 +24,10 @@ import {
|
|||||||
FlowNodeOutputItemType
|
FlowNodeOutputItemType
|
||||||
} from '@fastgpt/global/core/workflow/type/io';
|
} from '@fastgpt/global/core/workflow/type/io';
|
||||||
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
import { getWorkflowGlobalVariables } from './utils';
|
||||||
|
import { TFunction } from 'next-i18next';
|
||||||
|
|
||||||
export const systemConfigNode2VariableNode = (node: FlowNodeItemType) => {
|
export const getGlobalVariableNode = (nodes: FlowNodeItemType[], t: TFunction) => {
|
||||||
const template: FlowNodeTemplateType = {
|
const template: FlowNodeTemplateType = {
|
||||||
id: FlowNodeTypeEnum.globalVariable,
|
id: FlowNodeTypeEnum.globalVariable,
|
||||||
templateType: FlowNodeTemplateTypeEnum.other,
|
templateType: FlowNodeTemplateTypeEnum.other,
|
||||||
@ -41,17 +43,17 @@ export const systemConfigNode2VariableNode = (node: FlowNodeItemType) => {
|
|||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
const { variableModules } = splitGuideModule(node);
|
const globalVariables = getWorkflowGlobalVariables(nodes, t);
|
||||||
|
|
||||||
const variableNode: FlowNodeItemType = {
|
const variableNode: FlowNodeItemType = {
|
||||||
nodeId: VARIABLE_NODE_ID,
|
nodeId: VARIABLE_NODE_ID,
|
||||||
...template,
|
...template,
|
||||||
outputs: variableModules.map((item) => ({
|
outputs: globalVariables.map((item) => ({
|
||||||
id: item.key,
|
id: item.key,
|
||||||
type: FlowNodeOutputTypeEnum.dynamic,
|
type: FlowNodeOutputTypeEnum.static,
|
||||||
label: item.label,
|
label: item.label,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
valueType: WorkflowIOValueTypeEnum.any
|
valueType: item.valueType || WorkflowIOValueTypeEnum.any
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -13,9 +13,17 @@ import {
|
|||||||
import { EmptyNode } from '@fastgpt/global/core/workflow/template/system/emptyNode';
|
import { EmptyNode } from '@fastgpt/global/core/workflow/template/system/emptyNode';
|
||||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { systemConfigNode2VariableNode } from './adapt';
|
import { getGlobalVariableNode } from './adapt';
|
||||||
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
|
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { EditorVariablePickerType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
|
||||||
|
import {
|
||||||
|
formatEditorVariablePickerIcon,
|
||||||
|
getGuideModule,
|
||||||
|
splitGuideModule
|
||||||
|
} from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { getSystemVariables } from '../app/utils';
|
||||||
|
import { TFunction } from 'next-i18next';
|
||||||
|
|
||||||
export const nodeTemplate2FlowNode = ({
|
export const nodeTemplate2FlowNode = ({
|
||||||
template,
|
template,
|
||||||
@ -97,11 +105,13 @@ export const storeEdgesRenderEdge = ({ edge }: { edge: StoreEdgeItemType }) => {
|
|||||||
export const computedNodeInputReference = ({
|
export const computedNodeInputReference = ({
|
||||||
nodeId,
|
nodeId,
|
||||||
nodes,
|
nodes,
|
||||||
edges
|
edges,
|
||||||
|
t
|
||||||
}: {
|
}: {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
nodes: FlowNodeItemType[];
|
nodes: FlowNodeItemType[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
|
t: TFunction;
|
||||||
}) => {
|
}) => {
|
||||||
// get current node
|
// get current node
|
||||||
const node = nodes.find((item) => item.nodeId === nodeId);
|
const node = nodes.find((item) => item.nodeId === nodeId);
|
||||||
@ -126,14 +136,7 @@ export const computedNodeInputReference = ({
|
|||||||
};
|
};
|
||||||
findSourceNode(nodeId);
|
findSourceNode(nodeId);
|
||||||
|
|
||||||
// add system config node
|
sourceNodes.unshift(getGlobalVariableNode(nodes, t));
|
||||||
const systemConfigNode = nodes.find(
|
|
||||||
(item) => item.flowNodeType === FlowNodeTypeEnum.systemConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
if (systemConfigNode) {
|
|
||||||
sourceNodes.unshift(systemConfigNode2VariableNode(systemConfigNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sourceNodes;
|
return sourceNodes;
|
||||||
};
|
};
|
||||||
@ -232,3 +235,17 @@ export const filterSensitiveNodesData = (nodes: StoreNodeItemType[]) => {
|
|||||||
});
|
});
|
||||||
return cloneNodes;
|
return cloneNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* get workflowStart output to global variables */
|
||||||
|
export const getWorkflowGlobalVariables = (
|
||||||
|
nodes: FlowNodeItemType[],
|
||||||
|
t: TFunction
|
||||||
|
): EditorVariablePickerType[] => {
|
||||||
|
const globalVariables = formatEditorVariablePickerIcon(
|
||||||
|
splitGuideModule(getGuideModule(nodes))?.variableModules || []
|
||||||
|
);
|
||||||
|
|
||||||
|
const systemVariables = getSystemVariables(t);
|
||||||
|
|
||||||
|
return [...globalVariables, ...systemVariables];
|
||||||
|
};
|
||||||
|
|||||||
@ -1,26 +1,40 @@
|
|||||||
import { GET, POST, DELETE } from '@/web/common/api/request';
|
import { GET, POST, DELETE } from '@/web/common/api/request';
|
||||||
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
|
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
|
||||||
|
|
||||||
/**
|
// create a shareChat
|
||||||
* create a shareChat
|
export function createShareChat<T>(
|
||||||
*/
|
data: OutLinkEditType<T> & {
|
||||||
export const createShareChat = (
|
|
||||||
data: OutLinkEditType & {
|
|
||||||
appId: string;
|
appId: string;
|
||||||
type: OutLinkSchema['type'];
|
type: OutLinkSchema['type'];
|
||||||
}
|
}
|
||||||
) => POST<string>(`/support/outLink/create`, data);
|
) {
|
||||||
|
return POST<string>(`/support/outLink/create`, data);
|
||||||
|
}
|
||||||
|
|
||||||
export const putShareChat = (data: OutLinkEditType) =>
|
export const putShareChat = (data: OutLinkEditType) =>
|
||||||
POST<string>(`/support/outLink/update`, data);
|
POST<string>(`/support/outLink/update`, data);
|
||||||
|
|
||||||
/**
|
// get shareChat
|
||||||
* get shareChat
|
export function getShareChatList<T>(data: { appId: string; type: OutLinkSchema<T>['type'] }) {
|
||||||
*/
|
return GET<OutLinkSchema<T>[]>(`/support/outLink/list`, data);
|
||||||
export const getShareChatList = (appId: string) =>
|
}
|
||||||
GET<OutLinkSchema[]>(`/support/outLink/list`, { appId });
|
|
||||||
|
|
||||||
/**
|
// delete a shareChat
|
||||||
* delete a shareChat
|
export function delShareChatById(id: string) {
|
||||||
*/
|
return DELETE(`/support/outLink/delete?id=${id}`);
|
||||||
export const delShareChatById = (id: string) => DELETE(`/support/outLink/delete?id=${id}`);
|
}
|
||||||
|
|
||||||
|
// update a shareChat
|
||||||
|
export function updateShareChat<T>(data: OutLinkEditType<T>) {
|
||||||
|
return POST<string>(`/support/outLink/update`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * create a shareChat
|
||||||
|
// */
|
||||||
|
// export const createWecomLinkChat = (
|
||||||
|
// data: OutLinkConfigEditType & {
|
||||||
|
// appId: string;
|
||||||
|
// type: OutLinkSchema['type'];
|
||||||
|
// }
|
||||||
|
// ) => POST<string>(`/support/outLink/create`, data);
|
||||||
|
|||||||
@ -57,7 +57,7 @@ export const useSendCode = () => {
|
|||||||
}
|
}
|
||||||
setCodeSending(false);
|
setCodeSending(false);
|
||||||
},
|
},
|
||||||
[codeCountDown, toast]
|
[codeCountDown, feConfigs?.googleClientVerKey, toast]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user