Skip to content

Commit 5bc73ea

Browse files
authored
fix(canvas): guard star/hide toggles against double-submit races
Two Greptile findings on the hide hook, both inherited from the star hook, so fix them symmetrically: - Ignore toggle re-clicks while a create/delete is in flight. The cache only updates on success, so a quick double-tap fired two creates for the same path, leaving a duplicate shortcut that a single later toggle couldn't clear. - Swallow failures in the delete-on-channel-delete cleanup so a rejected request doesn't surface as an unhandled promise rejection. Generated-By: PostHog Code Task-Id: 4c16844c-acc9-4124-909d-f07335710a91
1 parent 615d95d commit 5bc73ea

2 files changed

Lines changed: 20 additions & 6 deletions

File tree

packages/ui/src/features/canvas/hooks/useChannelHides.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,16 @@ export function useChannelHideToggle(channel: Channel): {
116116
removeHidden: () => void;
117117
} {
118118
const { hiddenRefToShortcutId } = useChannelHides();
119-
const { hide, unhide } = useChannelHideMutations();
119+
const { hide, unhide, isHiding, isUnhiding } = useChannelHideMutations();
120120
const shortcutId = hiddenRefToShortcutId.get(channel.path);
121121
const isHidden = shortcutId !== undefined;
122122

123123
const toggleHidden = useCallback(() => {
124+
// Ignore re-clicks while a hide/unhide is in flight. The cache only updates
125+
// once the request resolves, so without this guard a quick double-tap would
126+
// fire two creates for the same path — leaving a duplicate marker that a
127+
// single later unhide can't fully clear.
128+
if (isHiding || isUnhiding) return;
124129
const run = shortcutId ? unhide(shortcutId) : hide(channel);
125130
run.catch((error: unknown) => {
126131
toast.error(
@@ -130,11 +135,13 @@ export function useChannelHideToggle(channel: Channel): {
130135
},
131136
);
132137
});
133-
}, [channel, shortcutId, isHidden, hide, unhide]);
138+
}, [channel, shortcutId, isHidden, hide, unhide, isHiding, isUnhiding]);
134139

135140
const removeHidden = useCallback(() => {
136141
if (shortcutId) {
137-
void unhide(shortcutId);
142+
// Best-effort cleanup when the channel is deleted; swallow failures so a
143+
// rejected delete doesn't surface as an unhandled rejection.
144+
void unhide(shortcutId).catch(() => {});
138145
}
139146
}, [shortcutId, unhide]);
140147

packages/ui/src/features/canvas/hooks/useChannelStars.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,16 @@ export function useChannelStarToggle(channel: Channel): {
117117
removeStar: () => void;
118118
} {
119119
const { starredRefToShortcutId } = useChannelStars();
120-
const { star, unstar } = useChannelStarMutations();
120+
const { star, unstar, isStarring, isUnstarring } = useChannelStarMutations();
121121
const shortcutId = starredRefToShortcutId.get(channel.path);
122122
const isStarred = shortcutId !== undefined;
123123

124124
const toggleStar = useCallback(() => {
125+
// Ignore re-clicks while a star/unstar is in flight. The cache only updates
126+
// once the request resolves, so without this guard a quick double-tap would
127+
// fire two creates for the same path — leaving a duplicate shortcut that a
128+
// single later unstar can't fully clear.
129+
if (isStarring || isUnstarring) return;
125130
const run = shortcutId ? unstar(shortcutId) : star(channel);
126131
run.catch((error: unknown) => {
127132
toast.error(
@@ -131,11 +136,13 @@ export function useChannelStarToggle(channel: Channel): {
131136
},
132137
);
133138
});
134-
}, [channel, shortcutId, isStarred, star, unstar]);
139+
}, [channel, shortcutId, isStarred, star, unstar, isStarring, isUnstarring]);
135140

136141
const removeStar = useCallback(() => {
137142
if (shortcutId) {
138-
void unstar(shortcutId);
143+
// Best-effort cleanup when the channel is deleted; swallow failures so a
144+
// rejected delete doesn't surface as an unhandled rejection.
145+
void unstar(shortcutId).catch(() => {});
139146
}
140147
}, [shortcutId, unstar]);
141148

0 commit comments

Comments
 (0)