mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-07-10 15:51:46 +08:00
Feat: support agent version history. (#6130)
### What problem does this PR solve? Add history version save - Allows users to view and download agent files by version revision history  _Briefly describe what this PR aims to solve. Include background context that will help reviewers understand the purpose of the PR._ ### Type of change - [ ] Bug Fix (non-breaking change which fixes an issue) - [x] New Feature (non-breaking change which adds functionality) - [ ] Documentation Update - [ ] Refactoring - [ ] Performance Improvement - [ ] Other (please describe): --------- Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
parent
e689532e6e
commit
53ac27c3ff
@ -18,13 +18,14 @@ import traceback
|
|||||||
from flask import request, Response
|
from flask import request, Response
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
|
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
|
||||||
|
from api.db.services.user_canvas_version import UserCanvasVersionService
|
||||||
from api.settings import RetCode
|
from api.settings import RetCode
|
||||||
from api.utils import get_uuid
|
from api.utils import get_uuid
|
||||||
from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
|
from api.utils.api_utils import get_json_result, server_error_response, validate_request, get_data_error_result
|
||||||
from agent.canvas import Canvas
|
from agent.canvas import Canvas
|
||||||
from peewee import MySQLDatabase, PostgresqlDatabase
|
from peewee import MySQLDatabase, PostgresqlDatabase
|
||||||
from api.db.db_models import APIToken
|
from api.db.db_models import APIToken
|
||||||
|
import time
|
||||||
|
|
||||||
@manager.route('/templates', methods=['GET']) # noqa: F821
|
@manager.route('/templates', methods=['GET']) # noqa: F821
|
||||||
@login_required
|
@login_required
|
||||||
@ -61,7 +62,6 @@ def save():
|
|||||||
req["user_id"] = current_user.id
|
req["user_id"] = current_user.id
|
||||||
if not isinstance(req["dsl"], str):
|
if not isinstance(req["dsl"], str):
|
||||||
req["dsl"] = json.dumps(req["dsl"], ensure_ascii=False)
|
req["dsl"] = json.dumps(req["dsl"], ensure_ascii=False)
|
||||||
|
|
||||||
req["dsl"] = json.loads(req["dsl"])
|
req["dsl"] = json.loads(req["dsl"])
|
||||||
if "id" not in req:
|
if "id" not in req:
|
||||||
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
|
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
|
||||||
@ -75,9 +75,14 @@ def save():
|
|||||||
data=False, message='Only owner of canvas authorized for this operation.',
|
data=False, message='Only owner of canvas authorized for this operation.',
|
||||||
code=RetCode.OPERATING_ERROR)
|
code=RetCode.OPERATING_ERROR)
|
||||||
UserCanvasService.update_by_id(req["id"], req)
|
UserCanvasService.update_by_id(req["id"], req)
|
||||||
|
# save version
|
||||||
|
UserCanvasVersionService.insert( user_canvas_id=req["id"], dsl=req["dsl"], title="{0}_{1}".format(req["title"], time.strftime("%Y_%m_%d_%H_%M_%S")))
|
||||||
|
UserCanvasVersionService.delete_all_versions(req["id"])
|
||||||
return get_json_result(data=req)
|
return get_json_result(data=req)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@manager.route('/get/<canvas_id>', methods=['GET']) # noqa: F821
|
@manager.route('/get/<canvas_id>', methods=['GET']) # noqa: F821
|
||||||
@login_required
|
@login_required
|
||||||
def get(canvas_id):
|
def get(canvas_id):
|
||||||
@ -284,3 +289,27 @@ def test_db_connect():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return server_error_response(e)
|
return server_error_response(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#api get list version dsl of canvas
|
||||||
|
@manager.route('/getlistversion/<canvas_id>', methods=['GET']) # noqa: F821
|
||||||
|
@login_required
|
||||||
|
def getlistversion(canvas_id):
|
||||||
|
try:
|
||||||
|
list =sorted([c.to_dict() for c in UserCanvasVersionService.list_by_canvas_id(canvas_id)], key=lambda x: x["update_time"]*-1)
|
||||||
|
return get_json_result(data=list)
|
||||||
|
except Exception as e:
|
||||||
|
return get_data_error_result(message=f"Error getting history files: {e}")
|
||||||
|
|
||||||
|
#api get version dsl of canvas
|
||||||
|
@manager.route('/getversion/<version_id>', methods=['GET']) # noqa: F821
|
||||||
|
@login_required
|
||||||
|
def getversion( version_id):
|
||||||
|
try:
|
||||||
|
|
||||||
|
e, version = UserCanvasVersionService.get_by_id(version_id)
|
||||||
|
if version:
|
||||||
|
return get_json_result(data=version.to_dict())
|
||||||
|
except Exception as e:
|
||||||
|
return get_json_result(data=f"Error getting history file: {e}")
|
||||||
|
@ -988,6 +988,16 @@ class CanvasTemplate(DataBaseModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
db_table = "canvas_template"
|
db_table = "canvas_template"
|
||||||
|
|
||||||
|
class UserCanvasVersion(DataBaseModel):
|
||||||
|
id = CharField(max_length=32, primary_key=True)
|
||||||
|
user_canvas_id = CharField(max_length=255, null=False, help_text="user_canvas_id", index=True)
|
||||||
|
|
||||||
|
title = CharField(max_length=255, null=True, help_text="Canvas title")
|
||||||
|
description = TextField(null=True, help_text="Canvas description")
|
||||||
|
dsl = JSONField(null=True, default={})
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "user_canvas_version"
|
||||||
|
|
||||||
def migrate_db():
|
def migrate_db():
|
||||||
with DB.transaction():
|
with DB.transaction():
|
||||||
|
43
api/db/services/user_canvas_version.py
Normal file
43
api/db/services/user_canvas_version.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from api.db.db_models import UserCanvasVersion, DB
|
||||||
|
from api.db.services.common_service import CommonService
|
||||||
|
from peewee import DoesNotExist
|
||||||
|
|
||||||
|
class UserCanvasVersionService(CommonService):
|
||||||
|
model = UserCanvasVersion
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@DB.connection_context()
|
||||||
|
def list_by_canvas_id(cls, user_canvas_id):
|
||||||
|
try:
|
||||||
|
user_canvas_version = cls.model.select(
|
||||||
|
*[cls.model.id,
|
||||||
|
cls.model.create_time,
|
||||||
|
cls.model.title,
|
||||||
|
cls.model.create_date,
|
||||||
|
cls.model.update_date,
|
||||||
|
cls.model.user_canvas_id,
|
||||||
|
cls.model.update_time]
|
||||||
|
).where(cls.model.user_canvas_id == user_canvas_id)
|
||||||
|
return user_canvas_version
|
||||||
|
except DoesNotExist:
|
||||||
|
return None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@DB.connection_context()
|
||||||
|
def delete_all_versions(cls, user_canvas_id):
|
||||||
|
try:
|
||||||
|
user_canvas_version = cls.model.select().where(cls.model.user_canvas_id == user_canvas_id).order_by(cls.model.create_time.desc())
|
||||||
|
if user_canvas_version.count() > 20:
|
||||||
|
for i in range(20, user_canvas_version.count()):
|
||||||
|
cls.delete(user_canvas_version[i].id)
|
||||||
|
return True
|
||||||
|
except DoesNotExist:
|
||||||
|
return None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,6 +17,8 @@ services:
|
|||||||
- ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf
|
- ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf
|
||||||
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
|
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
|
||||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ../history_data_agent:/ragflow/history_data_agent
|
||||||
|
|
||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
|
@ -90,6 +90,53 @@ export const useFetchFlowList = (): { data: IFlow[]; loading: boolean } => {
|
|||||||
return { data, loading };
|
return { data, loading };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useFetchListVersion = (
|
||||||
|
canvas_id: string,
|
||||||
|
): {
|
||||||
|
data: {
|
||||||
|
created_at: string;
|
||||||
|
title: string;
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
|
loading: boolean;
|
||||||
|
} => {
|
||||||
|
const { data, isFetching: loading } = useQuery({
|
||||||
|
queryKey: ['fetchListVersion'],
|
||||||
|
initialData: [],
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await flowService.getListVersion({}, canvas_id);
|
||||||
|
|
||||||
|
return data?.data ?? [];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchVersion = (
|
||||||
|
version_id?: string,
|
||||||
|
): {
|
||||||
|
data?: IFlow;
|
||||||
|
loading: boolean;
|
||||||
|
} => {
|
||||||
|
const { data, isFetching: loading } = useQuery({
|
||||||
|
queryKey: ['fetchVersion', version_id],
|
||||||
|
initialData: undefined,
|
||||||
|
gcTime: 0,
|
||||||
|
enabled: !!version_id, // Only call API when both values are provided
|
||||||
|
queryFn: async () => {
|
||||||
|
if (!version_id) return undefined;
|
||||||
|
|
||||||
|
const { data } = await flowService.getVersion({}, version_id);
|
||||||
|
|
||||||
|
return data?.data ?? undefined;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading };
|
||||||
|
};
|
||||||
|
|
||||||
export const useFetchFlow = (): {
|
export const useFetchFlow = (): {
|
||||||
data: IFlow;
|
data: IFlow;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -1194,6 +1194,16 @@ This delimiter is used to split the input text into several text pieces echo of
|
|||||||
nextStep: 'Next step',
|
nextStep: 'Next step',
|
||||||
datatype: 'MINE type of the HTTP request',
|
datatype: 'MINE type of the HTTP request',
|
||||||
insertVariableTip: `Enter / Insert variables`,
|
insertVariableTip: `Enter / Insert variables`,
|
||||||
|
historyversion: 'History version',
|
||||||
|
filename: 'File name',
|
||||||
|
version: {
|
||||||
|
created: 'Created',
|
||||||
|
details: 'Version details',
|
||||||
|
dsl: 'DSL',
|
||||||
|
download: 'Download',
|
||||||
|
version: 'Version',
|
||||||
|
select: 'No version selected',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
profile: 'All rights reserved @ React',
|
profile: 'All rights reserved @ React',
|
||||||
|
@ -46,7 +46,7 @@ import { RewriteNode } from './node/rewrite-node';
|
|||||||
import { SwitchNode } from './node/switch-node';
|
import { SwitchNode } from './node/switch-node';
|
||||||
import { TemplateNode } from './node/template-node';
|
import { TemplateNode } from './node/template-node';
|
||||||
|
|
||||||
const nodeTypes: NodeTypes = {
|
export const nodeTypes: NodeTypes = {
|
||||||
ragNode: RagNode,
|
ragNode: RagNode,
|
||||||
categorizeNode: CategorizeNode,
|
categorizeNode: CategorizeNode,
|
||||||
beginNode: BeginNode,
|
beginNode: BeginNode,
|
||||||
@ -66,7 +66,7 @@ const nodeTypes: NodeTypes = {
|
|||||||
iterationStartNode: IterationStartNode,
|
iterationStartNode: IterationStartNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
const edgeTypes = {
|
export const edgeTypes = {
|
||||||
buttonEdge: ButtonEdge,
|
buttonEdge: ButtonEdge,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@ import {
|
|||||||
} from '../hooks/use-save-graph';
|
} from '../hooks/use-save-graph';
|
||||||
import { BeginQuery } from '../interface';
|
import { BeginQuery } from '../interface';
|
||||||
|
|
||||||
|
import {
|
||||||
|
HistoryVersionModal,
|
||||||
|
useHistoryVersionModal,
|
||||||
|
} from '../history-version-modal';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -36,7 +40,8 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|||||||
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
||||||
useShowEmbedModal();
|
useShowEmbedModal();
|
||||||
const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe();
|
const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe();
|
||||||
|
const { setVisibleHistoryVersionModal, visibleHistoryVersionModal } =
|
||||||
|
useHistoryVersionModal();
|
||||||
const handleShowEmbedModal = useCallback(() => {
|
const handleShowEmbedModal = useCallback(() => {
|
||||||
showEmbedModal();
|
showEmbedModal();
|
||||||
}, [showEmbedModal]);
|
}, [showEmbedModal]);
|
||||||
@ -50,6 +55,9 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|||||||
}
|
}
|
||||||
}, [getBeginNodeDataQuery, handleRun, showChatDrawer]);
|
}, [getBeginNodeDataQuery, handleRun, showChatDrawer]);
|
||||||
|
|
||||||
|
const showListVersion = useCallback(() => {
|
||||||
|
setVisibleHistoryVersionModal(true);
|
||||||
|
}, [setVisibleHistoryVersionModal]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex
|
<Flex
|
||||||
@ -83,6 +91,9 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|||||||
>
|
>
|
||||||
<b>{t('embedIntoSite', { keyPrefix: 'common' })}</b>
|
<b>{t('embedIntoSite', { keyPrefix: 'common' })}</b>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button type="primary" onClick={showListVersion}>
|
||||||
|
<b>{t('historyversion')}</b>
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
{embedVisible && (
|
{embedVisible && (
|
||||||
@ -95,6 +106,13 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|||||||
isAgent
|
isAgent
|
||||||
></EmbedModal>
|
></EmbedModal>
|
||||||
)}
|
)}
|
||||||
|
{visibleHistoryVersionModal && (
|
||||||
|
<HistoryVersionModal
|
||||||
|
id={id || ''}
|
||||||
|
visible={visibleHistoryVersionModal}
|
||||||
|
hideModal={() => setVisibleHistoryVersionModal(false)}
|
||||||
|
></HistoryVersionModal>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
184
web/src/pages/flow/history-version-modal/index.tsx
Normal file
184
web/src/pages/flow/history-version-modal/index.tsx
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useFetchListVersion, useFetchVersion } from '@/hooks/flow-hooks';
|
||||||
|
import {
|
||||||
|
Background,
|
||||||
|
ConnectionMode,
|
||||||
|
ReactFlow,
|
||||||
|
ReactFlowProvider,
|
||||||
|
} from '@xyflow/react';
|
||||||
|
import { Card, Col, Empty, List, Modal, Row, Spin, Typography } from 'antd';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { nodeTypes } from '../canvas';
|
||||||
|
|
||||||
|
export function useHistoryVersionModal() {
|
||||||
|
const [visibleHistoryVersionModal, setVisibleHistoryVersionModal] =
|
||||||
|
React.useState(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
visibleHistoryVersionModal,
|
||||||
|
setVisibleHistoryVersionModal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type HistoryVersionModalProps = {
|
||||||
|
visible: boolean;
|
||||||
|
hideModal: () => void;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function HistoryVersionModal({
|
||||||
|
visible,
|
||||||
|
hideModal,
|
||||||
|
id,
|
||||||
|
}: HistoryVersionModalProps) {
|
||||||
|
const { t } = useTranslate('flow');
|
||||||
|
const { data, loading } = useFetchListVersion(id);
|
||||||
|
const [selectedVersion, setSelectedVersion] = useState<any>(null);
|
||||||
|
const { data: flow, loading: loadingVersion } = useFetchVersion(
|
||||||
|
selectedVersion?.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!loading && data?.length > 0 && !selectedVersion) {
|
||||||
|
setSelectedVersion(data[0]);
|
||||||
|
}
|
||||||
|
}, [data, loading, selectedVersion]);
|
||||||
|
|
||||||
|
const downloadfile = React.useCallback(
|
||||||
|
function (e: any) {
|
||||||
|
e.stopPropagation();
|
||||||
|
console.log('Restore version:', selectedVersion);
|
||||||
|
// Create a JSON blob and trigger download
|
||||||
|
const jsonContent = JSON.stringify(flow?.dsl.graph, null, 2);
|
||||||
|
const blob = new Blob([jsonContent], {
|
||||||
|
type: 'application/json',
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `${selectedVersion.filename || 'flow-version'}-${selectedVersion.id}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
},
|
||||||
|
[selectedVersion, flow?.dsl],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Modal
|
||||||
|
title={t('historyversion')}
|
||||||
|
open={visible}
|
||||||
|
width={'80vw'}
|
||||||
|
onCancel={hideModal}
|
||||||
|
footer={null}
|
||||||
|
getContainer={() => document.body}
|
||||||
|
>
|
||||||
|
<Row gutter={16} style={{ height: '60vh' }}>
|
||||||
|
<Col span={10} style={{ height: '100%', overflowY: 'auto' }}>
|
||||||
|
{loading && <Spin />}
|
||||||
|
{!loading && data.length === 0 && (
|
||||||
|
<Empty description="No versions found" />
|
||||||
|
)}
|
||||||
|
{!loading && data.length > 0 && (
|
||||||
|
<List
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={data}
|
||||||
|
pagination={{
|
||||||
|
pageSize: 5,
|
||||||
|
simple: true,
|
||||||
|
}}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item
|
||||||
|
key={item.id}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedVersion(item);
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
background:
|
||||||
|
selectedVersion?.id === item.id ? '#f0f5ff' : 'inherit',
|
||||||
|
padding: '8px 12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={`${t('filename')}: ${item.title || '-'}`}
|
||||||
|
description={item.created_at}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
{/* Right panel - Version details */}
|
||||||
|
<Col span={14} style={{ height: '100%', overflowY: 'auto' }}>
|
||||||
|
{selectedVersion ? (
|
||||||
|
<Card title={t('version.details')} bordered={false}>
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
{/* Add actions for the selected version (restore, download, etc.) */}
|
||||||
|
<Col span={24}>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
|
<Typography.Link onClick={downloadfile}>
|
||||||
|
{t('version.download')}
|
||||||
|
</Typography.Link>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{selectedVersion.title || '-'}
|
||||||
|
</Typography.Title>
|
||||||
|
|
||||||
|
<Typography.Text
|
||||||
|
type="secondary"
|
||||||
|
style={{ display: 'block', marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
{t('version.created')}: {selectedVersion.create_date}
|
||||||
|
</Typography.Text>
|
||||||
|
|
||||||
|
{/*render dsl form api*/}
|
||||||
|
{loadingVersion && <Spin />}
|
||||||
|
{!loadingVersion && flow?.dsl && (
|
||||||
|
<ReactFlowProvider key={`flow-${selectedVersion.id}`}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '400px',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ReactFlow
|
||||||
|
connectionMode={ConnectionMode.Loose}
|
||||||
|
nodes={flow?.dsl.graph?.nodes || []}
|
||||||
|
edges={
|
||||||
|
flow?.dsl.graph?.edges.flatMap((x) => ({
|
||||||
|
...x,
|
||||||
|
type: 'default',
|
||||||
|
})) || []
|
||||||
|
}
|
||||||
|
fitView
|
||||||
|
nodeTypes={nodeTypes}
|
||||||
|
edgeTypes={{}}
|
||||||
|
zoomOnScroll={true}
|
||||||
|
panOnDrag={true}
|
||||||
|
zoomOnDoubleClick={false}
|
||||||
|
preventScrolling={true}
|
||||||
|
minZoom={0.1}
|
||||||
|
>
|
||||||
|
<Background />
|
||||||
|
</ReactFlow>
|
||||||
|
</div>
|
||||||
|
</ReactFlowProvider>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Empty description={t('version.select')} />
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Modal>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
@ -6,6 +6,8 @@ const {
|
|||||||
getCanvas,
|
getCanvas,
|
||||||
getCanvasSSE,
|
getCanvasSSE,
|
||||||
setCanvas,
|
setCanvas,
|
||||||
|
getListVersion,
|
||||||
|
getVersion,
|
||||||
listCanvas,
|
listCanvas,
|
||||||
resetCanvas,
|
resetCanvas,
|
||||||
removeCanvas,
|
removeCanvas,
|
||||||
@ -29,6 +31,14 @@ const methods = {
|
|||||||
url: setCanvas,
|
url: setCanvas,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
},
|
},
|
||||||
|
getListVersion: {
|
||||||
|
url: getListVersion,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
getVersion: {
|
||||||
|
url: getVersion,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
listCanvas: {
|
listCanvas: {
|
||||||
url: listCanvas,
|
url: listCanvas,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@ -63,6 +73,6 @@ const methods = {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const chatService = registerServer<keyof typeof methods>(methods, request);
|
const flowService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
|
||||||
export default chatService;
|
export default flowService;
|
||||||
|
@ -127,6 +127,8 @@ export default {
|
|||||||
getCanvasSSE: `${api_host}/canvas/getsse`,
|
getCanvasSSE: `${api_host}/canvas/getsse`,
|
||||||
removeCanvas: `${api_host}/canvas/rm`,
|
removeCanvas: `${api_host}/canvas/rm`,
|
||||||
setCanvas: `${api_host}/canvas/set`,
|
setCanvas: `${api_host}/canvas/set`,
|
||||||
|
getListVersion: `${api_host}/canvas/getlistversion`,
|
||||||
|
getVersion: `${api_host}/canvas/getversion`,
|
||||||
resetCanvas: `${api_host}/canvas/reset`,
|
resetCanvas: `${api_host}/canvas/reset`,
|
||||||
runCanvas: `${api_host}/canvas/completion`,
|
runCanvas: `${api_host}/canvas/completion`,
|
||||||
testDbConnect: `${api_host}/canvas/test_db_connect`,
|
testDbConnect: `${api_host}/canvas/test_db_connect`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user