Files
vibe-kanban/frontend/src/components/ui-new/actions/index.ts

733 lines
21 KiB
TypeScript
Raw Normal View History

2026-01-08 22:14:38 +00:00
import type { Icon } from '@phosphor-icons/react';
import type { NavigateFunction } from 'react-router-dom';
import type { QueryClient } from '@tanstack/react-query';
import type { EditorType, Workspace } from 'shared/types';
import type { DiffViewMode } from '@/stores/useDiffViewStore';
import {
CopyIcon,
PushPinIcon,
ArchiveIcon,
TrashIcon,
PlusIcon,
GearIcon,
ColumnsIcon,
RowsIcon,
TextAlignLeftIcon,
EyeSlashIcon,
SidebarSimpleIcon,
ChatsTeardropIcon,
GitDiffIcon,
TerminalIcon,
SignOutIcon,
CaretDoubleUpIcon,
CaretDoubleDownIcon,
PlayIcon,
PauseIcon,
SpinnerIcon,
GitPullRequestIcon,
GitMergeIcon,
ArrowsClockwiseIcon,
CrosshairIcon,
DesktopIcon,
Add rename workspace functionality (Vibe Kanban) (#1868) * I've added the rename workspace functionality. Here's a summary of the changes: ## Summary The backend already had rename workspace support via the `PUT /api/task-attempts/{attemptId}` endpoint with the `name` field. I added the frontend UI to expose this functionality. ### Files Created 1. **`frontend/src/components/ui-new/dialogs/RenameWorkspaceDialog.tsx`** - New dialog component for renaming workspaces - Shows the current name (or branch name as fallback) - Allows user to input a new name - Handles mutation with proper error handling and cache invalidation ### Files Modified 1. **`frontend/src/components/ui-new/actions/index.ts`** - Added `PencilSimpleIcon` import - Added `RenameWorkspaceDialog` import - Added new `RenameWorkspace` action that shows the rename dialog 2. **`frontend/src/components/ui-new/actions/pages.ts`** - Added `Actions.RenameWorkspace` to the `workspaceActions` page (at the top of the list) 3. **`frontend/src/i18n/locales/en/common.json`** - Added translations for the rename workspace dialog under `workspaces.rename` ### How to Use Users can now rename a workspace by: 1. Clicking the three-dot menu (⋯) on any workspace in the sidebar 2. Selecting "Rename" from the command bar 3. Entering a new name in the dialog 4. Clicking "Rename" to save * Cleanup script changes for workspace 4eb64331-cc43-43af-849e-3731664e53b9 * Added the missing translations for the rename workspace dialog to all locale files: - **es** (Spanish) - **ja** (Japanese) - **ko** (Korean) - **zh-Hans** (Simplified Chinese) - **zh-Hant** (Traditional Chinese)
2026-01-09 10:06:29 +01:00
PencilSimpleIcon,
2026-01-08 22:14:38 +00:00
} from '@phosphor-icons/react';
import { useDiffViewStore } from '@/stores/useDiffViewStore';
import { useUiPreferencesStore } from '@/stores/useUiPreferencesStore';
import { useLayoutStore } from '@/stores/useLayoutStore';
import { attemptsApi, tasksApi, repoApi } from '@/lib/api';
import { attemptKeys } from '@/hooks/useAttempt';
import { taskKeys } from '@/hooks/useTask';
import { workspaceSummaryKeys } from '@/components/ui-new/hooks/useWorkspaces';
import { ConfirmDialog } from '@/components/ui-new/dialogs/ConfirmDialog';
import { ChangeTargetDialog } from '@/components/ui-new/dialogs/ChangeTargetDialog';
import { RebaseDialog } from '@/components/ui-new/dialogs/RebaseDialog';
Add rename workspace functionality (Vibe Kanban) (#1868) * I've added the rename workspace functionality. Here's a summary of the changes: ## Summary The backend already had rename workspace support via the `PUT /api/task-attempts/{attemptId}` endpoint with the `name` field. I added the frontend UI to expose this functionality. ### Files Created 1. **`frontend/src/components/ui-new/dialogs/RenameWorkspaceDialog.tsx`** - New dialog component for renaming workspaces - Shows the current name (or branch name as fallback) - Allows user to input a new name - Handles mutation with proper error handling and cache invalidation ### Files Modified 1. **`frontend/src/components/ui-new/actions/index.ts`** - Added `PencilSimpleIcon` import - Added `RenameWorkspaceDialog` import - Added new `RenameWorkspace` action that shows the rename dialog 2. **`frontend/src/components/ui-new/actions/pages.ts`** - Added `Actions.RenameWorkspace` to the `workspaceActions` page (at the top of the list) 3. **`frontend/src/i18n/locales/en/common.json`** - Added translations for the rename workspace dialog under `workspaces.rename` ### How to Use Users can now rename a workspace by: 1. Clicking the three-dot menu (⋯) on any workspace in the sidebar 2. Selecting "Rename" from the command bar 3. Entering a new name in the dialog 4. Clicking "Rename" to save * Cleanup script changes for workspace 4eb64331-cc43-43af-849e-3731664e53b9 * Added the missing translations for the rename workspace dialog to all locale files: - **es** (Spanish) - **ja** (Japanese) - **ko** (Korean) - **zh-Hans** (Simplified Chinese) - **zh-Hant** (Traditional Chinese)
2026-01-09 10:06:29 +01:00
import { RenameWorkspaceDialog } from '@/components/ui-new/dialogs/RenameWorkspaceDialog';
2026-01-08 22:14:38 +00:00
import { CreatePRDialog } from '@/components/dialogs/tasks/CreatePRDialog';
import { getIdeName } from '@/components/ide/IdeIcon';
import { EditorSelectionDialog } from '@/components/dialogs/tasks/EditorSelectionDialog';
// Special icon types for ContextBar
export type SpecialIconType = 'ide-icon' | 'copy-icon';
export type ActionIcon = Icon | SpecialIconType;
// Workspace type for sidebar (minimal subset needed for workspace selection)
interface SidebarWorkspace {
id: string;
}
// Dev server state type for visibility context
export type DevServerState = 'stopped' | 'starting' | 'running' | 'stopping';
// Context provided to action executors (from React hooks)
export interface ActionExecutorContext {
navigate: NavigateFunction;
queryClient: QueryClient;
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
selectWorkspace: (workspaceId: string) => void;
activeWorkspaces: SidebarWorkspace[];
currentWorkspaceId: string | null;
containerRef: string | null;
runningDevServerId: string | null;
startDevServer: () => void;
stopDevServer: () => void;
2026-01-08 22:14:38 +00:00
}
// Context for evaluating action visibility and state conditions
export interface ActionVisibilityContext {
// Layout state
isChangesMode: boolean;
isLogsMode: boolean;
isPreviewMode: boolean;
isSidebarVisible: boolean;
isMainPanelVisible: boolean;
isGitPanelVisible: boolean;
isCreateMode: boolean;
// Workspace state
hasWorkspace: boolean;
workspaceArchived: boolean;
// Diff state
hasDiffs: boolean;
diffViewMode: DiffViewMode;
isAllDiffsExpanded: boolean;
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
// Dev server state
editorType: EditorType | null;
devServerState: DevServerState;
runningDevServerId: string | null;
2026-01-08 22:14:38 +00:00
// Git panel state
hasGitRepos: boolean;
hasMultipleRepos: boolean;
}
// Base properties shared by all actions
interface ActionBase {
id: string;
label: string | ((workspace?: Workspace) => string);
icon: ActionIcon;
shortcut?: string;
variant?: 'default' | 'destructive';
// Optional visibility condition - if omitted, action is always visible
isVisible?: (ctx: ActionVisibilityContext) => boolean;
// Optional active state - if omitted, action is not active
isActive?: (ctx: ActionVisibilityContext) => boolean;
// Optional enabled state - if omitted, action is enabled
isEnabled?: (ctx: ActionVisibilityContext) => boolean;
// Optional dynamic icon - if omitted, uses static icon property
getIcon?: (ctx: ActionVisibilityContext) => ActionIcon;
// Optional dynamic tooltip - if omitted, uses label
getTooltip?: (ctx: ActionVisibilityContext) => string;
// Optional dynamic label - if omitted, uses static label property
getLabel?: (ctx: ActionVisibilityContext) => string;
}
// Global action (no target needed)
export interface GlobalActionDefinition extends ActionBase {
requiresTarget: false;
execute: (ctx: ActionExecutorContext) => Promise<void> | void;
}
// Workspace action (target required - validated by ActionsContext)
export interface WorkspaceActionDefinition extends ActionBase {
requiresTarget: true;
execute: (
ctx: ActionExecutorContext,
workspaceId: string
) => Promise<void> | void;
}
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
// Git action (requires workspace + repoId)
export interface GitActionDefinition extends ActionBase {
requiresTarget: 'git';
execute: (
ctx: ActionExecutorContext,
workspaceId: string,
repoId: string
) => Promise<void> | void;
}
2026-01-08 22:14:38 +00:00
// Discriminated union
export type ActionDefinition =
| GlobalActionDefinition
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
| WorkspaceActionDefinition
| GitActionDefinition;
2026-01-08 22:14:38 +00:00
// Helper to get workspace from query cache
function getWorkspaceFromCache(
queryClient: QueryClient,
workspaceId: string
): Workspace {
const workspace = queryClient.getQueryData<Workspace>(
attemptKeys.byId(workspaceId)
);
if (!workspace) {
throw new Error('Workspace not found');
}
return workspace;
}
// Helper to invalidate workspace-related queries
function invalidateWorkspaceQueries(
queryClient: QueryClient,
workspaceId: string
) {
queryClient.invalidateQueries({ queryKey: attemptKeys.byId(workspaceId) });
queryClient.invalidateQueries({ queryKey: workspaceSummaryKeys.all });
}
// All application actions
export const Actions = {
// === Workspace Actions ===
DuplicateWorkspace: {
id: 'duplicate-workspace',
label: 'Duplicate',
icon: CopyIcon,
requiresTarget: true,
execute: async (ctx, workspaceId) => {
try {
const firstMessage = await attemptsApi.getFirstUserMessage(workspaceId);
ctx.navigate('/workspaces/create', {
state: { duplicatePrompt: firstMessage },
});
} catch {
// Fallback to creating without the prompt
ctx.navigate('/workspaces/create');
}
},
},
Add rename workspace functionality (Vibe Kanban) (#1868) * I've added the rename workspace functionality. Here's a summary of the changes: ## Summary The backend already had rename workspace support via the `PUT /api/task-attempts/{attemptId}` endpoint with the `name` field. I added the frontend UI to expose this functionality. ### Files Created 1. **`frontend/src/components/ui-new/dialogs/RenameWorkspaceDialog.tsx`** - New dialog component for renaming workspaces - Shows the current name (or branch name as fallback) - Allows user to input a new name - Handles mutation with proper error handling and cache invalidation ### Files Modified 1. **`frontend/src/components/ui-new/actions/index.ts`** - Added `PencilSimpleIcon` import - Added `RenameWorkspaceDialog` import - Added new `RenameWorkspace` action that shows the rename dialog 2. **`frontend/src/components/ui-new/actions/pages.ts`** - Added `Actions.RenameWorkspace` to the `workspaceActions` page (at the top of the list) 3. **`frontend/src/i18n/locales/en/common.json`** - Added translations for the rename workspace dialog under `workspaces.rename` ### How to Use Users can now rename a workspace by: 1. Clicking the three-dot menu (⋯) on any workspace in the sidebar 2. Selecting "Rename" from the command bar 3. Entering a new name in the dialog 4. Clicking "Rename" to save * Cleanup script changes for workspace 4eb64331-cc43-43af-849e-3731664e53b9 * Added the missing translations for the rename workspace dialog to all locale files: - **es** (Spanish) - **ja** (Japanese) - **ko** (Korean) - **zh-Hans** (Simplified Chinese) - **zh-Hant** (Traditional Chinese)
2026-01-09 10:06:29 +01:00
RenameWorkspace: {
id: 'rename-workspace',
label: 'Rename',
icon: PencilSimpleIcon,
requiresTarget: true,
execute: async (ctx, workspaceId) => {
const workspace = getWorkspaceFromCache(ctx.queryClient, workspaceId);
await RenameWorkspaceDialog.show({
workspaceId,
currentName: workspace.name || workspace.branch,
});
},
},
2026-01-08 22:14:38 +00:00
PinWorkspace: {
id: 'pin-workspace',
label: (workspace?: Workspace) => (workspace?.pinned ? 'Unpin' : 'Pin'),
icon: PushPinIcon,
requiresTarget: true,
execute: async (ctx, workspaceId) => {
const workspace = getWorkspaceFromCache(ctx.queryClient, workspaceId);
await attemptsApi.update(workspaceId, {
pinned: !workspace.pinned,
});
invalidateWorkspaceQueries(ctx.queryClient, workspaceId);
},
},
ArchiveWorkspace: {
id: 'archive-workspace',
label: (workspace?: Workspace) =>
workspace?.archived ? 'Unarchive' : 'Archive',
icon: ArchiveIcon,
requiresTarget: true,
isVisible: (ctx) => ctx.hasWorkspace,
isActive: (ctx) => ctx.workspaceArchived,
execute: async (ctx, workspaceId) => {
const workspace = getWorkspaceFromCache(ctx.queryClient, workspaceId);
const wasArchived = workspace.archived;
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
// Calculate next workspace before archiving
2026-01-08 22:14:38 +00:00
let nextWorkspaceId: string | null = null;
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
if (!wasArchived) {
2026-01-08 22:14:38 +00:00
const currentIndex = ctx.activeWorkspaces.findIndex(
(ws) => ws.id === workspaceId
);
if (currentIndex >= 0 && ctx.activeWorkspaces.length > 1) {
const nextWorkspace =
ctx.activeWorkspaces[currentIndex + 1] ||
ctx.activeWorkspaces[currentIndex - 1];
nextWorkspaceId = nextWorkspace?.id ?? null;
}
}
// Perform the archive/unarchive
await attemptsApi.update(workspaceId, { archived: !wasArchived });
invalidateWorkspaceQueries(ctx.queryClient, workspaceId);
// Select next workspace after successful archive
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
if (!wasArchived && nextWorkspaceId) {
2026-01-08 22:14:38 +00:00
ctx.selectWorkspace(nextWorkspaceId);
}
},
},
DeleteWorkspace: {
id: 'delete-workspace',
label: 'Delete',
icon: TrashIcon,
variant: 'destructive',
requiresTarget: true,
execute: async (ctx, workspaceId) => {
const workspace = getWorkspaceFromCache(ctx.queryClient, workspaceId);
const result = await ConfirmDialog.show({
title: 'Delete Workspace',
message:
'Are you sure you want to delete this workspace? This action cannot be undone.',
confirmText: 'Delete',
cancelText: 'Cancel',
variant: 'destructive',
});
if (result === 'confirmed') {
await tasksApi.delete(workspace.task_id);
ctx.queryClient.invalidateQueries({ queryKey: taskKeys.all });
ctx.queryClient.invalidateQueries({
queryKey: workspaceSummaryKeys.all,
});
}
},
},
// === Global/Navigation Actions ===
NewWorkspace: {
id: 'new-workspace',
label: 'New Workspace',
icon: PlusIcon,
requiresTarget: false,
execute: (ctx) => {
ctx.navigate('/workspaces/create');
},
},
Settings: {
id: 'settings',
label: 'Settings',
icon: GearIcon,
requiresTarget: false,
execute: (ctx) => {
ctx.navigate('/settings');
},
},
// === Diff View Actions ===
ToggleDiffViewMode: {
id: 'toggle-diff-view-mode',
label: () =>
useDiffViewStore.getState().mode === 'unified'
? 'Switch to Side-by-Side View'
: 'Switch to Inline View',
icon: ColumnsIcon,
requiresTarget: false,
isVisible: (ctx) => ctx.isChangesMode,
isActive: (ctx) => ctx.diffViewMode === 'split',
getIcon: (ctx) => (ctx.diffViewMode === 'split' ? ColumnsIcon : RowsIcon),
getTooltip: (ctx) =>
ctx.diffViewMode === 'split' ? 'Inline view' : 'Side-by-side view',
execute: () => {
useDiffViewStore.getState().toggle();
},
},
ToggleIgnoreWhitespace: {
id: 'toggle-ignore-whitespace',
label: () =>
useDiffViewStore.getState().ignoreWhitespace
? 'Show Whitespace Changes'
: 'Ignore Whitespace Changes',
icon: EyeSlashIcon,
requiresTarget: false,
isVisible: (ctx) => ctx.isChangesMode,
execute: () => {
const store = useDiffViewStore.getState();
store.setIgnoreWhitespace(!store.ignoreWhitespace);
},
},
ToggleWrapLines: {
id: 'toggle-wrap-lines',
label: () =>
useDiffViewStore.getState().wrapText
? 'Disable Line Wrapping'
: 'Enable Line Wrapping',
icon: TextAlignLeftIcon,
requiresTarget: false,
isVisible: (ctx) => ctx.isChangesMode,
execute: () => {
const store = useDiffViewStore.getState();
store.setWrapText(!store.wrapText);
},
},
// === Layout Panel Actions ===
ToggleSidebar: {
id: 'toggle-sidebar',
label: () =>
useLayoutStore.getState().isSidebarVisible
? 'Hide Sidebar'
: 'Show Sidebar',
icon: SidebarSimpleIcon,
requiresTarget: false,
isActive: (ctx) => ctx.isSidebarVisible,
execute: () => {
useLayoutStore.getState().toggleSidebar();
},
},
ToggleMainPanel: {
id: 'toggle-main-panel',
label: () =>
useLayoutStore.getState().isMainPanelVisible
? 'Hide Chat Panel'
: 'Show Chat Panel',
icon: ChatsTeardropIcon,
requiresTarget: false,
isActive: (ctx) => ctx.isMainPanelVisible,
isEnabled: (ctx) => !(ctx.isMainPanelVisible && !ctx.isChangesMode),
execute: () => {
useLayoutStore.getState().toggleMainPanel();
},
},
ToggleGitPanel: {
id: 'toggle-git-panel',
label: () =>
useLayoutStore.getState().isGitPanelVisible
? 'Hide Git Panel'
: 'Show Git Panel',
icon: SidebarSimpleIcon,
requiresTarget: false,
isActive: (ctx) => ctx.isGitPanelVisible,
execute: () => {
useLayoutStore.getState().toggleGitPanel();
},
},
ToggleChangesMode: {
id: 'toggle-changes-mode',
label: () =>
useLayoutStore.getState().isChangesMode
? 'Hide Changes Panel'
: 'Show Changes Panel',
icon: GitDiffIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) => ctx.isChangesMode,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
useLayoutStore.getState().toggleChangesMode();
},
},
ToggleLogsMode: {
id: 'toggle-logs-mode',
label: () =>
useLayoutStore.getState().isLogsMode
? 'Hide Logs Panel'
: 'Show Logs Panel',
icon: TerminalIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) => ctx.isLogsMode,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
useLayoutStore.getState().toggleLogsMode();
},
},
TogglePreviewMode: {
id: 'toggle-preview-mode',
label: () =>
useLayoutStore.getState().isPreviewMode
? 'Hide Preview Panel'
: 'Show Preview Panel',
icon: DesktopIcon,
requiresTarget: false,
isVisible: (ctx) => !ctx.isCreateMode,
isActive: (ctx) => ctx.isPreviewMode,
isEnabled: (ctx) => !ctx.isCreateMode,
execute: () => {
useLayoutStore.getState().togglePreviewMode();
},
},
// === Navigation Actions ===
OpenInOldUI: {
id: 'open-in-old-ui',
label: 'Open in Old UI',
icon: SignOutIcon,
requiresTarget: false,
execute: async (ctx) => {
// If no workspace is selected, navigate to root
if (!ctx.currentWorkspaceId) {
ctx.navigate('/');
return;
}
const workspace = getWorkspaceFromCache(
ctx.queryClient,
ctx.currentWorkspaceId
);
if (!workspace?.task_id) {
ctx.navigate('/');
return;
}
// Fetch task lazily to get project_id
const task = await tasksApi.getById(workspace.task_id);
if (task?.project_id) {
ctx.navigate(
`/projects/${task.project_id}/tasks/${workspace.task_id}/attempts/${workspace.id}`
);
} else {
ctx.navigate('/');
}
},
},
// === Diff Actions for Navbar ===
ToggleAllDiffs: {
id: 'toggle-all-diffs',
label: () => {
const { diffPaths } = useDiffViewStore.getState();
const { expanded } = useUiPreferencesStore.getState();
const keys = diffPaths.map((p) => `diff:${p}`);
const isAllExpanded =
keys.length > 0 && keys.every((k) => expanded[k] !== false);
return isAllExpanded ? 'Collapse All Diffs' : 'Expand All Diffs';
},
icon: CaretDoubleUpIcon,
requiresTarget: false,
isVisible: (ctx) => ctx.isChangesMode,
getIcon: (ctx) =>
ctx.isAllDiffsExpanded ? CaretDoubleUpIcon : CaretDoubleDownIcon,
getTooltip: (ctx) =>
ctx.isAllDiffsExpanded ? 'Collapse all diffs' : 'Expand all diffs',
execute: () => {
const { diffPaths } = useDiffViewStore.getState();
const { expanded, setExpandedAll } = useUiPreferencesStore.getState();
const keys = diffPaths.map((p) => `diff:${p}`);
const isAllExpanded =
keys.length > 0 && keys.every((k) => expanded[k] !== false);
setExpandedAll(keys, !isAllExpanded);
},
},
// === ContextBar Actions ===
OpenInIDE: {
id: 'open-in-ide',
label: 'Open in IDE',
icon: 'ide-icon' as const,
requiresTarget: false,
isVisible: (ctx) => ctx.hasWorkspace,
getTooltip: (ctx) => `Open in ${getIdeName(ctx.editorType)}`,
execute: async (ctx) => {
if (!ctx.currentWorkspaceId) return;
try {
const response = await attemptsApi.openEditor(ctx.currentWorkspaceId, {
editor_type: null,
file_path: null,
});
if (response.url) {
window.open(response.url, '_blank');
}
} catch {
// Show editor selection dialog on failure
EditorSelectionDialog.show({
selectedAttemptId: ctx.currentWorkspaceId,
});
}
},
},
CopyPath: {
id: 'copy-path',
label: 'Copy path',
icon: 'copy-icon' as const,
requiresTarget: false,
isVisible: (ctx) => ctx.hasWorkspace,
execute: async (ctx) => {
if (!ctx.containerRef) return;
await navigator.clipboard.writeText(ctx.containerRef);
},
},
ToggleDevServer: {
id: 'toggle-dev-server',
label: 'Dev Server',
icon: PlayIcon,
requiresTarget: false,
isVisible: (ctx) => ctx.hasWorkspace,
isEnabled: (ctx) =>
ctx.devServerState !== 'starting' && ctx.devServerState !== 'stopping',
getIcon: (ctx) => {
if (
ctx.devServerState === 'starting' ||
ctx.devServerState === 'stopping'
) {
return SpinnerIcon;
}
if (ctx.devServerState === 'running') {
return PauseIcon;
}
return PlayIcon;
},
getTooltip: (ctx) => {
switch (ctx.devServerState) {
case 'starting':
return 'Starting dev server...';
case 'stopping':
return 'Stopping dev server...';
case 'running':
return 'Stop dev server';
default:
return 'Start dev server';
}
},
getLabel: (ctx) =>
ctx.devServerState === 'running' ? 'Stop Dev Server' : 'Start Dev Server',
execute: (ctx) => {
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
if (ctx.runningDevServerId) {
2026-01-08 22:14:38 +00:00
ctx.stopDevServer();
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
} else {
2026-01-08 22:14:38 +00:00
ctx.startDevServer();
}
},
},
// === Git Actions ===
GitCreatePR: {
id: 'git-create-pr',
label: 'Create Pull Request',
icon: GitPullRequestIcon,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
requiresTarget: 'git',
2026-01-08 22:14:38 +00:00
isVisible: (ctx) => ctx.hasWorkspace && ctx.hasGitRepos,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
execute: async (ctx, workspaceId, repoId) => {
2026-01-08 22:14:38 +00:00
const workspace = getWorkspaceFromCache(ctx.queryClient, workspaceId);
const task = await tasksApi.getById(workspace.task_id);
const result = await CreatePRDialog.show({
attempt: workspace,
task: {
...task,
has_in_progress_attempt: false,
last_attempt_failed: false,
executor: '',
},
repoId,
});
if (!result.success && result.error) {
throw new Error(result.error);
}
},
},
GitMerge: {
id: 'git-merge',
label: 'Merge',
icon: GitMergeIcon,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
requiresTarget: 'git',
2026-01-08 22:14:38 +00:00
isVisible: (ctx) => ctx.hasWorkspace && ctx.hasGitRepos,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
execute: async (ctx, workspaceId, repoId) => {
2026-01-08 22:14:38 +00:00
const confirmResult = await ConfirmDialog.show({
title: 'Merge Branch',
message:
'Are you sure you want to merge this branch into the target branch?',
confirmText: 'Merge',
cancelText: 'Cancel',
});
if (confirmResult === 'confirmed') {
await attemptsApi.merge(workspaceId, { repo_id: repoId });
invalidateWorkspaceQueries(ctx.queryClient, workspaceId);
}
},
},
GitRebase: {
id: 'git-rebase',
label: 'Rebase',
icon: ArrowsClockwiseIcon,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
requiresTarget: 'git',
2026-01-08 22:14:38 +00:00
isVisible: (ctx) => ctx.hasWorkspace && ctx.hasGitRepos,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
execute: async (_ctx, workspaceId, repoId) => {
2026-01-08 22:14:38 +00:00
const repos = await attemptsApi.getRepos(workspaceId);
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
const repo = repos.find((r) => r.id === repoId);
if (!repo) throw new Error('Repository not found');
2026-01-08 22:14:38 +00:00
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
const branches = await repoApi.getBranches(repoId);
2026-01-08 22:14:38 +00:00
await RebaseDialog.show({
attemptId: workspaceId,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
repoId,
2026-01-08 22:14:38 +00:00
branches,
initialTargetBranch: repo.target_branch,
});
},
},
GitChangeTarget: {
id: 'git-change-target',
label: 'Change Target Branch',
icon: CrosshairIcon,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
requiresTarget: 'git',
2026-01-08 22:14:38 +00:00
isVisible: (ctx) => ctx.hasWorkspace && ctx.hasGitRepos,
Fix CommandBar input and navigation issues with state machine refactor (Vibe Kanban) (#1885) * Done! I've removed all 7 `shortcut` properties from the action definitions in `index.ts`: - `NewWorkspace`: removed `shortcut: 'N'` - `Settings`: removed `shortcut: ','` - `ToggleSidebar`: removed `shortcut: '['` - `ToggleGitPanel`: removed `shortcut: ']'` - `ToggleChangesMode`: removed `shortcut: 'C'` - `ToggleLogsMode`: removed `shortcut: 'L'` - `TogglePreviewMode`: removed `shortcut: 'P'` The `ActionDefinition` type (and its base `ActionBase` interface) were left unchanged as requested. * fix tailwind nto auto creating styles * I've successfully completed all the changes. Here's a summary of what was done: ## Summary of Changes ### 1. `ActionExecutorContext` (index.ts) - Made all properties non-optional - Removed `gitRepoId` from context (now passed as action parameter) - Properties now use `| null` for values that may not exist ### 2. New `GitActionDefinition` Type (index.ts) - Added new action type with `requiresTarget: 'git'` - Git actions now explicitly require `repoId` as a parameter ### 3. Git Actions Updated (index.ts) - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` function takes `repoId` as third parameter - Simplified implementations (no more fallback repo fetching logic) ### 4. `ActionsContext` Provider (ActionsContext.tsx) - Now calls `useDevServer()` to get dev server state - Provides all required context properties - `executeAction` handles three action types: global, workspace, and git - Removed `contextOverride` pattern ### 5. `ContextBarContainer` (ContextBarContainer.tsx) - Simplified significantly - no longer builds extended context - Uses executor context directly from provider - Removed `containerPath` prop ### 6. `ActionVisibilityContext` (index.ts + useActionVisibility.ts) - Made `editorType`, `devServerState`, `runningDevServerId` required - Visibility hook now provides all values from hooks ### 7. Updated Call Sites - `WorkspacesLayout`: Git actions now pass `repoId` as third parameter - `WorkspacesMain`: Removed `containerPath` prop from ContextBarContainer * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * All changes are complete and type checks pass. Here's a summary of the changes made: ## Summary of Changes ### 1. `ActionExecutorContext` - Made all properties non-optional - Removed `?` from all properties - Removed `gitRepoId` (moved to per-action parameter) - Changed nullable properties to use `| null` type ### 2. New `GitActionDefinition` type - Added new action type with `requiresTarget: 'git'` - Takes `repoId` as explicit third parameter ### 3. Git actions updated - `GitCreatePR`, `GitMerge`, `GitRebase`, `GitChangeTarget` now use `requiresTarget: 'git'` - Each action's `execute` receives `repoId` as parameter ### 4. `ActionsContext` provider centralized - Now calls `useDevServer()` to provide dev server state - Provides all required context properties from hooks - `executeAction` handles three action types: global, workspace, git - Removed `contextOverride` pattern ### 5. `ActionVisibilityContext` - Made dev server properties required - `editorType`, `devServerState`, `runningDevServerId` now required - `useActionVisibilityContext` hook provides all values ### 6. `ContextBarContainer` simplified - Removed extended context creation - Uses executor context directly from provider ### 7. Provider order fix - Moved `ExecutionProcessesProvider` up to `NewDesignScope` - Required because `useDevServer` depends on `ExecutionProcessesContext` ### Files Modified: - `vibe-kanban/frontend/src/components/ui-new/actions/index.ts` - `vibe-kanban/frontend/src/components/ui-new/actions/useActionVisibility.ts` - `vibe-kanban/frontend/src/contexts/ActionsContext.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/ContextBarContainer.tsx` - `vibe-kanban/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx` - `vibe-kanban/frontend/src/components/ui-new/views/WorkspacesMain.tsx` - `vibe-kanban/frontend/src/components/ui-new/scope/NewDesignScope.tsx` * The implementation is complete. Let me summarize what was changed: ## Summary of Changes ### `pages.ts` - Added `'selectRepo'` to `PageId` type for dynamic repo selection page - Created `StaticPageId` type (excludes `selectRepo`) for static page records - Added `RepoItem` interface for repo selection items - Extended `ResolvedGroupItem` union type to include `{ type: 'repo'; repo: RepoItem }` - Updated `Pages` record and `getPageActions` to use `StaticPageId` ### `CommandBarDialog.tsx` - Added `repos` from `useWorkspaceContext()` - Added `pendingGitAction` state to track git actions awaiting repo selection - Reset `pendingGitAction` when dialog opens/closes - Modified `getPageWithItems` to generate dynamic `selectRepo` page with repo list - Updated `handleSelect` to: - Execute git actions immediately with single repo - Navigate to `selectRepo` page when multiple repos exist - Execute pending git action when user selects a repo - Clear `pendingGitAction` when navigating back from `selectRepo` page ### `CommandBar.tsx` - Added `FolderIcon` import - Added rendering for `'repo'` item type with folder icon ## Behavior 1. **Single repo**: When user selects a git action (e.g., "Create Pull Request") and the workspace has only one git repo, the action executes immediately with that repo's ID. 2. **Multiple repos**: When workspace has multiple repos, selecting a git action navigates to a "Select Repository" page where the user can choose which repo to use, then the action executes with the selected repo. 3. **Back navigation**: Pressing back from the repo selection page clears the pending action and returns to the previous page. * Done! The `CommandBarDialog` has been refactored to use a state machine pattern with `useReducer`. Here's a summary of the changes: ## Summary of Changes **State Machine Types (lines 38-67):** - `CommandBarState`: Discriminated union with `browsing` and `selectingRepo` states - `CommandBarEvent`: `RESET`, `SEARCH_CHANGE`, `GO_BACK`, `SELECT_ITEM` - `CommandBarEffect`: Side effects returned from reducer (`none` or `execute`) **Reducer (lines 73-201):** - Pure function returning `[newState, effect]` tuple - Handles all state transitions based on current state and event - Git action flow: single repo → execute, multiple repos → transition to `selectingRepo` **Component Changes:** - Replaced 4 `useState` calls with single `useReducer` - `currentPage` is now derived from state (line 249-250) - `handleSelect` computes effect from reducer, dispatches event, then handles effect (lines 456-475) - `goBack` and `handleSearchChange` simply dispatch events (lines 446-453) **Benefits:** - All state transitions in one place (the reducer) - State transitions are pure and testable - Clear separation between state updates and side effects - Impossible states are unrepresentable (e.g., can't have `pendingAction` while `browsing`) * Done! Here's the final result: ## Summary **Before:** 520 lines in 1 file (after initial state machine refactor) **After:** 487 lines across 4 files | File | Lines | Purpose | |------|-------|---------| | `CommandBarDialog.tsx` | 101 | Thin orchestration (down from 520) | | `useCommandBarState.ts` | 177 | State machine hook | | `useResolvedPage.ts` | 150 | Page building logic | | `injectSearchMatches.ts` | 59 | DRY search helper | **Key wins:** - Main component: **520 → 101 lines** (80% reduction) - Search injection code: **100 → 59 lines** (4× duplication eliminated) - Each file has single responsibility - State machine is testable in isolation - Page building logic is reusable * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * Done! Here are the final results: ## Final Summary | File | Before | After | Reduction | |------|--------|-------|-----------| | `CommandBarDialog.tsx` | 101 | 106 | +5 (linter formatting) | | `useCommandBarState.ts` | 177 | 95 | **-82 (46%)** | | `useResolvedPage.ts` | 150 | 95 | **-55 (37%)** | | `injectSearchMatches.ts` | 59 | 42 | **-17 (29%)** | | **Total** | **487** | **338** | **-149 (31%)** | **Original single file:** 398 lines **Final 4 files:** 338 lines (15% less code overall) Key wins: - Main component is now just 106 lines of thin orchestration - State machine is flattened (if statements instead of nested switch/case) - Page resolution is simplified with reused types - Search injection uses reduce() instead of for-loop - All files pass type check * Cleanup script changes for workspace e961e311-6db4-41bf-83a1-ef8dd96eb497 * I've fixed both issues with the CommandBar. Here's a summary of what was wrong and how I fixed it: ## Root Causes ### Issue 1: Nested `<Command>` Components The `CommandDialog` component was wrapping children in a `<Command>` component, and `CommandBar` also rendered its own `<Command>`. This nested cmdk context caused conflicts with state management. **Fix:** Removed the `<Command>` wrapper from `CommandDialog` in `Command.tsx:26-44`, and moved the styling classes to `CommandBar`'s `<Command>` component. ### Issue 2: Unstable `dispatch` Function Causing Infinite RESET Loop In `useCommandBarState.ts`, the `dispatch` function had `[state, repoCount]` in its `useCallback` dependency array. This caused `dispatch` to be recreated on every state change. In `CommandBarDialog.tsx`, the `useEffect` that resets state when the modal opens had `dispatch` in its dependency array: ```tsx useEffect(() => { if (modal.visible) { dispatch({ type: 'RESET', page }); } }, [modal.visible, page, dispatch]); // dispatch changes → useEffect runs → RESET ``` This created an infinite loop: 1. User types → state updates → `dispatch` recreated 2. `dispatch` changed → `useEffect` runs → `RESET` dispatched 3. State resets to empty → repeat **Fix:** Made `dispatch` stable by using refs instead of state in dependencies: ```tsx const stateRef = useRef<CommandBarState>(browsing(initialPage)); const repoCountRef = useRef(repoCount); const dispatch = useCallback( (event: CommandBarEvent): CommandBarEffect => { const [, effect] = reducer(stateRef.current, event, repoCountRef.current); rawDispatch(event); return effect; }, [] // No dependencies - uses refs for current values ); ``` ## Files Changed 1. `vibe-kanban/frontend/src/components/ui-new/primitives/Command.tsx` - Removed nested `<Command>` wrapper from `CommandDialog` 2. `vibe-kanban/frontend/src/components/ui-new/primitives/CommandBar.tsx` - Added styling classes that were on the removed wrapper 3. `vibe-kanban/frontend/src/components/ui-new/dialogs/commandBar/useCommandBarState.ts` - Made `dispatch` stable using refs
2026-01-09 16:25:42 +00:00
execute: async (_ctx, workspaceId, repoId) => {
2026-01-08 22:14:38 +00:00
const branches = await repoApi.getBranches(repoId);
await ChangeTargetDialog.show({
attemptId: workspaceId,
repoId,
branches,
});
},
},
} as const satisfies Record<string, ActionDefinition>;
// Helper to resolve dynamic label
export function resolveLabel(
action: ActionDefinition,
workspace?: Workspace
): string {
return typeof action.label === 'function'
? action.label(workspace)
: action.label;
}
// Divider marker for navbar action groups
export const NavbarDivider = { type: 'divider' } as const;
export type NavbarItem = ActionDefinition | typeof NavbarDivider;
// Navbar action groups define which actions appear in each section
export const NavbarActionGroups = {
left: [Actions.ArchiveWorkspace, Actions.OpenInOldUI] as ActionDefinition[],
right: [
Actions.ToggleDiffViewMode,
Actions.ToggleAllDiffs,
NavbarDivider,
Actions.ToggleSidebar,
Actions.ToggleMainPanel,
Actions.ToggleChangesMode,
Actions.ToggleLogsMode,
Actions.TogglePreviewMode,
Actions.ToggleGitPanel,
] as NavbarItem[],
};
// Divider marker for context bar action groups
export const ContextBarDivider = { type: 'divider' } as const;
export type ContextBarItem = ActionDefinition | typeof ContextBarDivider;
// ContextBar action groups define which actions appear in each section
export const ContextBarActionGroups = {
primary: [Actions.OpenInIDE, Actions.CopyPath] as ActionDefinition[],
secondary: [
Actions.ToggleDevServer,
Actions.TogglePreviewMode,
Actions.ToggleChangesMode,
] as ActionDefinition[],
};
// Helper to check if an icon is a special type
export function isSpecialIcon(icon: ActionIcon): icon is SpecialIconType {
return icon === 'ide-icon' || icon === 'copy-icon';
}