Add platform powder catalog management UI with full CRUD and AI lookup
- PowderCatalogController: Create, Edit, ToggleDiscontinued actions; searchable/filterable/sortable Index with pagination; AiLookup and AiAugmentFromUrl endpoints backed by IInventoryAiLookupService - New views: Create, Edit, _Form partial (with AI-assisted field population), overhauled Index grid with completeness quality badges and responsive mobile cards - New ViewModels: PowderCatalogIndexViewModel, PowderCatalogFormViewModel, PowderCatalogListItemViewModel - AI lookup improvements: SpecificGravity field added to InventoryAiLookupResult; ApplyPowderFallbacks derives CoverageSqFtPerLb from specific gravity when docs omit it; DefaultTransferEfficiency (65%) applied everywhere transfer efficiency is null - powder-catalog-ai-lookup.js: client-side AI lookup and URL augment wiring for the catalog form Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
@model PowderCoating.Web.ViewModels.PowderCatalog.PowderCatalogFormViewModel
|
||||
|
||||
@{
|
||||
var enableAiLookup = ViewData["EnableAiLookup"] as bool? == true;
|
||||
}
|
||||
|
||||
@if (enableAiLookup)
|
||||
{
|
||||
<div class="card border-0 bg-light-subtle mb-4">
|
||||
<div class="card-body p-3">
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-stars me-2 text-primary"></i>AI Lookup
|
||||
</h6>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="powder-ai-lookup-btn">
|
||||
<i class="bi bi-search me-1"></i>Search Missing Info
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="powder-ai-url-btn">
|
||||
<i class="bi bi-box-arrow-up-right me-1"></i>Use Product URL
|
||||
</button>
|
||||
</div>
|
||||
<div class="small text-muted mb-2">
|
||||
Search the web for missing specs, cure data, and SDS/TDS links. Existing values are left alone unless the field is blank.
|
||||
</div>
|
||||
<div id="ai-lookup-status" class="alert alert-info d-none py-2 small mb-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div asp-validation-summary="ModelOnly" class="alert alert-danger mb-3 small"></div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label asp-for="VendorName" class="form-label fw-medium"></label>
|
||||
<input asp-for="VendorName" class="form-control" id="field-vendorname" />
|
||||
<span asp-validation-for="VendorName" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="Sku" class="form-label fw-medium"></label>
|
||||
<input asp-for="Sku" class="form-control" id="field-sku" />
|
||||
<span asp-validation-for="Sku" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="UnitPrice" class="form-label fw-medium"></label>
|
||||
<input asp-for="UnitPrice" class="form-control" id="field-unitprice" />
|
||||
<span asp-validation-for="UnitPrice" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label asp-for="ColorName" class="form-label fw-medium"></label>
|
||||
<input asp-for="ColorName" class="form-control" id="field-colorname" />
|
||||
<span asp-validation-for="ColorName" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label asp-for="Description" class="form-label fw-medium"></label>
|
||||
<textarea asp-for="Description" class="form-control" id="field-description" rows="3"></textarea>
|
||||
<span asp-validation-for="Description" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label asp-for="Finish" class="form-label fw-medium"></label>
|
||||
<input asp-for="Finish" class="form-control" id="field-finish" placeholder="Gloss, Matte, Satin, Metallic..." />
|
||||
<span asp-validation-for="Finish" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="ColorFamilies" class="form-label fw-medium"></label>
|
||||
<input asp-for="ColorFamilies" class="form-control" id="field-colorfamilies" placeholder="Blue, Purple, Metallic" />
|
||||
<span asp-validation-for="ColorFamilies" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<label asp-for="CureTemperatureF" class="form-label fw-medium"></label>
|
||||
<input asp-for="CureTemperatureF" class="form-control" id="field-curetemp" />
|
||||
<span asp-validation-for="CureTemperatureF" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="CureTimeMinutes" class="form-label fw-medium"></label>
|
||||
<input asp-for="CureTimeMinutes" class="form-control" id="field-curetime" />
|
||||
<span asp-validation-for="CureTimeMinutes" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="CoverageSqFtPerLb" class="form-label fw-medium"></label>
|
||||
<input asp-for="CoverageSqFtPerLb" class="form-control" id="field-coverage" />
|
||||
<span asp-validation-for="CoverageSqFtPerLb" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="TransferEfficiency" class="form-label fw-medium"></label>
|
||||
<input asp-for="TransferEfficiency" class="form-control" id="field-transfer" />
|
||||
<span asp-validation-for="TransferEfficiency" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label asp-for="ProductUrl" class="form-label fw-medium"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="ProductUrl" class="form-control" id="field-producturl" />
|
||||
<a id="field-producturl-link" href="@Model.ProductUrl" target="_blank"
|
||||
class="btn btn-outline-secondary @(string.IsNullOrWhiteSpace(Model.ProductUrl) ? "d-none" : "")" title="Open Product URL">
|
||||
<i class="bi bi-box-arrow-up-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<span asp-validation-for="ProductUrl" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="ImageUrl" class="form-label fw-medium"></label>
|
||||
<input asp-for="ImageUrl" class="form-control" id="field-imageurl" />
|
||||
<span asp-validation-for="ImageUrl" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label asp-for="SdsUrl" class="form-label fw-medium"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="SdsUrl" class="form-control" id="field-sdsurl" />
|
||||
<a id="field-sdsurl-link" href="@Model.SdsUrl" target="_blank"
|
||||
class="btn btn-outline-secondary @(string.IsNullOrWhiteSpace(Model.SdsUrl) ? "d-none" : "")" title="Open SDS URL">
|
||||
<i class="bi bi-file-earmark-pdf"></i>
|
||||
</a>
|
||||
</div>
|
||||
<span asp-validation-for="SdsUrl" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="TdsUrl" class="form-label fw-medium"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="TdsUrl" class="form-control" id="field-tdsurl" />
|
||||
<a id="field-tdsurl-link" href="@Model.TdsUrl" target="_blank"
|
||||
class="btn btn-outline-secondary @(string.IsNullOrWhiteSpace(Model.TdsUrl) ? "d-none" : "")" title="Open TDS URL">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
</a>
|
||||
</div>
|
||||
<span asp-validation-for="TdsUrl" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="ApplicationGuideUrl" class="form-label fw-medium"></label>
|
||||
<div class="input-group">
|
||||
<input asp-for="ApplicationGuideUrl" class="form-control" id="field-applicationguideurl" />
|
||||
<a id="field-applicationguideurl-link" href="@Model.ApplicationGuideUrl" target="_blank"
|
||||
class="btn btn-outline-secondary @(string.IsNullOrWhiteSpace(Model.ApplicationGuideUrl) ? "d-none" : "")" title="Open Application Guide URL">
|
||||
<i class="bi bi-box-arrow-up-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<span asp-validation-for="ApplicationGuideUrl" class="text-danger small"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label asp-for="RequiresClearCoat" class="form-label fw-medium"></label>
|
||||
<select asp-for="RequiresClearCoat" class="form-select" id="field-clearcoat">
|
||||
<option value="">Unknown</option>
|
||||
<option value="true">Yes</option>
|
||||
<option value="false">No</option>
|
||||
</select>
|
||||
<span asp-validation-for="RequiresClearCoat" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check form-switch mt-4">
|
||||
<input asp-for="IsDiscontinued" class="form-check-input" type="checkbox" />
|
||||
<label asp-for="IsDiscontinued" class="form-check-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check form-switch mt-4">
|
||||
<input asp-for="IsUserContributed" class="form-check-input" type="checkbox" />
|
||||
<label asp-for="IsUserContributed" class="form-check-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.Id > 0)
|
||||
{
|
||||
<hr class="my-4" />
|
||||
<div class="row g-3 small text-muted">
|
||||
<div class="col-md-4">
|
||||
<div class="fw-semibold text-body">Created</div>
|
||||
<div>@Model.CreatedAt.ToString("MMM d, yyyy h:mm tt") UTC</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="fw-semibold text-body">Updated</div>
|
||||
<div>@(Model.UpdatedAt?.ToString("MMM d, yyyy h:mm tt") ?? "Never")@(Model.UpdatedAt.HasValue ? " UTC" : string.Empty)</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="fw-semibold text-body">Last Synced</div>
|
||||
<div>@(Model.LastSyncedAt?.ToString("MMM d, yyyy h:mm tt") ?? "Never")@(Model.LastSyncedAt.HasValue ? " UTC" : string.Empty)</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
Reference in New Issue
Block a user