Add catalog item images with thumbnail preview in wizard
Each catalog item now supports one optional image (jpg/jpeg/png/gif/webp,
max 10 MB). Uploading generates a 200x200 JPEG thumbnail automatically via
SixLabors.ImageSharp. Images are stored in Azure Blob Storage under a new
catalogimages container, keyed by {companyId}/catalog/{itemId}/.
- CatalogItem entity: ImagePath + ThumbnailPath (nullable string fields)
- Migration: AddCatalogItemImages applied
- ICatalogImageService / CatalogImageService: upload, thumbnail generation,
delete; old blobs replaced atomically on re-upload
- CatalogItemsController: Create/Edit accept optional IFormFile image;
Image(id, thumbnail) action serves blobs with [Authorize] so wizard users
can load thumbnails without CanManageProducts policy
- Catalog index (_CategoryNode): 40x40 thumbnail (or placeholder icon)
left of each item name
- Details view: image card in right column with click-to-full-size link
- Create/Edit views: file picker with live preview; Edit shows current
thumbnail with Remove checkbox
- Wizard (item-wizard.js): thumbnails in product list with hover preview
that follows the cursor (showCatalogPreview / moveCatalogPreview);
fixed Bootstrap d-flex !important bug that broke the filter box by
moving flex layout to an inner wrapper div
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace PowderCoating.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Handles upload, thumbnail generation, and deletion of catalog item images stored in Azure Blob Storage.
|
||||
/// All blobs are scoped under {companyId}/catalog/{itemId}/ so tenants never share a path.
|
||||
/// </summary>
|
||||
public interface ICatalogImageService
|
||||
{
|
||||
/// <summary>
|
||||
/// Uploads the image, generates a 200×200 JPEG thumbnail, stores both blobs, and returns their paths.
|
||||
/// On success the caller should persist the returned paths to <c>CatalogItem.ImagePath</c> and
|
||||
/// <c>CatalogItem.ThumbnailPath</c>. Any previously stored blobs for the same item are deleted first.
|
||||
/// </summary>
|
||||
Task<(bool Success, string ImagePath, string ThumbnailPath, string ErrorMessage)> UploadAsync(
|
||||
IFormFile file,
|
||||
int itemId,
|
||||
int companyId,
|
||||
string? existingImagePath,
|
||||
string? existingThumbnailPath);
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a catalog image blob and returns its raw bytes and content-type for streaming to the browser.
|
||||
/// </summary>
|
||||
Task<(bool Success, byte[] Content, string ContentType, string ErrorMessage)> DownloadAsync(string blobPath);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes both the full-size image and thumbnail blobs. Safe to call with null paths.
|
||||
/// </summary>
|
||||
Task DeleteAsync(string? imagePath, string? thumbnailPath);
|
||||
}
|
||||
Reference in New Issue
Block a user