[backport cloud/1.32] Use shared button components in queue overlay (#6855)

Backport of #6793 to `cloud/1.32`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6855-backport-cloud-1-32-Use-shared-button-components-in-queue-overlay-2b46d73d365081d69a6edd5e08e19edd)
by [Unito](https://www.unito.io)

Co-authored-by: Benjamin Lu <benceruleanlu@proton.me>
This commit is contained in:
Comfy Org PR Bot
2025-11-24 04:19:56 +09:00
committed by GitHub
parent e4ef961876
commit 66509b81c4
11 changed files with 189 additions and 138 deletions

View File

@@ -24,7 +24,7 @@ import {
import { cn } from '@/utils/tailwindUtil' import { cn } from '@/utils/tailwindUtil'
interface IconButtonProps extends BaseButtonProps { interface IconButtonProps extends BaseButtonProps {
onClick: (event: Event) => void onClick?: (event: MouseEvent) => void
} }
defineOptions({ defineOptions({

View File

@@ -47,7 +47,7 @@ const {
} = defineProps<IconTextButtonProps>() } = defineProps<IconTextButtonProps>()
const buttonStyle = computed(() => { const buttonStyle = computed(() => {
const baseClasses = `${getBaseButtonClasses()} justify-start! gap-2` const baseClasses = `${getBaseButtonClasses()} justify-start gap-2`
const sizeClasses = getButtonSizeClasses(size) const sizeClasses = getButtonSizeClasses(size)
const typeClasses = border const typeClasses = border
? getBorderButtonTypeClasses(type) ? getBorderButtonTypeClasses(type)

View File

@@ -1,8 +1,10 @@
<template> <template>
<button <IconButton
type="button" type="secondary"
class="group flex w-full items-center justify-between gap-3 rounded-lg border-0 bg-secondary-background p-1 text-left transition-colors duration-200 ease-in-out hover:cursor-pointer hover:bg-secondary-background-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-background" size="fit-content"
class="group w-full justify-between gap-3 rounded-lg p-1 text-left font-normal hover:cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-background"
:aria-label="props.ariaLabel" :aria-label="props.ariaLabel"
@click="emit('click', $event)"
> >
<span class="inline-flex items-center gap-2"> <span class="inline-flex items-center gap-2">
<span v-if="props.mode === 'allFailed'" class="inline-flex items-center"> <span v-if="props.mode === 'allFailed'" class="inline-flex items-center">
@@ -76,10 +78,11 @@
> >
<i class="icon-[lucide--chevron-down] block size-4 leading-none" /> <i class="icon-[lucide--chevron-down] block size-4 leading-none" />
</span> </span>
</button> </IconButton>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import IconButton from '@/components/button/IconButton.vue'
import type { import type {
CompletionSummary, CompletionSummary,
CompletionSummaryMode CompletionSummaryMode
@@ -96,4 +99,8 @@ type Props = {
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
thumbnailUrls: () => [] thumbnailUrls: () => []
}) })
const emit = defineEmits<{
(e: 'click', event: MouseEvent): void
}>()
</script> </script>

View File

@@ -42,17 +42,19 @@
t('sideToolbar.queueProgressOverlay.running') t('sideToolbar.queueProgressOverlay.running')
}}</span> }}</span>
</span> </span>
<button <IconButton
v-if="runningCount > 0" v-if="runningCount > 0"
v-tooltip.top="cancelJobTooltip" v-tooltip.top="cancelJobTooltip"
class="inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background p-0 transition-colors hover:bg-destructive-background" type="secondary"
size="sm"
class="size-6 bg-secondary-background hover:bg-destructive-background"
:aria-label="t('sideToolbar.queueProgressOverlay.interruptAll')" :aria-label="t('sideToolbar.queueProgressOverlay.interruptAll')"
@click="$emit('interruptAll')" @click="$emit('interruptAll')"
> >
<i <i
class="icon-[lucide--x] block size-4 leading-none text-text-primary" class="icon-[lucide--x] block size-4 leading-none text-text-primary"
/> />
</button> </IconButton>
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -62,26 +64,28 @@
t('sideToolbar.queueProgressOverlay.queuedSuffix') t('sideToolbar.queueProgressOverlay.queuedSuffix')
}}</span> }}</span>
</span> </span>
<button <IconButton
v-if="queuedCount > 0" v-if="queuedCount > 0"
v-tooltip.top="clearQueueTooltip" v-tooltip.top="clearQueueTooltip"
class="inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background p-0 transition-colors hover:bg-destructive-background" type="secondary"
size="sm"
class="size-6 bg-secondary-background hover:bg-destructive-background"
:aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')" :aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')"
@click="$emit('clearQueued')" @click="$emit('clearQueued')"
> >
<i <i
class="icon-[lucide--list-x] block size-4 leading-none text-text-primary" class="icon-[lucide--list-x] block size-4 leading-none text-text-primary"
/> />
</button> </IconButton>
</div> </div>
</div> </div>
<button <TextButton
class="inline-flex h-6 min-w-[120px] flex-1 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background px-2 py-0 text-[12px] text-text-primary hover:bg-secondary-background-hover hover:opacity-90" class="h-6 min-w-[120px] flex-1 px-2 py-0 text-[12px]"
type="secondary"
:label="t('sideToolbar.queueProgressOverlay.viewAllJobs')"
@click="$emit('viewAllJobs')" @click="$emit('viewAllJobs')"
> />
{{ t('sideToolbar.queueProgressOverlay.viewAllJobs') }}
</button>
</div> </div>
</div> </div>
</template> </template>
@@ -90,6 +94,8 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import TextButton from '@/components/button/TextButton.vue'
import { buildTooltipConfig } from '@/composables/useTooltipConfig' import { buildTooltipConfig } from '@/composables/useTooltipConfig'
defineProps<{ defineProps<{

View File

@@ -8,17 +8,20 @@
/> />
<div class="flex items-center justify-between px-3"> <div class="flex items-center justify-between px-3">
<button <IconTextButton
class="inline-flex grow cursor-pointer items-center justify-center gap-1 rounded border-0 bg-secondary-background p-2 text-center font-inter text-[12px] leading-none text-text-primary hover:bg-secondary-background-hover hover:opacity-90" class="grow gap-1 p-2 text-center font-inter text-[12px] leading-none hover:opacity-90 justify-center"
type="secondary"
:label="t('sideToolbar.queueProgressOverlay.showAssets')"
:aria-label="t('sideToolbar.queueProgressOverlay.showAssets')" :aria-label="t('sideToolbar.queueProgressOverlay.showAssets')"
@click="$emit('showAssets')" @click="$emit('showAssets')"
> >
<div <template #icon>
class="pointer-events-none block size-4 shrink-0 leading-none icon-[comfy--image-ai-edit]" <div
aria-hidden="true" class="pointer-events-none block size-4 shrink-0 leading-none icon-[comfy--image-ai-edit]"
/> aria-hidden="true"
<span>{{ t('sideToolbar.queueProgressOverlay.showAssets') }}</span> />
</button> </template>
</IconTextButton>
<div class="ml-4 inline-flex items-center"> <div class="ml-4 inline-flex items-center">
<div <div
class="inline-flex h-6 items-center text-[12px] leading-none text-text-primary opacity-90" class="inline-flex h-6 items-center text-[12px] leading-none text-text-primary opacity-90"
@@ -28,16 +31,18 @@
t('sideToolbar.queueProgressOverlay.queuedSuffix') t('sideToolbar.queueProgressOverlay.queuedSuffix')
}}</span> }}</span>
</div> </div>
<button <IconButton
v-if="queuedCount > 0" v-if="queuedCount > 0"
class="group ml-2 inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background p-0 transition-colors hover:bg-destructive-background" class="group ml-2 size-6 bg-secondary-background hover:bg-destructive-background"
type="secondary"
size="sm"
:aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')" :aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')"
@click="$emit('clearQueued')" @click="$emit('clearQueued')"
> >
<i <i
class="pointer-events-none icon-[lucide--list-x] block size-4 leading-none text-text-primary transition-colors group-hover:text-base-background" class="pointer-events-none icon-[lucide--list-x] block size-4 leading-none text-text-primary transition-colors group-hover:text-base-background"
/> />
</button> </IconButton>
</div> </div>
</div> </div>
@@ -75,6 +80,8 @@
import { ref } from 'vue' import { ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import type { import type {
JobGroup, JobGroup,
JobListItem, JobListItem,

View File

@@ -18,16 +18,18 @@
</span> </span>
</div> </div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<button <IconButton
v-tooltip.top="moreTooltipConfig" v-tooltip.top="moreTooltipConfig"
class="inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 hover:bg-secondary-background hover:opacity-100" type="transparent"
size="sm"
class="size-6 bg-transparent hover:bg-secondary-background hover:opacity-100"
:aria-label="t('sideToolbar.queueProgressOverlay.moreOptions')" :aria-label="t('sideToolbar.queueProgressOverlay.moreOptions')"
@click="onMoreClick" @click="onMoreClick"
> >
<i <i
class="icon-[lucide--more-horizontal] block size-4 leading-none text-text-secondary" class="icon-[lucide--more-horizontal] block size-4 leading-none text-text-secondary"
/> />
</button> </IconButton>
<Popover <Popover
ref="morePopoverRef" ref="morePopoverRef"
:dismissable="true" :dismissable="true"
@@ -45,18 +47,19 @@
<div <div
class="flex flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3 font-inter" class="flex flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3 font-inter"
> >
<button <IconTextButton
class="inline-flex w-full cursor-pointer items-center justify-start gap-2 rounded-lg border-0 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90" class="w-full justify-start gap-2 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90"
type="transparent"
:label="t('sideToolbar.queueProgressOverlay.clearHistory')"
:aria-label="t('sideToolbar.queueProgressOverlay.clearHistory')" :aria-label="t('sideToolbar.queueProgressOverlay.clearHistory')"
@click="onClearHistoryFromMenu" @click="onClearHistoryFromMenu"
> >
<i <template #icon>
class="icon-[lucide--file-x-2] block size-4 leading-none text-text-secondary" <i
/> class="icon-[lucide--file-x-2] block size-4 leading-none text-text-secondary"
<span>{{ />
t('sideToolbar.queueProgressOverlay.clearHistory') </template>
}}</span> </IconTextButton>
</button>
</div> </div>
</Popover> </Popover>
</div> </div>
@@ -69,6 +72,8 @@ import type { PopoverMethods } from 'primevue/popover'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import { buildTooltipConfig } from '@/composables/useTooltipConfig' import { buildTooltipConfig } from '@/composables/useTooltipConfig'
defineProps<{ defineProps<{

View File

@@ -8,13 +8,15 @@
<p class="m-0 text-[14px] font-normal leading-none"> <p class="m-0 text-[14px] font-normal leading-none">
{{ t('sideToolbar.queueProgressOverlay.clearHistoryDialogTitle') }} {{ t('sideToolbar.queueProgressOverlay.clearHistoryDialogTitle') }}
</p> </p>
<button <IconButton
class="inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-text-secondary transition hover:bg-secondary-background hover:opacity-100" type="transparent"
size="sm"
class="size-6 bg-transparent text-text-secondary hover:bg-secondary-background hover:opacity-100"
:aria-label="t('g.close')" :aria-label="t('g.close')"
@click="onCancel" @click="onCancel"
> >
<i class="icon-[lucide--x] block size-4 leading-none" /> <i class="icon-[lucide--x] block size-4 leading-none" />
</button> </IconButton>
</header> </header>
<div class="flex flex-col gap-4 px-4 py-4 text-[14px] text-text-secondary"> <div class="flex flex-col gap-4 px-4 py-4 text-[14px] text-text-secondary">
@@ -30,21 +32,19 @@
<footer class="flex items-center justify-end px-4 py-4"> <footer class="flex items-center justify-end px-4 py-4">
<div class="flex items-center gap-4 text-[14px] leading-none"> <div class="flex items-center gap-4 text-[14px] leading-none">
<button <TextButton
class="inline-flex min-h-[24px] cursor-pointer items-center rounded-md border-0 bg-transparent px-1 py-1 text-[14px] leading-[1] text-text-secondary transition hover:text-text-primary" class="min-h-[24px] px-1 py-1 text-[14px] leading-[1] text-text-secondary hover:text-text-primary"
:aria-label="t('g.cancel')" type="transparent"
:label="t('g.cancel')"
@click="onCancel" @click="onCancel"
> />
{{ t('g.cancel') }} <TextButton
</button> class="min-h-[32px] px-4 py-2 text-[12px] font-normal leading-[1]"
<button type="secondary"
class="inline-flex min-h-[32px] items-center rounded-lg border-0 bg-secondary-background px-4 py-2 text-[12px] font-normal leading-[1] text-text-primary transition hover:bg-secondary-background-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-60" :label="t('g.clear')"
:aria-label="t('g.clear')"
:disabled="isClearing" :disabled="isClearing"
@click="onConfirm" @click="onConfirm"
> />
{{ t('g.clear') }}
</button>
</div> </div>
</footer> </footer>
</section> </section>
@@ -54,6 +54,8 @@
import { ref } from 'vue' import { ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import TextButton from '@/components/button/TextButton.vue'
import { useErrorHandling } from '@/composables/useErrorHandling' import { useErrorHandling } from '@/composables/useErrorHandling'
import { useDialogStore } from '@/stores/dialogStore' import { useDialogStore } from '@/stores/dialogStore'
import { useQueueStore } from '@/stores/queueStore' import { useQueueStore } from '@/stores/queueStore'

View File

@@ -20,21 +20,24 @@
<div v-if="entry.kind === 'divider'" class="px-2 py-1"> <div v-if="entry.kind === 'divider'" class="px-2 py-1">
<div class="h-px bg-interface-stroke" /> <div class="h-px bg-interface-stroke" />
</div> </div>
<button <IconTextButton
v-else v-else
class="inline-flex w-full cursor-pointer items-center justify-start gap-2 rounded-lg border-0 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary transition-colors duration-150 hover:bg-interface-panel-hover-surface" class="w-full justify-start gap-2 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-interface-panel-hover-surface"
type="transparent"
:label="entry.label"
:aria-label="entry.label" :aria-label="entry.label"
@click="onEntry(entry)" @click="onEntry(entry)"
> >
<i <template #icon>
v-if="entry.icon" <i
:class="[ v-if="entry.icon"
entry.icon, :class="[
'block size-4 shrink-0 leading-none text-text-secondary' entry.icon,
]" 'block size-4 shrink-0 leading-none text-text-secondary'
/> ]"
<span>{{ entry.label }}</span> />
</button> </template>
</IconTextButton>
</template> </template>
</div> </div>
</Popover> </Popover>
@@ -44,6 +47,7 @@
import Popover from 'primevue/popover' import Popover from 'primevue/popover'
import { ref } from 'vue' import { ref } from 'vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import type { MenuEntry } from '@/composables/queue/useJobMenu' import type { MenuEntry } from '@/composables/queue/useJobMenu'
defineProps<{ entries: MenuEntry[] }>() defineProps<{ entries: MenuEntry[] }>()

View File

@@ -20,17 +20,18 @@
class="flex min-w-0 items-center text-[0.75rem] leading-normal font-normal text-text-secondary" class="flex min-w-0 items-center text-[0.75rem] leading-normal font-normal text-text-secondary"
> >
<span class="block min-w-0 truncate">{{ row.value }}</span> <span class="block min-w-0 truncate">{{ row.value }}</span>
<button <IconButton
v-if="row.canCopy" v-if="row.canCopy"
type="button" type="transparent"
class="ml-2 inline-flex size-6 items-center justify-center rounded border-0 bg-transparent p-0 hover:opacity-90" size="sm"
class="ml-2 size-6 bg-transparent hover:opacity-90"
:aria-label="copyAriaLabel" :aria-label="copyAriaLabel"
@click.stop="copyJobId" @click.stop="copyJobId"
> >
<i <i
class="icon-[lucide--copy] block size-4 leading-none text-text-secondary" class="icon-[lucide--copy] block size-4 leading-none text-text-secondary"
/> />
</button> </IconButton>
</div> </div>
</template> </template>
</div> </div>
@@ -60,25 +61,31 @@
{{ t('queue.jobDetails.errorMessage') }} {{ t('queue.jobDetails.errorMessage') }}
</div> </div>
<div class="flex items-center justify-between gap-4"> <div class="flex items-center justify-between gap-4">
<button <IconTextButton
type="button" class="h-6 justify-start gap-2 bg-transparent px-0 text-[0.75rem] leading-none text-text-secondary hover:opacity-90"
class="inline-flex h-6 items-center justify-center gap-2 rounded border-none bg-transparent px-0 text-[0.75rem] leading-none text-text-secondary hover:opacity-90" type="transparent"
:label="copyAriaLabel"
:aria-label="copyAriaLabel" :aria-label="copyAriaLabel"
icon-position="right"
@click.stop="copyErrorMessage" @click.stop="copyErrorMessage"
> >
<span>{{ copyAriaLabel }}</span> <template #icon>
<i class="icon-[lucide--copy] block size-3.5 leading-none" /> <i class="icon-[lucide--copy] block size-3.5 leading-none" />
</button> </template>
<button </IconTextButton>
type="button" <IconTextButton
class="inline-flex h-6 items-center justify-center gap-2 rounded border-none bg-transparent px-0 text-[0.75rem] leading-none text-text-secondary hover:opacity-90" class="h-6 justify-start gap-2 bg-transparent px-0 text-[0.75rem] leading-none text-text-secondary hover:opacity-90"
type="transparent"
:label="t('queue.jobDetails.report')"
icon-position="right"
@click.stop="reportJobError" @click.stop="reportJobError"
> >
<span>{{ t('queue.jobDetails.report') }}</span> <template #icon>
<i <i
class="icon-[lucide--message-circle-warning] block size-3.5 leading-none" class="icon-[lucide--message-circle-warning] block size-3.5 leading-none"
/> />
</button> </template>
</IconTextButton>
</div> </div>
<div <div
class="col-span-2 mt-2 rounded bg-interface-panel-hover-surface px-4 py-2 text-[0.75rem] leading-normal text-text-secondary" class="col-span-2 mt-2 rounded bg-interface-panel-hover-surface px-4 py-2 text-[0.75rem] leading-normal text-text-secondary"
@@ -94,6 +101,8 @@
import { computed, onMounted, onUnmounted, ref } from 'vue' import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import { useCopyToClipboard } from '@/composables/useCopyToClipboard' import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
import { t } from '@/i18n' import { t } from '@/i18n'
import { isCloud } from '@/platform/distribution/types' import { isCloud } from '@/platform/distribution/types'

View File

@@ -2,26 +2,26 @@
<div class="flex items-center justify-between gap-2 px-3"> <div class="flex items-center justify-between gap-2 px-3">
<div class="min-w-0 flex-1 overflow-x-auto"> <div class="min-w-0 flex-1 overflow-x-auto">
<div class="inline-flex items-center gap-1 whitespace-nowrap"> <div class="inline-flex items-center gap-1 whitespace-nowrap">
<button <TextButton
v-for="tab in visibleJobTabs" v-for="tab in visibleJobTabs"
:key="tab" :key="tab"
class="h-6 cursor-pointer rounded border-0 px-3 py-1 text-[12px] leading-none hover:opacity-90" class="h-6 px-3 py-1 text-[12px] leading-none hover:opacity-90"
:type="selectedJobTab === tab ? 'secondary' : 'transparent'"
:class="[ :class="[
selectedJobTab === tab selectedJobTab === tab ? 'text-text-primary' : 'text-text-secondary'
? 'bg-secondary-background text-text-primary'
: 'bg-transparent text-text-secondary'
]" ]"
:label="tabLabel(tab)"
@click="$emit('update:selectedJobTab', tab)" @click="$emit('update:selectedJobTab', tab)"
> />
{{ tabLabel(tab) }}
</button>
</div> </div>
</div> </div>
<div class="ml-2 flex shrink-0 items-center gap-2"> <div class="ml-2 flex shrink-0 items-center gap-2">
<button <IconButton
v-if="showWorkflowFilter" v-if="showWorkflowFilter"
v-tooltip.top="filterTooltipConfig" v-tooltip.top="filterTooltipConfig"
class="relative inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background p-0 hover:bg-secondary-background-hover hover:opacity-90" type="secondary"
size="sm"
class="relative size-6 bg-secondary-background hover:bg-secondary-background-hover hover:opacity-90"
:aria-label="t('sideToolbar.queueProgressOverlay.filterJobs')" :aria-label="t('sideToolbar.queueProgressOverlay.filterJobs')"
@click="onFilterClick" @click="onFilterClick"
> >
@@ -32,7 +32,7 @@
v-if="selectedWorkflowFilter !== 'all'" v-if="selectedWorkflowFilter !== 'all'"
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground" class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
/> />
</button> </IconButton>
<Popover <Popover
v-if="showWorkflowFilter" v-if="showWorkflowFilter"
ref="filterPopoverRef" ref="filterPopoverRef"
@@ -51,46 +51,48 @@
<div <div
class="flex min-w-[12rem] flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3" class="flex min-w-[12rem] flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3"
> >
<button <IconTextButton
class="inline-flex w-full cursor-pointer items-center justify-start gap-1 rounded-lg border-0 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90" class="w-full justify-between gap-1 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90"
type="transparent"
icon-position="right"
:label="t('sideToolbar.queueProgressOverlay.filterAllWorkflows')"
:aria-label=" :aria-label="
t('sideToolbar.queueProgressOverlay.filterAllWorkflows') t('sideToolbar.queueProgressOverlay.filterAllWorkflows')
" "
@click="selectWorkflowFilter('all')" @click="selectWorkflowFilter('all')"
> >
<span>{{ <template #icon>
t('sideToolbar.queueProgressOverlay.filterAllWorkflows')
}}</span>
<span class="ml-auto inline-flex items-center">
<i <i
v-if="selectedWorkflowFilter === 'all'" v-if="selectedWorkflowFilter === 'all'"
class="icon-[lucide--check] block size-4 leading-none text-text-secondary" class="icon-[lucide--check] block size-4 leading-none text-text-secondary"
/> />
</span> </template>
</button> </IconTextButton>
<div class="mx-2 mt-1 h-px" /> <div class="mx-2 mt-1 h-px" />
<button <IconTextButton
class="inline-flex w-full cursor-pointer items-center justify-start gap-1 rounded-lg border-0 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90" class="w-full justify-between gap-1 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90"
type="transparent"
icon-position="right"
:label="t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow')"
:aria-label=" :aria-label="
t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow') t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow')
" "
@click="selectWorkflowFilter('current')" @click="selectWorkflowFilter('current')"
> >
<span>{{ <template #icon>
t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow')
}}</span>
<span class="ml-auto inline-flex items-center">
<i <i
v-if="selectedWorkflowFilter === 'current'" v-if="selectedWorkflowFilter === 'current'"
class="icon-[lucide--check] block size-4 leading-none text-text-secondary" class="icon-[lucide--check] block size-4 leading-none text-text-secondary"
/> />
</span> </template>
</button> </IconTextButton>
</div> </div>
</Popover> </Popover>
<button <IconButton
v-tooltip.top="sortTooltipConfig" v-tooltip.top="sortTooltipConfig"
class="relative inline-flex size-6 cursor-pointer items-center justify-center rounded border-0 bg-secondary-background p-0 hover:bg-secondary-background-hover hover:opacity-90" type="secondary"
size="sm"
class="relative size-6 bg-secondary-background hover:bg-secondary-background-hover hover:opacity-90"
:aria-label="t('sideToolbar.queueProgressOverlay.sortJobs')" :aria-label="t('sideToolbar.queueProgressOverlay.sortJobs')"
@click="onSortClick" @click="onSortClick"
> >
@@ -101,7 +103,7 @@
v-if="selectedSortMode !== 'mostRecent'" v-if="selectedSortMode !== 'mostRecent'"
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground" class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
/> />
</button> </IconButton>
<Popover <Popover
ref="sortPopoverRef" ref="sortPopoverRef"
:dismissable="true" :dismissable="true"
@@ -120,19 +122,21 @@
class="flex min-w-[12rem] flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3" class="flex min-w-[12rem] flex-col items-stretch rounded-lg border border-interface-stroke bg-interface-panel-surface px-2 py-3"
> >
<template v-for="(mode, index) in jobSortModes" :key="mode"> <template v-for="(mode, index) in jobSortModes" :key="mode">
<button <IconTextButton
class="inline-flex w-full cursor-pointer items-center justify-start gap-1 rounded-lg border-0 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90" class="w-full justify-between gap-1 bg-transparent p-2 font-inter text-[12px] leading-none text-text-primary hover:bg-transparent hover:opacity-90"
type="transparent"
icon-position="right"
:label="sortLabel(mode)"
:aria-label="sortLabel(mode)" :aria-label="sortLabel(mode)"
@click="selectSortMode(mode)" @click="selectSortMode(mode)"
> >
<span>{{ sortLabel(mode) }}</span> <template #icon>
<span class="ml-auto inline-flex items-center">
<i <i
v-if="selectedSortMode === mode" v-if="selectedSortMode === mode"
class="icon-[lucide--check] block size-4 leading-none text-text-secondary" class="icon-[lucide--check] block size-4 leading-none text-text-secondary"
/> />
</span> </template>
</button> </IconTextButton>
<div <div
v-if="index < jobSortModes.length - 1" v-if="index < jobSortModes.length - 1"
class="mx-2 mt-1 h-px" class="mx-2 mt-1 h-px"
@@ -149,6 +153,9 @@ import Popover from 'primevue/popover'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import TextButton from '@/components/button/TextButton.vue'
import { jobSortModes, jobTabs } from '@/composables/queue/useJobList' import { jobSortModes, jobTabs } from '@/composables/queue/useJobList'
import type { JobSortMode, JobTab } from '@/composables/queue/useJobList' import type { JobSortMode, JobTab } from '@/composables/queue/useJobList'
import { buildTooltipConfig } from '@/composables/useTooltipConfig' import { buildTooltipConfig } from '@/composables/useTooltipConfig'

View File

@@ -108,45 +108,47 @@
key="actions" key="actions"
class="inline-flex items-center gap-2 pr-1" class="inline-flex items-center gap-2 pr-1"
> >
<button <IconButton
v-if="props.state === 'failed' && computedShowClear" v-if="props.state === 'failed' && computedShowClear"
v-tooltip.top="deleteTooltipConfig" v-tooltip.top="deleteTooltipConfig"
type="button" type="transparent"
class="inline-flex h-6 transform cursor-pointer items-center gap-1 rounded border-0 bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background hover:opacity-95" size="sm"
class="h-6 transform gap-1 rounded bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background hover:opacity-95"
:aria-label="t('g.delete')" :aria-label="t('g.delete')"
@click.stop="emit('delete')" @click.stop="emit('delete')"
> >
<i class="icon-[lucide--trash-2] size-4" /> <i class="icon-[lucide--trash-2] size-4" />
</button> </IconButton>
<button <IconButton
v-else-if="props.state !== 'completed' && computedShowClear" v-else-if="props.state !== 'completed' && computedShowClear"
v-tooltip.top="cancelTooltipConfig" v-tooltip.top="cancelTooltipConfig"
type="button" type="transparent"
class="inline-flex h-6 transform cursor-pointer items-center gap-1 rounded border-0 bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background hover:opacity-95" size="sm"
class="h-6 transform gap-1 rounded bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background hover:opacity-95"
:aria-label="t('g.cancel')" :aria-label="t('g.cancel')"
@click.stop="emit('cancel')" @click.stop="emit('cancel')"
> >
<i class="icon-[lucide--x] size-4" /> <i class="icon-[lucide--x] size-4" />
</button> </IconButton>
<button <TextButton
v-else-if="props.state === 'completed'" v-else-if="props.state === 'completed'"
type="button" class="h-6 transform gap-1 rounded bg-modal-card-button-surface px-2 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:opacity-95"
class="inline-flex h-6 transform cursor-pointer items-center gap-1 rounded border-0 bg-modal-card-button-surface px-2 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:opacity-95" type="transparent"
:label="t('menuLabels.View')"
:aria-label="t('menuLabels.View')" :aria-label="t('menuLabels.View')"
@click.stop="emit('view')" @click.stop="emit('view')"
> />
<span>{{ t('menuLabels.View') }}</span> <IconButton
</button>
<button
v-if="props.showMenu !== undefined ? props.showMenu : true" v-if="props.showMenu !== undefined ? props.showMenu : true"
v-tooltip.top="moreTooltipConfig" v-tooltip.top="moreTooltipConfig"
type="button" type="transparent"
class="inline-flex h-6 transform cursor-pointer items-center gap-1 rounded border-0 bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:opacity-95" size="sm"
class="h-6 transform gap-1 rounded bg-modal-card-button-surface px-1 py-0 text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:opacity-95"
:aria-label="t('g.more')" :aria-label="t('g.more')"
@click.stop="emit('menu', $event)" @click.stop="emit('menu', $event)"
> >
<i class="icon-[lucide--more-horizontal] size-4" /> <i class="icon-[lucide--more-horizontal] size-4" />
</button> </IconButton>
</div> </div>
<div v-else key="secondary" class="pr-2"> <div v-else key="secondary" class="pr-2">
<slot name="secondary">{{ props.rightText }}</slot> <slot name="secondary">{{ props.rightText }}</slot>
@@ -161,6 +163,8 @@
import { computed, nextTick, ref, watch } from 'vue' import { computed, nextTick, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import TextButton from '@/components/button/TextButton.vue'
import JobDetailsPopover from '@/components/queue/job/JobDetailsPopover.vue' import JobDetailsPopover from '@/components/queue/job/JobDetailsPopover.vue'
import QueueAssetPreview from '@/components/queue/job/QueueAssetPreview.vue' import QueueAssetPreview from '@/components/queue/job/QueueAssetPreview.vue'
import { buildTooltipConfig } from '@/composables/useTooltipConfig' import { buildTooltipConfig } from '@/composables/useTooltipConfig'