makeplane / makeplane/plane

[bug]: Optimistic kanban drag/drop silently no-ops in epic-filtered views with 'Show sub-issues' off

Open
#9,049 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
59.6k
Forks
5.8k
Avg merge
1d 22h
Merged PRs (30d)
49

Description

Description

In a kanban view filtered by epic (epic_id__in), grouped by state, and ordered manually, dragging a card between state columns:

  • Persists correctly to the backend (PATCH /issues/ returns 204)
  • Does NOT update the local kanban. The card stays in the source column until I reload the page.

A reload reflects the new state correctly. There are no console errors, no toasts, and no exceptions in the optimistic-update path. So nothing visibly tells the user the drop "worked."

This makes drag/drop in epic-filtered kanban views feel broken: every move requires a refresh to confirm.

Affected version
  • web-commercial:v2.5.3 (self-hosted)
  • The relevant code path is also present on current main, so the OSS build is likely affected too.
Steps to reproduce
  1. Create a project view filtered by a specific epic (epic_id__in: <epicId>).
  2. Set Layout: Kanban, Group by: State, Order by: Manual.
  3. Open the view. Confirm displayFilters.sub_issue is false (the default).
  4. Drag any card from one state column to another.
  5. Card stays visually in the source column.
  6. Reload the page. Card now appears in the destination column.
Expected behavior

Card should optimistically move to the destination column right after the drop, matching the persisted server state.

Root cause

In apps/web/core/store/issue/helpers/base-issues.store.ts, inside BaseIssuesStore.updateIssueList (around line 1218):

for (const issueUpdate of issueUpdates) {
  if (issueUpdate.action === EIssueGroupedAction.ADD) {
    const isSubIssue = issue?.parent_id;
    if (isSubIssue && !isShowWorkItemsEnabled) continue;   // <-- this guard
    update(this, ["groupedIssueIds", ...issueUpdate.path], (issueIds = []) =>
      this.issuesSortWithOrderBy(uniq(concat(issueIds, issueId)), this.orderBy)
    );
  }
  ...
}

When isShowWorkItemsEnabled (derived from displayFilters.sub_issue) is false AND the issue has a parent_id, the ADD action is skipped.

In an epic-filtered view, every listed item is a child of the epic — its parent_id equals the epic's UUID. So this guard fires on every drop, and the optimistic move never runs.

The guard makes sense for the list-view case where users collapse sub-issues under their parents. It does not make sense in a kanban view that's explicitly filtered by epic, because in that view the epic's children ARE the primary content.

Live evidence (verified against the running MobX store)

Captured by walking the React fiber to the ProjectViewIssues instance, then calling pv.updateIssueList(newIssue, oldIssue) with controlled inputs:

Test parent_id displayFilters.sub_issue bucket moved?
1 <epicId> (real) false no
2 null (forced) false yes
3 <epicId> (real) true yes

The PATCH succeeds in all three cases (the issue's state_id updates correctly in the issue map). Only the groupedIssueIds bucket move is suppressed.

Workaround

Toggle Display Settings → "Show sub-issues" to ON (displayFilters.sub_issue = true). This bypasses the guard and restores optimistic kanban behavior.

It works, but it's not at all obvious that "Show sub-issues" affects kanban drag/drop reactivity. Users will not connect those two things.

Suggested fix

The cleanest fix is to recognize that when a view's filters target items by epic/parent, those items aren't "sub-issues" in the display sense. They're the primary content. So the isSubIssue && !isShowWorkItemsEnabled guard should be skipped when:

  • The active filter includes epic_id__in (or any parent-targeted filter), or
  • The item's parent_id is itself the filter target.

If a narrower fix is preferred, just removing the guard for the kanban layout entirely would also resolve this, since hiding a card in kanban mid-drag is a worse UX than showing all matching items.

Environment
  • Self-hosted, image artifacts.plane.so/makeplane/web-commercial:v2.5.3
  • Browser: Chrome 148 on macOS
  • Stack: api + web + space + live + worker + admin (12-container compose)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/web/core/store/issue/helpers/base-issues.store.ts and inspect BaseIssuesStore.updateIssueList, especially the ADD path and its sub-issue guard. Reproduce the epic-filtered kanban drag/drop case with displayFilters.sub_issue disabled, then verify that the groupedIssueIds bucket moves immediately after the persisted update. Done when the optimistic move works for epic-filtered cards without breaking the intended list-view behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
67/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.