Louis Knight-Webb 14c9df626a Add ESLint rule to ban optional props in container components (Vibe Kanban) (#2115)
* Done. The ESLint rule is now in place, banning optional props in all ui-new components.

**Summary:**
- Added the rule to `frontend/.eslintrc.cjs` targeting `TSPropertySignature[optional=true]`
- The rule applies to all files under `src/components/ui-new/**/*.{ts,tsx}`

**Impact Assessment - 100 violations across:**

| Category | Files | Violations |
|----------|-------|------------|
| **primitives/** | 11 files | ~40 violations |
| **views/** | 5 files | ~15 violations |
| **containers/** | 5 files | ~10 violations |
| **dialogs/** | 7 files | ~15 violations |
| **Root-level** | 5 files | ~15 violations |
| **types/** | 1 file | 5 violations |

The most affected files are:
- `primitives/Dropdown.tsx` (14 violations)
- `primitives/RepoCard.tsx` (12 violations)
- `NewDisplayConversationEntry.tsx` (11 violations)
- `primitives/CommandBar.tsx` (5 violations)

Would you like me to start refactoring these components to comply with the new rule?

* Done. The rule now only applies to `containers/`.

**Summary:**
- Removed the optional props ban from the general `ui-new/**` override
- Added a new override specifically for `src/components/ui-new/containers/**/*.{ts,tsx}`

**Impact reduced from 100 to 48 violations**, all now in container components:

| File | Violations |
|------|------------|
| SessionChatBoxContainer.tsx | 11 |
| DiffViewCardWithComments.tsx | 9 |
| SearchableDropdownContainer.tsx | 6 |
| FileTreeContainer.tsx | 3 |
| PreviewControlsContainer.tsx | 3 |
| ChangesPanelContainer.tsx | 2 |
| LogsContentContainer.tsx | 2 |
| PreviewBrowserContainer.tsx | 2 |
| WorkspacesLayout.tsx | 2 |
| WorkspacesMainContainer.tsx | 2 |
| + 6 more files | 6 |

* All ESLint issues in `SessionChatBoxContainer.tsx` have been fixed. Here's a summary of the changes:

1. **Removed dead code**:
   - Removed `taskId` prop (never passed by call site)
   - Removed `workspaceId` aliasing and fallback (`propWorkspaceId ?? session?.workspace_id`)

2. **Updated interface** - Changed all optional props (`?`) to explicit types:
   - Props that can be undefined use `Type | undefined` instead of `Type?`
   - Props with defaults (`sessions`, `isNewSessionMode`) are now required in the interface

3. **Added explicit defaults** in destructuring for all props:
   - `session = undefined`, `onSelectSession = undefined`, `projectId = undefined`, `onStartNewSession = undefined`, `workspaceId = undefined`
   - `filesChanged = 0`, `linesAdded = 0`, `linesRemoved = 0`
   - `sessions = []`, `isNewSessionMode = false`

* Done. I've refactored `SessionChatBoxContainer.tsx` to use a discriminated union for props. Here's a summary:

**Changes made:**

1. **Defined discriminated union type** with three modes:
   - `existing-session`: Has a `session` (required), `onSelectSession`, `onStartNewSession`
   - `new-session`: Has a `workspaceId` (required), `onSelectSession`
   - `placeholder`: Has `workspaceId` (optional), no callbacks

2. **Updated component** to extract mode-specific values from props based on the discriminant

3. **Updated call site** (`WorkspacesMain.tsx`) to pass the correct mode and props based on state

**Benefits:**
- No more redundant `= undefined` defaults for props that are required in their respective modes
- Type safety ensures each mode has exactly the props it needs
- Self-documenting code with explicit mode discriminant
- ESLint and TypeScript checks pass

* Cleanup script changes for workspace f4ec6f6e-a524-4760-889a-7ec2ebbce4c6

* Both lint and type check pass. I've removed `workspaceId` from `PlaceholderProps` since it's not needed when the editor is disabled in placeholder mode.

* All tasks are complete. Here's a summary of the changes made:

## Summary

I've refactored `DiffViewCardWithComments.tsx` and its related files to fix 11 ESLint errors (9 in DiffViewCardWithComments, 1 in CommentWidgetLine, 1 in ReviewCommentRenderer).

### Changes Made:

1. **`DiffViewCardWithComments.tsx`** - Converted to use discriminated unions:
   - `DiffInput` type: Changed optional props (`oldPath?`, `changeKind?`, `hasLineNumbers?`) to explicit union types (`oldPath: string | undefined`)
   - `DiffViewCardWithCommentsProps`: Split into two modes using a discriminated union:
     - `CollapsibleProps` (mode: 'collapsible') - requires `expanded` and `onToggle`
     - `StaticProps` (mode: 'static') - always expanded, no toggle
   - Base props (`status`, `className`, `projectId`, `attemptId`) now use `T | undefined` instead of `T?`

2. **`CommentWidgetLine.tsx`** - Changed `projectId?: string` to `projectId: string | undefined`

3. **`ReviewCommentRenderer.tsx`** - Changed `projectId?: string` to `projectId: string | undefined`

4. **`ChangesPanel.tsx`** (callsite) - Updated to pass the new required props:
   - Added `mode="collapsible"`
   - Added `status={undefined}`
   - Added `className=""`

### Verification:
-  ESLint passes for all modified files
-  TypeScript type check passes

* Cleanup script changes for workspace f4ec6f6e-a524-4760-889a-7ec2ebbce4c6

* Done. Here's a summary of all changes:

## Summary

Refactored `DiffViewCardWithComments.tsx` and its callsites to fix ESLint issues:

### Changes Made:

1. **`DiffViewCardWithComments.tsx`**:
   - Removed unused `status` prop and `ToolStatusDot` rendering
   - Made `projectId` and `attemptId` required strings (no longer `undefined`)
   - Removed conditional check for `attemptId` on the Open in IDE button (always shown now)

2. **`ChangesPanel.tsx`**:
   - Made `projectId` and `attemptId` required strings
   - Removed `status={undefined}` from the component call

3. **`CommentWidgetLine.tsx`**:
   - Changed `projectId: string | undefined` to `projectId: string`

4. **`ReviewCommentRenderer.tsx`**:
   - Changed `projectId: string | undefined` to `projectId: string`

5. **`ChangesPanelContainer.tsx`**:
   - Made `className` and `attemptId` required props
   - Added guard: if `projectId` is unavailable, renders empty panel

6. **`WorkspacesLayout.tsx`**:
   - Added guard: only renders `ChangesPanelContainer` when `selectedWorkspace?.id` exists
   - Passes required `className=""` prop

### Verification:
-  TypeScript type check passes
-  ESLint passes for all modified files

* Done. Changed `changeKind` from `DiffChangeKind | undefined` to `DiffChangeKind` in the `DiffInput` type. Both TypeScript and ESLint pass.

* Done. I've successfully refactored `SearchableDropdownContainer.tsx` to fix the 6 ESLint errors:

**Changes made:**

1. **`SearchableDropdownContainer.tsx`** (interface):
   - `selectedValue: string | null` (removed `?`)
   - `filterItem: ((item: T, query: string) => boolean) | null` (removed `?`, added `| null`)
   - `contentClassName: string` (removed `?`)
   - `placeholder: string` (removed `?`)
   - `emptyMessage: string` (removed `?`)
   - `getItemBadge: ((item: T) => string | undefined) | null` (removed `?`, added `| null`)

2. **`SearchableDropdownContainer.tsx`** (implementation):
   - Removed default values from destructuring (`placeholder = 'Search'`, `emptyMessage = 'No items found'`)
   - Changed `if (filterItem)` to `if (filterItem !== null)`
   - Changed `getItemBadge={getItemBadge}` to `getItemBadge={getItemBadge ?? undefined}`

3. **`RepoCardSimple.tsx`** (callsite):
   - Added `filterItem={null}`
   - Changed `selectedValue={selectedBranch}` to `selectedValue={selectedBranch ?? null}` to handle the case when `selectedBranch` is `undefined`

All ESLint errors for `SearchableDropdownContainer.tsx` are now resolved, and TypeScript compiles without errors.

* Refactor FileTreeContainer to fix ESLint errors for optional props

- Make all props required in FileTreeContainerProps interface
- Add guard in RightSidebar to only render Changes section when
  selectedWorkspace exists, ensuring workspaceId is always defined
- Remove redundant null check for onSelectFile callback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Refactor NewDisplayConversationEntry to fix ESLint errors for optional props

- Remove dead `task` prop from NewDisplayConversationEntry and ConversationListContainer
  (was only passed to legacy DisplayConversationEntry for entry types that don't use it)
- Make `executionProcessId` and `taskAttempt` required props
- Convert internal helper component optional props from `prop?: T` to `prop: T | undefined`
  to satisfy ESLint while preserving the same runtime behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Refactor VirtualizedProcessLogs to fix ESLint errors for optional props

Made search-related props required instead of optional:
- searchQuery: string (was optional)
- matchIndices: number[] (was optional)
- currentMatchIndex: number (was optional)

Updated callsites to provide explicit "no search" values where search
functionality is not used.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Cleanup script changes for workspace f4ec6f6e-a524-4760-889a-7ec2ebbce4c6

* Refactor container components to fix ESLint errors for optional props

Made the following props required (parents always provide them):
- BrowseRepoButtonContainer: disabled
- CopyButton: disabled
- WorkspacesMainContainer: isNewSessionMode, onStartNewSession
- LogsContentContainer: className
- PreviewBrowserContainer: attemptId, className
- PreviewControlsContainer: attemptId, className

Changed to union types (legitimately optional values):
- LogsContentContainer: command: string | undefined
- ProjectSelectorContainer: selectedProjectName: string | undefined

Added guards in parent components to only render children when
required data is available (RightSidebar, WorkspacesLayout).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Cleanup script changes for workspace f4ec6f6e-a524-4760-889a-7ec2ebbce4c6

* Refactor WorkspacesLayout to fix ESLint errors for optional props

Extract create mode sections into dedicated container components:
- CreateModeProjectSectionContainer: project selector with useCreateMode
- CreateModeReposSectionContainer: repos list with branch auto-selection
- CreateModeAddReposSectionContainer: add repos section

This removes the ModeProviderProps interface with optional props that
violated the ESLint rule. Now CreateModeProvider is only rendered when
in create mode, and each container manages its own context access.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Cleanup script changes for workspace f4ec6f6e-a524-4760-889a-7ec2ebbce4c6

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 13:14:08 +00:00
2025-08-08 13:53:27 +01:00
2026-01-17 09:43:17 +00:00
2026-01-17 09:43:17 +00:00
2025-11-14 15:37:56 +00:00
2025-12-16 10:55:27 +00:00
2025-11-14 15:37:56 +00:00
2026-01-17 09:43:17 +00:00
2025-07-11 15:57:30 +01:00
2025-12-15 19:42:13 +00:00
2025-07-11 16:31:08 +01:00
2026-01-17 09:43:17 +00:00
2025-06-25 09:27:29 +01:00

Vibe Kanban Logo

Get 10X more out of Claude Code, Gemini CLI, Codex, Amp and other coding agents...

npm Build status Ask DeepWiki

We're hiring!

Overview

AI coding agents are increasingly writing the world's code and human engineers now spend the majority of their time planning, reviewing, and orchestrating tasks. Vibe Kanban streamlines this process, enabling you to:

  • Easily switch between different coding agents
  • Orchestrate the execution of multiple coding agents in parallel or in sequence
  • Quickly review work and start dev servers
  • Track the status of tasks that your coding agents are working on
  • Centralise configuration of coding agent MCP configs
  • Open projects remotely via SSH when running Vibe Kanban on a remote server

You can watch a video overview here.

Installation

Make sure you have authenticated with your favourite coding agent. A full list of supported coding agents can be found in the docs. Then in your terminal run:

npx vibe-kanban

Documentation

Please head to the website for the latest documentation and user guides.

Support

We use GitHub Discussions for feature requests. Please open a discussion to create a feature request. For bugs please open an issue on this repo.

Contributing

We would prefer that ideas and changes are first raised with the core team via GitHub Discussions or Discord, where we can discuss implementation details and alignment with the existing roadmap. Please do not open PRs without first discussing your proposal with the team.

Development

Prerequisites

Additional development tools:

cargo install cargo-watch
cargo install sqlx-cli

Install dependencies:

pnpm i

Running the dev server

pnpm run dev

This will start the backend. A blank DB will be copied from the dev_assets_seed folder.

Building the frontend

To build just the frontend:

cd frontend
pnpm build

Build from source (macOS)

  1. Run ./local-build.sh
  2. Test with cd npx-cli && node bin/cli.js

Environment Variables

The following environment variables can be configured at build time or runtime:

Variable Type Default Description
POSTHOG_API_KEY Build-time Empty PostHog analytics API key (disables analytics if empty)
POSTHOG_API_ENDPOINT Build-time Empty PostHog analytics endpoint (disables analytics if empty)
PORT Runtime Auto-assign Production: Server port. Dev: Frontend port (backend uses PORT+1)
BACKEND_PORT Runtime 0 (auto-assign) Backend server port (dev mode only, overrides PORT+1)
FRONTEND_PORT Runtime 3000 Frontend dev server port (dev mode only, overrides PORT)
HOST Runtime 127.0.0.1 Backend server host
MCP_HOST Runtime Value of HOST MCP server connection host (use 127.0.0.1 when HOST=0.0.0.0 on Windows)
MCP_PORT Runtime Value of BACKEND_PORT MCP server connection port
DISABLE_WORKTREE_ORPHAN_CLEANUP Runtime Not set Disable git worktree cleanup (for debugging)

Build-time variables must be set when running pnpm run build. Runtime variables are read when the application starts.

Remote Deployment

When running Vibe Kanban on a remote server (e.g., via systemctl, Docker, or cloud hosting), you can configure your editor to open projects via SSH:

  1. Access via tunnel: Use Cloudflare Tunnel, ngrok, or similar to expose the web UI
  2. Configure remote SSH in Settings → Editor Integration:
    • Set Remote SSH Host to your server hostname or IP
    • Set Remote SSH User to your SSH username (optional)
  3. Prerequisites:
    • SSH access from your local machine to the remote server
    • SSH keys configured (passwordless authentication)
    • VSCode Remote-SSH extension

When configured, the "Open in VSCode" buttons will generate URLs like vscode://vscode-remote/ssh-remote+user@host/path that open your local editor and connect to the remote server.

See the documentation for detailed setup instructions.

Description
Get 10X more out of Claude Code, Codex or any coding agent
https://www.vibekanban.com/
Readme Apache-2.0 48 MiB
Languages
Rust 51.1%
TypeScript 46.6%
CSS 1.1%
JavaScript 0.7%
PLpgSQL 0.2%
Other 0.2%