Fix assignee edit guard scoping

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-05-30 09:21:22 -07:00
co-authored by Orca
parent c23e0e4b42
commit e755190baa
2 changed files with 16 additions and 22 deletions
@@ -4285,14 +4285,8 @@ function GHEditSection({
const [labelPopoverOpen, setLabelPopoverOpen] = useState(false)
const [assigneePopoverOpen, setAssigneePopoverOpen] = useState(false)
const [localAssignees, setLocalAssignees] = useState<string[]>(assignees)
const hasEditedAssigneesRef = useRef(false)
const assigneesItemIdRef = useRef(item.id)
if (assigneesItemIdRef.current !== item.id) {
assigneesItemIdRef.current = item.id
// Why: item switches must clear the optimistic-edit guard before the
// assignee sync Effect runs, or the new item's assignees can render stale.
hasEditedAssigneesRef.current = false
}
const editedAssigneesItemKeyRef = useRef<string | null>(null)
const assigneesItemKey = `${item.repoId}\0${item.id}`
const patchWorkItem = useAppStore((s) => s.patchWorkItem)
const patchProjectRowContent = useAppStore((s) => s.patchProjectRowContent)
const { isPending, run } = useImmediateMutation()
@@ -4333,11 +4327,11 @@ function GHEditSection({
// resolves with real data — but skip if the user already made an
// optimistic edit so we don't clobber in-flight changes.
useEffect(() => {
if (hasEditedAssigneesRef.current) {
if (editedAssigneesItemKeyRef.current === assigneesItemKey) {
return
}
setLocalAssignees(assignees)
}, [item.id, assignees])
}, [assigneesItemKey, assignees])
const handleStateChange = useCallback(
(newState: 'open' | 'closed') => {
@@ -4468,7 +4462,9 @@ function GHEditSection({
? prevAssignees.filter((l) => l !== login)
: [...prevAssignees, login]
hasEditedAssigneesRef.current = true
// Why: the optimistic guard is scoped to this repo item so switching
// items does not suppress the next item's assignee sync.
editedAssigneesItemKeyRef.current = assigneesItemKey
if (isAssigned) {
run('assignees', {
mutate: () =>
@@ -4520,6 +4516,7 @@ function GHEditSection({
[
item.number,
item.repoId,
assigneesItemKey,
repoPath,
projectOrigin,
localAssignees,
@@ -4396,14 +4396,8 @@ function GHEditSection({
const [labelPopoverOpen, setLabelPopoverOpen] = useState(false)
const [assigneePopoverOpen, setAssigneePopoverOpen] = useState(false)
const [localAssignees, setLocalAssignees] = useState<string[]>(assignees)
const hasEditedAssigneesRef = useRef(false)
const assigneesItemIdRef = useRef(item.id)
if (assigneesItemIdRef.current !== item.id) {
assigneesItemIdRef.current = item.id
// Why: item switches must clear the optimistic-edit guard before the
// assignee sync Effect runs, or the new item's assignees can render stale.
hasEditedAssigneesRef.current = false
}
const editedAssigneesItemKeyRef = useRef<string | null>(null)
const assigneesItemKey = `${item.repoId}\0${item.id}`
const patchWorkItem = useAppStore((s) => s.patchWorkItem)
const patchProjectRowContent = useAppStore((s) => s.patchProjectRowContent)
const { isPending, run } = useImmediateMutation()
@@ -4444,11 +4438,11 @@ function GHEditSection({
// resolves with real data — but skip if the user already made an
// optimistic edit so we don't clobber in-flight changes.
useEffect(() => {
if (hasEditedAssigneesRef.current) {
if (editedAssigneesItemKeyRef.current === assigneesItemKey) {
return
}
setLocalAssignees(assignees)
}, [item.id, assignees])
}, [assigneesItemKey, assignees])
const handleStateChange = useCallback(
(newState: 'open' | 'closed') => {
@@ -4579,7 +4573,9 @@ function GHEditSection({
? prevAssignees.filter((l) => l !== login)
: [...prevAssignees, login]
hasEditedAssigneesRef.current = true
// Why: the optimistic guard is scoped to this repo item so switching
// items does not suppress the next item's assignee sync.
editedAssigneesItemKeyRef.current = assigneesItemKey
if (isAssigned) {
run('assignees', {
mutate: () =>
@@ -4631,6 +4627,7 @@ function GHEditSection({
[
item.number,
item.repoId,
assigneesItemKey,
repoPath,
projectOrigin,
localAssignees,