fix(review): resolve deep-review findings across quickfix batch #2

- Button: `loading` always disables (|| not ??) — stops a double-submit
  when a call-site passes an explicit boolean `disabled` (VideoEditor).
- playlists: track un-ingestable-but-live YouTube ids in the sync baseline
  so a linked playlist containing a private/deleted video converges instead
  of re-classifying it as a pending pull forever; re-attempt ingestion each
  sync so a restored (private->public) video heals, and prune ids that
  leave YouTube.
- SettingsPanel: download-auth section renders an honest error/loading
  state (StateMessage + retry) instead of a bare empty section on a failed
  credentials fetch; HU+EN loadError string.
- tests: reorder-order, partial-failure baseline hold, un-ingestable
  converge/heal/prune, Button loading-disables, download-auth error/retry.
This commit is contained in:
2026-08-29 03:52:13 +02:00
parent 9af4e8f4ff
commit 3369587412
8 changed files with 352 additions and 97 deletions
@@ -55,6 +55,22 @@ describe("Button primitive (S5)", () => {
expect(onClick).not.toHaveBeenCalled();
});
it("loading disables even when an explicit disabled={false} is passed", () => {
// Regression: `disabled ?? loading` let an explicit boolean disabled shadow loading, so a
// call-site with `disabled={!valid} loading={pending}` (valid → disabled=false) stayed
// clickable mid-mutation and double-submitted. The contract is: loading always disables.
const onClick = vi.fn();
render(
<Button disabled={false} loading onClick={onClick}>
Create
</Button>,
);
const btn = screen.getByRole("button", { name: "Create" }) as HTMLButtonElement;
expect(btn.disabled).toBe(true);
fireEvent.click(btn);
expect(onClick).not.toHaveBeenCalled();
});
it("fullWidth adds the w-full utility", () => {
render(<Button fullWidth>Wide</Button>);
expect(screen.getByRole("button", { name: "Wide" }).className).toContain("w-full");
+4 -1
View File
@@ -86,7 +86,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
<button
ref={ref}
type={type ?? "button"}
disabled={disabled ?? loading}
// `loading` must always disable (see the prop's contract above), even when a call-site also
// passes an explicit boolean `disabled` — so `||`, not `??`. With `??`, `disabled={false}`
// would shadow `loading` and leave the button clickable mid-mutation (double-submit).
disabled={disabled || loading}
aria-busy={loading || undefined}
aria-label={label}
title={label}