feat: add image drag and drop to Kanban card description

Add ability to drag and drop images into the description section when creating
new Kanban cards. Images are saved to a temp directory and their paths are stored
with the feature for agent context.

- Create DescriptionImageDropZone component with drag/drop support
- Integrate with Add Feature dialog in board-view
- Add FeatureImagePath interface to track temp file paths
- Update saveFeatures to persist imagePaths
- Add saveImageToTemp to mock electron API
- Add test utilities for image upload testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Cody Seibert
2025-12-09 12:47:24 -05:00
parent b3a8e60ce6
commit 081f7c6007
5 changed files with 488 additions and 8 deletions

View File

@@ -1788,3 +1788,75 @@ export async function setupMockMultipleProjects(
localStorage.setItem("automaker-storage", JSON.stringify(mockState));
}, projectCount);
}
/**
* Get the description image dropzone element
*/
export async function getDescriptionImageDropzone(page: Page): Promise<Locator> {
return page.locator('[data-testid="feature-description-input"]');
}
/**
* Get the description image hidden input element
*/
export async function getDescriptionImageInput(page: Page): Promise<Locator> {
return page.locator('[data-testid="description-image-input"]');
}
/**
* Check if the description image previews section is visible
*/
export async function isDescriptionImagePreviewsVisible(page: Page): Promise<boolean> {
const previews = page.locator('[data-testid="description-image-previews"]');
return await previews.isVisible().catch(() => false);
}
/**
* Get the number of description image previews
*/
export async function getDescriptionImagePreviewCount(page: Page): Promise<number> {
const previews = page.locator('[data-testid^="description-image-preview-"]');
return await previews.count();
}
/**
* Upload an image to the description dropzone via the file input
*/
export async function uploadDescriptionImage(
page: Page,
imagePath: string
): Promise<void> {
const input = page.locator('[data-testid="description-image-input"]');
await input.setInputFiles(imagePath);
}
/**
* Create a test PNG image as a data URL
*/
export function createTestImageDataUrl(): string {
// A tiny 1x1 transparent PNG as base64
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
}
/**
* Wait for description image preview to appear
*/
export async function waitForDescriptionImagePreview(
page: Page,
options?: { timeout?: number }
): Promise<Locator> {
const preview = page.locator('[data-testid^="description-image-preview-"]').first();
await preview.waitFor({
timeout: options?.timeout ?? 5000,
state: "visible",
});
return preview;
}
/**
* Check if the drop overlay is visible on the description area
*/
export async function isDropOverlayVisible(page: Page): Promise<boolean> {
const overlay = page.locator('[data-testid="drop-overlay"]');
return await overlay.isVisible().catch(() => false);
}