mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 17:54:14 +00:00
refactor: rename internal promptId/PromptId to jobId/JobId (#8730)
## Summary Rename all internal TypeScript usage of legacy `promptId`/`PromptId` naming to `jobId`/`JobId` across ~38 files for consistency with the domain model. ## Changes - **What**: Renamed internal variable names, type aliases, function names, class getters, interface fields, and comments from `promptId`/`PromptId` to `jobId`/`JobId`. Wire-protocol field names (`prompt_id` in Zod schemas and `e.detail.prompt_id` accesses) are intentionally preserved since they match the backend API contract. ## Review Focus - All changes are pure renames with no behavioral changes - Wire-protocol fields (`prompt_id`) are deliberately unchanged to maintain backend compatibility - Test fixtures updated to use consistent `job-id` naming ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8730-refactor-rename-internal-promptId-PromptId-to-jobId-JobId-3016d73d3650813ca40ce337f7c5271a) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -27,7 +27,7 @@ export function mapTaskOutputToAssetItem(
|
||||
output: ResultItemImpl
|
||||
): AssetItem {
|
||||
const metadata: OutputAssetMetadata = {
|
||||
promptId: taskItem.promptId,
|
||||
jobId: taskItem.jobId,
|
||||
nodeId: output.nodeId,
|
||||
subfolder: output.subfolder,
|
||||
executionTimeInSeconds: taskItem.executionTimeInSeconds,
|
||||
@@ -36,7 +36,7 @@ export function mapTaskOutputToAssetItem(
|
||||
}
|
||||
|
||||
return {
|
||||
id: taskItem.promptId,
|
||||
id: taskItem.jobId,
|
||||
name: output.filename,
|
||||
size: 0,
|
||||
created_at: taskItem.executionStartTimestamp
|
||||
|
||||
@@ -46,12 +46,12 @@ export function useMediaAssetActions() {
|
||||
assetType: string
|
||||
): Promise<void> => {
|
||||
if (assetType === 'output') {
|
||||
const promptId =
|
||||
getOutputAssetMetadata(asset.user_metadata)?.promptId || asset.id
|
||||
if (!promptId) {
|
||||
throw new Error('Unable to extract prompt ID from asset')
|
||||
const jobId =
|
||||
getOutputAssetMetadata(asset.user_metadata)?.jobId || asset.id
|
||||
if (!jobId) {
|
||||
throw new Error('Unable to extract job ID from asset')
|
||||
}
|
||||
await api.deleteItem('history', promptId)
|
||||
await api.deleteItem('history', jobId)
|
||||
} else {
|
||||
// Input assets can only be deleted in cloud environment
|
||||
if (!isCloud) {
|
||||
@@ -141,16 +141,16 @@ export function useMediaAssetActions() {
|
||||
for (const asset of assets) {
|
||||
if (getAssetType(asset) === 'output') {
|
||||
const metadata = getOutputAssetMetadata(asset.user_metadata)
|
||||
const promptId = metadata?.promptId || asset.id
|
||||
if (!jobIds.includes(promptId)) {
|
||||
jobIds.push(promptId)
|
||||
const jobId = metadata?.jobId || asset.id
|
||||
if (!jobIds.includes(jobId)) {
|
||||
jobIds.push(jobId)
|
||||
}
|
||||
if (metadata?.promptId && asset.name) {
|
||||
if (!jobAssetNameFilters[metadata.promptId]) {
|
||||
jobAssetNameFilters[metadata.promptId] = []
|
||||
if (metadata?.jobId && asset.name) {
|
||||
if (!jobAssetNameFilters[metadata.jobId]) {
|
||||
jobAssetNameFilters[metadata.jobId] = []
|
||||
}
|
||||
if (!jobAssetNameFilters[metadata.promptId].includes(asset.name)) {
|
||||
jobAssetNameFilters[metadata.promptId].push(asset.name)
|
||||
if (!jobAssetNameFilters[metadata.jobId].includes(asset.name)) {
|
||||
jobAssetNameFilters[metadata.jobId].push(asset.name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -191,11 +191,11 @@ export function useMediaAssetActions() {
|
||||
if (!targetAsset) return
|
||||
|
||||
const metadata = getOutputAssetMetadata(targetAsset.user_metadata)
|
||||
const promptId =
|
||||
metadata?.promptId ||
|
||||
const jobId =
|
||||
metadata?.jobId ||
|
||||
(getAssetType(targetAsset) === 'output' ? targetAsset.id : undefined)
|
||||
|
||||
if (!promptId) {
|
||||
if (!jobId) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: t('g.warning'),
|
||||
@@ -205,7 +205,7 @@ export function useMediaAssetActions() {
|
||||
return
|
||||
}
|
||||
|
||||
await copyToClipboard(promptId)
|
||||
await copyToClipboard(jobId)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,7 @@ function createAsset(overrides: Partial<AssetItem> = {}): AssetItem {
|
||||
tags: [],
|
||||
created_at: '2025-01-01T00:00:00.000Z',
|
||||
user_metadata: {
|
||||
promptId: 'prompt-1',
|
||||
jobId: 'job-1',
|
||||
nodeId: 'node-1',
|
||||
subfolder: 'outputs'
|
||||
},
|
||||
@@ -74,7 +74,7 @@ describe('useOutputStacks', () => {
|
||||
await toggleStack(parent)
|
||||
|
||||
expect(mocks.resolveOutputAssetItems).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ promptId: 'prompt-1' }),
|
||||
expect.objectContaining({ jobId: 'job-1' }),
|
||||
{
|
||||
createdAt: parent.created_at,
|
||||
excludeOutputKey: 'node-1-outputs-parent.png'
|
||||
|
||||
@@ -19,25 +19,25 @@ type UseOutputStacksOptions = {
|
||||
}
|
||||
|
||||
export function useOutputStacks({ assets }: UseOutputStacksOptions) {
|
||||
const expandedStackPromptIds = ref<Set<string>>(new Set())
|
||||
const stackChildrenByPromptId = ref<Record<string, AssetItem[]>>({})
|
||||
const loadingStackPromptIds = ref<Set<string>>(new Set())
|
||||
const expandedStackJobIds = ref<Set<string>>(new Set())
|
||||
const stackChildrenByJobId = ref<Record<string, AssetItem[]>>({})
|
||||
const loadingStackJobIds = ref<Set<string>>(new Set())
|
||||
|
||||
const assetItems = computed<OutputStackListItem[]>(() => {
|
||||
const items: OutputStackListItem[] = []
|
||||
|
||||
for (const asset of assets.value) {
|
||||
const promptId = getStackPromptId(asset)
|
||||
const jobId = getStackJobId(asset)
|
||||
items.push({
|
||||
key: `asset-${asset.id}`,
|
||||
asset
|
||||
})
|
||||
|
||||
if (!promptId || !expandedStackPromptIds.value.has(promptId)) {
|
||||
if (!jobId || !expandedStackJobIds.value.has(jobId)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const children = stackChildrenByPromptId.value[promptId] ?? []
|
||||
const children = stackChildrenByJobId.value[jobId] ?? []
|
||||
for (const child of children) {
|
||||
items.push({
|
||||
key: `asset-${child.id}`,
|
||||
@@ -54,55 +54,55 @@ export function useOutputStacks({ assets }: UseOutputStacksOptions) {
|
||||
assetItems.value.map((item) => item.asset)
|
||||
)
|
||||
|
||||
function getStackPromptId(asset: AssetItem): string | null {
|
||||
function getStackJobId(asset: AssetItem): string | null {
|
||||
const metadata = getOutputAssetMetadata(asset.user_metadata)
|
||||
return metadata?.promptId ?? null
|
||||
return metadata?.jobId ?? null
|
||||
}
|
||||
|
||||
function isStackExpanded(asset: AssetItem): boolean {
|
||||
const promptId = getStackPromptId(asset)
|
||||
if (!promptId) return false
|
||||
return expandedStackPromptIds.value.has(promptId)
|
||||
const jobId = getStackJobId(asset)
|
||||
if (!jobId) return false
|
||||
return expandedStackJobIds.value.has(jobId)
|
||||
}
|
||||
|
||||
async function toggleStack(asset: AssetItem) {
|
||||
const promptId = getStackPromptId(asset)
|
||||
if (!promptId) return
|
||||
const jobId = getStackJobId(asset)
|
||||
if (!jobId) return
|
||||
|
||||
if (expandedStackPromptIds.value.has(promptId)) {
|
||||
const next = new Set(expandedStackPromptIds.value)
|
||||
next.delete(promptId)
|
||||
expandedStackPromptIds.value = next
|
||||
if (expandedStackJobIds.value.has(jobId)) {
|
||||
const next = new Set(expandedStackJobIds.value)
|
||||
next.delete(jobId)
|
||||
expandedStackJobIds.value = next
|
||||
return
|
||||
}
|
||||
|
||||
if (!stackChildrenByPromptId.value[promptId]?.length) {
|
||||
if (loadingStackPromptIds.value.has(promptId)) {
|
||||
if (!stackChildrenByJobId.value[jobId]?.length) {
|
||||
if (loadingStackJobIds.value.has(jobId)) {
|
||||
return
|
||||
}
|
||||
const nextLoading = new Set(loadingStackPromptIds.value)
|
||||
nextLoading.add(promptId)
|
||||
loadingStackPromptIds.value = nextLoading
|
||||
const nextLoading = new Set(loadingStackJobIds.value)
|
||||
nextLoading.add(jobId)
|
||||
loadingStackJobIds.value = nextLoading
|
||||
|
||||
const children = await resolveStackChildren(asset)
|
||||
|
||||
const afterLoading = new Set(loadingStackPromptIds.value)
|
||||
afterLoading.delete(promptId)
|
||||
loadingStackPromptIds.value = afterLoading
|
||||
const afterLoading = new Set(loadingStackJobIds.value)
|
||||
afterLoading.delete(jobId)
|
||||
loadingStackJobIds.value = afterLoading
|
||||
|
||||
if (!children.length) {
|
||||
return
|
||||
}
|
||||
|
||||
stackChildrenByPromptId.value = {
|
||||
...stackChildrenByPromptId.value,
|
||||
[promptId]: children
|
||||
stackChildrenByJobId.value = {
|
||||
...stackChildrenByJobId.value,
|
||||
[jobId]: children
|
||||
}
|
||||
}
|
||||
|
||||
const nextExpanded = new Set(expandedStackPromptIds.value)
|
||||
nextExpanded.add(promptId)
|
||||
expandedStackPromptIds.value = nextExpanded
|
||||
const nextExpanded = new Set(expandedStackJobIds.value)
|
||||
nextExpanded.add(jobId)
|
||||
expandedStackJobIds.value = nextExpanded
|
||||
}
|
||||
|
||||
async function resolveStackChildren(asset: AssetItem): Promise<AssetItem[]> {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { ResultItemImpl } from '@/stores/queueStore'
|
||||
* Extends Record<string, unknown> for compatibility with AssetItem schema
|
||||
*/
|
||||
export interface OutputAssetMetadata extends Record<string, unknown> {
|
||||
promptId: string
|
||||
jobId: string
|
||||
nodeId: string | number
|
||||
subfolder: string
|
||||
executionTimeInSeconds?: number
|
||||
@@ -24,7 +24,7 @@ function isOutputAssetMetadata(
|
||||
): metadata is OutputAssetMetadata {
|
||||
if (!metadata) return false
|
||||
return (
|
||||
typeof metadata.promptId === 'string' &&
|
||||
typeof metadata.jobId === 'string' &&
|
||||
(typeof metadata.nodeId === 'string' || typeof metadata.nodeId === 'number')
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
url: 'https://example.com/b.png'
|
||||
})
|
||||
const metadata: OutputAssetMetadata = {
|
||||
promptId: 'prompt-1',
|
||||
jobId: 'job-1',
|
||||
nodeId: '1',
|
||||
subfolder: 'sub',
|
||||
executionTimeInSeconds: 12.5,
|
||||
@@ -66,7 +66,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
expect(results).toHaveLength(1)
|
||||
expect(results[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
id: 'prompt-1-1-sub-a.png',
|
||||
id: 'job-1-1-sub-a.png',
|
||||
name: 'a.png',
|
||||
created_at: '2025-01-01T00:00:00.000Z',
|
||||
tags: ['output'],
|
||||
@@ -75,7 +75,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
)
|
||||
expect(results[0].user_metadata).toEqual(
|
||||
expect.objectContaining({
|
||||
promptId: 'prompt-1',
|
||||
jobId: 'job-1',
|
||||
nodeId: '1',
|
||||
subfolder: 'sub',
|
||||
executionTimeInSeconds: 12.5
|
||||
@@ -95,7 +95,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
url: 'https://example.com/full.png'
|
||||
})
|
||||
const metadata: OutputAssetMetadata = {
|
||||
promptId: 'prompt-2',
|
||||
jobId: 'job-2',
|
||||
nodeId: '1',
|
||||
subfolder: 'sub',
|
||||
outputCount: 3,
|
||||
@@ -111,7 +111,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
|
||||
const results = await resolveOutputAssetItems(metadata)
|
||||
|
||||
expect(mocks.getJobDetail).toHaveBeenCalledWith('prompt-2')
|
||||
expect(mocks.getJobDetail).toHaveBeenCalledWith('job-2')
|
||||
expect(mocks.getPreviewableOutputsFromJobDetail).toHaveBeenCalledWith(
|
||||
jobDetail
|
||||
)
|
||||
@@ -129,7 +129,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
url: 'https://example.com/root.png'
|
||||
})
|
||||
const metadata: OutputAssetMetadata = {
|
||||
promptId: 'prompt-root',
|
||||
jobId: 'job-root',
|
||||
nodeId: '1',
|
||||
subfolder: '',
|
||||
outputCount: 1,
|
||||
@@ -144,7 +144,7 @@ describe('resolveOutputAssetItems', () => {
|
||||
if (!asset) {
|
||||
throw new Error('Expected a root output asset')
|
||||
}
|
||||
expect(asset.id).toBe('prompt-root-1--root.png')
|
||||
expect(asset.id).toBe('job-root-1--root.png')
|
||||
if (!asset.user_metadata) {
|
||||
throw new Error('Expected output metadata')
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import type { ResultItemImpl } from '@/stores/queueStore'
|
||||
|
||||
type OutputAssetMapOptions = {
|
||||
promptId: string
|
||||
jobId: string
|
||||
outputs: readonly ResultItemImpl[]
|
||||
createdAt?: string
|
||||
executionTimeInSeconds?: number
|
||||
@@ -51,7 +51,7 @@ export function getOutputKey({
|
||||
}
|
||||
|
||||
function mapOutputsToAssetItems({
|
||||
promptId,
|
||||
jobId,
|
||||
outputs,
|
||||
createdAt,
|
||||
executionTimeInSeconds,
|
||||
@@ -67,14 +67,14 @@ function mapOutputsToAssetItems({
|
||||
}
|
||||
|
||||
items.push({
|
||||
id: `${promptId}-${outputKey}`,
|
||||
id: `${jobId}-${outputKey}`,
|
||||
name: output.filename,
|
||||
size: 0,
|
||||
created_at: createdAtValue,
|
||||
tags: ['output'],
|
||||
preview_url: output.url,
|
||||
user_metadata: {
|
||||
promptId,
|
||||
jobId,
|
||||
nodeId: output.nodeId,
|
||||
subfolder: output.subfolder,
|
||||
executionTimeInSeconds,
|
||||
@@ -92,7 +92,7 @@ export async function resolveOutputAssetItems(
|
||||
): Promise<AssetItem[]> {
|
||||
let outputsToDisplay = metadata.allOutputs ?? []
|
||||
if (shouldLoadFullOutputs(metadata.outputCount, outputsToDisplay.length)) {
|
||||
const jobDetail = await getJobDetail(metadata.promptId)
|
||||
const jobDetail = await getJobDetail(metadata.jobId)
|
||||
const previewableOutputs = getPreviewableOutputsFromJobDetail(jobDetail)
|
||||
if (previewableOutputs.length) {
|
||||
outputsToDisplay = previewableOutputs
|
||||
@@ -100,7 +100,7 @@ export async function resolveOutputAssetItems(
|
||||
}
|
||||
|
||||
return mapOutputsToAssetItems({
|
||||
promptId: metadata.promptId,
|
||||
jobId: metadata.jobId,
|
||||
outputs: outputsToDisplay,
|
||||
createdAt,
|
||||
executionTimeInSeconds: metadata.executionTimeInSeconds,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import { validateComfyWorkflow } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import type { PromptId } from '@/schemas/apiSchema'
|
||||
import type { JobId } from '@/schemas/apiSchema'
|
||||
|
||||
import type {
|
||||
JobDetail,
|
||||
@@ -119,19 +119,19 @@ export async function fetchQueue(
|
||||
*/
|
||||
export async function fetchJobDetail(
|
||||
fetchApi: (url: string) => Promise<Response>,
|
||||
promptId: PromptId
|
||||
jobId: JobId
|
||||
): Promise<JobDetail | undefined> {
|
||||
try {
|
||||
const res = await fetchApi(`/jobs/${encodeURIComponent(promptId)}`)
|
||||
const res = await fetchApi(`/jobs/${encodeURIComponent(jobId)}`)
|
||||
|
||||
if (!res.ok) {
|
||||
console.warn(`Job not found for prompt ${promptId}`)
|
||||
console.warn(`Job not found for job ${jobId}`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
return zJobDetail.parse(await res.json())
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch job detail for prompt ${promptId}:`, error)
|
||||
console.error(`Failed to fetch job detail for job ${jobId}:`, error)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const mockWorkflow: ComfyWorkflowJSON = {
|
||||
// Jobs API detail response structure (matches actual /jobs/{id} response)
|
||||
// workflow is nested at: workflow.extra_data.extra_pnginfo.workflow
|
||||
const mockJobDetailResponse: JobDetail = {
|
||||
id: 'test-prompt-id',
|
||||
id: 'test-job-id',
|
||||
status: 'completed',
|
||||
create_time: 1234567890,
|
||||
update_time: 1234567900,
|
||||
@@ -43,15 +43,15 @@ const mockJobDetailResponse: JobDetail = {
|
||||
}
|
||||
|
||||
describe('fetchJobDetail', () => {
|
||||
it('should fetch job detail from /jobs/{prompt_id} endpoint', async () => {
|
||||
it('should fetch job detail from /jobs/{job_id} endpoint', async () => {
|
||||
const mockFetchApi = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => mockJobDetailResponse
|
||||
})
|
||||
|
||||
await fetchJobDetail(mockFetchApi, 'test-prompt-id')
|
||||
await fetchJobDetail(mockFetchApi, 'test-job-id')
|
||||
|
||||
expect(mockFetchApi).toHaveBeenCalledWith('/jobs/test-prompt-id')
|
||||
expect(mockFetchApi).toHaveBeenCalledWith('/jobs/test-job-id')
|
||||
})
|
||||
|
||||
it('should return job detail with workflow and outputs', async () => {
|
||||
@@ -60,10 +60,10 @@ describe('fetchJobDetail', () => {
|
||||
json: async () => mockJobDetailResponse
|
||||
})
|
||||
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id')
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-job-id')
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result?.id).toBe('test-prompt-id')
|
||||
expect(result?.id).toBe('test-job-id')
|
||||
expect(result?.outputs).toEqual(mockJobDetailResponse.outputs)
|
||||
expect(result?.workflow).toBeDefined()
|
||||
})
|
||||
@@ -82,7 +82,7 @@ describe('fetchJobDetail', () => {
|
||||
it('should handle fetch errors gracefully', async () => {
|
||||
const mockFetchApi = vi.fn().mockRejectedValue(new Error('Network error'))
|
||||
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id')
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-job-id')
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
@@ -95,7 +95,7 @@ describe('fetchJobDetail', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id')
|
||||
const result = await fetchJobDetail(mockFetchApi, 'test-job-id')
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
@@ -19,7 +19,7 @@ import { getJobWorkflow } from '@/services/jobOutputCache'
|
||||
* @returns WorkflowSource with workflow and generated filename
|
||||
*
|
||||
* @example
|
||||
* const asset = { name: 'output.png', user_metadata: { promptId: '123' } }
|
||||
* const asset = { name: 'output.png', user_metadata: { jobId: '123' } }
|
||||
* const { workflow, filename } = await extractWorkflowFromAsset(asset)
|
||||
*/
|
||||
export async function extractWorkflowFromAsset(asset: AssetItem): Promise<{
|
||||
@@ -30,8 +30,8 @@ export async function extractWorkflowFromAsset(asset: AssetItem): Promise<{
|
||||
|
||||
// For output assets: use jobs API (with caching and validation)
|
||||
const metadata = getOutputAssetMetadata(asset.user_metadata)
|
||||
if (metadata?.promptId) {
|
||||
const workflow = await getJobWorkflow(metadata.promptId)
|
||||
if (metadata?.jobId) {
|
||||
const workflow = await getJobWorkflow(metadata.jobId)
|
||||
return { workflow: workflow ?? null, filename: baseFilename }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user