Add progress bars and progress text

This commit is contained in:
Benjamin Lu
2025-12-07 00:27:11 -08:00
parent 5e1dc915a0
commit d965fb01fc
6 changed files with 325 additions and 72 deletions

View File

@@ -0,0 +1,169 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import QueueInlineProgressSummary from './QueueInlineProgressSummary.vue'
import { useExecutionStore } from '@/stores/executionStore'
type SeedOptions = {
promptId: string
nodes: Record<string, boolean>
runningNodeId?: string
runningNodeTitle?: string
runningNodeType?: string
currentValue?: number
currentMax?: number
}
function resetExecutionStore() {
const exec = useExecutionStore()
exec.activePromptId = null
exec.queuedPrompts = {}
exec.nodeProgressStates = {}
exec.nodeProgressStatesByPrompt = {}
exec._executingNodeProgress = null
exec.lastExecutionError = null
exec.lastNodeErrors = null
exec.initializingPromptIds = new Set()
exec.promptIdToWorkflowId = new Map()
}
function seedExecutionState({
promptId,
nodes,
runningNodeId,
runningNodeTitle,
runningNodeType,
currentValue = 0,
currentMax = 100
}: SeedOptions) {
resetExecutionStore()
const exec = useExecutionStore()
const workflow = runningNodeId
? ({
changeTracker: {
activeState: {
nodes: Object.keys(nodes).map((id) => ({
id,
title:
id === runningNodeId ? (runningNodeTitle ?? '') : `Node ${id}`,
type: id === runningNodeId ? (runningNodeType ?? 'Node') : 'Node'
}))
}
}
} as any)
: undefined
exec.activePromptId = promptId
exec.queuedPrompts = {
[promptId]: {
nodes,
...(workflow ? { workflow } : {})
}
} as any
const nodeProgress = runningNodeId
? {
[runningNodeId]: {
value: currentValue,
max: currentMax,
state: 'running',
node_id: runningNodeId,
prompt_id: promptId
}
}
: {}
exec.nodeProgressStates = nodeProgress as any
exec.nodeProgressStatesByPrompt = runningNodeId
? ({ [promptId]: nodeProgress } as any)
: {}
exec._executingNodeProgress = runningNodeId
? ({
value: currentValue,
max: currentMax,
prompt_id: promptId,
node: runningNodeId
} as any)
: null
}
const meta: Meta<typeof QueueInlineProgressSummary> = {
title: 'Queue/QueueInlineProgressSummary',
component: QueueInlineProgressSummary,
parameters: {
layout: 'padded',
backgrounds: {
default: 'light'
}
}
}
export default meta
type Story = StoryObj<typeof meta>
export const RunningKSampler: Story = {
render: () => ({
components: { QueueInlineProgressSummary },
setup() {
seedExecutionState({
promptId: 'prompt-running',
nodes: { '1': true, '2': false, '3': false, '4': true },
runningNodeId: '2',
runningNodeTitle: 'KSampler',
runningNodeType: 'KSampler',
currentValue: 12,
currentMax: 100
})
return {}
},
template: `
<div style="background: var(--color-surface-primary); width: 420px; padding: 12px;">
<QueueInlineProgressSummary />
</div>
`
})
}
export const RunningWithFallbackName: Story = {
render: () => ({
components: { QueueInlineProgressSummary },
setup() {
seedExecutionState({
promptId: 'prompt-fallback',
nodes: { '10': true, '11': true, '12': false, '13': true },
runningNodeId: '12',
runningNodeTitle: '',
runningNodeType: 'custom_node',
currentValue: 78,
currentMax: 100
})
return {}
},
template: `
<div style="background: var(--color-surface-primary); width: 420px; padding: 12px;">
<QueueInlineProgressSummary />
</div>
`
})
}
export const ProgressWithoutCurrentNode: Story = {
render: () => ({
components: { QueueInlineProgressSummary },
setup() {
seedExecutionState({
promptId: 'prompt-progress-only',
nodes: { '21': true, '22': true, '23': true, '24': false }
})
return {}
},
template: `
<div style="background: var(--color-surface-primary); width: 420px; padding: 12px;">
<QueueInlineProgressSummary />
</div>
`
})
}

View File

@@ -0,0 +1,64 @@
<template>
<div v-if="shouldShow" class="flex justify-end">
<div
class="flex items-center gap-4 whitespace-nowrap text-[0.75rem] leading-[normal] drop-shadow-[1px_1px_8px_rgba(0,0,0,0.4)]"
aria-hidden="true"
>
<div class="flex items-center gap-1 text-base-foreground">
<span class="font-normal">{{ totalLabel }}:</span>
<span class="w-[5ch] shrink-0 text-right font-bold tabular-nums">
{{ totalPercentFormatted }}
</span>
</div>
<div class="flex items-center gap-1 text-muted-foreground">
<span
class="w-[16ch] shrink-0 truncate text-right"
:title="currentNodeLabel"
>
{{ currentNodeLabel }}:
</span>
<span class="w-[5ch] shrink-0 text-right tabular-nums">
{{ currentNodePercentFormatted }}
</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCurrentNodeName } from '@/composables/queue/useCurrentNodeName'
import { useQueueProgress } from '@/composables/queue/useQueueProgress'
import { useExecutionStore } from '@/stores/executionStore'
const props = defineProps<{
hidden?: boolean
}>()
const { t } = useI18n()
const executionStore = useExecutionStore()
const { currentNodeName } = useCurrentNodeName()
const {
totalPercent,
totalPercentFormatted,
currentNodePercent,
currentNodePercentFormatted
} = useQueueProgress()
const totalLabel = computed<string>(() =>
t('sideToolbar.queueProgressOverlay.inlineTotalLabel')
)
const currentNodeLabel = computed<string>(() => currentNodeName.value)
const shouldShow = computed(
() =>
!props.hidden &&
(!executionStore.isIdle ||
totalPercent.value > 0 ||
currentNodePercent.value > 0)
)
</script>