Skip to content

Commit 5542845

Browse files
authored
Task output folder view (#579)
* Change to button * Folder view
1 parent f2de9b0 commit 5542845

File tree

4 files changed

+102
-51
lines changed

4 files changed

+102
-51
lines changed

src/components/sidebar/tabs/QueueSidebarTab.vue

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
<template>
2-
<SideBarTabTemplate :title="$t('sideToolbar.queue')">
2+
<SidebarTabTemplate :title="$t('sideToolbar.queue')">
33
<template #tool-buttons>
44
<Button
5-
:icon="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
5+
v-if="isInFolderView"
6+
icon="pi pi-arrow-left"
67
text
78
severity="secondary"
8-
@click="toggleExpanded"
9-
class="toggle-expanded-button"
10-
v-tooltip="$t('sideToolbar.queueTab.showFlatList')"
11-
/>
12-
<Button
13-
icon="pi pi-trash"
14-
text
15-
severity="primary"
16-
@click="confirmRemoveAll($event)"
17-
class="clear-all-button"
9+
@click="exitFolderView"
10+
class="back-button"
11+
v-tooltip="$t('sideToolbar.queueTab.backToAllTasks')"
1812
/>
13+
<template v-else>
14+
<Button
15+
:icon="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
16+
text
17+
severity="secondary"
18+
@click="toggleExpanded"
19+
class="toggle-expanded-button"
20+
v-tooltip="$t('sideToolbar.queueTab.showFlatList')"
21+
/>
22+
<Button
23+
icon="pi pi-trash"
24+
text
25+
severity="primary"
26+
@click="confirmRemoveAll($event)"
27+
class="clear-all-button"
28+
/>
29+
</template>
1930
</template>
2031
<template #body>
2132
<div
@@ -28,9 +39,10 @@
2839
v-for="task in visibleTasks"
2940
:key="task.key"
3041
:task="task"
31-
:isFlatTask="isExpanded"
42+
:isFlatTask="isExpanded || isInFolderView"
3243
@contextmenu="handleContextMenu"
3344
@preview="handlePreview"
45+
@taskOutputLengthClicked="enterFolderView($event)"
3446
/>
3547
</div>
3648
<div ref="loadMoreTrigger" style="height: 1px" />
@@ -43,7 +55,7 @@
4355
/>
4456
</div>
4557
</template>
46-
</SideBarTabTemplate>
58+
</SidebarTabTemplate>
4759
<ConfirmPopup />
4860
<ContextMenu ref="menu" :model="menuItems" />
4961
<ResultGallery
@@ -64,7 +76,7 @@ import ContextMenu from 'primevue/contextmenu'
6476
import type { MenuItem } from 'primevue/menuitem'
6577
import TaskItem from './queue/TaskItem.vue'
6678
import ResultGallery from './queue/ResultGallery.vue'
67-
import SideBarTabTemplate from './SidebarTabTemplate.vue'
79+
import SidebarTabTemplate from './SidebarTabTemplate.vue'
6880
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
6981
import { TaskItemImpl, useQueueStore } from '@/stores/queueStore'
7082
import { api } from '@/scripts/api'
@@ -74,17 +86,27 @@ const toast = useToast()
7486
const queueStore = useQueueStore()
7587
const { t } = useI18n()
7688
89+
// Expanded view: show all outputs in a flat list.
7790
const isExpanded = ref(false)
7891
const visibleTasks = ref<TaskItemImpl[]>([])
7992
const scrollContainer = ref<HTMLElement | null>(null)
8093
const loadMoreTrigger = ref<HTMLElement | null>(null)
8194
const galleryActiveIndex = ref(-1)
95+
// Folder view: only show outputs from a single selected task.
96+
const folderTask = ref<TaskItemImpl | null>(null)
97+
const isInFolderView = computed(() => folderTask.value !== null)
8298
8399
const ITEMS_PER_PAGE = 8
84100
const SCROLL_THRESHOLD = 100 // pixels from bottom to trigger load
85101
86102
const allTasks = computed(() =>
87-
isExpanded.value ? queueStore.flatTasks : queueStore.tasks
103+
isInFolderView.value
104+
? folderTask.value
105+
? folderTask.value.flatten()
106+
: []
107+
: isExpanded.value
108+
? queueStore.flatTasks
109+
: queueStore.tasks
88110
)
89111
const allGalleryItems = computed(() =>
90112
allTasks.value.flatMap((task: TaskItemImpl) => {
@@ -129,9 +151,13 @@ useResizeObserver(scrollContainer, () => {
129151
})
130152
})
131153
154+
const updateVisibleTasks = () => {
155+
visibleTasks.value = allTasks.value.slice(0, ITEMS_PER_PAGE)
156+
}
157+
132158
const toggleExpanded = () => {
133159
isExpanded.value = !isExpanded.value
134-
visibleTasks.value = allTasks.value.slice(0, ITEMS_PER_PAGE)
160+
updateVisibleTasks()
135161
}
136162
137163
const removeTask = (task: TaskItemImpl) => {
@@ -173,7 +199,7 @@ const confirmRemoveAll = (event: Event) => {
173199
174200
const onStatus = async () => {
175201
await queueStore.update()
176-
visibleTasks.value = allTasks.value.slice(0, ITEMS_PER_PAGE)
202+
updateVisibleTasks()
177203
}
178204
179205
const menu = ref(null)
@@ -182,7 +208,8 @@ const menuItems = computed<MenuItem[]>(() => [
182208
{
183209
label: t('delete'),
184210
icon: 'pi pi-trash',
185-
command: () => menuTargetTask.value && removeTask(menuTargetTask.value)
211+
command: () => menuTargetTask.value && removeTask(menuTargetTask.value),
212+
disabled: isExpanded.value || isInFolderView.value
186213
},
187214
{
188215
label: t('loadWorkflow'),
@@ -208,6 +235,16 @@ const handlePreview = (task: TaskItemImpl) => {
208235
)
209236
}
210237
238+
const enterFolderView = (task: TaskItemImpl) => {
239+
folderTask.value = task
240+
updateVisibleTasks()
241+
}
242+
243+
const exitFolderView = () => {
244+
folderTask.value = null
245+
updateVisibleTasks()
246+
}
247+
211248
onMounted(() => {
212249
api.addEventListener('status', onStatus)
213250
queueStore.update()
@@ -225,7 +262,7 @@ watch(
225262
visibleTasks.value.length === 0 ||
226263
visibleTasks.value.length > newTasks.length
227264
) {
228-
visibleTasks.value = newTasks.slice(0, ITEMS_PER_PAGE)
265+
updateVisibleTasks()
229266
}
230267
231268
nextTick(() => {

src/components/sidebar/tabs/queue/TaskItem.vue

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,20 @@
3838
</Tag>
3939
</div>
4040
<div class="tag-wrapper">
41-
<Tag v-if="task.isHistory && flatOutputs.length > 1">
42-
<span>{{ flatOutputs.length }}</span>
43-
</Tag>
41+
<Button
42+
v-if="task.isHistory && flatOutputs.length > 1"
43+
outlined
44+
@click="handleOutputLengthClick"
45+
>
46+
<span style="font-weight: bold">{{ flatOutputs.length }}</span>
47+
</Button>
4448
</div>
4549
</div>
4650
</div>
4751
</template>
4852

4953
<script setup lang="ts">
54+
import Button from 'primevue/button'
5055
import Tag from 'primevue/tag'
5156
import ResultItem from './ResultItem.vue'
5257
import { TaskItemDisplayStatus, type TaskItemImpl } from '@/stores/queueStore'
@@ -61,6 +66,7 @@ const flatOutputs = props.task.flatOutputs
6166
const emit = defineEmits<{
6267
(e: 'contextmenu', value: { task: TaskItemImpl; event: MouseEvent }): void
6368
(e: 'preview', value: TaskItemImpl): void
69+
(e: 'task-output-length-clicked', value: TaskItemImpl): void
6470
}>()
6571
6672
const handleContextMenu = (e: MouseEvent) => {
@@ -71,6 +77,10 @@ const handlePreview = () => {
7177
emit('preview', props.task)
7278
}
7379
80+
const handleOutputLengthClick = () => {
81+
emit('task-output-length-clicked', props.task)
82+
}
83+
7484
const taskTagSeverity = (status: TaskItemDisplayStatus) => {
7585
switch (status) {
7686
case TaskItemDisplayStatus.Pending:

src/i18n.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const messages = {
2525
sortOrder: 'Sort Order'
2626
},
2727
queueTab: {
28-
showFlatList: 'Show Flat List'
28+
showFlatList: 'Show Flat List',
29+
backToAllTasks: 'Back to All Tasks'
2930
}
3031
}
3132
},
@@ -51,7 +52,8 @@ const messages = {
5152
sortOrder: '排序顺序'
5253
},
5354
queueTab: {
54-
showFlatList: '平铺结果'
55+
showFlatList: '平铺结果',
56+
backToAllTasks: '返回'
5557
}
5658
}
5759
}

src/stores/queueStore.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,33 @@ export class TaskItemImpl {
219219
app.nodeOutputs = toRaw(this.outputs)
220220
}
221221
}
222+
223+
public flatten(): TaskItemImpl[] {
224+
if (this.displayStatus !== TaskItemDisplayStatus.Completed) {
225+
return [this]
226+
}
227+
228+
return this.flatOutputs.map(
229+
(output: ResultItemImpl, i: number) =>
230+
new TaskItemImpl(
231+
this.taskType,
232+
[
233+
this.queueIndex,
234+
`${this.promptId}-${i}`,
235+
this.promptInputs,
236+
this.extraData,
237+
this.outputsToExecute
238+
],
239+
this.status,
240+
{
241+
[output.nodeId]: {
242+
[output.mediaType]: [output]
243+
}
244+
},
245+
[output]
246+
)
247+
)
248+
}
222249
}
223250

224251
interface State {
@@ -244,32 +271,7 @@ export const useQueueStore = defineStore('queue', {
244271
]
245272
},
246273
flatTasks(): TaskItemImpl[] {
247-
return this.tasks.flatMap((task: TaskItemImpl) => {
248-
if (task.displayStatus !== TaskItemDisplayStatus.Completed) {
249-
return [task]
250-
}
251-
252-
return task.flatOutputs.map(
253-
(output: ResultItemImpl, i: number) =>
254-
new TaskItemImpl(
255-
task.taskType,
256-
[
257-
task.queueIndex,
258-
`${task.promptId}-${i}`,
259-
task.promptInputs,
260-
task.extraData,
261-
task.outputsToExecute
262-
],
263-
task.status,
264-
{
265-
[output.nodeId]: {
266-
[output.mediaType]: [output]
267-
}
268-
},
269-
[output]
270-
)
271-
)
272-
})
274+
return this.tasks.flatMap((task: TaskItemImpl) => task.flatten())
273275
},
274276
lastHistoryQueueIndex(state) {
275277
return state.historyTasks.length ? state.historyTasks[0].queueIndex : -1

0 commit comments

Comments
 (0)