diff --git a/web/package-lock.json b/web/package-lock.json index b15d7a62e3..ccc02d2d64 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -36,6 +36,7 @@ "react-pdf-highlighter": "^6.1.0", "react-string-replace": "^1.1.1", "react-syntax-highlighter": "^15.5.0", + "react18-json-view": "^0.2.8", "reactflow": "^11.11.2", "recharts": "^2.12.4", "remark-gfm": "^4.0.0", @@ -5011,9 +5012,9 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/lodash": { - "version": "4.14.202", - "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "version": "4.17.6", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.6.tgz", + "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", "dev": true }, "node_modules/@types/mdast": { @@ -22274,6 +22275,14 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react18-json-view": { + "version": "0.2.8", + "resolved": "https://registry.npmmirror.com/react18-json-view/-/react18-json-view-0.2.8.tgz", + "integrity": "sha512-uJlcf5PEDaba6yTqfcDAcMSYECZ15SLcpP94mLFTa/+fa1kZANjERqKzS7YxxsrGP4+jDxt6sIaglR0PbQcKPw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/reactcss": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", diff --git a/web/package.json b/web/package.json index 493d077bd0..a1e3151432 100644 --- a/web/package.json +++ b/web/package.json @@ -47,6 +47,7 @@ "react-pdf-highlighter": "^6.1.0", "react-string-replace": "^1.1.1", "react-syntax-highlighter": "^15.5.0", + "react18-json-view": "^0.2.8", "reactflow": "^11.11.2", "recharts": "^2.12.4", "remark-gfm": "^4.0.0", diff --git a/web/src/pages/flow/canvas/node/categorize-node.tsx b/web/src/pages/flow/canvas/node/categorize-node.tsx index f58ab40a00..2ea40cac1c 100644 --- a/web/src/pages/flow/canvas/node/categorize-node.tsx +++ b/web/src/pages/flow/canvas/node/categorize-node.tsx @@ -14,65 +14,67 @@ import OperatorIcon from '../../operator-icon'; import CategorizeHandle from './categorize-handle'; import NodeDropdown from './dropdown'; import styles from './index.less'; +import NodePopover from './popover'; export function CategorizeNode({ id, data, selected }: NodeProps) { const categoryData = get(data, 'form.category_description') ?? {}; const style = operatorMap[data.label as Operator]; const { t } = useTranslate('flow'); return ( -
- - - - {Object.keys(categoryData).map((x, idx) => { - console.info(categoryData, id, data); - return ( - - ); - })} - - - {t(lowerFirst(data.label))} - - -
-
{data.name}
+ +
+ + + + {Object.keys(categoryData).map((x, idx) => { + return ( + + ); + })} + + + {t(lowerFirst(data.label))} + + +
+
{data.name}
+
-
+ ); } diff --git a/web/src/pages/flow/canvas/node/index.tsx b/web/src/pages/flow/canvas/node/index.tsx index 9bd8d1e79e..9bc28d694d 100644 --- a/web/src/pages/flow/canvas/node/index.tsx +++ b/web/src/pages/flow/canvas/node/index.tsx @@ -9,6 +9,7 @@ import { NodeData } from '../../interface'; import OperatorIcon from '../../operator-icon'; import NodeDropdown from './dropdown'; import styles from './index.less'; +import NodePopover from './popover'; export function RagNode({ id, @@ -18,53 +19,54 @@ export function RagNode({ }: NodeProps) { const style = operatorMap[data.label as Operator]; const { t } = useTranslate('flow'); + return ( -
- - - - - +
- - + + + + - {data.label === Operator.RewriteQuestion - ? t(lowerFirst('Rewrite')) - : t(lowerFirst(data.label))} - - - + + + {t(lowerFirst(data.label))} + + + -
-
{data.name}
+
+
{data.name}
+
-
+ ); } diff --git a/web/src/pages/flow/canvas/node/popover.tsx b/web/src/pages/flow/canvas/node/popover.tsx new file mode 100644 index 0000000000..53c9c93fc9 --- /dev/null +++ b/web/src/pages/flow/canvas/node/popover.tsx @@ -0,0 +1,47 @@ +import { useFetchFlow } from '@/hooks/flow-hooks'; +import { Popover } from 'antd'; +import get from 'lodash/get'; +import React, { useMemo } from 'react'; +import JsonView from 'react18-json-view'; +import 'react18-json-view/src/style.css'; +import { Operator } from '../../constant'; +import { useReplaceIdWithText } from '../../hooks'; + +interface IProps extends React.PropsWithChildren { + nodeId: string; +} + +const NodePopover = ({ children, nodeId }: IProps) => { + const { data } = useFetchFlow(); + const component = useMemo(() => { + return get(data, ['dsl', 'components', nodeId], {}); + }, [nodeId, data]); + + const output = get(component, ['obj', 'params', 'output'], {}); + const componentName = get(component, ['obj', 'component_name'], ''); + const replacedOutput = useReplaceIdWithText(output); + + const content = + componentName !== Operator.Answer ? ( +
{ + e.preventDefault(); + e.stopPropagation(); + }} + > + +
+ ) : undefined; + + return ( + + {children} + + ); +}; + +export default NodePopover; diff --git a/web/src/pages/flow/canvas/node/relevant-node.tsx b/web/src/pages/flow/canvas/node/relevant-node.tsx index a5879621dc..50cc47d7d7 100644 --- a/web/src/pages/flow/canvas/node/relevant-node.tsx +++ b/web/src/pages/flow/canvas/node/relevant-node.tsx @@ -11,56 +11,59 @@ import NodeDropdown from './dropdown'; import CategorizeHandle from './categorize-handle'; import styles from './index.less'; +import NodePopover from './popover'; export function RelevantNode({ id, data, selected }: NodeProps) { const style = operatorMap[data.label as Operator]; const { t } = useTranslate('flow'); return ( -
- - - - - - - - - {t(lowerFirst(data.label))} - - - -
-
{data.name}
+ +
+ + + + + + + + + {t(lowerFirst(data.label))} + + + +
+
{data.name}
+
-
+ ); } diff --git a/web/src/pages/flow/hooks.ts b/web/src/pages/flow/hooks.ts index e052fb773e..7c19eb723c 100644 --- a/web/src/pages/flow/hooks.ts +++ b/web/src/pages/flow/hooks.ts @@ -38,7 +38,11 @@ import { initialRewriteQuestionValues, } from './constant'; import useGraphStore, { RFState } from './store'; -import { buildDslComponentsByGraph, receiveMessageError } from './utils'; +import { + buildDslComponentsByGraph, + receiveMessageError, + replaceIdWithText, +} from './utils'; const selector = (state: RFState) => ({ nodes: state.nodes, @@ -376,3 +380,13 @@ export const useSaveGraphBeforeOpeningDebugDrawer = (show: () => void) => { return handleRun; }; + +export const useReplaceIdWithText = (output: unknown) => { + const getNode = useGraphStore((state) => state.getNode); + + const getNameById = (id?: string) => { + return getNode(id)?.data.name; + }; + + return replaceIdWithText(output, getNameById); +}; diff --git a/web/src/pages/flow/utils.ts b/web/src/pages/flow/utils.ts index 80a5a32144..e070e54854 100644 --- a/web/src/pages/flow/utils.ts +++ b/web/src/pages/flow/utils.ts @@ -4,6 +4,7 @@ import dagre from 'dagre'; import { humanId } from 'human-id'; import { curry } from 'lodash'; import pipe from 'lodash/fp/pipe'; +import isObject from 'lodash/isObject'; import { Edge, Node, Position } from 'reactflow'; import { v4 as uuidv4 } from 'uuid'; import { NodeMap, Operator } from './constant'; @@ -184,3 +185,26 @@ export const buildDslComponentsByGraph = ( export const receiveMessageError = (res: any) => res && (res?.response.status !== 200 || res?.data?.retcode !== 0); + +// Replace the id in the object with text +export const replaceIdWithText = ( + obj: Record | unknown[] | unknown, + getNameById: (id?: string) => string | undefined, +) => { + if (isObject(obj)) { + const ret: Record | unknown[] = Array.isArray(obj) + ? [] + : {}; + Object.keys(obj).forEach((key) => { + const val = (obj as Record)[key]; + const text = typeof val === 'string' ? getNameById(val) : undefined; + (ret as Record)[key] = text + ? text + : replaceIdWithText(val, getNameById); + }); + + return ret; + } + + return obj; +};