fix progress state on Vue nodes in subgraphs (#5842)
## Summary Fixes two errors with subgraph progress states: 1. Nodes inside subgraphs were not having progress state shown 2. Subgraph nodes (outer representation) themselves did not have a visible progress state 1 is fixed by using locator IDs instead of local node IDs. 2 is fixed by ensuring the subgraph title button does not wrap to a newline and thus block the progress bar under the node header. ## Changes - **What**: Updated `useNodeExecutionState` composable to use `nodeLocatorId` for tracking execution state across subgraph boundaries - **What**: Modified NodeHeader layout to fix subgraph enter button positioning with proper flexbox gap ## Review Focus Execution state tracking accuracy for nested subgraph nodes and NodeHeader layout consistency across different node types. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5842-fix-progress-state-on-Vue-nodes-in-subgraphs-27c6d73d365081cb8335c8bb5dbd74f7) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 68 KiB |
@@ -211,7 +211,8 @@ const isSelected = computed(() => {
|
||||
})
|
||||
|
||||
// Use execution state composable
|
||||
const { executing, progress } = useNodeExecutionState(() => nodeData.id)
|
||||
const nodeLocatorId = computed(() => getLocatorIdFromNodeData(nodeData))
|
||||
const { executing, progress } = useNodeExecutionState(nodeLocatorId)
|
||||
|
||||
// Direct access to execution store for error state
|
||||
const executionStore = useExecutionStore()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:data-testid="`node-header-${nodeData?.id || ''}`"
|
||||
@dblclick="handleDoubleClick"
|
||||
>
|
||||
<div class="flex items-center justify-between relative">
|
||||
<div class="flex items-center justify-between gap-2.5 relative">
|
||||
<!-- Collapse/Expand Button -->
|
||||
<button
|
||||
v-show="!readonly"
|
||||
@@ -43,24 +43,22 @@
|
||||
data-testid="node-pin-indicator"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!readonly" class="flex items-center lod-toggle shrink-0">
|
||||
<IconButton
|
||||
v-if="isSubgraphNode"
|
||||
size="sm"
|
||||
type="transparent"
|
||||
class="text-stone-200 dark-theme:text-slate-300"
|
||||
data-testid="subgraph-enter-button"
|
||||
title="Enter Subgraph"
|
||||
@click.stop="handleEnterSubgraph"
|
||||
@dblclick.stop
|
||||
>
|
||||
<i class="pi pi-external-link"></i>
|
||||
</IconButton>
|
||||
</div>
|
||||
<LODFallback />
|
||||
</div>
|
||||
|
||||
<!-- Title Buttons -->
|
||||
<div v-if="!readonly" class="flex items-center lod-toggle">
|
||||
<IconButton
|
||||
v-if="isSubgraphNode"
|
||||
size="sm"
|
||||
type="transparent"
|
||||
class="text-stone-200 dark-theme:text-slate-300"
|
||||
data-testid="subgraph-enter-button"
|
||||
title="Enter Subgraph"
|
||||
@click.stop="handleEnterSubgraph"
|
||||
@dblclick.stop
|
||||
>
|
||||
<i class="pi pi-external-link"></i>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,27 +9,27 @@ import { useExecutionStore } from '@/stores/executionStore'
|
||||
* Provides reactive access to execution state and progress for a specific node
|
||||
* by injecting execution data from the parent GraphCanvas provider.
|
||||
*
|
||||
* @param nodeIdMaybe - The ID of the node to track execution state for
|
||||
* @param nodeLocatorIdMaybe - Locator ID (root or subgraph scoped) of the node to track
|
||||
* @returns Object containing reactive execution state and progress
|
||||
*/
|
||||
export const useNodeExecutionState = (
|
||||
nodeIdMaybe: MaybeRefOrGetter<string>
|
||||
nodeLocatorIdMaybe: MaybeRefOrGetter<string | undefined>
|
||||
) => {
|
||||
const nodeId = toValue(nodeIdMaybe)
|
||||
const { uniqueExecutingNodeIdStrings, nodeProgressStates } =
|
||||
storeToRefs(useExecutionStore())
|
||||
const locatorId = computed(() => toValue(nodeLocatorIdMaybe) ?? '')
|
||||
const { nodeLocationProgressStates } = storeToRefs(useExecutionStore())
|
||||
|
||||
const executing = computed(() => {
|
||||
return uniqueExecutingNodeIdStrings.value.has(nodeId)
|
||||
const progressState = computed(() => {
|
||||
const id = locatorId.value
|
||||
return id ? nodeLocationProgressStates.value[id] : undefined
|
||||
})
|
||||
|
||||
const executing = computed(() => progressState.value?.state === 'running')
|
||||
|
||||
const progress = computed(() => {
|
||||
const state = nodeProgressStates.value[nodeId]
|
||||
return state?.max > 0 ? state.value / state.max : undefined
|
||||
const state = progressState.value
|
||||
return state && state.max > 0 ? state.value / state.max : undefined
|
||||
})
|
||||
|
||||
const progressState = computed(() => nodeProgressStates.value[nodeId])
|
||||
|
||||
const progressPercentage = computed(() => {
|
||||
const prog = progress.value
|
||||
return prog !== undefined ? Math.round(prog * 100) : undefined
|
||||
|
||||