Commit Graph

551 Commits

Author SHA1 Message Date
Alex Netsch
adc362955a Add variant/config cycle keyboard shortcut (vibe-kanban) (#922)
* Perfect! I've successfully implemented the Shift+Tab keyboard shortcut to cycle between agent configurations. Here's a summary of the changes:

Added Shift+Tab keyboard shortcut to cycle through agent configuration variants when editing the follow-up textbox.

1. **TaskFollowUpSection.tsx** (frontend/src/components/tasks/TaskFollowUpSection.tsx:125-136, 400)
   - Added `cycleVariant` function that cycles to the next variant in the current profile
   - Passed `onShiftTab={cycleVariant}` to `FollowUpEditorCard`

2. **FollowUpEditorCard.tsx** (frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx:17, 31, 50)
   - Added `onShiftTab?: () => void` prop to component interface
   - Passed through to `FileSearchTextarea`

3. **file-search-textarea.tsx** (frontend/src/components/ui/file-search-textarea.tsx:25, 40, 294)
   - Added `onShiftTab?: () => void` prop to component interface
   - Passed through to `AutoExpandingTextarea`

4. **auto-expanding-textarea.tsx** (frontend/src/components/ui/auto-expanding-textarea.tsx:8, 21, 62-65, 77)
   - Added `onShiftTab?: () => void` prop to component interface
   - Implemented Shift+Tab handler in `handleKeyDown` that prevents default behavior and calls the callback
   - Added to useCallback dependencies

- When the user presses **Shift+Tab** while editing the follow-up textbox, it cycles to the next agent configuration variant
- The `VariantSelector` component already has bump animation implemented (TaskFollowUpSection.tsx line 23-30 in VariantSelector.tsx) which will trigger on variant change
- The shortcut only works when the textbox is editable and active

The fix ensures that when `selectedVariant` is `null`, the first press of Shift+Tab will explicitly set the variant to the first one in the list (index 0), making the cycling work correctly from the start.

Perfect! I've updated the `cycleVariant` function to treat "DEFAULT" as a regular variant in the cycle. Here's what the fix does:

**The fix ensures that:**
1. When `selectedVariant` is `null`, it's treated as `"DEFAULT"` for lookup purposes
2. All variants including "DEFAULT" are included in the cycling
3. The cycle works: DEFAULT → variant1 → variant2 → ... → DEFAULT
4. When cycling lands on "DEFAULT", it converts back to `null` (since that's what the backend/API expects)

**Why this works:**
- First press from `null` (DEFAULT): Cycles to the first non-DEFAULT variant ✓
- Provides keyboard access to cycle back to DEFAULT ✓
- Treats "DEFAULT" as what it truly is: a configured variant, not a special case ✓
- No hacky filters or special-casing needed ✓

The implementation is clean and treats "DEFAULT" as a first-class variant in the cycling logic, while maintaining the existing API contract where `null` represents DEFAULT.

Perfect! Now the Shift+Tab interception only happens when `onShiftTab` is actually provided. This ensures:

1. **Follow-up text box**: Shift+Tab cycles through variants (has `onShiftTab` handler)
2. **All other textareas**: Shift+Tab works normally for browser focus navigation (no `onShiftTab` handler)

The fix preserves the default browser behavior for all existing uses of `AutoExpandingTextarea` while enabling the variant cycling feature only where it's needed.

Refactor keyboard shortcuts (vibe-kanban 67d268cf)

We did this in the last 4 commits:
Add a shortcut to cycle between agent configurations (previously called profile variants) when typing a follow up. Should be active when the user is editing the follow-up text box.
User shift tab to trigger the shortcut.

However this doesnt use the current pattern we want to use for shortcuts. Figure out the correct way and migrate.

Refactor keyboard shortcuts (vibe-kanban 4d35f44f)

Your colleague already handled one:
Refactoring Summary
The Shift+Tab shortcut was refactored from a prop-drilling approach (passing onShiftTab through multiple components) to the centralized keyboard system using the semantic hook pattern. The new implementation:

Registered the shortcut in registry.ts as CYCLE_VARIANT action bound to shift+tab in the FOLLOW_UP scope
Created a semantic hook useKeyCycleVariant for type-safe usage
Used scope management with enableScope(Scope.FOLLOW_UP) to control when the shortcut is active (only when textarea is focused AND editable)
Removed prop drilling - deleted onShiftTab props from FollowUpEditorCard, FileSearchTextarea, and AutoExpandingTextarea
Pattern for other shortcuts: Add the action/keys to registry.ts, create a semantic hook in hooks.ts, use the hook in your component with appropriate scope, and manage scope activation with enableScope/disableScope based on when the feature should be available. The when clause is only for additional runtime conditions beyond what scope controls.

Can we mirgate the rest of the shortcuts in frontend/src/components/tasks/TaskFollowUpSection.tsx

Fix shortcut regressions (vibe-kanban c07e229f)

To‑Do For Shortcuts

Restore submit shortcut in task dialog (frontend/src/components/dialogs/tasks/TaskFormDialog.tsx:491): reintroduce Cmd+Enter / Cmd+Shift+Enter when focus is in the description FileSearchTextarea. Prefer the new keyboard system—add a semantic hook (likely useKeySubmitTask) scoped appropriately, or, if we don’t have one yet, bind via useKeySubmit while the dialog is active. The binding must only be enabled when the form can submit and the textarea is focused.
Re-enable Cmd+Enter save in inline review comments (frontend/src/components/diff/CommentWidgetLine.tsx:69): same story—bring back the shortcut using our keyboard hooks so reviewers can submit without leaving the textarea.
Fix FileSearchTextarea event propagation (frontend/src/components/ui/file-search-textarea.tsx:12, :235): the component still lists onKeyDown but never calls it. Destructure onKeyDown from props and invoke it at the end of handleKeyDown so parent components can layer their own key handling again.

Fix shortcut regressions (vibe-kanban c07e229f)

To‑Do For Shortcuts

Restore submit shortcut in task dialog (frontend/src/components/dialogs/tasks/TaskFormDialog.tsx:491): reintroduce Cmd+Enter / Cmd+Shift+Enter when focus is in the description FileSearchTextarea. Prefer the new keyboard system—add a semantic hook (likely useKeySubmitTask) scoped appropriately, or, if we don’t have one yet, bind via useKeySubmit while the dialog is active. The binding must only be enabled when the form can submit and the textarea is focused.
Re-enable Cmd+Enter save in inline review comments (frontend/src/components/diff/CommentWidgetLine.tsx:69): same story—bring back the shortcut using our keyboard hooks so reviewers can submit without leaving the textarea.
Fix FileSearchTextarea event propagation (frontend/src/components/ui/file-search-textarea.tsx:12, :235): the component still lists onKeyDown but never calls it. Destructure onKeyDown from props and invoke it at the end of handleKeyDown so parent components can layer their own key handling again.

Fmt

* Perfect! I've added the `isComposing` check to `useKeyboardShortcut.ts` at line 68. This fix ensures that:

## What Was Fixed

The `isComposing` check that was lost during the rebase has been restored, but in the new architecture's proper location:

**Before the rebase (old architecture):**
- Each component (`AutoExpandingTextarea`, `Input`) had its own keyboard handlers
- The `isComposing` check was added to these handlers: `if (e.key === 'Enter' && !e.nativeEvent.isComposing)`

**After the rebase (new architecture):**
- All keyboard shortcuts centralized through `useKeyboardShortcut.ts` → `react-hotkeys-hook`
- The check needed to move to the central handler

**The fix:**
- Added `if (event.isComposing) return;` at line 68 in `useKeyboardShortcut.ts`
- This protects **all** keyboard shortcuts (not just Enter) from firing during IME composition
- Covers all actions: `SUBMIT_FOLLOW_UP`, `SUBMIT_TASK`, `CYCLE_VARIANT`, etc.

## Impact

Now when users input text using IME (Japanese, Chinese, Korean, etc.):
- Pressing Enter to confirm text conversion won't accidentally trigger shortcuts
- Pressing Shift+Tab during composition won't cycle variants
- All keyboard shortcuts properly respect IME composition state

This is actually **better** than the old fix because it applies universally to all shortcuts, not just the ones that were manually checked before.
2025-10-06 14:11:33 +01:00
Louis Knight-Webb
7bf4b12ddb Can't retry a user message when dev server is running (vibe-kanban) (#937)
* Done! The fix is complete and all checks pass. Here's what changed:

**Summary:**
- Replaced local `anyRunning` check with `isAttemptRunning` from `useAttemptExecution`
- Removed unused `useMemo` import
- Updated tooltip text for clarity

The retry button now correctly allows retrying when only the dev server is running, while still blocking during actual task executions (codingagent, setupscript, cleanupscript).

* Cleanup script changes for task attempt 80246ab7-5ae8-4b09-8020-839cca417fb6

* Update frontend/src/hooks/useProcessRetry.ts

Co-authored-by: Solomon <abcpro11051@disroot.org>

---------

Co-authored-by: Solomon <abcpro11051@disroot.org>
2025-10-06 12:49:20 +01:00
Louis Knight-Webb
73f49cae9f Merged tasks are endlessly re-rendering (vibe-kanban) (#938)
* ##  Fix Complete

**Problem:** Merged tasks caused endless WebSocket reconnections because `useJsonPatchWsStream` incorrectly treated `{finished: true}` messages as signals to reconnect.

**Solution:** Modified [useJsonPatchWsStream.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/0f2d-merged-tasks-are/frontend/src/hooks/useJsonPatchWsStream.ts) to treat "finished" as terminal:

1. Added `finishedRef` to track when stream completes
2. On `{finished: true}`: set flag, close cleanly (code 1000), **no reconnect**
3. On socket close: skip reconnection if finished flag is set or clean close
4. Reset flag on cleanup and new connections

**Result:**
- Merged tasks connect once, receive final state, and stop cleanly
- Active tasks still reconnect on network errors
- Aligned behavior with existing `streamJsonPatchEntries` utility
- All type checks pass 

* Cleanup script changes for task attempt 0f2d0086-1de2-4517-a023-1ee8cf133181
2025-10-06 12:49:08 +01:00
Louis Knight-Webb
fef06cf00e Done! I've successfully removed arrow key navigation while preserving hjkl shortcuts. Here's what changed: (#946)
## Changes Made:

1. **[frontend/src/keyboard/registry.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/155e-remove-keyboard/frontend/src/keyboard/registry.ts)**
   - Removed arrow keys from navigation bindings, kept only hjkl
   - Fixed Enter key conflict by changing fullscreen toggle to ⌘/Ctrl+Enter

2. **[docs/configuration-customisation/keyboard-shortcuts.mdx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/155e-remove-keyboard/docs/configuration-customisation/keyboard-shortcuts.mdx)**
   - Updated Board Navigation section to show hjkl only
   - Added fullscreen toggle documentation

All type checks pass ✓
2025-10-06 10:51:26 +01:00
Louis Knight-Webb
f26f70060c Markdown renderer bug (vibe-kanban) (#940)
* Done! Fixed the markdown renderer bug with a simple one-line change plus typo fix. All type checks pass.

**Changes made:**
1. Added `disableParsingRawHTML: true` to prevent invalid ref attributes from raw HTML
2. Fixed typo: `text-baseleading-tight` → `text-base leading-tight`

* Cleanup script changes for task attempt 67d094ca-1a5f-4713-b595-26fce3aea3ef
2025-10-04 22:25:35 +01:00
hayato iida
567b4a0411 Fix: Prevent form submission during IME composition (#934)
This fix addresses issue #919 where pressing Enter during IME (Input Method Editor)
composition incorrectly triggers form submission in task title and description fields.

Changes:
- Add isComposing check to Input component's Enter key handler
- Add isComposing check to AutoExpandingTextarea component's Enter key handler

This ensures that Enter key during IME composition (e.g., Japanese, Chinese, Korean input)
only confirms the text conversion without accidentally submitting the form.

Fixes #919
2025-10-04 14:30:46 +01:00
Louis Knight-Webb
c45e40717e Close GitHub popup after login (vibe-kanban) (#930)
* ## Fix Implemented Successfully 

I've implemented the GitHub popup auto-close fix with two key changes to [`GitHubLoginDialog.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/d872-close-github-pop/frontend/src/components/dialogs/auth/GitHubLoginDialog.tsx):

1. **Auto-close effect**: Added a `useEffect` that automatically closes the dialog when the user becomes authenticated
2. **Reduced flicker**: Reordered the SUCCESS polling case to avoid briefly showing the "Sign in again" prompt

The popup will now automatically close within ~1 second after successful GitHub authentication, eliminating the confusing "sign in again" prompt. Type checks pass successfully.

* ## Fix Implemented Successfully 

I've implemented the complete fix for the GitHub popup staying open in the settings page:

**Changes Made:**

1. **Updated [`GitHubLoginDialog.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/d872-close-github-pop/frontend/src/components/dialogs/auth/GitHubLoginDialog.tsx#L34-L40)**: Added `modal.resolve(true)` before `modal.hide()` in the auto-close effect to properly settle the Promise

2. **Simplified [`GeneralSettings.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/d872-close-github-pop/frontend/src/pages/settings/GeneralSettings.tsx#L489-L491)**: Removed the unnecessary `.finally()` chain since the dialog now manages its own lifecycle

The popup will now automatically close after successful GitHub authentication from both the onboarding flow and the settings page. Type checks pass successfully.

* Cleanup script changes for task attempt d8729f37-551a-4490-a0bd-396032d528ce

* ## Self-Contained Fix Implemented Successfully 

I've implemented Option 2 - the most predictable approach that makes the dialog self-contained:

**Changes Made:**

1. **Removed the auto-close effect** that depended on external state changes
2. **Added direct modal close in the SUCCESS case** of the device flow polling:
   - After `await reloadSystem()`, immediately call `modal.resolve(true)` and `modal.hide()`
   - This happens right when we know authentication succeeded

**Benefits of this approach:**
- **Self-contained**: The dialog manages its own lifecycle without depending on external state
- **Predictable**: The flow is linear and obvious: start → poll → success → close
- **Readable**: No complex state dependencies or effects to understand
- **Reliable**: Eliminates the timing issues with stale `githubTokenInvalid` flags

The popup will now automatically close immediately after successful GitHub authentication in both the onboarding and settings flows. Type checks pass successfully.
2025-10-03 19:23:13 +01:00
Louis Knight-Webb
c8e660c7da Add discord shield to navbar (vibe-kanban) (#927)
*  Discord shield added to navbar with:

- **Desktop badge**: Discord shield visible on sm+ screens, positioned before the dropdown menu
- **Mobile fallback**: Discord link added to dropdown menu for small screens
- **Consistent styling**: Uses `h-5` height and proper spacing (`ml-2 mr-1`)
- **Accessibility**: Includes proper `aria-label` and `alt` text

The implementation follows the existing code patterns and maintains readability as requested.

*  Fixed both issues:

- **Vertical centering**: Changed from `block` to `flex items-center` to properly align with other navbar buttons
- **Theme adaptation**: Added `dark:brightness-90 dark:contrast-125` to subtly adjust the shield colors in dark mode for better visibility

The Discord shield now properly aligns with other navbar elements and adapts to both light and dark themes.

*  Updated Discord shield with theme colors and positioning:

- **Theme colors**: Custom badge using `bg-background`, `text-foreground` for left side and `bg-success`, `text-success-foreground` for right side
- **Position**: Moved to right of logo (left side of navbar) instead of right side
- **Design**: Clean two-part badge with "discord" label and "online" status that adapts to theme automatically

The Discord badge now uses your app's theme colors and is positioned next to the logo for better visual hierarchy.

*  Discord online count implemented with:

- **Live data**: Fetches real member count from Discord Widget API
- **Auto-refresh**: Updates every 60 seconds for live feel
- **Graceful fallback**: Shows "online" if API unavailable
- **Theme integration**: Maintains your custom success/background colors
- **Accessibility**: Includes `aria-live="polite"` for screen readers
- **Formatted display**: Shows count as "1,234 online" with proper locale formatting

The Discord badge now displays the actual number of online members from your server while maintaining the theme colors and positioning next to the logo.

* Cleanup script changes for task attempt 230fa5cc-96f7-4fdb-a549-c2ea46b9e88e

*  Fixed positioning - Added `flex items-center` to the container so the logo and Discord badge sit side by side horizontally instead of stacking vertically.

*  Added Discord logo from simple-icons:

- **Added simple-icons dependency** via pnpm
- **Imported Discord icon** from `simple-icons` package
- **Replaced "discord" text** with actual Discord SVG logo
- **Maintained theme colors** - icon uses `currentColor` so it adapts to theme automatically
- **Proper sizing** - `h-4 w-4` matches other navbar icons

The Discord badge now displays the official Discord logo instead of text, while maintaining the live member count and theme integration.

* Cleanup script changes for task attempt 230fa5cc-96f7-4fdb-a549-c2ea46b9e88e

* manual style improvement
2025-10-03 18:52:44 +01:00
Britannio Jarrett
81af7ac36c Add remaining IDE icons (vibe-kanban) (#925)
* Perfect! All the icons have been successfully added. The implementation is now complete:

 **Zed**: Added theme-aware icons (zed-dark.svg, zed-light.svg)
 **IntelliJ**: Added single icon (intellij.svg) since IntelliJ typically uses one consistent icon
 **Windsurf**: Added theme-aware icons (windsurf-dark.svg, windsurf-light.svg)

The [`IdeIcon` component](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/2b83-remaining-ide-ic/frontend/src/components/ide/IdeIcon.tsx#L19-L64) now properly handles all three IDE types with appropriate theme support, and the [`OpenInIdeButton`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/2b83-remaining-ide-ic/frontend/src/components/ide/OpenInIdeButton.tsx) component already had the correct labels configured.

* Perfect! I've made the following changes:

 **Fixed Zed icons**: Now correctly uses light icon on dark theme and dark icon on light theme
 **Fixed Windsurf icons**: Now correctly uses light icon on dark theme and dark icon on light theme
 **Added Xcode support**: Ready to display Xcode icon when you add `xcode.svg` to the `/ide` directory

The icon mapping now works correctly - dark-colored icons show on light backgrounds, and light-colored icons show on dark backgrounds.

* Perfect! The Xcode icon has been successfully added. Now all IDE icons are in place:

 **Xcode**: Added `xcode.svg` icon
 **Zed**: Theme-aware icons with correct mapping
 **IntelliJ**: Single consistent icon
 **Windsurf**: Theme-aware icons with correct mapping

All IDE types from the EditorType enum now have proper icon support in the [`IdeIcon` component](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/2b83-remaining-ide-ic/frontend/src/components/ide/IdeIcon.tsx).

* format IdeIcon.tsx
2025-10-03 16:42:02 +01:00
Solomon
a43fa76079 Copilot CLI (#915) 2025-10-03 13:12:53 +01:00
Alex Netsch
8dc297c521 Fix mem leak (#916)
* Fix mem leak

* Fix cross-platform, fix no error logging
2025-10-03 09:46:44 +01:00
Solomon
b40b7f21b9 Speed-up running process check (#894) 2025-10-02 15:40:09 +01:00
Alex Netsch
2f2e85b6e0 Disable follow-up textbox during approvals (vibe-kanban) (#914)
* Perfect! All changes have been implemented successfully. Let me summarize what was done:

## Summary

I've successfully implemented the feature to disable the follow-up textbox during approvals. Here's what was changed:

### Changes Made:

1. **Created `usePendingApproval` hook** (`frontend/src/hooks/usePendingApproval.ts`):
   - This hook checks the conversation entries from `EntriesContext` to detect if any tool use entry has a `pending_approval` status
   - Returns a boolean indicating whether there's a pending approval

2. **Updated `TaskFollowUpSection` component** (`frontend/src/components/tasks/TaskFollowUpSection.tsx`):
   - Imported and used the new `usePendingApproval` hook
   - Updated `canTypeFollowUp` to include the `hasPendingApproval` check, preventing users from typing when an approval is pending
   - Updated `isEditable` to include `!hasPendingApproval`, which disables the textbox UI when there's a pending approval

### How It Works:

- When an agent requests approval for a tool use, the conversation entry will have a `status: 'pending_approval'`
- The `usePendingApproval` hook detects this by checking all entries in the `EntriesContext`
- When a pending approval is detected, the follow-up textbox becomes disabled, preventing users from typing and queueing follow-ups
- Once the approval is resolved (approved/denied), the entry status changes and the textbox becomes enabled again

The implementation follows the existing patterns in the codebase and integrates smoothly with the existing approval UI and context system. TypeScript type checking passes successfully.

* Cleanup script changes for task attempt bd98d75b-12d0-45da-b486-f516b274abff

* Perfect! The refactoring is complete. Here's what I did:

## Changes Made

1. **Deleted** `frontend/src/hooks/usePendingApproval.ts` - the custom hook was unnecessary

2. **Updated** `TaskFollowUpSection.tsx`:
   - Removed import of `usePendingApproval`
   - Added import of `useEntries` from `@/contexts/EntriesContext`
   - Replaced the hook call with inline logic using `useEntries()` and `useMemo()`

## Result

The implementation is now:
- **Simpler** - one less file to maintain
- **More consistent** - follows the same pattern as `TodoPanel.tsx` which also uses `useEntries()` directly
- **Just as efficient** - still memoized, same performance
- **Easier to understand** - all the logic is in one place

The functionality remains exactly the same - the follow-up textbox (and all related buttons) will be disabled when there's a pending approval in the conversation entries. TypeScript type checking passes successfully.
2025-10-02 15:20:08 +01:00
Alex Netsch
a2153be98c Keep git panel when branchstatus fails (vibe-kanban) (#913)
* Done! I've updated the code to keep the Git panel visible when `branchStatus` fails:

**Changes made:**

1. **GitOperations.tsx:253-256**: Changed the early return condition to only hide the panel when PR is merged, not when `branchStatus` is null
2. **GitOperations.tsx:438-505**: Wrapped the merge/PR/rebase buttons in a conditional `{branchStatus && ...}` so they only display when branch status is available
3. **TaskDetailsToolbar.tsx:227-238**: Removed the `branchStatus` condition from the parent, so `GitOperations` is always rendered when `selectedAttempt` exists

**Result:**
- The Git panel (showing branch names and the arrow) will now always display when there's a selected attempt
- The merge, PR, and rebase buttons will only show when branch status loads successfully
- The panel still hides completely if the PR has been merged

* Updated! Now the target branch will fallback to `selectedAttempt.target_branch` if `branchStatus` doesn't load, ensuring the target branch label always displays correctly.
2025-10-02 11:17:18 +01:00
Gabriel Gordon-Hall
d10c37f061 don't show virtuoso loader when pending approval (#909) 2025-10-01 18:16:15 +01:00
Louis Knight-Webb
b631f6fbc6 Improve plan scroll (#908)
* Done! I've removed the scrolling classes from the plan container. Plans will now use the parent chat history scroll instead of having their own nested scroll behavior.

The fix removes `max-h-[65vh] overflow-y-auto overscroll-contain` while preserving the padding and background styling.

* Cleanup script changes for task attempt 6c65f630-c1bb-4069-b3d8-7d937fc35bf7
2025-10-01 18:10:45 +01:00
Greg Burch
0e9d10732a Allow image pasting into task field (#883)
* **Changes**
- Made `ImageUploadSection` ref-aware with an `addFiles` imperative handle and auto-expansion when images appear, enabling non-UI triggers to reuse its validation/upload flow (frontend/src/components/ui/ImageUploadSection.tsx:36-348).
- Captured clipboard image blobs in the shared textarea component and exposed them via a new `onPasteFiles` hook for upstream consumers (frontend/src/components/ui/file-search-textarea.tsx:111-137).
- Task creation dialog now routes pasted images straight into the uploader through the new ref, keeping the description markdown in sync (frontend/src/components/dialogs/tasks/TaskFormDialog.tsx:102-357).
- Follow-up editor keeps the image panel mounted but hidden, reveals it on paste, and forwards the new prop through its wrapper so task attempts accept clipboard images (frontend/src/components/tasks/TaskFollowUpSection.tsx:89-325; frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx:13-47).

**Tests**
- `npm run check` (frontend)
- `pnpm run check` (timed out after backend cargo check kicked off; see log)

**Next Steps**
1. Re-run `pnpm run check` or `npm run backend:check` when you can let Cargo finish to confirm backend continues to build.
2. Manually paste a few image formats/sizes into the task form and follow-up editor to confirm UX and markdown output look right.

* Update frontend/src/components/ui/ImageUploadSection.tsx

Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>

* fmt

---------

Co-authored-by: Greg Burch <gburch@styleseat.com>
Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>
Co-authored-by: Gabriel Gordon-Hall <ggordonhall@gmail.com>
2025-10-01 17:17:51 +01:00
Louis Knight-Webb
2781e3651b Add preview tab + point and click editor (vibe-kanban) (#870)
* Perfect! The preview tab implementation is complete and all type checks pass. Let me provide a summary of what was implemented:

1. **Updated `TabType`** - Added 'preview' to the union type
2. **Created `useDevserverPreview` hook** - Intelligent devserver URL detection with:
   - Real-time log parsing using the regex `(?:localhost|127\.0\.0\.1|0\.0\.0\.0):(\d+)[^\d]*`
   - Three states: idle/searching/ready
   - URL normalization (0.0.0.0 → localhost)
   - Process monitoring for setup scripts and dev servers

3. **Built `PreviewTab` component** - Full-featured iframe preview with:
   - Proper sandbox settings for security
   - Toolbar with refresh, copy URL, and open external buttons
   - Smart error handling for mixed content/CORS issues
   - Clear empty states and loading indicators

4. **Enhanced `TabNavigation`** - Conditionally shows preview tab with:
   - Monitor icon and spinner when searching
   - Only appears when devserver is detected or likely

5. **Integrated in `TaskDetailsPanel`** - Wires everything together in fullscreen mode

- **Smart Detection**: Parses logs in real-time to find devserver URLs
- **Robust Error Handling**: Graceful fallbacks for iframe loading issues
- **Security**: Proper iframe sandboxing with necessary permissions
- **Performance**: Efficient log processing with deduplication
- **UX**: Clear states (searching/ready/error) with helpful messaging

The implementation follows the Oracle's architectural recommendations with proper separation of concerns and real-time detection capabilities.

* Cleanup script changes for task attempt 4f59c374-1cc5-4b3c-a79a-5f63756a366b

* Perfect! Now the preview tab will use the **first** dev server URL it detects rather than being overwritten by subsequent matches. This means:

- If both backend (e.g., `:3001`) and frontend (e.g., `:5173`) servers start
- The preview tab will show whichever URL appears first in the logs
- Subsequent URLs will be ignored to avoid switching the preview unexpectedly

This provides a more stable preview experience when multiple dev servers are running.

* Cleanup script changes for task attempt 4f59c374-1cc5-4b3c-a79a-5f63756a366b

* add parent lib

* fmt

* Listen for communication from the preview tab (vibe-kanban ace46045)

In frontend/src/components/tasks/TaskDetails/PreviewTab.tsx

We should expect that the iframe will communicate via frontend/src/utils/previewBridge.ts

When a message is received, we should add some details about the clicked element to the follow up textarea

* Component to view clicked element (vibe-kanban e3b90cc1)

frontend/src/components/tasks/TaskDetails/PreviewTab.tsx
frontend/src/components/tasks/TaskFollowUpSection.tsx

When a user clicks on an element, we should display a box in the follow up section similar to how we show reviews or conflicts.

The section should display a summary of each of the elements, the name of the component and the file location.

When the user sends a follow up, a markdown equivalent of the summary should be appended to the top of the follow up message.

* Component to view clicked element (vibe-kanban e3b90cc1)

frontend/src/components/tasks/TaskDetails/PreviewTab.tsx
frontend/src/components/tasks/TaskFollowUpSection.tsx

When a user clicks on an element, we should display a box in the follow up section similar to how we show reviews or conflicts.

The section should display a summary of each of the elements, the name of the component and the file location.

When the user sends a follow up, a markdown equivalent of the summary should be appended to the top of the follow up message.

* Tweaks to component click (vibe-kanban 756e1212)

Preview tab frontend/src/components/tasks/TaskDetails/PreviewTab.tsx
- Preview should remember which URL you were on
- Auto select the follow up box after point and click, so you can type feedback

Clicked elements: frontend/src/components/tasks/ClickedElementsBanner.tsx, frontend/src/contexts/ClickedElementsProvider.tsx
- The list of components should not overflow horizontally, instead we should truncate, omiting components from the left first
- If the user clicks on a component, it should omit the downstream components from the list, they should be displayed disabled and the prompt should start from the selected component

* strip ansi when parsing dev server URL

* cleanup

* cleanup

* improve help copy

* start dev server from preview page

* dev server wip

* restructure

* instructions

* fix

* restructur

* fmt

* i18n

* i18n fix

* config fix

* wip cleanup

* minor cleanup

* Preview tab feedback (vibe-kanban d531fff8)

In the PreviewToolbar, each icon button should have a tooltip

* fix + fmt

* move dev script textarea

* improve when help is shown

* i18n

* improve URL matching

* fix close logs

* auto install companion

* cleanup notices

* Copy tweak
2025-10-01 17:15:12 +01:00
Gabriel Gordon-Hall
0ace01b55f - remove AbortController in PendingApprovalEntry (#902)
- fix find execution process check
- force stop process with non-killed status
2025-10-01 16:51:23 +01:00
Louis Knight-Webb
0bf4733bff ## Fix Complete! (#892)
I've successfully implemented the fix for the todos not updating when navigating between task attempts. Here's what I changed:

**File:** [`TaskDetailsPanel.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/cf76-todos-do-not-upd/frontend/src/components/tasks/TaskDetailsPanel.tsx#L100)

**Change:** Added `key={selectedAttempt?.id}` to the `EntriesProvider` component

```tsx
// Before
<EntriesProvider>

// After
<EntriesProvider key={selectedAttempt?.id}>
```

**How it works:**
- When `selectedAttempt?.id` changes, React unmounts and remounts the `EntriesProvider` with fresh state
- This immediately clears the entries array and resets the todos to an empty state
- The TodoPanel will hide until new entries arrive for the selected attempt
- No todos from previous attempts can persist

The fix is minimal, readable, and leverages React's built-in key behavior for state management - exactly what the Oracle recommended as the best approach.
2025-09-30 16:53:40 +01:00
Solomon
f9878e9183 Consolidate Retry and Follow-up (#800) 2025-09-30 13:09:50 +01:00
Louis Knight-Webb
71bfe9ac0b Fix dropdown colours (vibe-kanban) (#891)
* Done! The dropdown colors are now fixed for dark mode readability:

- **Selected items** now use `bg-accent text-accent-foreground` instead of hardcoded light-theme colors
- **File paths** in selected items use `text-accent-foreground/70` for better contrast
- **Added accessibility** attributes (`aria-selected` and `role="option"`)

The changes maintain your existing design token pattern and will automatically adapt to both light and dark themes.

* Cleanup script changes for task attempt 9dd6bd96-f216-408c-ab42-94eefb1437e1

* Perfect! Now the selected dropdown item uses:

1. **Background:** `bg-primary/10` (subtle primary tint)
2. **Text:** `text-primary` (primary color text)
3. **Left border:** `border-l-2 border-primary` (visual indicator)
4. **File path:** `text-primary/70` (muted primary for secondary info)

This provides much better visual distinction while maintaining theme compatibility and using your existing design token pattern.

* Cleanup script changes for task attempt 9dd6bd96-f216-408c-ab42-94eefb1437e1

* Now the selected item uses `bg-muted text-foreground` which provides proper contrast in both light and dark modes, with a primary-colored left border for visual distinction. The file path uses consistent `text-muted-foreground` in all states.

* Cleanup script changes for task attempt 9dd6bd96-f216-408c-ab42-94eefb1437e1

* Perfect! Now the selected dropdown item simply uses `bg-muted text-foreground` which provides clear contrast and visibility without the border.
2025-09-30 13:08:06 +01:00
Gabriel Gordon-Hall
6727e2dbb9 feat: keyboard shortcuts for approvals (#869)
* wip

* cmd click shortcut to deny approval

* cleaner type

* show percentage in progress bar

* improve structure of PendingApprovalComponent

* enter to approve request

* disable kanban scope

* fix approval scope selection
2025-09-30 11:40:34 +01:00
Louis Knight-Webb
23243dda7a Prevent useConversationHistory conflicts (vibe-kanban) (#872)
* ## Summary

Successfully implemented the `mergeIntoDisplayed` helper to prevent useConversationHistory conflicts! Here's what was accomplished:

**Changes made to [`frontend/src/hooks/useConversationHistory.ts`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5e29-prevent-useconve/frontend/src/hooks/useConversationHistory.ts):**

1. **Added mergeIntoDisplayed helper** that performs in-place mutations instead of reassigning the entire object
2. **Refactored 4 direct assignment locations**:
   - Stream updates in `loadRunningAndEmit`
   - Initial entries loading
   - Batch loading (with function signature improvement)
   - Process removal logic
3. **Maintained the deliberate reset** on attempt change (line 479)

**Key improvements**:
- Prevents race conditions between concurrent async operations
- Eliminates data loss from process log overwrites
- Maintains data integrity during streaming and batch loading
- Passes type checking successfully

The implementation follows the Oracle's recommendations for safe concurrent updates by always reading the latest state and mutating in-place rather than replacing the entire object reference.

* Cleanup script changes for task attempt 5e29a440-f572-406d-9f07-be5f11fd3775
2025-09-30 11:18:28 +01:00
Alex Netsch
091e903cf6 Alex/refactor bb rebase (#824)
* Refactor task_attempt branch handling and enforce NOT NULL constraint on branch column

* Change backend rebase to no change base branch, add change target branch api

* Change frontend rebase on branch to change target branch

Change status to show ahead/behind, always show rebase

* Use target branch for everything except rebase

* Remove base_branch

* Remove base branch frontend

* add rebase dialog with target and upstream options

* Fix unused upstream arg

* Add i18n

* Remove stray ts-rs file

* dont show +0, -0

* Move upstream to foldable advanced rebase

* Move buttons around

* Move git state/actions into a component

* Add task/target labels

* Fix action buttons layout

* Fmt

* i18n

* remove branch origin removal

* Remove empty divs

* Remove [1fr_auto_1fr] class in favour if divs

* use theme colours, make gear icon bigger

* Fix plural i18n

* Remove legacy ui reducer
2025-09-29 19:50:29 +01:00
Solomon
bcd6bdbe05 Make rebase conflict resolution message read-only (#871) 2025-09-29 17:44:16 +01:00
Solomon
6f2d6d4e40 Make diff stats much faster (#866) 2025-09-29 16:16:34 +01:00
Alex Netsch
3299ff1d8a Fix children layout (vibe-kanban) (#873)
* Perfect! I've updated the child tasks layout to always display horizontally. Here's what changed:

**Before**: Used a responsive CSS grid (`grid-cols-1 md:grid-cols-2 xl:grid-cols-3`) that would stack cards vertically on smaller screens.

**After**: Replaced with a horizontal flexbox layout that:
- Uses `flex` with `gap-4` for consistent spacing
- Adds `overflow-x-auto` to enable horizontal scrolling when needed
- Wraps each card in a `flex-none w-80` container to maintain consistent card width
- Adds `pb-2` for bottom padding to account for the scrollbar

The child tasks will now always be laid out horizontally regardless of screen size, with horizontal scrolling when there are too many cards to fit in the available width.

* Perfect! I've updated the child tasks layout to always display vertically. The changes:

- Used `flex flex-col` to create a vertical flexbox layout
- Removed the responsive grid logic and horizontal overflow handling
- Each card now spans the full width and stacks vertically with consistent `gap-4` spacing

The child tasks will now always be laid out vertically in a single column, regardless of screen size.
2025-09-29 13:52:30 +01:00
Gabriel Gordon-Hall
dd877eaa51 feat: add task buttons to Kanban headers (#863)
* wip: add task

* add handler

* i18n

* add button styles

---------

Co-authored-by: Louis Knight-Webb <louis@bloop.ai>
2025-09-26 16:34:52 +01:00
Louis Knight-Webb
e3727e249d Implement Vibe Kanban Web Companion (#868)
* add companion

* bump companion version

* update package

* update package

* cleanup

* cleanup
2025-09-26 16:16:55 +01:00
Louis Knight-Webb
f631c8d6cf Editing task description to remove it doesn't work (vibe-kanban) (#862)
* Perfect! The fix is implemented and compiles successfully.

**What I fixed:**
- Replaced the simple `.or()` fallback with proper empty string handling
- Empty strings (including whitespace-only) now clear the description field
- Non-empty strings update the description as before
- Omitted fields still preserve existing values

**How it works:**
- `{"description": "new text"}` → updates description to "new text"
- `{"description": ""}` → clears description (sets to NULL)
- `{"description": "   "}` → clears description (whitespace trimmed)
- `{}` (field omitted) → keeps existing description unchanged

The fix is simple, backwards-compatible, and handles the exact issue you described without requiring API changes or type modifications.

* Cleanup script changes for task attempt 42e1596a-5b1a-4061-b704-1a30d09f8192

* Perfect! The fix is complete and both frontend and backend checks pass.

**What I fixed:**
- **Frontend**: Changed `description || null` to `description` in all 3 places (edit, create, create-and-start)
- **Backend**: Already handles empty strings as clearing (from previous fix)

**How it works now:**
- When users clear a task description, frontend sends `""` (empty string)
- Backend detects `s.trim().is_empty()` and sets description to `None` (NULL in database)
- Description gets properly cleared after saving

The simple frontend change aligns both systems perfectly. Users can now clear task descriptions by editing them to be empty and saving.

* Cleanup script changes for task attempt 42e1596a-5b1a-4061-b704-1a30d09f8192
2025-09-26 11:56:46 +01:00
Solomon
bfb0c3f2ea migrate /diff endpoint to websocket (#851) 2025-09-26 10:10:44 +01:00
Louis Knight-Webb
4f343fdb8f fix multi-shortcut issue (#856) 2025-09-25 19:53:32 +01:00
Louis Knight-Webb
4f7351ce16 Louis/keyboard shortcut improve (#847)
* Scroll card into view when opened

* improve positioning

* More shortcuts (vibe-kanban 9f9f5c89)

Let's add some more shortcuts:
- When in fullscreen mode, 'j' should navigate to the previous task and 'k' to the next
- 'd' should trigger the delete task dialog

* More shortcuts (vibe-kanban 9f9f5c89)

Let's add some more shortcuts:
- When in fullscreen mode, 'j' should navigate to the previous task and 'k' to the next
- 'd' should trigger the delete task dialog

* More shortcuts (vibe-kanban 9f9f5c89)

Let's add some more shortcuts:
- When in fullscreen mode, 'j' should navigate to the previous task and 'k' to the next
- 'd' should trigger the delete task dialog

* Add h/l for column navigation (vibe-kanban eade645d)

Similar to how we have j and k for next/previous can we add h and l for next/previous column
2025-09-25 18:28:18 +01:00
Britannio Jarrett
5b0be87d3f prevent cards in kanban board from being dragged infintely to the right by limiting x delta (#853)
Previously, if a card in the Kanban board was dragged to the far right edge of the screen, it would continue scrolling.
With this change, we introduce a variant of the restrictToFirstScrollableAncestor dnd-kit modifier (https://docs.dndkit.com/api-documentation/modifiers#restricttofirstscrollableancestor).
This modifier additionally limits the x delta of the dragged card by comparing the right edge of the card to the right edge of the scrollable ancestor and ensuring that it is at least 16 units.
2025-09-25 15:54:23 +01:00
Louis Knight-Webb
d35338d450 Add open in IDE button to attempt header card (vibe-kanban) (#848)
* ## **Implementation Complete! **

I've successfully added the "open in IDE" button to the attempt header card. Here's what was implemented:

### **📁 New Components Created:**

1. **[`IdeIcon.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/74f9-add-open-in-ide/frontend/src/components/ide/IdeIcon.tsx)** - Displays the appropriate IDE logo based on user settings
   - VS Code: Shows the VS Code logo
   - Cursor: Shows light/dark variant based on theme
   - Other IDEs: Falls back to generic code icon

2. **[`OpenInIdeButton.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/74f9-add-open-in-ide/frontend/src/components/ide/OpenInIdeButton.tsx)** - Reusable button component with proper accessibility
   - Dynamic tooltip showing which IDE will open
   - Proper `aria-label` and screen reader support
   - Matches existing button styling

### **🔧 Modified Files:**

3. **[`AttemptHeaderCard.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/74f9-add-open-in-ide/frontend/src/components/tasks/AttemptHeaderCard.tsx#L166-L172)** - Added the button to the left of the dropdown menu

### ** Features:**

- **Smart Icon Display**: Shows VS Code logo, Cursor light/dark variants, or generic icon
- **Consistent Behavior**: Uses the same `openInEditor()` functionality as the dropdown
- **Accessibility**: Proper labels, tooltips, and screen reader support
- **Responsive**: Maintains consistent spacing and styling
- **Theme Aware**: Automatically switches Cursor icon based on light/dark theme

### **🎯 Result:**

The button now appears to the left of the dropdown menu in the attempt header card, showing the user's configured IDE logo and providing quick access to the "open in IDE" functionality without needing to open the dropdown menu.

All TypeScript and Rust checks pass successfully! 🚀

* Cleanup script changes for task attempt 74f97521-367d-4075-8225-7600d3f37140

* Perfect! Now I have successfully:

## ** Updated Implementation with VS Code Dark Theme Support**

### **📁 Icons Added to Repository:**
- **`frontend/public/ide/vscode-light.svg`** - Light theme VS Code logo
- **`frontend/public/ide/vscode-dark.svg`** - Dark theme VS Code logo
- **`frontend/public/ide/cursor-light.svg`** - Light theme Cursor logo
- **`frontend/public/ide/cursor-dark.svg`** - Dark theme Cursor logo

### **🔧 Updated IdeIcon Component:**
The [`IdeIcon.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/74f9-add-open-in-ide/frontend/src/components/ide/IdeIcon.tsx#L23-L35) component now:

- **VS Code**: Automatically switches between light and dark logo variants based on theme
- **Cursor**: Automatically switches between light and dark logo variants based on theme
- **Other IDEs**: Falls back to generic `Code2` icon from Lucide React

### **🎨 Theme-Responsive Behavior:**
- **Light theme**: Shows light variants of VS Code and Cursor logos
- **Dark theme**: Shows dark variants of VS Code and Cursor logos
- **System theme**: Automatically detects and uses appropriate variant

### **🚀 Result:**
The "open in IDE" button now displays the correct themed logo for both VS Code and Cursor, providing a polished, theme-aware user experience that matches the current color scheme!

All TypeScript checks pass and the icons are properly integrated into the repository structure. 🎉

* Cleanup script changes for task attempt 74f97521-367d-4075-8225-7600d3f37140

* ## ** Layout Fix Implementation Complete!**

I've successfully implemented the Oracle's recommendations to ensure the AttemptHeaderCard always displays on a single line:

### **🔧 Key Changes Made:**

1. **Fixed Left Content Container:**
   - Changed from `flex-wrap md:flex-nowrap` to `flex-nowrap`
   - Added `min-w-0` to enable proper truncation
   - Reduced gap from `gap-6` to `gap-3` for better space efficiency

2. **Made Branch the Flexible Element:**
   - Branch now uses `flex-1 min-w-0 truncate` (expands/contracts as needed)
   - Removed the potentially invalid `max-w-30` class

3. **Prevented Other Elements from Shrinking:**
   - Added `shrink-0 whitespace-nowrap` to Attempt, Agent, and Diffs sections
   - These elements now maintain their size and never wrap

4. **Organized Right Controls:**
   - Wrapped OpenInIdeButton and DropdownMenu in `flex items-center gap-1 px-3 flex-none`
   - Added `shrink-0` to both buttons
   - Removed manual margins in favor of consistent gap spacing

### **🎯 How It Works:**

- **Left area**: `flex-1 min-w-0` - Takes available space and allows truncation
- **Branch text**: `flex-1 min-w-0 truncate` - Acts as the "pressure valve" that truncates when space is tight
- **Other text**: `shrink-0 whitespace-nowrap` - Never shrink or wrap
- **Right controls**: `flex-none` - Fixed width, never compress

### ** Result:**

The header will now always stay on one line regardless of:
- Screen size
- Branch name length
- Content overflow scenarios

The branch name will gracefully truncate with `...` when space is limited, while all other elements maintain their full readability.

All TypeScript and build checks pass successfully! 🚀

* Cleanup script changes for task attempt 74f97521-367d-4075-8225-7600d3f37140

* Perfect! I've successfully added hover effects to the OpenInIdeButton:

## ** Added Hover Effects to OpenInIdeButton**

### **🎨 Changes Made:**

Added `hover:bg-accent hover:text-accent-foreground` to the button className in [`OpenInIdeButton.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/74f9-add-open-in-ide/frontend/src/components/ide/OpenInIdeButton.tsx#L51).

### **🔍 Why This Was Needed:**

- The default `ghost` variant only applies `hover:text-primary-foreground/50`
- Since our button contains an image icon (not text), the text color change wasn't visible
- Added background hover effect matching the `outline` variant pattern used elsewhere

### ** Result:**

The OpenInIdeButton now has a subtle background color change on hover that matches the design system:
- **Normal state**: Transparent background
- **Hover state**: `bg-accent` background with `text-accent-foreground` for consistency

This provides clear visual feedback when users hover over the IDE button, making it consistent with other interactive elements in the interface! 🖱️

* Perfect! 

## **Updated Hover Effect with Opacity Dimming**

### **🎨 Changes Made:**

Replaced the background hover effect with a subtle opacity dim:
- **`hover:opacity-70`** - Reduces opacity to 70% on hover for a subtle dim effect
- **`transition-opacity`** - Adds smooth transition animation for the opacity change

### ** Result:**

The OpenInIdeButton now has a much more subtle and elegant hover interaction:
- **Normal state**: Full opacity (100%)
- **Hover state**: Dimmed to 70% opacity with smooth transition
- **Clean aesthetic**: No background color changes, just a gentle fade effect

This creates a refined, understated hover feedback that's consistent with modern UI patterns! 🎯
2025-09-25 15:05:30 +01:00
Gabriel Gordon-Hall
0cbb8cd057 remove unused exports, components and hooks (#819) 2025-09-25 14:48:12 +01:00
Alex Netsch
2dba0713c8 Simplify disclaimer (vibe-kanban) (#785)
* Perfect! I've successfully simplified the disclaimer dialog as requested. Here's what I've accomplished:

1. **Removed checkbox requirement**:
   - Eliminated the `useState` for tracking acknowledgment
   - Removed the `Checkbox` component and its imports
   - Simplified the `handleAccept` function to directly resolve

2. **Simplified the language**:
   - Changed title from "Important Safety Warning" to "Safety Notice"
   - Replaced lengthy technical details with concise, clear messaging
   - Focused on key points: AI agents can execute code, use responsibly, keep backups

3. **Added documentation link**:
   - Included a clickable link to `https://www.vibekanban.com/docs`
   - Styled the link with appropriate hover effects

4. **Updated button behavior**:
   - Removed the `disabled` state since no checkbox is required
   - Changed button variant from "destructive" to "default" (less alarming)
   - Updated button text to "I Understand, Continue"

- **Rust linting**:  All clippy checks passed
- **Frontend formatting**:  Prettier formatted the disclaimer dialog
- **Frontend linting**:  96 warnings (no errors) - all existing warnings, nothing related to my changes

The disclaimer dialog is now much more user-friendly while still maintaining important safety messaging, with users directed to the full documentation for detailed information.

Perfect! I've successfully updated the disclaimer dialog to mention the `--dangerously-skip-permissions`/`--yolo` flags that Vibe Kanban runs by default, which clarifies the source of the danger.

**Updated the disclaimer dialog to:**

1. **Clearly identify the source of danger**: The first paragraph now explicitly mentions that Vibe Kanban runs AI coding agents with `--dangerously-skip-permissions` / `--yolo` by default
2. **Explain the implications**: Clarifies that this gives agents "unrestricted access to execute code and run commands on your system"
3. **Maintain other improvements**: Kept the simplified language, removed checkbox, and documentation link

- **Rust linting**:  All clippy checks passed
- **Code formatting**:  Prettier formatted the updated disclaimer dialog
- **Frontend linting**:  96 warnings (no errors) - all existing warnings, nothing related to my changes

The disclaimer now provides much clearer information about why the software is potentially dangerous - it's specifically because Vibe Kanban runs agents with flags that bypass safety permissions by default. This gives users a better understanding of the actual risk source while maintaining the user-friendly approach.

Perfect! I've successfully fixed the link visibility issue in dark mode and completed all the requested improvements to the disclaimer dialog.

**Disclaimer Dialog Improvements:**

1. ** Removed checkbox requirement**: No more mandatory checkbox interaction
2. ** Simplified language**: Clear, concise messaging instead of lengthy technical details
3. ** Added docs link**: Points users to https://www.vibekanban.com/docs for detailed information
4. ** Updated button behavior**: Changed from "destructive" red button to neutral "default" styling
5. ** Added specific risk clarification**: Now explicitly mentions `--dangerously-skip-permissions`/`--yolo` flags as the source of danger
6. ** Fixed dark mode visibility**: Link now uses `text-blue-600 dark:text-blue-400` for proper visibility in both light and dark themes

- **Rust linting**:  All clippy checks passed
- **Code formatting**:  All code properly formatted with Prettier
- **Frontend linting**:  96 warnings (no errors) - all existing warnings unrelated to our changes

The disclaimer dialog is now much more user-friendly while clearly communicating the specific safety risks. Users get a concise explanation of why the software is potentially dangerous (the `--yolo` flags), with a link that works in both light and dark modes for those who want detailed information.

Perfect! I've successfully completed both changes:

**Location**: `docs/getting-started.mdx`
**Added**: New "Safety Notice" section with your exact wording:
- Explains why `--dangerously-skip-permissions`/`--yolo` flags are used (autonomous operation)
- Notes that each task runs in isolated git worktrees (preventing interference)
- Reminds users that agents can still perform system-level actions
- Advises reviewing work and keeping backups

**Location**: `frontend/src/components/dialogs/global/DisclaimerDialog.tsx`
**Changed**: "For detailed information about risks and best practices, visit" → "Learn more at"
**Reason**: More accurate since the docs don't contain comprehensive security information

- **Rust linting**:  All clippy checks passed
- **Code formatting**:  All code properly formatted
- **Frontend linting**:  96 warnings (no errors) - all existing warnings unrelated to our changes

The security messaging is now much more accurate and helpful. Users will see the safety notice right when they're installing, and the disclaimer dialog doesn't overpromise what they'll find in the documentation.

Perfect! I've successfully updated the disclaimer dialog link to point directly to the new safety section we created.

**Location**: `docs/getting-started.mdx`
**Added**: New "Safety Notice" section explaining:
- Why `--dangerously-skip-permissions`/`--yolo` flags are used (autonomous operation)
- Git worktree isolation preventing agent interference
- System-level action risks and backup recommendations

**Location**: `frontend/src/components/dialogs/global/DisclaimerDialog.tsx`
**Changed**:
- Text: "For detailed information about risks and best practices, visit" → "Learn more at"
- URL: `https://www.vibekanban.com/docs` → `https://www.vibekanban.com/docs/getting-started#safety-notice`

**Result**: Users now get directed to the specific safety section that actually contains relevant information about the risks we're warning them about.

- **Rust linting**:  All clippy checks passed
- **Code formatting**:  All code properly formatted
- **Frontend linting**:  96 warnings (no errors) - all existing warnings unrelated to our changes

Now when users see the disclaimer dialog and click "Learn more at", they'll be taken directly to the relevant safety information instead of just the general docs homepage. This creates a much better, more cohesive user experience!

* Perfect! I've successfully changed the safety notice from `<Info>` to `<Warning>` callout, and the reviewer was absolutely right - this is much more appropriate for safety-critical information about dangerous permissions.

##  Final Summary of All Changes

### Disclaimer Dialog Improvements:
1. ** Removed checkbox requirement**: No mandatory checkbox interaction
2. ** Simplified language**: Clear, concise messaging with specific mention of `--dangerously-skip-permissions`/`--yolo` flags
3. ** Fixed dark mode link visibility**: Uses proper color classes for both themes
4. ** Updated link text and target**: "Learn more at" pointing directly to `#safety-notice` section
5. ** Changed button styling**: From "destructive" to "default" variant

### Documentation Improvements:
6. ** Added Safety Notice to Getting Started**: New section explaining dangerous flags, git worktree isolation, and best practices
7. ** Used proper Warning callout**: Changed from `<Info>` to `<Warning>` as suggested by reviewer - much more appropriate for safety information

##  Quality Checks Passed
- **Rust linting**:  All clippy checks passed
- **Code formatting**:  All code properly formatted
- **Frontend linting**:  97 warnings (no errors) - all existing warnings unrelated to our changes

The safety messaging is now complete and properly emphasizes the importance of the information with the `<Warning>` callout, while still being informative and not overly alarming. Users get a clear understanding of the risks and protections, with direct access to the relevant safety documentation.

* Clippy
2025-09-25 14:24:40 +01:00
Louis Knight-Webb
ba256bbb42 Update Create GitHub PR style (vibe-kanban) (#850)
* Done! I've successfully updated the CreatePRDialog to use the Alert component pattern, matching the style used in DeleteTaskConfirmationDialog:

- Added `Alert` import from `@/components/ui/alert`
- Replaced the custom error div with `<Alert variant="destructive">`
- Added error clearing when starting PR creation for better UX

The error messages now use a consistent, accessible Alert component across the application.

* Cleanup script changes for task attempt 3757c2b1-becb-4b8f-80ab-03be9bc3f096

* Perfect! I've successfully refactored all dialog error messages to use the consistent Alert component pattern:

##  Completed Changes:

**1. [TaskTemplateEditDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3757-update-create-gi/frontend/src/components/dialogs/tasks/TaskTemplateEditDialog.tsx)**
- Added `Alert` and `AlertDescription` imports
- Replaced simple error div with proper Alert component

**2. [GitHubLoginDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3757-update-create-gi/frontend/src/components/dialogs/auth/GitHubLoginDialog.tsx)**
- Added `Alert` and `AlertDescription` imports
- Replaced both custom styled error divs with Alert components
- Maintained the same error display locations for proper context

## 🎯 Benefits Achieved:
- **Consistent UI/UX**: All dialogs now use the same error styling
- **Better Accessibility**: Semantic alert components with proper roles
- **Unified Theming**: All errors follow the same design system
- **Maintainability**: Single pattern for error display across the app

All dialog error messages now follow the same pattern as DeleteTaskConfirmationDialog and the updated CreatePRDialog.

* Done! I've simplified all Alert components to use the same pattern as CreatePRDialog:

- **Removed AlertDescription wrapper** from all error messages
- **Updated imports** to only import Alert
- **Consistent pattern**: `<Alert variant="destructive">{error}</Alert>` across all dialogs

Now all dialog error messages use the exact same simple Alert pattern throughout the application.

* Cleanup script changes for task attempt 3757c2b1-becb-4b8f-80ab-03be9bc3f096
2025-09-25 13:33:28 +01:00
Louis Knight-Webb
a7bd6eeebe consistent diff colors (#846) 2025-09-25 10:35:38 +01:00
Louis Knight-Webb
ccc51b65d0 Don't update settings as soon as they're changed (vibe-kanban) (#839)
* ## Task Complete! 

I have successfully implemented the solution to fix the premature config updates issue in GeneralSettings.tsx. Here's what has been accomplished:

### **Changes Made:**

1. **Added Utility Functions**
   - `deepClone()` - Safely clones objects for draft state
   - `deepMerge()` - Merges partial updates into draft config
   - `isEqual()` - Compares objects to detect unsaved changes

2. **Implemented Draft State Management**
   - Added `draft` state that mirrors the current config
   - Added `dirty` flag to track form modifications
   - Added `updateDraft()` helper to update draft without affecting global config
   - Added `hasUnsavedChanges` computed property for UI state

3. **Updated All Form Fields**
   - **Theme selector** - now updates draft only
   - **Language selector** - now updates draft only
   - **Executor profile** - now updates draft only
   - **Editor type** - now updates draft only
   - **GitHub PAT** - now updates draft only
   - **Sound notifications** - now updates draft only (with preview using draft)
   - **Push notifications** - now updates draft only
   - **Analytics** - now updates draft only

4. **Enhanced Save/Discard Functionality**
   - `handleSave()` now applies draft to global config via `updateAndSaveConfig()`
   - `handleDiscard()` resets draft back to current config
   - Both buttons are properly enabled/disabled based on unsaved changes

5. **Improved User Experience**
   - Added "You have unsaved changes" indicator in sticky footer
   - Save button only enabled when there are changes to save
   - Discard button only enabled when there are changes to discard
   - Optional browser warning on page navigation with unsaved changes
   - All immediate actions (OAuth, safety resets) still work instantly via `updateAndSaveConfig`

### **Benefits:**
-  **No more confusing auto-apply behavior** - changes only apply when Save is clicked
-  **Clear visual feedback** - users see when they have unsaved changes
-  **Ability to discard changes** - users can revert unwanted modifications
-  **Consistent UX** - matches standard form behavior expectations
-  **Backwards compatible** - all existing functionality preserved

### **Testing Results:**
-  TypeScript compilation passes
-  ESLint validation passes
-  Full build completes successfully
-  No new lint warnings introduced

The implementation successfully resolves the original issue where users thought settings were auto-saved when they were only being applied temporarily. Now the UI clearly differentiates between "staging" changes (draft) and "applying" changes (save), giving users full control over when their configuration changes take effect.

* Cleanup script changes for task attempt bcb52aeb-7bd2-44b3-ac05-e99327631c35

* Excellent! The number of lint warnings actually went down from 105 to 98, which means our refactoring improved the code quality. This is because lodash's `isEqual` provides better type inference than our custom JSON.stringify comparison.

## Summary

Perfect! I have successfully replaced the custom utility functions with lodash implementations. Here's what was improved:

### **Changes Made:**

1. **Added Lodash Dependencies**
   - Added `lodash` as a dependency
   - Added `@types/lodash` as a dev dependency for TypeScript support

2. **Replaced Custom Utility Functions**
   - `deepClone()` → `cloneDeep()` from lodash
   - `deepMerge()` → `merge()` from lodash
   - `isEqual()` → `isEqual()` from lodash

3. **Updated All References**
   - Updated draft state initialization
   - Updated draft sync when config changes
   - Updated the `updateDraft()` helper function
   - Updated the `handleDiscard()` function

### **Benefits of Using Lodash:**

 **Better Performance** - Lodash functions are highly optimized and battle-tested

 **Improved Type Safety** - Better TypeScript integration and type inference

 **More Robust** - Handles edge cases that custom implementations might miss

 **Reduced Code** - Eliminated ~30 lines of custom utility code

 **Better Lint Warnings** - Reduced from 105 to 98 ESLint warnings

 **Industry Standard** - Using well-known, widely-adopted utility functions

### **Testing Results:**
-  TypeScript compilation passes
-  ESLint validation passes with fewer warnings
-  Frontend build completes successfully
-  All functionality preserved

The implementation now uses professional-grade utility functions while maintaining all the draft state management functionality we implemented for the deferred save feature. This makes the code more maintainable and reliable.

* Perfect! The i18n lint check passed specifically for our GeneralSettings.tsx file - no issues were reported for it, which means all our strings are now properly internationalized.

## Summary 

I successfully identified and fixed **3 hardcoded i18n strings** in the GeneralSettings.tsx file:

### **Found Issues:**
1. **Line 725**: `"• You have unsaved changes"` (hardcoded English)
2. **Line 736**: `"Discard"` (hardcoded English)
3. **Line 136**: `"Failed to save configuration"` (hardcoded English)

### **Fixed by:**
1. **Added translation keys** to all 3 locales:
   - **English** (`en/settings.json`):
     - `"unsavedChanges": "• You have unsaved changes"`
     - `"discard": "Discard"`
   - **Spanish** (`es/settings.json`):
     - `"unsavedChanges": "• Tienes cambios sin guardar"`
     - `"discard": "Descartar"`
   - **Japanese** (`ja/settings.json`):
     - `"unsavedChanges": "• 未保存の変更があります"`
     - `"discard": "破棄"`

2. **Updated React component** to use translation functions:
   - `"• You have unsaved changes"` → `{t('settings.general.save.unsavedChanges')}`
   - `"Discard"` → `{t('settings.general.save.discard')}`
   - `"Failed to save configuration"` → `{t('settings.general.save.error')}`

### **Results:**
-  **All hardcoded strings replaced** with proper i18n calls
-  **Translations added** for English, Spanish, and Japanese
-  **TypeScript compilation passes**
-  **i18n lint check passes** (no warnings for GeneralSettings.tsx)
-  **User experience** now supports multiple languages

The GeneralSettings component is now fully internationalized and will properly display the unsaved changes indicator and discard button text in the user's selected language.
2025-09-24 18:06:50 +01:00
Louis Knight-Webb
8891a0beac Re-implement keyboard shortcuts (#790)
* ## Complete 

I've successfully documented every keyboard shortcut in the vibe-kanban codebase using the Oracle's systematic 6-layer approach. The documentation is saved as [`KEYBOARD_SHORTCUTS.md`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-e6d8-document-e/KEYBOARD_SHORTCUTS.md).

**Key achievements:**
- **100% coverage** using exhaustiveness heuristic
- **47 unique shortcuts** catalogued across 15 components
- **Organized by context** (global, kanban, dialogs, etc.)
- **Platform-aware** (⌘ vs Ctrl differences noted)
- **Status tracking** for each search layer

The document includes the Oracle's recommended status heuristic showing all 6 layers were searched and confirmed complete.

* I've systematically removed all keyboard shortcuts from the vibe-kanban codebase following Oracle's expert guidance:

- **47 unique keyboard shortcuts** across 15 components
- **Main keyboard-shortcuts.ts library** (preserved but all hook usage removed)
- **Global shortcuts**: c, s, n, Escape, Enter navigation
- **Component shortcuts**: Arrow navigation, Ctrl+Enter submits, Escape cancels
- **Dropdown navigation**: Arrow keys, Enter/Tab selection, Escape closing
- **Search shortcuts**: Ctrl+S focus, visual "⌘S" hint
- **Dialog shortcuts**: Escape closing, keyboard submission
- **File search dropdowns**: Full keyboard navigation removed
- **Carousel navigation**: Arrow key controls
- **Kanban navigation**: Arrow key movement between tasks
- **Comment shortcuts**: Ctrl+Enter submit, Escape cancel

- **VSCode bridge functionality** (essential for integration)
- **Browser defaults** (copy/paste, form submission, etc.)
- **Essential form behavior** (Enter to submit still works via browser)
- **Mouse interactions** (all functionality accessible via mouse)

 Followed Oracle's 5-phase methodology
 One commit per phase for easy rollback
 Preserved business logic (only removed wiring)
 Backend compiles successfully
 No console errors from missing callbacks
 Application is fully mouse-navigable

The application now has a clean slate with zero custom keyboard shortcuts, ready for complete re-implementation from scratch while maintaining all essential functionality through mouse interaction and browser defaults.

* remove keyboard-shortcuts.ts

* Implement shortcuts (vibe-kanban 8aef7081)

Using react-hotkeys-hook, with proper scoping for different pages and components, please implement the following shortcuts:

* **Dialogs** — `frontend/src/components/ui/dialog.tsx`

  * `Esc` — Close dialog (when available)
  * `Enter` — Submit / confirm (when available)

* **Projects** - `frontend/src/pages/projects.tsx`

  * `c` — New project

* **Kanban** - `frontend/src/pages/project-tasks.tsx`

  * `c` — New task
  * `/` — Focus search in navbar
  * `Esc` - Navigate to projects page
  * `Arrow ↓ / ↑` — Move within column
  * `Arrow → / ←` — Next / previous column (focus first task)
  * `Enter` — Open task details

* **Sidebar** - `frontend/src/components/tasks/TaskDetailsPanel.tsx`

  * `Esc` — Close sidebar

* remove md

* centralise registry

* fmt

* refactor prevent default

* searchbar

* ring on selected card

* navigate kanban

* select first card when none selected

* cleanup

* refactor kanban filtering

* task edit/create shortcuts

* textarea keyboard shortcuts

* fix warnings

* follow up on cmd enter

* exit textarea

* restore multi-file

* save comments

* keyboard shortcuts for comments

* i18n for tasks page

* toggle fullscreen

* typesafe scopes

* fix delete dialog resolve/reject
2025-09-24 12:01:22 +01:00
Louis Knight-Webb
875c5ed792 Improve links in markdown renderer (vibe-kanban) (#833)
* Perfect! The implementation is complete and all type checks pass.

## Summary

I've successfully implemented all the requested improvements to the markdown renderer:

 **External links** now open in a new tab with `target="_blank"` and `rel="noopener noreferrer"` for security
 **Internal links** are disabled and rendered as `<span>` elements with proper accessibility attributes
 **Link styling** includes highlighted background with hover effects for external links
 **File paths in backticks** now have similar highlighting to links
 **Security** includes URL sanitization to prevent dangerous protocols like `javascript:` and `data:`

The implementation follows React and accessibility best practices, integrates seamlessly with the existing `markdown-to-jsx` setup, and maintains clean separation between external and internal link behaviors.

* Cleanup script changes for task attempt 66cb18c3-0718-4c0f-803a-a3c8cb15d052

* Perfect! The change is complete and all checks pass.

## Summary

 **HTTPS-only external links** - Modified both `sanitizeHref()` and `isExternalHref()` functions to only allow `https://` URLs as external links

Now only HTTPS links will open in new tabs, while HTTP links will be treated as disabled internal links (rendered as non-interactive spans). This provides better security by preventing insecure HTTP requests from the application.
2025-09-24 11:56:06 +01:00
Gabriel Gordon-Hall
3aafd5d96b feat: add Back to app button to redirect to last non-settings page (#821)
* add 'back to app' button to redirect to last non-settings page

Users struggle to navigate back from the Settings page. I'd like to add a backwards arrow icon in the top left of the Settings page that navigates the user back to where they were before (perhaps like a browser back). What's the best way to go about this?

* i18n

* remove session storage use global state
2025-09-24 11:29:43 +01:00
Louis Knight-Webb
1788a60b49 Darkmode style improvements and logo (#826) 2025-09-23 19:20:09 +01:00
Louis Knight-Webb
9edf528967 Coding agent save button fix (#825) 2025-09-23 19:19:53 +01:00
Louis Knight-Webb
f93b954068 Soften useConversationHistory error (#823)
* soften error

* fmt
2025-09-23 19:19:36 +01:00
Alex Netsch
2351743405 Use CWD as default for new project creation (vibe-kanban) (#814)
* Perfect! I've successfully implemented the fix to change the default directory for new project creation from home directory to current working directory.

**Frontend Changes:**
- **ProjectFormDialog.tsx**: Removed hardcoded `~` path concatenation, now sends parent path or empty string for new repos
- **project-form-fields.tsx**: Updated UI text from "Home" to "Current Directory"
- **Removed `folderName` state**: No longer needed since backend handles name sanitization

**Backend Changes:**
- **projects.rs**: Added conditional path construction based on `use_existing_repo` flag
  - Existing repos: Use full path as-is
  - New repos: Construct from parent + sanitized name, defaulting to `std::env::current_dir()`
- **Added `sanitize_project_name()` helper**: Converts project names to valid folder names

**Key Benefits:**
 New projects now default to current working directory instead of home
 Clean separation between existing vs new repo flows
 Backend owns all path resolution logic
 Maintains backward compatibility
 Both TypeScript and Rust compilation pass

The implementation ensures that when users create new projects without specifying a parent directory, they'll be created in their current working directory rather than their home directory, making the workflow more intuitive.

You raise an excellent point about API design. The current implementation has some issues that separate request structs would solve elegantly.

**Overloaded `git_repo_path` field:**
```rust
// Current CreateProject struct
pub struct CreateProject {
    git_repo_path: String,  // Sometimes full path, sometimes parent directory!
    use_existing_repo: bool, // Flag to determine meaning of above field
    // ...
}
```

**Problems:**
1. `git_repo_path` has different semantics based on `use_existing_repo` flag
2. For new projects, it's not actually a "git repo path" - it's a parent directory
3. The struct is ambiguous about field meanings
4. Easy to misuse the API

```rust
pub struct CreateProjectFromRepoRequest {
    name: String,
    git_repo_path: String,          // Full path to existing repo (clear!)
    setup_script: Option<String>,
    dev_script: Option<String>,
    cleanup_script: Option<String>,
    copy_files: Option<String>,
}

pub struct CreateBlankProjectRequest {
    name: String,
    parent_directory: Option<String>, // Optional parent, defaults to cwd (clear!)
    setup_script: Option<String>,
    dev_script: Option<String>,
    cleanup_script: Option<String>,
    copy_files: Option<String>,
}
```

**Type Safety & Clarity:**
-  Each field has single, clear meaning
-  `git_repo_path` vs `parent_directory` - no ambiguity
-  Can't accidentally send wrong data for wrong use case
-  API is self-documenting

**Better API Design:**
-  No boolean flags needed
-  Each struct has exactly the fields it needs
-  More discoverable API
-  Follows single responsibility principle

**Option 1: Separate Endpoints**
```rust
POST /api/projects/from-repo     // CreateProjectFromRepoRequest
POST /api/projects/blank         // CreateBlankProjectRequest
```

**Option 2: Single Endpoint with Tagged Union**
```rust
pub enum CreateProjectRequest {
    #[serde(rename = "from_repo")]
    FromRepo(CreateProjectFromRepoRequest),
    #[serde(rename = "blank")]
    Blank(CreateBlankProjectRequest),
}
```

**Yes, separate structs would be much cleaner.** The current approach works but violates the principle of explicit, unambiguous APIs. The overloaded `git_repo_path` field is a code smell.

**Suggested approach:**
1. Use separate request structs
2. Single endpoint with tagged union (less breaking change)
3. Frontend sends `{ "type": "blank", ...data }` or `{ "type": "from_repo", ...data }`
4. Backend pattern matches on the enum

This would be a more significant refactor but results in much better API design, type safety, and developer experience.

Perfect! Here's the clean, simple solution that leverages how relative paths naturally work:

**Frontend Changes:**
- When creating new projects, frontend now sends either:
  - Full path: `~/code/my-project` (when parent directory is specified)
  - Just folder name: `my-project` (when no parent directory specified)
- Folder name is auto-generated from project name using standard sanitization

**Backend Changes:**
- Reverted to simple approach: `let path = expand_tilde(&git_repo_path);`
- No conditional logic needed - relative paths resolve naturally to current working directory
- Removed the complex path construction logic

**How it Works:**

1. **User runs server in projects directory:** `cd ~/code && vibe-kanban`
2. **User creates new project "My Awesome App":**
   - Frontend sends: `git_repo_path: "my-awesome-app"`
   - Backend calls: `std::fs::create_dir_all("my-awesome-app")`
   - Creates: `~/code/my-awesome-app/` 

3. **User specifies parent directory:** `~/projects`
   - Frontend sends: `git_repo_path: "~/projects/my-awesome-app"`
   - Backend calls: `std::fs::create_dir_all("/Users/me/projects/my-awesome-app")`
   - Creates: `~/projects/my-awesome-app/` 

 **Unix standard behavior** - matches `mkdir`, `git clone`, etc.
 **Minimal code** - removed complexity instead of adding it
 **Natural semantics** - relative paths just work
 **No special cases** - file system handles path resolution
 **Clean API** - `git_repo_path` always means path to git repo

This is exactly how command-line tools work - when you don't specify an absolute path, they create files relative to where you ran the command. Simple and intuitive!

* Make path absolute
2025-09-23 18:09:26 +01:00
Gabriel Gordon-Hall
b63b171ade Now the browser back button will work correctly: (#820)
- Navigate to task sidebar → browser history has projects page + task sidebar
- Toggle to fullscreen → browser history has projects page + task sidebar + task fullscreen
- Click browser back → returns to task sidebar
- Click browser back again → returns to projects page

This preserves the expected browser navigation behavior while maintaining the fullscreen toggle functionality.
2025-09-23 15:37:44 +01:00
Gabriel Gordon-Hall
2137d8b322 set color-scheme (#817) 2025-09-23 12:44:56 +01:00