mirror of
https://github.com/OpenBMB/ChatDev.git
synced 2026-09-14 16:08:42 +00:00
feat: wrapping nodes with tooltip content
This commit is contained in:
parent
b3b7376ef2
commit
53870bd6f0
@ -1,6 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { Handle, Position } from '@vue-flow/core'
|
import { Handle, Position } from '@vue-flow/core'
|
||||||
|
import RichTooltip from './RichTooltip.vue'
|
||||||
|
import { helpContent } from '../utils/helpContent.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
@ -15,11 +17,13 @@ const props = defineProps({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="start-node" :style="{ opacity: data.opacity ?? 1 }">
|
<RichTooltip :content="helpContent.startNode" placement="right">
|
||||||
<div class="start-node-bubble" title="Start Node"></div>
|
<div class="start-node" :style="{ opacity: data.opacity ?? 1 }">
|
||||||
<!-- Provide source handle at right -->
|
<div class="start-node-bubble" title="Start Node"></div>
|
||||||
<Handle id="source" type="source" :position="Position.Right" class="start-node-handle" />
|
<!-- Provide source handle at right -->
|
||||||
</div>
|
<Handle id="source" type="source" :position="Position.Right" class="start-node-handle" />
|
||||||
|
</div>
|
||||||
|
</RichTooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
import { computed, ref, nextTick, watch } from 'vue'
|
import { computed, ref, nextTick, watch } from 'vue'
|
||||||
import { BaseEdge, EdgeLabelRenderer, getBezierPath, getSmoothStepPath, MarkerType } from '@vue-flow/core'
|
import { BaseEdge, EdgeLabelRenderer, getBezierPath, getSmoothStepPath, MarkerType } from '@vue-flow/core'
|
||||||
import { useVueFlow } from '@vue-flow/core'
|
import { useVueFlow } from '@vue-flow/core'
|
||||||
|
import RichTooltip from './RichTooltip.vue'
|
||||||
|
import { getEdgeHelp } from '../utils/helpContent.js'
|
||||||
|
|
||||||
const { findNode } = useVueFlow()
|
const { findNode } = useVueFlow()
|
||||||
|
|
||||||
@ -562,6 +564,8 @@ const labelStyle = computed(() => {
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const edgeHelpContent = computed(() => getEdgeHelp(props.data))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -614,6 +618,23 @@ const labelStyle = computed(() => {
|
|||||||
:animated="false"
|
:animated="false"
|
||||||
class="nodrag nopan"
|
class="nodrag nopan"
|
||||||
/>
|
/>
|
||||||
|
<!-- Tooltip-enabled hover area at edge midpoint -->
|
||||||
|
<EdgeLabelRenderer>
|
||||||
|
<RichTooltip :content="edgeHelpContent" placement="top">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
position: 'absolute',
|
||||||
|
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
|
||||||
|
pointerEvents: 'all',
|
||||||
|
width: '20px',
|
||||||
|
height: '20px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}"
|
||||||
|
class="edge-tooltip-trigger"
|
||||||
|
/>
|
||||||
|
</RichTooltip>
|
||||||
|
</EdgeLabelRenderer>
|
||||||
<EdgeLabelRenderer v-if="edgeLabel">
|
<EdgeLabelRenderer v-if="edgeLabel">
|
||||||
<div
|
<div
|
||||||
:key="edgeLabelKey"
|
:key="edgeLabelKey"
|
||||||
@ -649,4 +670,13 @@ const labelStyle = computed(() => {
|
|||||||
.animated-label {
|
.animated-label {
|
||||||
animation: label-pulse var(--label-anim-duration) infinite linear;
|
animation: label-pulse var(--label-anim-duration) infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edge-tooltip-trigger {
|
||||||
|
background: transparent;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edge-tooltip-trigger:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { computed, ref, onMounted, onUnmounted, watch } from 'vue'
|
|||||||
import { Handle, Position } from '@vue-flow/core'
|
import { Handle, Position } from '@vue-flow/core'
|
||||||
import { getNodeStyles } from '../utils/colorUtils.js'
|
import { getNodeStyles } from '../utils/colorUtils.js'
|
||||||
import { spriteFetcher } from '../utils/spriteFetcher.js'
|
import { spriteFetcher } from '../utils/spriteFetcher.js'
|
||||||
|
import RichTooltip from './RichTooltip.vue'
|
||||||
|
import { getNodeHelp } from '../utils/helpContent.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
@ -37,6 +39,8 @@ const nodeDescription = computed(() => props.data?.description || '')
|
|||||||
const isActive = computed(() => props.isActive)
|
const isActive = computed(() => props.isActive)
|
||||||
const dynamicStyles = computed(() => getNodeStyles(nodeType.value))
|
const dynamicStyles = computed(() => getNodeStyles(nodeType.value))
|
||||||
|
|
||||||
|
const nodeHelpContent = computed(() => getNodeHelp(nodeType.value))
|
||||||
|
|
||||||
// Compute the current sprite path based on active state and walking frame
|
// Compute the current sprite path based on active state and walking frame
|
||||||
const currentSprite = computed(() => {
|
const currentSprite = computed(() => {
|
||||||
if (!props.sprite) return ''
|
if (!props.sprite) return ''
|
||||||
@ -83,40 +87,42 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="workflow-node-container">
|
<RichTooltip :content="nodeHelpContent" placement="top">
|
||||||
<div v-if="props.sprite" class="workflow-node-sprite">
|
<div class="workflow-node-container">
|
||||||
<img :src="currentSprite" :alt="`${nodeId} sprite`" class="node-sprite-image" />
|
<div v-if="props.sprite" class="workflow-node-sprite">
|
||||||
</div>
|
<img :src="currentSprite" :alt="`${nodeId} sprite`" class="node-sprite-image" />
|
||||||
<div
|
|
||||||
class="workflow-node"
|
|
||||||
:class="{ 'workflow-node-active': isActive }"
|
|
||||||
:data-type="nodeType"
|
|
||||||
:style="dynamicStyles"
|
|
||||||
@mouseenter="$emit('hover', nodeId)"
|
|
||||||
@mouseleave="$emit('leave', nodeId)"
|
|
||||||
>
|
|
||||||
<div class="workflow-node-header">
|
|
||||||
<span class="workflow-node-type">{{ nodeType }}</span>
|
|
||||||
<span class="workflow-node-id">{{ nodeId }}</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="nodeDescription" class="workflow-node-description">
|
|
||||||
{{ nodeDescription }}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="workflow-node"
|
||||||
|
:class="{ 'workflow-node-active': isActive }"
|
||||||
|
:data-type="nodeType"
|
||||||
|
:style="dynamicStyles"
|
||||||
|
@mouseenter="$emit('hover', nodeId)"
|
||||||
|
@mouseleave="$emit('leave', nodeId)"
|
||||||
|
>
|
||||||
|
<div class="workflow-node-header">
|
||||||
|
<span class="workflow-node-type">{{ nodeType }}</span>
|
||||||
|
<span class="workflow-node-id">{{ nodeId }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="nodeDescription" class="workflow-node-description">
|
||||||
|
{{ nodeDescription }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Handle
|
<Handle
|
||||||
id="source"
|
id="source"
|
||||||
type="source"
|
type="source"
|
||||||
:position="Position.Right"
|
:position="Position.Right"
|
||||||
class="workflow-node-handle"
|
class="workflow-node-handle"
|
||||||
/>
|
/>
|
||||||
<Handle
|
<Handle
|
||||||
id="target"
|
id="target"
|
||||||
type="target"
|
type="target"
|
||||||
:position="Position.Left"
|
:position="Position.Left"
|
||||||
class="workflow-node-handle"
|
class="workflow-node-handle"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</RichTooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -87,38 +87,46 @@
|
|||||||
>
|
>
|
||||||
<!-- Pane context menu -->
|
<!-- Pane context menu -->
|
||||||
<template v-if="contextMenuType === 'pane'">
|
<template v-if="contextMenuType === 'pane'">
|
||||||
<div
|
<RichTooltip :content="helpContent.contextMenu.createNode" placement="right">
|
||||||
class="context-menu-item"
|
<div
|
||||||
@click.stop="() => { hideContextMenu(); openCreateNodeModal(); }"
|
class="context-menu-item"
|
||||||
>
|
@click.stop="() => { hideContextMenu(); openCreateNodeModal(); }"
|
||||||
Create Node
|
>
|
||||||
</div>
|
Create Node
|
||||||
|
</div>
|
||||||
|
</RichTooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Node context menu -->
|
<!-- Node context menu -->
|
||||||
<template v-else-if="contextMenuType === 'node'">
|
<template v-else-if="contextMenuType === 'node'">
|
||||||
<div
|
<RichTooltip :content="helpContent.contextMenu.copyNode" placement="right">
|
||||||
class="context-menu-item"
|
<div
|
||||||
@click.stop="() => { hideContextMenu(); onCopyNodeFromContext(); }"
|
class="context-menu-item"
|
||||||
>
|
@click.stop="() => { hideContextMenu(); onCopyNodeFromContext(); }"
|
||||||
Copy Node
|
>
|
||||||
</div>
|
Copy Node
|
||||||
<div
|
</div>
|
||||||
class="context-menu-item"
|
</RichTooltip>
|
||||||
@click.stop="() => { hideContextMenu(); onDeleteNodeFromContext(); }"
|
<RichTooltip :content="helpContent.contextMenu.deleteNode" placement="right">
|
||||||
>
|
<div
|
||||||
Delete Node
|
class="context-menu-item"
|
||||||
</div>
|
@click.stop="() => { hideContextMenu(); onDeleteNodeFromContext(); }"
|
||||||
|
>
|
||||||
|
Delete Node
|
||||||
|
</div>
|
||||||
|
</RichTooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Edge context menu -->
|
<!-- Edge context menu -->
|
||||||
<template v-else-if="contextMenuType === 'edge'">
|
<template v-else-if="contextMenuType === 'edge'">
|
||||||
<div
|
<RichTooltip :content="helpContent.contextMenu.deleteEdge" placement="right">
|
||||||
class="context-menu-item"
|
<div
|
||||||
@click.stop="() => { hideContextMenu(); onDeleteEdgeFromContext(); }"
|
class="context-menu-item"
|
||||||
>
|
@click.stop="() => { hideContextMenu(); onDeleteEdgeFromContext(); }"
|
||||||
Delete Edge
|
>
|
||||||
</div>
|
Delete Edge
|
||||||
|
</div>
|
||||||
|
</RichTooltip>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
@ -141,15 +149,21 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'graph'" class="editor-actions">
|
<div v-if="activeTab === 'graph'" class="editor-actions">
|
||||||
<button @click="openCreateNodeModal" class="glass-button">
|
<RichTooltip :content="helpContent.contextMenu.createNodeButton" placement="bottom">
|
||||||
<span>Create Node</span>
|
<button @click="openCreateNodeModal" class="glass-button">
|
||||||
</button>
|
<span>Create Node</span>
|
||||||
<button @click="openConfigureGraphModal" class="glass-button">
|
</button>
|
||||||
<span>Configure Graph</span>
|
</RichTooltip>
|
||||||
</button>
|
<RichTooltip :content="helpContent.contextMenu.configureGraph" placement="bottom">
|
||||||
<button @click="goToLaunch" class="launch-button-primary">
|
<button @click="openConfigureGraphModal" class="glass-button">
|
||||||
<span>Launch</span>
|
<span>Configure Graph</span>
|
||||||
</button>
|
</button>
|
||||||
|
</RichTooltip>
|
||||||
|
<RichTooltip :content="helpContent.contextMenu.launch" placement="bottom">
|
||||||
|
<button @click="goToLaunch" class="launch-button-primary">
|
||||||
|
<span>Launch</span>
|
||||||
|
</button>
|
||||||
|
</RichTooltip>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="menu-container"
|
class="menu-container"
|
||||||
@ -166,11 +180,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div v-if="showMenu" class="menu-dropdown">
|
<div v-if="showMenu" class="menu-dropdown">
|
||||||
<div @click="openRenameWorkflowModal" class="menu-item">Rename Workflow</div>
|
<RichTooltip :content="helpContent.contextMenu.renameWorkflow" placement="left">
|
||||||
<div @click="openCopyWorkflowModal" class="menu-item">Copy Workflow</div>
|
<div @click="openRenameWorkflowModal" class="menu-item">Rename Workflow</div>
|
||||||
<div @click="openManageVarsModal" class="menu-item">Manage Variables</div>
|
</RichTooltip>
|
||||||
<div @click="openManageMemoriesModal" class="menu-item">Manage Memories</div>
|
<RichTooltip :content="helpContent.contextMenu.copyWorkflow" placement="left">
|
||||||
<div @click="openCreateEdgeModal" class="menu-item">Create Edge</div>
|
<div @click="openCopyWorkflowModal" class="menu-item">Copy Workflow</div>
|
||||||
|
</RichTooltip>
|
||||||
|
<RichTooltip :content="helpContent.contextMenu.manageVariables" placement="left">
|
||||||
|
<div @click="openManageVarsModal" class="menu-item">Manage Variables</div>
|
||||||
|
</RichTooltip>
|
||||||
|
<RichTooltip :content="helpContent.contextMenu.manageMemories" placement="left">
|
||||||
|
<div @click="openManageMemoriesModal" class="menu-item">Manage Memories</div>
|
||||||
|
</RichTooltip>
|
||||||
|
<RichTooltip :content="helpContent.contextMenu.createEdge" placement="left">
|
||||||
|
<div @click="openCreateEdgeModal" class="menu-item">Create Edge</div>
|
||||||
|
</RichTooltip>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@ -270,8 +294,10 @@ import WorkflowNode from '../components/WorkflowNode.vue'
|
|||||||
import WorkflowEdge from '../components/WorkflowEdge.vue'
|
import WorkflowEdge from '../components/WorkflowEdge.vue'
|
||||||
import StartNode from '../components/StartNode.vue'
|
import StartNode from '../components/StartNode.vue'
|
||||||
import FormGenerator from '../components/FormGenerator.vue'
|
import FormGenerator from '../components/FormGenerator.vue'
|
||||||
|
import RichTooltip from '../components/RichTooltip.vue'
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml'
|
||||||
import { fetchYaml, fetchVueGraph, postVuegraphs, updateYaml, postYamlNameChange, postYamlCopy } from '../utils/apiFunctions'
|
import { fetchYaml, fetchVueGraph, postVuegraphs, updateYaml, postYamlNameChange, postYamlCopy } from '../utils/apiFunctions'
|
||||||
|
import { helpContent } from '../utils/helpContent.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
workflowName: {
|
workflowName: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user