fix: address coderabbit review — a11y, error handling, defensive guards

- Guard widget.options with optional chaining (RC1)
- Await async handleUpload in file input/drop handlers (M4)
- Add toast warning on cloud media verification failure (M5)
- Add aria-labels to confirm/cancel icon buttons (m1)
- Expand clearMissingMedia test to verify full lifecycle reset (n8)
This commit is contained in:
jaeone94
2026-03-25 21:01:35 +09:00
parent 899f3bc09e
commit cfe3917e95
5 changed files with 35 additions and 9 deletions

View File

@@ -3539,7 +3539,9 @@
"uploading": "Uploading...",
"uploaded": "Uploaded",
"selectedFromLibrary": "Selected from library",
"useFromLibrary": "Use from Library"
"useFromLibrary": "Use from Library",
"confirmSelection": "Confirm selection",
"cancelSelection": "Cancel selection"
}
},
"errorOverlay": {

View File

@@ -37,6 +37,7 @@
<Button
variant="textonly"
size="icon-sm"
:aria-label="t('rightSidePanel.missingMedia.confirmSelection')"
:disabled="!isPending"
:class="
cn(
@@ -164,6 +165,7 @@
<Button
variant="textonly"
size="icon-sm"
:aria-label="t('rightSidePanel.missingMedia.cancelSelection')"
class="relative z-10 size-6 shrink-0 text-muted-foreground hover:text-base-foreground"
@click="cancelSelection(item.name)"
>
@@ -302,20 +304,23 @@ function openFilePicker() {
fileInputRef.value?.click()
}
function handleFileInputChange(e: Event) {
async function handleFileInputChange(e: Event) {
const input = e.target as HTMLInputElement
const file = input.files?.[0]
if (file) {
handleUpload(file, item.name, item.mediaType)
try {
if (file) {
await handleUpload(file, item.name, item.mediaType)
}
} finally {
input.value = ''
}
input.value = ''
}
function handleDrop(e: DragEvent) {
async function handleDrop(e: DragEvent) {
isDragOver.value = false
const file = e.dataTransfer?.files[0]
if (file) {
handleUpload(file, item.name, item.mediaType)
await handleUpload(file, item.name, item.mediaType)
}
}
</script>

View File

@@ -48,7 +48,7 @@ function resolveComboOptions(
const result = getMediaComboWidget(candidate)
if (!result) return []
const values = result.widget.options.values
const values = result.widget.options?.values
if (!values) return []
const list: string[] =

View File

@@ -67,18 +67,29 @@ describe('useMissingMediaStore', () => {
expect(store.hasMissingMedia).toBe(false)
})
it('clearMissingMedia resets all state', () => {
it('clearMissingMedia resets all state including interaction state', () => {
const store = useMissingMediaStore()
store.setMissingMedia([
makeCandidate('1', 'photo.png'),
makeCandidate('2', 'clip.mp4', 'video')
])
store.expandState['photo.png'] = true
store.uploadState['photo.png'] = {
fileName: 'photo.png',
status: 'uploaded'
}
store.pendingSelection['photo.png'] = 'uploaded/photo.png'
const controller = store.createVerificationAbortController()
store.clearMissingMedia()
expect(store.missingMediaCandidates).toBeNull()
expect(store.hasMissingMedia).toBe(false)
expect(store.missingMediaCount).toBe(0)
expect(controller.signal.aborted).toBe(true)
expect(store.expandState).toEqual({})
expect(store.uploadState).toEqual({})
expect(store.pendingSelection).toEqual({})
})
it('missingMediaNodeIds tracks unique node IDs', () => {

View File

@@ -1594,6 +1594,14 @@ export class ComfyApp {
'[Missing Media Pipeline] Asset verification failed:',
err
)
useToastStore().add({
severity: 'warn',
summary: st(
'toastMessages.missingMediaVerificationFailed',
'Failed to verify missing media. Some inputs may not be shown in the Errors tab.'
),
life: 5000
})
})
} else {
const confirmed = candidates.filter((c) => c.isMissing === true)