makeplane / makeplane/plane

[bug]: v1.3.1 web app unusable on iOS/WebKit: unguarded requestIdleCallback crashes workspace pages; expanded sidebar overlays the board and swallows all taps

Open
#9,356 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

Environment

Self-hosted CE v1.3.1 (docker compose deploy). Reproduced on real iPhone Safari (iOS 26) and with Playwright WebKit (iPhone 13 device profile). Desktop browsers are unaffected (both bugs are WebKit/viewport-specific).

Two independent bugs make the v1.3.1 web app effectively unusable on iOS. Root-cause analysis for both is included below (file/line refs are against the v1.3.1 tag).


Bug 1 — unguarded requestIdleCallback crashes every workspace page on WebKit

Symptom: any workspace page (kanban, list, …) immediately shows the "🚧 Looks like something went wrong!" error boundary.

Console:

TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})')
React Router caught the following error during render TypeError: window.requestIdleCallback is not a function.

Root cause: Safari/WebKit still does not ship requestIdleCallback (it remains behind an experimental flag), and a layout component rendered by workspace pages calls window.requestIdleCallback(...) unguarded, throwing during render.

Suggested fix: feature-guard the call (window.requestIdleCallback ?? setTimeout fallback) or add a polyfill to the app entry.

Workaround we're running: a setTimeout-based polyfill injected into index.html ahead of the bundle — with it, the pages render fine, which confirms this is the only fatal error on the path.

(While debugging we also consistently see React hydration errors #418/#423 on the prerendered shell in WebKit — non-fatal since React recovers, but noisy and possibly related to Bug 2's state confusion.)


Bug 2 — on <768px viewports the expanded sidebar overlays the entire board and swallows every tap

Symptom: tapping any kanban card does nothing — users report "opening/modifying a card never loads". The peek overlay itself is healthy: programmatically force-clicking a card through the overlay opens it normally.

Evidence: Playwright cannot deliver a tap to any card:

<div id="main-sidebar" ... class="z-20 ... translate-x-0 opacity-100 absolute"> subtree intercepts pointer events

Root cause chain (v1.3.1):

  1. apps/web/core/components/sidebar/resizable-sidebar.tsx (~line 185): when not collapsed the sidebar renders translate-x-0 opacity-100, plus absolute when isMobile — i.e. a full-height z-20 overlay on phones.
  2. The mobile auto-collapse lives in apps/web/core/components/sidebar/sidebar-wrapper.tsx (~line 46): if (windowSize[0] < 768 && !sidebarCollapsed) toggleSidebar(). On project/workspace issue pages this component's effect does not end up collapsing the sidebar (and a synthetic resize event doesn't either), so the overlay stays up.
  3. That effect also calls toggleSidebar() (toggle) instead of toggleSidebar(true) (set): if it runs more than once (two wrapper instances / re-mounts), the state flips collapsed → expanded again. We observed app_sidebar_collapsed being written "true" then "false" during a single boot on a fresh profile.
  4. store-wrapper.tsx (~line 48) only applies localStorage.app_sidebar_collapsed when it exists, and there is no width-aware default — so a fresh mobile visitor always starts expanded/overlaying.

Suggested fix: default sidebarCollapsed to true when the viewport is <768px, and make the auto-collapse effect use toggleSidebar(true) so repeated runs are idempotent.

Workaround we're running: setting localStorage.app_sidebar_collapsed = "true" for narrow screens in a script before the bundle boots. (Gotcha for anyone reproducing: that script runs before the viewport meta is parsed, so window.innerWidth still reports iOS's legacy 980px layout viewport — screen.width must be used.)


Steps to reproduce
  1. Self-host CE v1.3.1, log in on an iPhone (or Playwright WebKit with an iPhone descriptor).
  2. Open any project's work-items page → error boundary (Bug 1).
  3. Apply a requestIdleCallback polyfill so the page renders → tap any kanban card → nothing happens (Bug 2).

Repro harness (Playwright):

import { webkit, devices } from 'playwright';
const browser = await webkit.launch();
const ctx = await browser.newContext({ ...devices['iPhone 13'] });
// + authenticated session cookie
const page = await ctx.newPage();
page.on('pageerror', e => console.log('PAGEERROR:', e.message));
await page.goto('https://<instance>/<workspace>/projects/<id>/issues/');
await page.waitForTimeout(10000);
// Bug 1: pageerror = requestIdleCallback TypeError
// Bug 2 (after polyfill): tap times out with "subtree intercepts pointer events" from #main-sidebar
await (await page.$('[id^="issue-"]')).tap({ timeout: 10000 });

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 with apps/web/core/components/sidebar/resizable-sidebar.tsx, sidebar-wrapper.tsx, and store-wrapper.tsx, then run the provided Playwright WebKit harness on an iPhone profile. Done means workspace pages render without a requestIdleCallback error and narrow viewports keep the sidebar from intercepting taps on kanban cards.

Written by the indexing model from the issue text.

Assessment

Tech stack
playwright, react, typescript
Domain
frontend, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.