mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-06 06:01:58 +00:00
*PR Created by the Glary-Bot Agent* --- ## Summary Registers a new nightly feature survey for the Queue Progress Overlay using the existing feature-survey registry (same pattern as the merged node-search survey, PRs #8175/#8355/#9934). - New registry entry `queue-progress-overlay` → Typeform `HZ5saxry`, threshold **16**, 5s display delay. - `trackFeatureUsed()` wired at the major user-initiated handlers inside the overlay so the survey triggers regardless of panel location (floating-right v1 or docked-left v2). - Run button and other ActionBar items that the overlay pops over from are deliberately **not** tracked — tracking is scoped to interactions that originate inside the job panel / queue progress overlay itself. ## Tracked interactions Both variants share most sub-components, so tracking is instrumented once at each logical surface: - **`QueueProgressOverlay.vue`** (v1 container): `viewAllJobs`, `interruptAll`, `cancelQueuedWorkflows`, `onClearHistoryFromMenu`, `toggleAssetsSidebar`, `onCancelItem`, `onDeleteItem`, `inspectJobAsset` - **`QueueOverlayExpanded.vue`**: job tab switches - **`JobHistorySidebarTab.vue`** (v2 docked): job tab switches, `clearQueuedWorkflows`, `onClearHistory`, `onCancelItem`, `onDeleteItem`, `onViewItem` - **`JobFilterActions.vue`** (shared): workflow filter + sort mode selections - **`JobHistoryActionsMenu.vue`** (shared): docked-history toggle + run-progress-bar toggle Deliberately **not tracked** to keep the signal clean: - Hover handlers (ambient preview behaviour) - Search-box keystrokes (debounced typing) - Context menu open and menu-item dispatch — menu actions either bubble through already-tracked terminal handlers (e.g. inspect-asset → `onViewItem`) or are secondary operations (copy-id, open-workflow, download). Avoids double-counting per code review feedback. ## How it works (inherits from existing infrastructure) 1. `surveyRegistry.ts` drives `NightlySurveyController` → `NightlySurveyPopover`, which handles the Typeform embed. 2. Eligibility already gated on `isNightly && !isCloud && !isDesktop`, once-per-user, 4-day global cooldown across all surveys, and opt-out. 3. Typeform response routing to #C0ALLT6Q3SQ is handled on the Typeform side. ## Verification - `pnpm typecheck` ✅ - `pnpm lint` ✅ (no new warnings) - `pnpm knip` ✅ - `pnpm test:unit` on `src/components/queue`, `src/components/sidebar/tabs/JobHistorySidebarTab`, `src/platform/surveys` → **123/123 passing** - Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck) all pass - Manual: dev server + backend boot cleanly, app loads without new runtime errors, `localStorage['Comfy.FeatureUsage']` layout verified to match what `useFeatureUsageTracker` writes ## Notes - Survey key `queue-progress-overlay` covers both v1 (floating-right) and v2 (docked-sidebar) per product guidance: _"This should trigger regardless of the location of the panel (docked from left or floating on right)."_ Both surfaces are the same product feature — the survey is intentionally scoped to the whole job-panel experience. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11560-feat-add-queue-progress-overlay-feature-survey-34b6d73d3650819a9a50fd67fd9b5941) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
116 lines
3.4 KiB
Vue
116 lines
3.4 KiB
Vue
<template>
|
|
<div class="flex w-full flex-col gap-4">
|
|
<QueueOverlayHeader
|
|
:header-title="headerTitle"
|
|
:queued-count="queuedCount"
|
|
@clear-history="$emit('clearHistory')"
|
|
@clear-queued="$emit('clearQueued')"
|
|
/>
|
|
|
|
<JobFiltersBar
|
|
:selected-job-tab="selectedJobTab"
|
|
:selected-workflow-filter="selectedWorkflowFilter"
|
|
:selected-sort-mode="selectedSortMode"
|
|
:has-failed-jobs="hasFailedJobs"
|
|
@show-assets="$emit('showAssets')"
|
|
@update:selected-job-tab="onUpdateSelectedJobTab"
|
|
@update:selected-workflow-filter="
|
|
$emit('update:selectedWorkflowFilter', $event)
|
|
"
|
|
@update:selected-sort-mode="$emit('update:selectedSortMode', $event)"
|
|
/>
|
|
|
|
<div class="min-h-0 flex-1">
|
|
<JobAssetsList
|
|
:displayed-job-groups="displayedJobGroups"
|
|
@cancel-item="onCancelItemEvent"
|
|
@delete-item="onDeleteItemEvent"
|
|
@view-item="$emit('viewItem', $event)"
|
|
@menu="onMenuItem"
|
|
/>
|
|
</div>
|
|
|
|
<JobContextMenu
|
|
ref="jobContextMenuRef"
|
|
:entries="jobMenuEntries"
|
|
@action="onJobMenuAction"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
|
|
import type {
|
|
JobGroup,
|
|
JobListItem,
|
|
JobSortMode,
|
|
JobTab
|
|
} from '@/composables/queue/useJobList'
|
|
import type { MenuEntry } from '@/composables/queue/useJobMenu'
|
|
import { useJobMenu } from '@/composables/queue/useJobMenu'
|
|
import { useErrorHandling } from '@/composables/useErrorHandling'
|
|
import { useSurveyFeatureTracking } from '@/platform/surveys/useSurveyFeatureTracking'
|
|
|
|
import QueueOverlayHeader from './QueueOverlayHeader.vue'
|
|
import JobContextMenu from './job/JobContextMenu.vue'
|
|
import JobAssetsList from './job/JobAssetsList.vue'
|
|
import JobFiltersBar from './job/JobFiltersBar.vue'
|
|
|
|
defineProps<{
|
|
headerTitle: string
|
|
queuedCount: number
|
|
selectedJobTab: JobTab
|
|
selectedWorkflowFilter: 'all' | 'current'
|
|
selectedSortMode: JobSortMode
|
|
displayedJobGroups: JobGroup[]
|
|
hasFailedJobs: boolean
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'showAssets'): void
|
|
(e: 'clearHistory'): void
|
|
(e: 'clearQueued'): void
|
|
(e: 'update:selectedJobTab', value: JobTab): void
|
|
(e: 'update:selectedWorkflowFilter', value: 'all' | 'current'): void
|
|
(e: 'update:selectedSortMode', value: JobSortMode): void
|
|
(e: 'cancelItem', item: JobListItem): void
|
|
(e: 'deleteItem', item: JobListItem): void
|
|
(e: 'viewItem', item: JobListItem): void
|
|
}>()
|
|
|
|
const currentMenuItem = ref<JobListItem | null>(null)
|
|
const jobContextMenuRef = ref<InstanceType<typeof JobContextMenu> | null>(null)
|
|
const { wrapWithErrorHandlingAsync } = useErrorHandling()
|
|
const { trackFeatureUsed } = useSurveyFeatureTracking('queue-progress-overlay')
|
|
|
|
const { jobMenuEntries } = useJobMenu(
|
|
() => currentMenuItem.value,
|
|
(item) => emit('viewItem', item)
|
|
)
|
|
|
|
const onCancelItemEvent = (item: JobListItem) => {
|
|
emit('cancelItem', item)
|
|
}
|
|
|
|
const onDeleteItemEvent = (item: JobListItem) => {
|
|
emit('deleteItem', item)
|
|
}
|
|
|
|
const onUpdateSelectedJobTab = (value: JobTab) => {
|
|
trackFeatureUsed()
|
|
emit('update:selectedJobTab', value)
|
|
}
|
|
|
|
const onMenuItem = (item: JobListItem, event: Event) => {
|
|
currentMenuItem.value = item
|
|
jobContextMenuRef.value?.open(event)
|
|
}
|
|
|
|
const onJobMenuAction = wrapWithErrorHandlingAsync(async (entry: MenuEntry) => {
|
|
if (entry.kind === 'divider') return
|
|
if (entry.onClick) await entry.onClick()
|
|
jobContextMenuRef.value?.hide()
|
|
})
|
|
</script>
|