fix(admin): keep Restore original working after REMBG_URL is unset (#281)
The DraftQueue background-removal control gated both "Remove background" and "Restore original" on the same `backgroundRemoval` flag, which only reflects whether a sidecar is currently configured. Restoring is a pure database swap and never calls the sidecar, so once photos had already been cut out and REMBG_URL was later removed from the stack, the admin was left looking at a cut-out photo with no control at all and no way back to the original short of a hand-written SQL UPDATE — directly breaking the "the original is always restorable" invariant the feature is built on. DraftCard now computes `enabled` per photo as `backgroundRemoval || image.original_image_path !== null`, so Restore original stays available whenever a photo has an original regardless of whether the sidecar is configured, while Remove background still requires a configured sidecar. Also corrected the docstring on `DraftQueueResponse.backgroundRemoval` in draftsApi.ts, which claimed the flag hides "the control" generically — it only ever governed the remove-background control. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,16 @@ function priceLabel(source: PriceSource): string {
|
|||||||
*
|
*
|
||||||
* The label is the state. `original_image_path` is the only thing consulted,
|
* The label is the state. `original_image_path` is the only thing consulted,
|
||||||
* so there is no second flag that could disagree with what the button does.
|
* so there is no second flag that could disagree with what the button does.
|
||||||
|
*
|
||||||
|
* `enabled` is computed by the caller as `backgroundRemoval || cutOut`, not as
|
||||||
|
* `backgroundRemoval` alone. The two branches this button offers need opposite
|
||||||
|
* things: removing calls the sidecar and has nothing to do without one, but
|
||||||
|
* restoring is a pure database swap that needs no sidecar at all. Gating both
|
||||||
|
* on `backgroundRemoval` hides Restore the moment REMBG_URL is unset — which
|
||||||
|
* happens for real when the sidecar is decommissioned after photos were
|
||||||
|
* already cut out — leaving a cut-out photo with no control and no way back to
|
||||||
|
* the original short of hand-editing the database. That breaks the invariant
|
||||||
|
* this whole feature rests on: the original is always restorable.
|
||||||
*/
|
*/
|
||||||
function DraftPhoto({
|
function DraftPhoto({
|
||||||
image,
|
image,
|
||||||
@@ -148,7 +158,7 @@ function DraftCard({
|
|||||||
key={image.id}
|
key={image.id}
|
||||||
image={image}
|
image={image}
|
||||||
itemId={draft.item_id}
|
itemId={draft.item_id}
|
||||||
enabled={backgroundRemoval}
|
enabled={backgroundRemoval || image.original_image_path !== null}
|
||||||
onChanged={onChanged}
|
onChanged={onChanged}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -41,8 +41,11 @@ export interface DraftQueueResponse {
|
|||||||
drafts: Draft[];
|
drafts: Draft[];
|
||||||
/**
|
/**
|
||||||
* Whether a background-removal sidecar is configured. False hides the
|
* Whether a background-removal sidecar is configured. False hides the
|
||||||
* control rather than showing one that would answer 502 — an environment
|
* remove-background control rather than showing one that would answer 502
|
||||||
* without a sidecar is a working environment.
|
* — an environment without a sidecar is a working environment. It does
|
||||||
|
* *not* hide Restore original: that endpoint is a pure database swap and
|
||||||
|
* needs no sidecar, so DraftQueue shows it whenever a photo has an
|
||||||
|
* original to restore, regardless of this flag.
|
||||||
*/
|
*/
|
||||||
backgroundRemoval: boolean;
|
backgroundRemoval: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user