feat(F-088): completed feature
This commit is contained in:
@@ -2,13 +2,41 @@
|
||||
"feature_id": "F-082",
|
||||
"verdict": "APPROVED",
|
||||
"trace": [
|
||||
{ "acceptance": "Every editable cell in /inventory saves on blur or Enter via PATCH", "result": "PASS", "evidence": "SKU/EAN/Stock in /inventory + SKU/EAN/Stock/Precio in InventorySection all use onBlur + Enter -> save* handlers -> existing PATCH endpoints." },
|
||||
{ "acceptance": "Stock cell enters edit mode on a single click; pencil icon is removed", "result": "PASS", "evidence": "Stock value is rendered as a <button> with the cell text; click swaps to <input autoFocus>; no ✏️ icon anywhere." },
|
||||
{ "acceptance": "Successful save shows visual confirmation; new value stays in the cell", "result": "PASS", "evidence": "saveMsg = '✓ Guardado'; row updated with API response (variant.sku/ean, stock.available, price.netUnitAmountCents)." },
|
||||
{ "acceptance": "Failed save shows inline error and restores the previous value", "result": "PASS", "evidence": "catch in saveSku/saveEan/saveStock/savePrice resets edit field from row's persisted state and sets msg = 'Error'." },
|
||||
{ "acceptance": "Concurrent edits do not silently overwrite", "result": "PASS", "evidence": "Per-cell saving* boolean disables the input; second submit ignored. Last-write-wins at backend as per acceptance." },
|
||||
{ "acceptance": "No regressions in Prices tab or product editor", "result": "PASS", "evidence": "PricingSection.tsx not modified." },
|
||||
{ "acceptance": "verify.sh is green", "result": "PASS", "evidence": "tsc --noEmit exit 0; eslint exit 0." }
|
||||
{
|
||||
"acceptance": "Every editable cell in /inventory saves on blur or Enter via PATCH",
|
||||
"result": "PASS",
|
||||
"evidence": "SKU/EAN/Stock in /inventory + SKU/EAN/Stock/Precio in InventorySection all use onBlur + Enter -> save* handlers -> existing PATCH endpoints."
|
||||
},
|
||||
{
|
||||
"acceptance": "Stock cell enters edit mode on a single click; pencil icon is removed",
|
||||
"result": "PASS",
|
||||
"evidence": "Stock value is rendered as a <button> with the cell text; click swaps to <input autoFocus>; no ✏️ icon anywhere."
|
||||
},
|
||||
{
|
||||
"acceptance": "Successful save shows visual confirmation; new value stays in the cell",
|
||||
"result": "PASS",
|
||||
"evidence": "saveMsg = '✓ Guardado'; row updated with API response (variant.sku/ean, stock.available, price.netUnitAmountCents)."
|
||||
},
|
||||
{
|
||||
"acceptance": "Failed save shows inline error and restores the previous value",
|
||||
"result": "PASS",
|
||||
"evidence": "catch in saveSku/saveEan/saveStock/savePrice resets edit field from row's persisted state and sets msg = 'Error'."
|
||||
},
|
||||
{
|
||||
"acceptance": "Concurrent edits do not silently overwrite",
|
||||
"result": "PASS",
|
||||
"evidence": "Per-cell saving* boolean disables the input; second submit ignored. Last-write-wins at backend as per acceptance."
|
||||
},
|
||||
{
|
||||
"acceptance": "No regressions in Prices tab or product editor",
|
||||
"result": "PASS",
|
||||
"evidence": "PricingSection.tsx not modified."
|
||||
},
|
||||
{
|
||||
"acceptance": "verify.sh is green",
|
||||
"result": "PASS",
|
||||
"evidence": "tsc --noEmit exit 0; eslint exit 0."
|
||||
}
|
||||
],
|
||||
"regression_checks": [
|
||||
"Pricing tab save still works",
|
||||
@@ -17,5 +45,6 @@
|
||||
],
|
||||
"verdict_reason": "All acceptance criteria trace to PASS. UX is now consistent across editable cells.",
|
||||
"reviewer": "qa",
|
||||
"reviewed_at": "2026-08-20T04:06:00Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:06:00Z",
|
||||
"agent": "qa"
|
||||
}
|
||||
|
||||
@@ -2,16 +2,43 @@
|
||||
"feature_id": "F-082",
|
||||
"verdict": "APPROVED",
|
||||
"checks": [
|
||||
{ "name": "Stock cell is click-to-edit (no pencil)", "result": "PASS", "notes": "Both /inventory page and InventorySection: cell <button> value -> <input autoFocus>; no ✏️ anywhere." },
|
||||
{ "name": "All editable cells save on blur or Enter", "result": "PASS", "notes": "SKU, EAN, Stock, Precio neto all use onBlur + Enter (Escape cancels) via dedicated save handlers." },
|
||||
{ "name": "Persisted via existing PATCH /variants/:id and pricing endpoints", "result": "PASS", "notes": "productsApi.updateVariant for sku/ean; pricingApi.setVariantPrice for price; inventoryApi.setStock for stock." },
|
||||
{ "name": "Failed save restores previous value", "result": "PASS", "notes": "catch blocks in saveStock/savePrice/saveSku/saveEan reset the edit field from r.variant/r.price and set saveMsg = 'Error'." },
|
||||
{ "name": "Visual feedback on success", "result": "PASS", "notes": "saveMsg shows '✓ Guardado' for 3s after success." },
|
||||
{ "name": "No regressions", "result": "PASS", "notes": "PricingSection.tsx untouched; only inventory files changed." }
|
||||
{
|
||||
"name": "Stock cell is click-to-edit (no pencil)",
|
||||
"result": "PASS",
|
||||
"notes": "Both /inventory page and InventorySection: cell <button> value -> <input autoFocus>; no ✏️ anywhere."
|
||||
},
|
||||
{
|
||||
"name": "All editable cells save on blur or Enter",
|
||||
"result": "PASS",
|
||||
"notes": "SKU, EAN, Stock, Precio neto all use onBlur + Enter (Escape cancels) via dedicated save handlers."
|
||||
},
|
||||
{
|
||||
"name": "Persisted via existing PATCH /variants/:id and pricing endpoints",
|
||||
"result": "PASS",
|
||||
"notes": "productsApi.updateVariant for sku/ean; pricingApi.setVariantPrice for price; inventoryApi.setStock for stock."
|
||||
},
|
||||
{
|
||||
"name": "Failed save restores previous value",
|
||||
"result": "PASS",
|
||||
"notes": "catch blocks in saveStock/savePrice/saveSku/saveEan reset the edit field from r.variant/r.price and set saveMsg = 'Error'."
|
||||
},
|
||||
{
|
||||
"name": "Visual feedback on success",
|
||||
"result": "PASS",
|
||||
"notes": "saveMsg shows '✓ Guardado' for 3s after success."
|
||||
},
|
||||
{
|
||||
"name": "No regressions",
|
||||
"result": "PASS",
|
||||
"notes": "PricingSection.tsx untouched; only inventory files changed."
|
||||
}
|
||||
],
|
||||
"lint": { "errors_introduced": 0 },
|
||||
"lint": {
|
||||
"errors_introduced": 0
|
||||
},
|
||||
"typecheck": "PASS",
|
||||
"verdict_reason": "Standardised click-to-edit UX across both inventory surfaces; same pattern in three places (stock, price, sku/ean).",
|
||||
"reviewer": "reviewer",
|
||||
"reviewed_at": "2026-08-20T04:05:00Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:05:00Z",
|
||||
"agent": "reviewer"
|
||||
}
|
||||
|
||||
@@ -2,15 +2,32 @@
|
||||
"feature_id": "F-082",
|
||||
"verdict": "APPROVED",
|
||||
"checks": [
|
||||
{ "name": "Auth/RBAC unchanged", "result": "PASS", "notes": "Same admin-gated endpoints." },
|
||||
{ "name": "Input sanitisation", "result": "PASS", "notes": "SKU/EAN sent as plain text; trimmed; null allowed for EAN; server validates." },
|
||||
{ "name": "XSS", "result": "PASS", "notes": "Values rendered as text in JSX; no dangerouslySetInnerHTML." },
|
||||
{ "name": "Dependencies", "result": "PASS", "notes": "No new packages." }
|
||||
{
|
||||
"name": "Auth/RBAC unchanged",
|
||||
"result": "PASS",
|
||||
"notes": "Same admin-gated endpoints."
|
||||
},
|
||||
{
|
||||
"name": "Input sanitisation",
|
||||
"result": "PASS",
|
||||
"notes": "SKU/EAN sent as plain text; trimmed; null allowed for EAN; server validates."
|
||||
},
|
||||
{
|
||||
"name": "XSS",
|
||||
"result": "PASS",
|
||||
"notes": "Values rendered as text in JSX; no dangerouslySetInnerHTML."
|
||||
},
|
||||
{
|
||||
"name": "Dependencies",
|
||||
"result": "PASS",
|
||||
"notes": "No new packages."
|
||||
}
|
||||
],
|
||||
"sast": "PASS",
|
||||
"dependency_review": "PASS",
|
||||
"secret_scan": "PASS",
|
||||
"verdict_reason": "Pure UX refactor; no new attack surface.",
|
||||
"reviewer": "security",
|
||||
"reviewed_at": "2026-08-20T04:05:30Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:05:30Z",
|
||||
"agent": "security"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user