Building a modern alternative to Salesforce, powered by the community.
Find a file
Sonarly Claude Code 3adee873d6 fix: guard handleTransitionEnd against bubbled child transitions and harden workflow component during close
https://sonarly.com/issue/29397?type=bug

When a user navigates away from a workflow page while the side panel is open to a workflow step editor (e.g. WorkflowTriggerSelectType), PageChangeEffect calls closeSidePanelMenu() which initiates a two-phase close: Phase 1 sets isSidePanelOpenedState=false and isSidePanelClosingState=true but does NOT clear sidePanelPageState or sidePanelPageInfoState. Phase 2 (the actual cleanup) is deferred to the CSS transitionend event on StyledSidePanelWrapper's width transition.

During the close animation, the side panel content continues to render (shouldShowContent = isSidePanelOpened || shouldRenderContent — shouldRenderContent remains true until handleTransitionEnd fires). The SidePanelRouter contains a framer-motion motion.div that animates opacity. When this inner opacity transition completes, its transitionend event bubbles up to StyledSidePanelWrapper's onTransitionEnd handler. Because handleTransitionEnd does NOT filter by event.propertyName === 'width' or event.target === event.currentTarget, the handler runs prematurely on the bubbled opacity event.

At this point, isSidePanelOpened is false and isSidePanelClosing is true, so handleTransitionEnd executes setShouldRenderContent(false) AND sidePanelCloseAnimationCompleteCleanup(). The cleanup resets sidePanelPageInfoState.instanceId to '' and sidePanelPageState to CommandMenuDisplay. However, between the cleanup's Jotai store.set calls, React may re-render the still-mounted SidePanelRouter. If sidePanelPageInfoState.instanceId is reset to '' while sidePanelPageState is still WorkflowTriggerSelectType during an intermediate render, SidePanelRouter renders SidePanelWorkflowSelectTriggerType with instanceId=''. This component calls useSidePanelWorkflowIdOrThrow() which reads sidePanelWorkflowIdComponentState scoped to instanceId='' — an atom instance that was never populated (the workflow ID was set for the original UUID-based instanceId). The atom returns undefined (its default), and the hook throws.

Fix: Added event filtering to `handleTransitionEnd` in `SidePanelForDesktop.tsx` to only process `width` transitions on the wrapper element itself (`event.target !== event.currentTarget || event.propertyName !== 'width'`). This prevents bubbled `transitionend` events from child elements (specifically the framer-motion `<motion.div>` opacity animation inside `SidePanelRouter`) from triggering premature `sidePanelCloseAnimationCompleteCleanup()` during the close animation. Without this filter, the cleanup resets `sidePanelPageInfoState.instanceId` to `''` while workflow components are still mounted, causing them to read an unpopulated atom instance and throw.

An identical fix already exists on unmerged branch `sonarly-19891-side-panel-crash-from-unguarded-ontransitionend` (commit `256dbd7fc2`) for the same root cause manifesting as a different symptom ("Record id is not defined" in SidePanelRecordPage).
2026-04-21 11:17:35 +00:00
.claude-pr Upgrade command internal doc (#19541) 2026-04-10 09:43:06 +00:00
.cursor Rename standard and custom apps (#19631) 2026-04-13 13:13:59 +00:00
.github feat: move admin panel to dedicated /admin-panel GraphQL endpoint (#19852) 2026-04-19 20:55:10 +02:00
.vscode Migrate from ESLint to OxLint (#18443) 2026-03-06 01:03:50 +01:00
.yarn Refactor dependency graph for SDK, client-sdk and create-app (#18963) 2026-03-26 10:56:52 +00:00
packages fix: guard handleTransitionEnd against bubbled child transitions and harden workflow component during close 2026-04-21 11:17:35 +00:00
.dockerignore Scaffold light twenty app dev container (#18734) 2026-03-18 20:10:54 +01:00
.gitattributes Consolidate Prettier config and improve consistency (#15191) 2025-10-18 12:24:35 +02:00
.gitignore Partners, customers and more (#19862) 2026-04-20 07:13:56 +00:00
.mcp.json Fix AI chat re-renders and refactored code (#18585) 2026-03-21 12:52:21 +00:00
.nvmrc Upgrade to Node 24 (#13730) 2025-08-07 17:02:12 +02:00
.yarnrc.yml Refactor dependency graph for SDK, client-sdk and create-app (#18963) 2026-03-26 10:56:52 +00:00
CLAUDE.md Upgrade command internal doc (#19541) 2026-04-10 09:43:06 +00:00
jest.preset.js Move tools/eslint-rules to packages/twenty-eslint-rules (#17203) 2026-01-17 07:37:17 +01:00
LICENSE feat(sso): allow to use OIDC and SAML (#7246) 2024-10-21 20:07:08 +02:00
nx.json fix: replace npm pkg set with node script in set-local-version target (#19344) 2026-04-05 18:56:37 +00:00
package.json Bump @storybook/react-vite from 10.2.13 to 10.3.3 (#19232) 2026-04-02 08:49:11 +00:00
README.md Docs: restructure navigation, add halftone illustrations, clean up hero images (#19728) 2026-04-21 09:13:55 +02:00
tsconfig.base.json Revert "[hacktoberfest] feat: add fireflies" (#15589) 2025-11-04 12:25:23 +01:00
yarn.config.cjs [ENHC] Create Yarn constraints to validate node version (#10542) 2025-02-27 15:18:07 +01:00
yarn.lock [Website] Self-host billing migration and some responsiveness fixes. (#19894) 2026-04-20 21:23:54 +02:00

We're live on Product Hunt — Support us

Twenty logo

The #1 Open-Source CRM

Website · Documentation · Roadmap · Discord · Figma

Twenty banner


Why Twenty

Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.

Learn more about why we built Twenty


Installation

Cloud

The fastest way to get started. Sign up at twenty.com and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.

Build an app

Scaffold a new app with the Twenty CLI:

npx create-twenty-app my-app

Define objects, fields, and views as code:

import { defineObject, FieldType } from 'twenty-sdk/define';

export default defineObject({
  nameSingular: 'deal',
  namePlural: 'deals',
  labelSingular: 'Deal',
  labelPlural: 'Deals',
  fields: [
    { name: 'name', label: 'Name', type: FieldType.TEXT },
    { name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
    { name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
  ],
});

Then ship it to your workspace:

npx twenty deploy

See the app development guide for objects, views, agents, and logic functions.

Self-hosting

Run Twenty on your own infrastructure with Docker Compose, or contribute locally via the local setup guide.



Everything you need

Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.

Want to go deeper? Read the User Guide for product walkthroughs, or the Documentation for developer reference.

Create your apps

Learn more about apps in doc

Stay on top with version control

Learn more about version control in doc

All the tools you need to build anything

Learn more about primitives in doc

Customize your layouts

Learn more about layouts in doc

AI agents and chats

Learn more about AI in doc

Plus all the tools of a good CRM

Learn more about CRM features in doc


Stack

Thanks

Chromatic      Greptile      Sentry      Crowdin

Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).

Join the Community

Star the repo · Discord · Feature requests · Releases · X · LinkedIn · Crowdin · Contribute