Build image / build-and-push (push) Successful in 23s
- Reject a degenerate (zero-area or inverted) fill rect with 400 instead of
silently planting a single plop at the object centre. An empty `"rect": {}`
decodes to all-zeros and is caught the same way. New fillRect.degenerate()
and a table test covering {}, zero-width, zero-height, and inverted.
- Make the rect a named type (fillRect) rather than an anonymous inline struct,
matching the rest of internal/api, and bind the pointer to a local in the
handler so the deref is visibly guarded rather than reading req.Rect.MinX
under an invariant from a line above.
- ops_test: drop gid from the unpack instead of the `_ = gid` shim.
- ClearBedModal: drop the `const n = plopCount` no-op alias.
Not taken: moving createPlantAPI/makeFillPlant to a shared helper — that
consolidation spans this branch and #88 and is cleanest once both land, as
noted in the PR. Reusing an objectPlantingsPath helper: there isn't one in this
package, and the one inline use doesn't earn a new helper on its own.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import { Modal } from '@/components/ui/Modal'
|
|
import { Button } from '@/components/ui/Button'
|
|
import { useClearObject } from '@/lib/objects'
|
|
|
|
/** Confirm clearing every active plop from a focused bed (soft-remove — the rows
|
|
* are kept with removed_at, so history survives). */
|
|
export function ClearBedModal({
|
|
objectId,
|
|
objectName,
|
|
plopCount,
|
|
gardenId,
|
|
onClose,
|
|
}: {
|
|
objectId: number
|
|
objectName: string
|
|
plopCount: number
|
|
gardenId: number
|
|
onClose: () => void
|
|
}) {
|
|
const clear = useClearObject(gardenId)
|
|
return (
|
|
<Modal title="Clear bed" onClose={onClose} busy={clear.isPending}>
|
|
<div className="flex flex-col gap-4">
|
|
<p className="text-sm text-muted">
|
|
Remove all <span className="font-medium text-fg">{plopCount}</span>{' '}
|
|
{plopCount === 1 ? 'plant' : 'plants'} from{' '}
|
|
<span className="font-medium text-fg">{objectName}</span>? They're marked removed but kept in history.
|
|
</p>
|
|
<div className="flex justify-end gap-2">
|
|
<Button type="button" variant="ghost" onClick={onClose} disabled={clear.isPending}>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
variant="danger"
|
|
disabled={clear.isPending || plopCount === 0}
|
|
onClick={() => clear.mutate(objectId, { onSuccess: onClose })}
|
|
>
|
|
{clear.isPending ? 'Clearing…' : 'Clear bed'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
)
|
|
}
|