From d61dcaf1dfa1da9667c14b2ae85d106fee939988 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Mon, 19 Oct 2026 12:24:14 +0700 Subject: [PATCH] fix(app): give subagent rows room on compact and standard press feedback (#7364) The subagent track rows were as dense on a phone as in the desktop popover, and the archive and detach actions were hand-rolled pressables that only recoloured the glyph, so a tap or hover never showed the rounded highlight every other icon action has. Rows now take the compact menu-row height and padding below the `md` breakpoint, decided once in the track row style; the desktop popover keeps its density. The actions are `ToolbarButton`, which owns the hitbox, the rounded highlight on hover and press, the compact size, and the tooltip. A repo oxlint rule, `paseo/no-raw-pressable`, reports `Pressable` and `Touchable*` imports outside `components/ui/` so the next tap target reaches for a primitive. Existing importers are on a burn-down list they can only leave. The rule is its own name rather than another `no-restricted-imports` entry so its override cannot interact with the existing burn-downs. Its test runs the real oxlint binary and is wired into the CI quality job. --- .github/workflows/ci.yml | 4 + .oxlintrc.json | 112 +++++++++++++++++++++++++++ docs/design.md | 3 +- packages/app/src/composer/tracks.tsx | 42 +++++----- packages/app/src/subagents/track.tsx | 98 +++++++++++------------ scripts/ci-workflow.test.mjs | 1 + scripts/oxlint/paseo-plugin.mjs | 42 ++++++++++ scripts/oxlint/paseo-plugin.test.mjs | 54 +++++++++++++ 8 files changed, 278 insertions(+), 78 deletions(-) create mode 100644 scripts/oxlint/paseo-plugin.mjs create mode 100644 scripts/oxlint/paseo-plugin.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d2d489f09..7c2a397170 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,6 +93,10 @@ jobs: if: ${{ !cancelled() && steps.install.outcome == 'success' && (needs.changes.outputs.full != 'false' || needs.changes.outputs.quality != 'false') }} run: npm run lint + - name: Test lint rules + if: ${{ !cancelled() && steps.install.outcome == 'success' && (needs.changes.outputs.full != 'false' || needs.changes.outputs.quality != 'false') }} + run: node --test scripts/oxlint/paseo-plugin.test.mjs + - name: Build relay if: ${{ !cancelled() && steps.install.outcome == 'success' && (needs.changes.outputs.full != 'false' || needs.changes.outputs.relay != 'false') }} run: npm run build:relay diff --git a/.oxlintrc.json b/.oxlintrc.json index 4582602a97..f5078649c9 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -5,6 +5,7 @@ }, "ignorePatterns": [".dev/**"], "plugins": ["react", "react-perf", "unicorn", "typescript", "oxc", "import", "promise"], + "jsPlugins": ["./scripts/oxlint/paseo-plugin.mjs"], "categories": { "correctness": "error", "suspicious": "error", @@ -356,6 +357,117 @@ "no-restricted-imports": "off" } }, + { + "files": ["packages/app/src/**/*.{ts,tsx}"], + "rules": { + "paseo/no-raw-pressable": "error" + } + }, + // Press feedback is owned by the primitives in components/ui. Raw pressable burn-down: + // 94 files. They may only leave this list. + { + "files": [ + "packages/app/src/components/ui/**/*.{ts,tsx}", + "packages/app/src/**/*.{test,spec}.{ts,tsx}", + "packages/app/src/agent-profiles/settings/agent-profile-appearance-field.tsx", + "packages/app/src/agent-skills/selection-sheet.tsx", + "packages/app/src/agent-stream/chat-outline/rail.web.tsx", + "packages/app/src/agent-stream/view.tsx", + "packages/app/src/app/pair-scan.tsx", + "packages/app/src/changelog/internal/changelog-sheet.tsx", + "packages/app/src/command-center/command-center.tsx", + "packages/app/src/components/adaptive-modal-sheet.tsx", + "packages/app/src/components/add-host-method-modal.tsx", + "packages/app/src/components/add-host-modal.tsx", + "packages/app/src/components/add-project-flow.tsx", + "packages/app/src/components/add-remote-ssh-host-modal.tsx", + "packages/app/src/components/agent-list.tsx", + "packages/app/src/components/app-diagnostic-sheet.tsx", + "packages/app/src/components/attachment-lightbox.tsx", + "packages/app/src/components/attachment-pill.tsx", + "packages/app/src/components/combined-model-selector.tsx", + "packages/app/src/components/compact-explorer-sidebar.tsx", + "packages/app/src/components/context-window-meter.tsx", + "packages/app/src/components/desktop/window-controls.tsx", + "packages/app/src/components/dictation-controls.tsx", + "packages/app/src/components/download-toast.tsx", + "packages/app/src/components/file-explorer-pane.tsx", + "packages/app/src/components/headers/back-header.tsx", + "packages/app/src/components/highlighted-code-block.tsx", + "packages/app/src/components/hosts/host-filter.tsx", + "packages/app/src/components/hosts/host-picker.tsx", + "packages/app/src/components/import-session-sheet.tsx", + "packages/app/src/components/left-sidebar.tsx", + "packages/app/src/components/markdown/fence/mermaid/host.native.tsx", + "packages/app/src/components/markdown/fence/mermaid/host.web.tsx", + "packages/app/src/components/message.tsx", + "packages/app/src/components/model-browser.tsx", + "packages/app/src/components/plan-card.tsx", + "packages/app/src/components/provider-diagnostic-sheet.tsx", + "packages/app/src/components/question-form-card.tsx", + "packages/app/src/components/realtime-voice-overlay.tsx", + "packages/app/src/components/schedules/schedule-row.tsx", + "packages/app/src/components/settings/collapsible-row.tsx", + "packages/app/src/components/settings/headings/settings-info-tip.tsx", + "packages/app/src/components/sidebar-callout.tsx", + "packages/app/src/components/sidebar-resize-handle.tsx", + "packages/app/src/components/sidebar-workspace-list.tsx", + "packages/app/src/components/sidebar/sidebar-group-toggle-row.tsx", + "packages/app/src/components/sidebar/sidebar-header-row.tsx", + "packages/app/src/components/sidebar/sidebar-section-header.tsx", + "packages/app/src/components/sidebar/sidebar-status-list.tsx", + "packages/app/src/components/sidebar/workspace-meta-row/index.tsx", + "packages/app/src/components/terminal-copy-paste-actions.tsx", + "packages/app/src/components/terminal-emulator-native-grid.native.tsx", + "packages/app/src/components/terminal-pane.tsx", + "packages/app/src/components/toast-host.tsx", + "packages/app/src/components/tool-call-sheet.tsx", + "packages/app/src/components/welcome-screen.tsx", + "packages/app/src/components/workspace-hover-card.tsx", + "packages/app/src/components/zoomable-viewport/toolbar.tsx", + "packages/app/src/composer/agent-controls/index.tsx", + "packages/app/src/composer/diff-stat-pill.tsx", + "packages/app/src/composer/dock/internal/background.native.tsx", + "packages/app/src/composer/draft/import-pill.tsx", + "packages/app/src/composer/index.tsx", + "packages/app/src/composer/tracks.tsx", + "packages/app/src/desktop/browser/pane/index.electron.tsx", + "packages/app/src/git/actions-split-button.tsx", + "packages/app/src/git/commits-section/commit-row.tsx", + "packages/app/src/git/commits-section/commits-section.tsx", + "packages/app/src/git/diff-pane.tsx", + "packages/app/src/git/forges/gitlab.view.tsx", + "packages/app/src/git/pull-request-panel/checks-section.tsx", + "packages/app/src/git/pull-request-panel/pane.tsx", + "packages/app/src/git/pull-request-panel/section-kit.tsx", + "packages/app/src/hosts/host-chooser.tsx", + "packages/app/src/mobile-panels/presentation.tsx", + "packages/app/src/panels/new-tab-panel.tsx", + "packages/app/src/panels/setup-panel.tsx", + "packages/app/src/plugins/buttons/view.tsx", + "packages/app/src/review/surface.tsx", + "packages/app/src/screens/open-project-screen.tsx", + "packages/app/src/screens/project-settings-screen.tsx", + "packages/app/src/screens/projects-screen.tsx", + "packages/app/src/screens/settings-screen.tsx", + "packages/app/src/screens/settings/host-appearance-section.tsx", + "packages/app/src/screens/settings/host-page.tsx", + "packages/app/src/screens/settings/providers-section.tsx", + "packages/app/src/screens/workspace/compact-workspace-header/tab-switcher.tsx", + "packages/app/src/screens/workspace/scripts/workspace-scripts-button.tsx", + "packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx", + "packages/app/src/screens/workspace/workspace-tab-presentation.tsx", + "packages/app/src/tool-calls/detail-level/overview/sheet.tsx", + "packages/app/src/usage/sidebar-item.tsx", + "packages/app/src/usage/window-bar.tsx", + "packages/app/src/workspace-labels/manager-modal.tsx", + "packages/app/src/workspace-labels/swatch.tsx", + "packages/app/src/workspace/open-in-editor/button.tsx" + ], + "rules": { + "paseo/no-raw-pressable": "off" + } + }, { "files": ["**/e2e/**/fixtures.ts"], "rules": { diff --git a/docs/design.md b/docs/design.md index e21270c85d..ce45577b69 100644 --- a/docs/design.md +++ b/docs/design.md @@ -20,7 +20,7 @@ A semantic element used in three or more places is a primitive. One of a kind is Primitives live in `packages/app/src/components/ui/` and `packages/app/src/components/headers/`. Card and row layout live in `packages/app/src/styles/settings.ts`. Section structure lives in `packages/app/src/screens/settings/settings-section.tsx`. -A pressable styled to look like a button is wrong; the button is `