From f7bc95b64287c121d928321d2bd5ed6eb55f3811 Mon Sep 17 00:00:00 2001 From: joe Date: Wed, 15 Jan 2025 13:29:06 +0800 Subject: [PATCH] [WIP] transition form --- web/apps/web/src/app/container.ts | 4 -- web/apps/web/src/components/app/edges/type.ts | 6 -- .../components/app/edges/x-custom-edge.tsx | 12 ++-- .../app/new-transition-sheet/index.tsx | 70 ++++++++++--------- .../app/new-transition-sheet/utils/index.ts | 0 .../app/nodes/condition-state-node/index.tsx | 10 +-- .../app/nodes/x-intro-node/index.tsx | 10 +-- .../app/nodes/x-state-node/index.tsx | 12 ++-- .../stores/app/models/app-builder.model.ts | 19 +---- .../app/schema/get-transition-schema.ts | 7 +- web/apps/web/src/stores/app/use-app-state.tsx | 11 ++- web/apps/web/src/types/app/types.ts | 9 --- .../shared/src/protocol/transition/index.ts | 12 +++- 13 files changed, 87 insertions(+), 95 deletions(-) create mode 100644 web/apps/web/src/components/app/new-transition-sheet/utils/index.ts diff --git a/web/apps/web/src/app/container.ts b/web/apps/web/src/app/container.ts index 5c1f3ab0..7cabcc8f 100644 --- a/web/apps/web/src/app/container.ts +++ b/web/apps/web/src/app/container.ts @@ -123,10 +123,6 @@ export const webModule = new ContainerModule(bind => { return model.nodeData; }; /* eslint-disable no-underscore-dangle, func-names */ - (window as any)._get_app_builder_transitions_data = function () { - return model.transitionsData; - }; - /* eslint-disable no-underscore-dangle, func-names */ (window as any)._get_app_builder_scopes = function () { return model.scopes; }; diff --git a/web/apps/web/src/components/app/edges/type.ts b/web/apps/web/src/components/app/edges/type.ts index 2aebd9aa..8a114f2d 100644 --- a/web/apps/web/src/components/app/edges/type.ts +++ b/web/apps/web/src/components/app/edges/type.ts @@ -33,10 +33,4 @@ export type CustomEdgeData = { display_name?: string; }; -export type XCustomEdgeData = { - id?: string; - type?: TransitionTargetEnum; - display_name?: string; -}; - export type ICustomEdge = Edge; diff --git a/web/apps/web/src/components/app/edges/x-custom-edge.tsx b/web/apps/web/src/components/app/edges/x-custom-edge.tsx index a7a15ee1..5e8fc500 100644 --- a/web/apps/web/src/components/app/edges/x-custom-edge.tsx +++ b/web/apps/web/src/components/app/edges/x-custom-edge.tsx @@ -13,8 +13,11 @@ import React, { useEffect } from 'react'; import { useAppState } from '@/stores/app/use-app-state'; import { AppBuilderModel } from '@/stores/app/models/app-builder.model'; -import { XCustomEdgeData } from './type'; -import { TransitionTypeEnum } from '@shellagent/shared/protocol/transition'; + +import { + TransitionTypeEnum, + TransitionData, +} from '@shellagent/shared/protocol/transition'; export const XCustomEdge = ({ id, sourceX, @@ -29,7 +32,7 @@ export const XCustomEdge = ({ source, sourceHandleId, data, -}: EdgeProps) => { +}: EdgeProps) => { const appBuilder = useInjection('AppBuilderModel'); const [edgePath] = getBezierPath({ sourceX: sourceX - 8, @@ -76,6 +79,7 @@ export const XCustomEdge = ({ open: true, source, sourceHandle: sourceHandleId || '', + id, data: { ...(data || {}), id, @@ -103,7 +107,7 @@ export const XCustomEdge = ({ = observer(() => { const appBuilder = useInjection('AppBuilderModel'); + const { setEdges, onChangeEdgeData, edges } = useReactFlowStore(state => ({ + setEdges: state.setEdges, + onChangeEdgeData: state.onChangeEdgeData, + edges: state.edges, + })); + const { sourceHandle, source, - currentEdegData, + currentEdgeId, newTransitionSheetOpen, setNewTransitionSheetOpen, transitionType, @@ -30,59 +36,57 @@ const TransitionSheetNew: React.FC<{}> = observer(() => { source: state.currentTransitionSource, newTransitionSheetOpen: state.newTransitionSheetOpen, setNewTransitionSheetOpen: state.setNewTransitionSheetOpen, - currentEdegData: state.currentEdegData, + currentEdgeId: state.currentEdgeId, transitionType: state.transitionType, })); - const handleId = currentEdegData?.id as string; - const handleClose = useCallback(() => { setNewTransitionSheetOpen({ open: false, source: '', sourceHandle: '' }); }, []); + const edgeData = edges.find(edge => edge.id === currentEdgeId) + ?.data as TransitionData; + const handleChange = useCallback( (values: TransitionData) => { - appBuilder.setTransitionsData( - currentEdegData?.source || '', - handleId, - values, - ); + if (edgeData?.target !== values.target) { + const currentEdge = edges.find(edge => edge.id === currentEdgeId); + if (currentEdge) { + setEdges( + edges.map(edge => { + if (edge.id === currentEdge.id) { + return { + ...edge, + target: values.target, + data: values, + }; + } + return edge; + }), + ); + } + } else { + onChangeEdgeData(currentEdgeId, values); + } }, - [currentEdegData?.source, handleId], + [edgeData, edges, setEdges, onChangeEdgeData, currentEdgeId], ); const schema = useMemo(() => { return getXTransitionSchema( - appBuilder.nodeData[currentEdegData?.target || '']?.inputs ?? {}, + appBuilder.nodeData[edgeData?.target || '']?.inputs ?? {}, transitionType, ); - }, [appBuilder.nodeData, currentEdegData, transitionType]); + }, [appBuilder.nodeData, edgeData, transitionType]); const title = useMemo(() => { - const name = - appBuilder.transitionsData[currentEdegData?.source || '']?.[handleId] - ?.name; return ( { - if (currentEdegData?.source) { - appBuilder.setTransitionsData(currentEdegData.source, handleId, { - ...appBuilder.transitionsData[currentEdegData.source][handleId], - name: value, - }); - } - }} + value={edgeData?.name} + onChange={value => handleChange({ ...edgeData, name: value })} /> ); - }, [appBuilder.transitionsData, currentEdegData?.source]); - - const values = useMemo(() => { - return ( - appBuilder.transitionsData[currentEdegData?.source || '']?.[handleId] || - {} - ); - }, [appBuilder.transitionsData, currentEdegData?.source, handleId]); + }, [edgeData]); return ( = observer(() => { parent="condition.twitter" key={sourceHandle} schema={schema} - values={values} + values={edgeData} onChange={values => handleChange(values as TransitionData)} /> diff --git a/web/apps/web/src/components/app/new-transition-sheet/utils/index.ts b/web/apps/web/src/components/app/new-transition-sheet/utils/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/web/apps/web/src/components/app/nodes/condition-state-node/index.tsx b/web/apps/web/src/components/app/nodes/condition-state-node/index.tsx index 1c65d639..97adacfe 100644 --- a/web/apps/web/src/components/app/nodes/condition-state-node/index.tsx +++ b/web/apps/web/src/components/app/nodes/condition-state-node/index.tsx @@ -21,7 +21,8 @@ import { useKeyPress } from 'ahooks'; import { useInjection } from 'inversify-react'; import React, { useCallback, useRef, useEffect, useState } from 'react'; -import { EdgeDataTypeEnum, EdgeTypeEnum } from '@/components/app/edges'; +import { TransitionTargetEnum } from '@shellagent/shared/protocol/transition'; +import { EdgeTypeEnum } from '@/components/app/edges'; import NodeCard from '@/components/app/node-card'; import NodeForm from '@/components/app/node-form'; import { AppBuilderModel } from '@/stores/app/models/app-builder.model'; @@ -180,11 +181,12 @@ const ConditionStateNode: React.FC> = ({ type: EdgeTypeEnum.custom, data: { id: data.id, - custom: true, - type: EdgeDataTypeEnum.ALWAYS, + name: 'transition', + timers: {}, + type: TransitionTargetEnum.ALWAYS, source: connection.source, target: connection.target, - conditions: [], + target_inputs: {}, }, style: { stroke: '#B6BABF', diff --git a/web/apps/web/src/components/app/nodes/x-intro-node/index.tsx b/web/apps/web/src/components/app/nodes/x-intro-node/index.tsx index b90cfd8c..cbc0d9bf 100644 --- a/web/apps/web/src/components/app/nodes/x-intro-node/index.tsx +++ b/web/apps/web/src/components/app/nodes/x-intro-node/index.tsx @@ -14,7 +14,7 @@ import { FormRef } from '@shellagent/ui'; import { useInjection } from 'inversify-react'; import React, { useCallback, useRef, useEffect, useState } from 'react'; -import { EdgeDataTypeEnum, EdgeTypeEnum } from '@/components/app/edges'; +import { EdgeTypeEnum } from '@/components/app/edges'; import NodeCard from '@/components/app/node-card'; import NodeForm from '@/components/app/node-form'; import { AppBuilderModel } from '@/stores/app/models/app-builder.model'; @@ -24,6 +24,7 @@ import emitter, { } from '@/stores/app/models/emitter'; import { useAppState } from '@/stores/app/use-app-state'; import { getXStateSchema } from '@/stores/app/schema/get-x-state-schema'; +import { TransitionTargetEnum } from '@shellagent/shared/protocol/transition'; const IntroNode: React.FC> = ({ selected, data }) => { const stateFormRef = useRef(null); @@ -97,11 +98,12 @@ const IntroNode: React.FC> = ({ selected, data }) => { type: EdgeTypeEnum.custom, data: { id: data.id, - custom: true, - type: EdgeDataTypeEnum.ALWAYS, + name: 'transition', + timers: {}, + type: TransitionTargetEnum.TIMER, source: connection.source, target: connection.target, - conditions: [], + target_inputs: {}, }, style: { stroke: '#B6BABF', diff --git a/web/apps/web/src/components/app/nodes/x-state-node/index.tsx b/web/apps/web/src/components/app/nodes/x-state-node/index.tsx index 27d3a028..d1c274c7 100644 --- a/web/apps/web/src/components/app/nodes/x-state-node/index.tsx +++ b/web/apps/web/src/components/app/nodes/x-state-node/index.tsx @@ -19,9 +19,10 @@ import { customSnakeCase, getTaskDisplayName } from '@shellagent/shared/utils'; import { FormRef } from '@shellagent/ui'; import { useKeyPress } from 'ahooks'; import { useInjection } from 'inversify-react'; -import React, { useCallback, useRef, useEffect, useState } from 'react'; -import { EdgeDataTypeEnum, EdgeTypeEnum } from '@/components/app/edges'; +import React, { useCallback, useRef, useEffect, useState } from 'react'; +import { TransitionTargetEnum } from '@shellagent/shared/protocol/transition'; +import { EdgeTypeEnum } from '@/components/app/edges'; import NodeCard from '@/components/app/node-card'; import NodeForm from '@/components/app/node-form'; import { AppBuilderModel } from '@/stores/app/models/app-builder.model'; @@ -177,11 +178,12 @@ const XStateNode: React.FC> = ({ selected, data }) => { type: EdgeTypeEnum.custom, data: { id: data.id, - custom: true, - type: EdgeDataTypeEnum.ALWAYS, + name: 'transition', + timers: {}, + type: TransitionTargetEnum.ALWAYS, source: connection.source, target: connection.target, - conditions: [], + target_inputs: {}, }, style: { stroke: '#B6BABF', diff --git a/web/apps/web/src/stores/app/models/app-builder.model.ts b/web/apps/web/src/stores/app/models/app-builder.model.ts index d79cf941..59cd19f9 100644 --- a/web/apps/web/src/stores/app/models/app-builder.model.ts +++ b/web/apps/web/src/stores/app/models/app-builder.model.ts @@ -59,14 +59,8 @@ import { genAutomata, formatReactFlow2Flow, } from '@/stores/app/utils/data-transformer'; -import type { - Config, - Metadata, - NodeDataType, - TransitionDataType, -} from '@/types/app/types'; +import type { Config, Metadata, NodeDataType } from '@/types/app/types'; import { ToastModel } from '@/utils/toast.model'; -import { type TransitionData } from '@shellagent/shared/protocol/transition'; import { CascaderOption, convertRefOptsToCascaderOpts, @@ -87,7 +81,6 @@ const settingsDisabled = process.env.NEXT_PUBLIC_DISABLE_SETTING === 'yes'; @injectable() export class AppBuilderModel { nodeData: NodeDataType = {}; - transitionsData: TransitionDataType = {}; @observable rerenderButtons: Record = {}; @observable metadata: Metadata = { name: '', @@ -178,8 +171,6 @@ export class AppBuilderModel { eventKey, ); - console.log('refOpts>>', refOpts); - const cascaderOpts = convertRefOptsToCascaderOpts(refOpts); return cascaderOpts; } @@ -195,14 +186,6 @@ export class AppBuilderModel { this.nodeData[id] = data; } - @action.bound - setTransitionsData(id: string, handleId: string, data: TransitionData) { - if (!this.transitionsData[id]) { - this.transitionsData[id] = {}; - } - this.transitionsData[id][handleId] = data; - } - @action.bound deleteNodeData(id: string) { delete this.nodeData[id]; diff --git a/web/apps/web/src/stores/app/schema/get-transition-schema.ts b/web/apps/web/src/stores/app/schema/get-transition-schema.ts index c8a7842e..b0003ce9 100644 --- a/web/apps/web/src/stores/app/schema/get-transition-schema.ts +++ b/web/apps/web/src/stores/app/schema/get-transition-schema.ts @@ -23,12 +23,7 @@ export const getXTransitionSchema = ( properties: { name: { type: 'string', - default: 'transition', - 'x-hidden': true, - }, - id: { - type: 'string', - default: generateUUID(), + 'x-type': 'Control', 'x-hidden': true, }, type: { diff --git a/web/apps/web/src/stores/app/use-app-state.tsx b/web/apps/web/src/stores/app/use-app-state.tsx index 1134f9c7..5ae5ec17 100644 --- a/web/apps/web/src/stores/app/use-app-state.tsx +++ b/web/apps/web/src/stores/app/use-app-state.tsx @@ -22,6 +22,7 @@ export type State = { currentEdegData: CustomEdgeData; targetInputsSheetOpen: boolean; transitionType: TransitionTypeEnum; + currentEdgeId: string; }; type Action = { @@ -40,6 +41,7 @@ type Action = { sourceHandle: string; data?: CustomEdgeData; transitionType?: TransitionTypeEnum; + id?: string; }) => void; setNewTransitionSheetOpen: (params: { open: boolean; @@ -47,6 +49,7 @@ type Action = { sourceHandle: string; data?: CustomEdgeData; transitionType?: TransitionTypeEnum; + id?: string; }) => void; setTargetInputsSheetOpen: (open: State['targetInputsSheetOpen']) => void; setRunDrawerWidth: (width: number) => void; @@ -59,6 +62,7 @@ const initialState: State = { newTransitionSheetOpen: false, selectedNode: undefined, currentStateId: '', + currentEdgeId: '', currentButtonId: '', insideSheetOpen: false, insideSheetMode: '', @@ -113,7 +117,7 @@ export const useAppState = create(set => ({ } return state; }), - setTransitionSheetOpen: ({ open, source, sourceHandle, data }) => { + setTransitionSheetOpen: ({ open, source, sourceHandle, data, id }) => { set(() => { if (open) { return { @@ -123,6 +127,7 @@ export const useAppState = create(set => ({ currentEdegData: data || undefined, stateConfigSheetOpen: false, currentStateId: '', + currentEdgeId: id, insideSheetOpen: false, insideSheetMode: '', currentButtonId: '', @@ -136,6 +141,7 @@ export const useAppState = create(set => ({ currentEdegData: undefined, targetInputsSheetOpen: false, transitionType: TransitionTypeEnum.intro, + currentEdgeId: '', }; }); }, @@ -145,6 +151,7 @@ export const useAppState = create(set => ({ sourceHandle, data, transitionType, + id, }) => { set(() => { if (open) { @@ -160,6 +167,7 @@ export const useAppState = create(set => ({ insideSheetMode: '', currentButtonId: '', currentTaskIndex: undefined, + currentEdgeId: id, }; } return { @@ -169,6 +177,7 @@ export const useAppState = create(set => ({ currentEdegData: undefined, targetInputsSheetOpen: false, transitionType: TransitionTypeEnum.intro, + currentEdgeId: '', }; }); }, diff --git a/web/apps/web/src/types/app/types.ts b/web/apps/web/src/types/app/types.ts index ac5c27c9..13d4da53 100644 --- a/web/apps/web/src/types/app/types.ts +++ b/web/apps/web/src/types/app/types.ts @@ -4,10 +4,6 @@ import { Automata } from '@shellagent/pro-config'; import { Refs } from '@shellagent/shared/protocol/app-scope'; import { Issue } from '@shellagent/shared/type'; import { Metadata } from '@/services/home/type'; -import { - TransitionData, - TransitionTargetType, -} from '@shellagent/shared/protocol/transition'; export type Config = { // 弃用 @@ -26,8 +22,3 @@ export type ShellAgent = { export type { Metadata }; export type NodeDataType = Record; - -export type TransitionDataType = Record< - string, - Record ->; diff --git a/web/packages/shared/src/protocol/transition/index.ts b/web/packages/shared/src/protocol/transition/index.ts index b4244fec..256536ce 100644 --- a/web/packages/shared/src/protocol/transition/index.ts +++ b/web/packages/shared/src/protocol/transition/index.ts @@ -3,14 +3,15 @@ import { timerSchema } from '../pro-config'; import { NodeTypeEnum } from '../node'; export type TransitionData = { + id: string; name: string; type: TransitionTargetEnum; timers: z.infer; + source: string; target: string; target_inputs: { [key: string]: any; }; - id: string; }; export enum TransitionTypeEnum { @@ -19,6 +20,7 @@ export enum TransitionTypeEnum { condition_state = NodeTypeEnum.condition_state, } +// 临时 export enum TransitionTargetEnum { 'X.MENTIONED' = 'X.MENTIONED', 'X.PINNED.REPLIED' = 'X.PINNED.REPLIED', @@ -38,3 +40,11 @@ export type TransitionTargetType = | 'X.PINNED.REPLIED' | 'ALWAYS' | 'CHAT'; + +export const transitionTargetTypeSchema = z.union([ + z.literal('X.MENTIONED'), + z.literal('X.PINNED.REPLIED'), + z.literal('ALWAYS'), + z.literal('CHAT'), + z.string().uuid(), +]);