twenty/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerTabsRow.tsx

260 lines
8.6 KiB
TypeScript
Raw Normal View History

chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import {
IconComment,
IconHome,
IconMessageCirclePlus,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
Deprecate runtime theme objects in favor of CSS variables (#18402) ## Summary - **Eliminate `ICON_SIZES` / `ICON_STROKES` constants**: all icon dimensions are now resolved at runtime via `resolveThemeVariableAsNumber(themeCssVariables.icon.size.X)`, ensuring values always come from computed CSS variables - **No more consumer imports from `twenty-ui/theme`**: moved `ColorSchemeContext`, `ColorSchemeProvider`, `ThemeColor`, `MAIN_COLOR_NAMES`, `getNextThemeColor`, `AnimationDuration` to `twenty-ui/theme-constants` - **Remove `ThemeContext` / `ThemeContextProvider` / `ThemeProvider` / `ThemeType`**: replaced across ~300 files with `themeCssVariables` (for CSS contexts) or `resolveThemeVariable` / `resolveThemeVariableAsNumber` (for JS runtime values) - **Simplify provider chain**: only `ColorSchemeProvider` remains — it toggles `light`/`dark` class on `document.documentElement` and provides `colorScheme` via React context - **Fix pre-existing test failures**: `useIcons.test.ts` (non-configurable ES module spy) and `turnRecordFilterGroupIntoGqlOperationFilter.test.ts` (`Omit<RecordFilter, 'id'>` type mismatch) ### Theme access pattern (before → after) | Context | Before | After | |---------|--------|-------| | CSS (Linaria) | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | JS runtime (icon size, animation) | `theme.icon.size.md` / `ICON_SIZES.md` | `resolveThemeVariableAsNumber(themeCssVariables.icon.size.md)` | | Color scheme check | `theme.name === 'dark'` | `useContext(ColorSchemeContext).colorScheme === 'dark'` |
2026-03-05 13:39:01 +00:00
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import { useIsMobile } from 'twenty-ui/utilities';
Deprecate runtime theme objects in favor of CSS variables (#18402) ## Summary - **Eliminate `ICON_SIZES` / `ICON_STROKES` constants**: all icon dimensions are now resolved at runtime via `resolveThemeVariableAsNumber(themeCssVariables.icon.size.X)`, ensuring values always come from computed CSS variables - **No more consumer imports from `twenty-ui/theme`**: moved `ColorSchemeContext`, `ColorSchemeProvider`, `ThemeColor`, `MAIN_COLOR_NAMES`, `getNextThemeColor`, `AnimationDuration` to `twenty-ui/theme-constants` - **Remove `ThemeContext` / `ThemeContextProvider` / `ThemeProvider` / `ThemeType`**: replaced across ~300 files with `themeCssVariables` (for CSS contexts) or `resolveThemeVariable` / `resolveThemeVariableAsNumber` (for JS runtime values) - **Simplify provider chain**: only `ColorSchemeProvider` remains — it toggles `light`/`dark` class on `document.documentElement` and provides `colorScheme` via React context - **Fix pre-existing test failures**: `useIcons.test.ts` (non-configurable ES module spy) and `turnRecordFilterGroupIntoGqlOperationFilter.test.ts` (`Omit<RecordFilter, 'id'>` type mismatch) ### Theme access pattern (before → after) | Context | Before | After | |---------|--------|-------| | CSS (Linaria) | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | JS runtime (icon size, animation) | `theme.icon.size.md` / `ICON_SIZES.md` | `resolveThemeVariableAsNumber(themeCssVariables.icon.size.md)` | | Color scheme check | `theme.name === 'dark'` | `useContext(ColorSchemeContext).colorScheme === 'dark'` |
2026-03-05 13:39:01 +00:00
import { useContext } from 'react';
refactor: standardize AI acronym to Ai (PascalCase) across internal identifiers (#19837) ## Summary The "AI" acronym was rendered inconsistently across the codebase. The backend AI module had settled on PascalCase `Ai` (`AiAgentModule`, `AiBillingService`, `AiChatModule`, `AiModelRegistryService`, etc.), while frontend components, several DTOs, a few types, and shared identifiers still used all-caps `AI` (`AIChatTab`, `AISystemPromptPreviewDTO`, `SettingsPath.AIPrompts`, ...). CLAUDE.md specifies PascalCase for classes; this PR normalizes everything internal to `Ai`. **This is a pure internal rename.** The GraphQL schema is untouched — `@ObjectType` decorator string arguments, resolver method names (which become Query/Mutation field names), gql template contents, and the `generated-metadata/graphql.ts` file are preserved verbatim. The only visible change is TypeScript identifiers and file names. ## Also folded in (adjacent cleanups) - **`AgentModelConfigService` → `AiModelConfigService`**. Lives in `ai-models/` and is used by multiple AI code paths, not just the Agent entity. The "Agent" prefix was misleading. - **`generate-text-input.dto.ts` → `generate-text.input.ts`**. The `ai-agent/dtos/` folder already uses `<entity>.input.ts` convention for Input classes (`create-agent.input.ts` etc.); the old path mixed `.dto.ts` file extension with a class that has no DTO suffix. File rename only; class stays `GenerateTextInput`. - **Removed stale TODO** in `ai-model-config.type.ts` that asked for the `AiModelConfig` rename that this PR performs. ## Rename methodology Bulk rename via perl with anchored regex `(?<!['"])(?<![A-Z.])AI([A-Z])(?=[a-z])/Ai$1/g`: - **Lookbehind for non-uppercase** skips adjacent acronyms (`MOSAIC`, `OIDCSSO`) and leaves `AIRBNB_ID` alone. - **Lookbehind for non-quote** protects most string literals. - **Lookahead for lowercase** restricts matches to PascalCase identifiers (`AIChatTab`), leaving SCREAMING_SNAKE constants untouched. Strict file-scope exclusions: `generated-metadata/**`, `generated/**`, `locales/**`, `migrations/**`, `illustrations/**`, `halftone/**`, and the two gql template files (`queries/getAISystemPromptPreview.ts`, `mutations/uploadAIChatFile.ts`). Post-rename reverts for identifiers where the regex was too eager: - Backend resolver method names kept: `getAISystemPromptPreview`, `uploadAIChatFile` (they are GraphQL field names). - `@ObjectType('AdminAIModels')` / `('AISystemPromptPreview')` / `('AISystemPromptSection')` kept as-is. - Backend classes `ClientAIModelConfig` / `AdminAIModelConfig` kept as-is (they use `@ObjectType()` with no argument, so the class name IS the schema name). - External-library symbols restored: `OpenAIProvider`, `createOpenAICompatible`, `vercelAIIntegration`. File renames use a two-step rename to work on macOS case-insensitive filesystems: `git mv X.tsx X.tsx.tmp && git mv X.tsx.tmp renamed.tsx`. ## Diff audit - 0 changes to migrations - 0 changes to locale `.po` / `.ts` files - 0 changes to `generated-metadata/graphql.ts` - 0 changes to website illustration files (base64 blobs preserved) - 0 renames inside user-facing translation strings (`t\`…\``, `msg\`…\``, `<Trans>…</Trans>`) ## Test plan - [x] `npx nx typecheck twenty-server` — PASS - [x] `npx nx typecheck twenty-front` — PASS - [x] `npx jest ai-model admin agent-role` — 79/79 PASS - [x] `npx oxlint --type-aware` on 118 changed files — 0 errors - [x] `npx prettier --check` on 118 changed files — clean - [ ] CI
2026-04-19 11:29:35 +00:00
import { useSwitchToNewAiChat } from '@/ai/hooks/useSwitchToNewAiChat';
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
import {
type NavigationDrawerActiveTab,
NAVIGATION_DRAWER_TABS,
} from '@/ui/navigation/states/navigationDrawerTabs';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
const StyledRow = styled.div<{ isExpanded: boolean }>`
align-items: center;
display: flex;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
gap: ${({ isExpanded }) => (isExpanded ? themeCssVariables.spacing[2] : 0)};
justify-content: ${({ isExpanded }) =>
isExpanded ? 'space-between' : 'center'};
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
transition: gap calc(${themeCssVariables.animation.duration.normal} * 1s) ease;
width: ${({ isExpanded }) => (isExpanded ? '100%' : 'max-content')};
`;
const StyledTabsPill = styled.div`
align-items: center;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background: ${themeCssVariables.background.secondary};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
border: 1px solid ${themeCssVariables.border.color.medium};
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
border-radius: ${themeCssVariables.border.radius.pill};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
box-sizing: border-box;
display: flex;
flex-shrink: 0;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
gap: ${themeCssVariables.spacing[0.5]};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
height: ${themeCssVariables.spacing[7]};
padding: 3px;
width: ${themeCssVariables.spacing[18]};
`;
const StyledTabWrapper = styled.div<{ isActive: boolean }>`
align-items: center;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background: ${({ isActive }) =>
isActive ? themeCssVariables.background.transparent.light : 'transparent'};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
border-radius: ${themeCssVariables.border.radius.pill};
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
color: ${({ isActive }) =>
isActive
? themeCssVariables.font.color.primary
: themeCssVariables.font.color.tertiary};
cursor: pointer;
display: flex;
flex: 1;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
height: 100%;
justify-content: center;
&:hover {
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background: ${({ isActive }) =>
isActive
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
? themeCssVariables.background.transparent.light
: themeCssVariables.background.transparent.lighter};
}
`;
const StyledTabIcon = styled.div`
align-items: center;
display: flex;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
height: ${themeCssVariables.spacing[5]};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
justify-content: center;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
width: ${themeCssVariables.spacing[5]};
`;
const StyledNewChatIcon = styled.div`
align-items: center;
display: flex;
flex-grow: 0;
flex-shrink: 0;
justify-content: center;
`;
const StyledNewChatButtonWrapper = styled.div<{ isExpanded: boolean }>`
align-items: center;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background: ${themeCssVariables.background.secondary};
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
border: 1px solid ${themeCssVariables.border.color.medium};
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
border-radius: ${themeCssVariables.border.radius.pill};
box-sizing: border-box;
display: flex;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
height: ${({ isExpanded }) =>
isExpanded ? themeCssVariables.spacing[7] : themeCssVariables.spacing[6]};
justify-content: center;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
padding: ${({ isExpanded }) =>
isExpanded ? '3px' : themeCssVariables.spacing[0.5]};
transition:
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
height calc(${themeCssVariables.animation.duration.normal} * 1s) ease,
padding calc(${themeCssVariables.animation.duration.normal} * 1s) ease;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
width: ${({ isExpanded }) =>
isExpanded ? '103px' : themeCssVariables.spacing[6]};
`;
const StyledNewChatButton = styled.div`
align-items: center;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
border-radius: inherit;
color: ${themeCssVariables.font.color.secondary};
cursor: pointer;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
display: flex;
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
font-size: ${themeCssVariables.font.size.sm};
font-weight: ${themeCssVariables.font.weight.medium};
gap: ${themeCssVariables.spacing[1]};
height: 100%;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
justify-content: center;
min-width: 0;
overflow: hidden;
padding-inline: ${themeCssVariables.spacing[1]};
transition:
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background calc(${themeCssVariables.animation.duration.fast} * 1s) ease,
color calc(${themeCssVariables.animation.duration.fast} * 1s) ease;
Re-enable disabled lint rules and right-size CI runners (#18461) ## Summary - Re-enable one lint rule that was temporarily disabled during the ESLint-to-Oxlint migration: - **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578 violations auto-fixed across 390 files - Document why **`typescript/consistent-type-imports`** cannot be auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata` for DI, so converting constructor parameter imports to `import type` erases them at compile time and breaks dependency injection at runtime - Right-size CI runners, reducing 8-core usage from 18 jobs to 3: | Change | Jobs | Rationale | |--------|------|-----------| | **Keep 8-core** | `ci-merge-queue/e2e-test`, `ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) | | **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation, test, integration-test), `ci-front/front-sb-test`, `ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into 10-12 parallel instances, I/O-bound (DB/Redis), or moderate single builds | | **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight (build + curl health check) | | **Removed** | `ci-front/front-chromatic-deployment` | Dead code — permanently disabled with `if: false` | - Fix merge queue CI issues: - **Concurrency**: Use `merge_group.base_ref` instead of unique merge group ref so new queue entries cancel previous runs - **Required status checks**: Add `merge_group` trigger to all 6 required CI workflows (front, server, shared, website, docker-compose, sdk) with `changed-files-check` auto-skipped for merge_group events — status check jobs auto-pass without re-running full CI - **Build caching**: Add Nx build cache restore/save to E2E test job with fallback to `main` branch cache for faster frontend and server builds ## Test plan - [ ] CI passes on this PR (verifies lint rule auto-fix works) - [ ] Verify 4-core runner jobs complete within their 30-minute timeouts - [ ] Verify merge queue status checks auto-pass (ci-front-status-check, ci-server-status-check, etc.) - [ ] Verify merge queue E2E concurrency cancels previous runs when a new PR enters the queue
2026-03-06 13:33:02 +00:00
width: 100%;
&:hover {
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
background: ${themeCssVariables.background.transparent.light};
color: ${themeCssVariables.font.color.primary};
}
`;
export const MainNavigationDrawerTabsRow = () => {
chore(twenty-front): migrate small modules from Emotion to Linaria (PR 1/10) (#18314) ## Emotion → Linaria migration — PR 1 of 10 First batch of the `twenty-front` migration from Emotion (runtime CSS-in-JS) to Linaria (zero-runtime, build-time extraction via wyw-in-js). Covers **100 files** across 10 small standalone modules — chosen as the lowest-risk starting point. ### Modules migrated spreadsheet-import (28) · navigation-menu-item (17) · views (14) · billing (10) · blocknote-editor (7) · advanced-text-editor (7) · favorites (7) · navigation (4) · information-banner (3) · sign-in-background-mock (3) ### Migration pattern Every file follows the same mechanical transformation: | Emotion | Linaria | |---|---| | `import styled from '@emotion/styled'` | `import { styled } from '@linaria/react'` | | `${({ theme }) => theme.font.color.primary}` | `${themeCssVariables.font.color.primary}` | | `${({ theme }) => theme.spacing(4)}` | `${themeCssVariables.spacing[4]}` | | `const theme = useTheme()` | `const { theme } = useContext(ThemeContext)` | | `import { type Theme } from '@emotion/react'` | `import { type ThemeType } from 'twenty-ui/theme'` | `themeCssVariables` is a build-time object where every leaf is a `var(--t-xxx)` CSS custom property reference, evaluated statically by wyw-in-js. Runtime theme access (icon sizes, colors passed as props) uses `useContext(ThemeContext)`. ### Gotchas encountered & fixed - **Interpolation return types** — wyw-in-js requires `string | number`, never `false`/`undefined`. Replaced `condition && 'css'` with `condition ? 'css' : ''`. - **`css` tag inside `styled` templates** — Linaria `css` returns a class name, not CSS text. Replaced with plain template strings. - **`styled(Component)` needs `className`** — added `className` prop to `NavigationDrawerSection`, `DropdownMenuItemsContainer`, and `Heading`. - **`shouldForwardProp` not supported** — Linaria filters invalid DOM props automatically for HTML elements. For custom components, used wrapper divs where needed. - **`FormFieldPlaceholderStyles`** — converted from Emotion `css` function to a static string using `themeCssVariables`.
2026-03-02 15:33:40 +00:00
const { theme } = useContext(ThemeContext);
const isMobile = useIsMobile();
const isNavigationDrawerExpanded = useAtomStateValue(
isNavigationDrawerExpandedState,
);
const [navigationDrawerActiveTab, setNavigationDrawerActiveTab] =
useAtomState(navigationDrawerActiveTabState);
refactor: standardize AI acronym to Ai (PascalCase) across internal identifiers (#19837) ## Summary The "AI" acronym was rendered inconsistently across the codebase. The backend AI module had settled on PascalCase `Ai` (`AiAgentModule`, `AiBillingService`, `AiChatModule`, `AiModelRegistryService`, etc.), while frontend components, several DTOs, a few types, and shared identifiers still used all-caps `AI` (`AIChatTab`, `AISystemPromptPreviewDTO`, `SettingsPath.AIPrompts`, ...). CLAUDE.md specifies PascalCase for classes; this PR normalizes everything internal to `Ai`. **This is a pure internal rename.** The GraphQL schema is untouched — `@ObjectType` decorator string arguments, resolver method names (which become Query/Mutation field names), gql template contents, and the `generated-metadata/graphql.ts` file are preserved verbatim. The only visible change is TypeScript identifiers and file names. ## Also folded in (adjacent cleanups) - **`AgentModelConfigService` → `AiModelConfigService`**. Lives in `ai-models/` and is used by multiple AI code paths, not just the Agent entity. The "Agent" prefix was misleading. - **`generate-text-input.dto.ts` → `generate-text.input.ts`**. The `ai-agent/dtos/` folder already uses `<entity>.input.ts` convention for Input classes (`create-agent.input.ts` etc.); the old path mixed `.dto.ts` file extension with a class that has no DTO suffix. File rename only; class stays `GenerateTextInput`. - **Removed stale TODO** in `ai-model-config.type.ts` that asked for the `AiModelConfig` rename that this PR performs. ## Rename methodology Bulk rename via perl with anchored regex `(?<!['"])(?<![A-Z.])AI([A-Z])(?=[a-z])/Ai$1/g`: - **Lookbehind for non-uppercase** skips adjacent acronyms (`MOSAIC`, `OIDCSSO`) and leaves `AIRBNB_ID` alone. - **Lookbehind for non-quote** protects most string literals. - **Lookahead for lowercase** restricts matches to PascalCase identifiers (`AIChatTab`), leaving SCREAMING_SNAKE constants untouched. Strict file-scope exclusions: `generated-metadata/**`, `generated/**`, `locales/**`, `migrations/**`, `illustrations/**`, `halftone/**`, and the two gql template files (`queries/getAISystemPromptPreview.ts`, `mutations/uploadAIChatFile.ts`). Post-rename reverts for identifiers where the regex was too eager: - Backend resolver method names kept: `getAISystemPromptPreview`, `uploadAIChatFile` (they are GraphQL field names). - `@ObjectType('AdminAIModels')` / `('AISystemPromptPreview')` / `('AISystemPromptSection')` kept as-is. - Backend classes `ClientAIModelConfig` / `AdminAIModelConfig` kept as-is (they use `@ObjectType()` with no argument, so the class name IS the schema name). - External-library symbols restored: `OpenAIProvider`, `createOpenAICompatible`, `vercelAIIntegration`. File renames use a two-step rename to work on macOS case-insensitive filesystems: `git mv X.tsx X.tsx.tmp && git mv X.tsx.tmp renamed.tsx`. ## Diff audit - 0 changes to migrations - 0 changes to locale `.po` / `.ts` files - 0 changes to `generated-metadata/graphql.ts` - 0 changes to website illustration files (base64 blobs preserved) - 0 renames inside user-facing translation strings (`t\`…\``, `msg\`…\``, `<Trans>…</Trans>`) ## Test plan - [x] `npx nx typecheck twenty-server` — PASS - [x] `npx nx typecheck twenty-front` — PASS - [x] `npx jest ai-model admin agent-role` — 79/79 PASS - [x] `npx oxlint --type-aware` on 118 changed files — 0 errors - [x] `npx prettier --check` on 118 changed files — clean - [ ] CI
2026-04-19 11:29:35 +00:00
const { switchToNewChat } = useSwitchToNewAiChat();
const setIsNavigationDrawerExpanded = useSetAtomState(
isNavigationDrawerExpandedState,
);
const isExpanded = isNavigationDrawerExpanded || isMobile;
const handleTabClick = (tab: NavigationDrawerActiveTab) => () => {
setNavigationDrawerActiveTab(tab);
};
const handleTabKeyDown =
(tab: NavigationDrawerActiveTab) => (event: React.KeyboardEvent) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
setNavigationDrawerActiveTab(tab);
}
};
const handleNewChatClick = () => {
if (isMobile) {
setIsNavigationDrawerExpanded(false);
}
switchToNewChat();
};
const handleNewChatKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
handleNewChatClick();
}
};
const getTabIconColor = (isActive: boolean) =>
isActive ? theme.font.color.primary : theme.font.color.tertiary;
return (
<StyledRow isExpanded={isExpanded}>
<NavigationDrawerAnimatedCollapseWrapper>
<StyledTabsPill role="tablist" aria-label={t`Navigation tabs`}>
<StyledTabWrapper
isActive={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.NAVIGATION_MENU
}
role="tab"
aria-selected={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.NAVIGATION_MENU
}
aria-label={t`Home`}
tabIndex={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.NAVIGATION_MENU
? 0
: -1
}
onClick={handleTabClick(NAVIGATION_DRAWER_TABS.NAVIGATION_MENU)}
onKeyDown={handleTabKeyDown(NAVIGATION_DRAWER_TABS.NAVIGATION_MENU)}
>
<StyledTabIcon>
<IconHome
size={theme.icon.size.md}
color={getTabIconColor(
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.NAVIGATION_MENU,
)}
/>
</StyledTabIcon>
</StyledTabWrapper>
<StyledTabWrapper
isActive={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY
}
role="tab"
aria-selected={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY
}
aria-label={t`Chat`}
tabIndex={
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY
? 0
: -1
}
onClick={handleTabClick(NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY)}
onKeyDown={handleTabKeyDown(NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY)}
>
<StyledTabIcon>
<IconComment
size={theme.icon.size.md}
color={getTabIconColor(
navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY,
)}
/>
</StyledTabIcon>
</StyledTabWrapper>
</StyledTabsPill>
</NavigationDrawerAnimatedCollapseWrapper>
<StyledNewChatButtonWrapper isExpanded={isExpanded}>
<StyledNewChatButton
role="button"
tabIndex={0}
aria-label={t`New chat`}
onClick={handleNewChatClick}
onKeyDown={handleNewChatKeyDown}
>
<StyledNewChatIcon>
<IconMessageCirclePlus size={theme.icon.size.md} />
</StyledNewChatIcon>
{isExpanded && <OverflowingTextWithTooltip text={t`New chat`} />}
</StyledNewChatButton>
</StyledNewChatButtonWrapper>
</StyledRow>
);
};