Skip to content

feat: Tidying up kanban board#1900

Open
fireapache wants to merge 17 commits intoAndyMik90:developfrom
fireapache:feat/tidying-up-kanban-board
Open

feat: Tidying up kanban board#1900
fireapache wants to merge 17 commits intoAndyMik90:developfrom
fireapache:feat/tidying-up-kanban-board

Conversation

@fireapache
Copy link
Contributor

@fireapache fireapache commented Feb 25, 2026

Base Branch

  • This PR targets the develop branch (required for all feature/fix PRs)
  • This PR targets main (hotfix only - maintainers)

Description

  1. Moving elements like + sign to add project after the last added project tab
  2. Refresh kanban board and show archived tasks move to top bar to improve visibility and free up kanban board real state

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 📚 Documentation
  • ♻️ Refactor
  • 🧪 Test

Area

  • Frontend
  • Backend
  • Fullstack

AI Disclosure

  • This PR includes AI-generated code (Claude, Codex, Copilot, etc.)

Tool(s) used:
Testing level:

  • Untested -- AI output not yet verified

  • Lightly tested -- ran the app / spot-checked key paths

  • Fully tested -- all tests pass, manually verified behavior

  • I understand what this PR does and how the underlying code works

Checklist

  • I've synced with develop branch
  • I've tested my changes locally
  • I've followed the code principles (SOLID, DRY, KISS)
  • My PR is small and focused (< 400 lines ideally)

Platform Testing Checklist

CRITICAL: This project supports Windows, macOS, and Linux. Platform-specific bugs are a common source of breakage.

  • Windows tested (either on Windows or via CI)
  • macOS tested (either on macOS or via CI)
  • Linux tested (CI covers this)
  • Used centralized platform/ module instead of direct process.platform checks
  • No hardcoded paths (used findExecutable() or platform abstractions)

If you only have access to one OS: CI now tests on all platforms. Ensure all checks pass before submitting.

CI/Testing Requirements

  • All CI checks pass on all platforms (Windows, macOS, Linux)
  • All existing tests pass
  • New features include test coverage
  • Bug fixes include regression tests

Screenshots

Before After
{4DC3AC4D-573B-4F20-ADFC-A1F00259EF74} {2A7CEA0B-6454-41B5-A241-BC581C63046C}

Feature Toggle

  • Behind localStorage flag: use_feature_name
  • Behind settings toggle
  • Behind environment variable/config
  • N/A - Feature is complete and ready for all users

Breaking Changes

Breaking: No

Summary by CodeRabbit

Release Notes

  • New Features

    • Refresh tasks and show/hide archived controls now available in the project tab bar for easier access.
  • Improvements

    • Simplified Kanban board header for a cleaner interface.
    • Removed per-tab settings button to reduce UI clutter.
    • Consolidated archive visibility controls across views.
  • Chores

    • Added French and English translations for new controls.

fireapache and others added 15 commits January 15, 2026 16:59
…sh header bar and Show Archived button

Changes made:
- Removed refresh header bar from KanbanBoard component
- Removed Show Archived toggle button from Done column
- Removed unused imports (useViewState, RefreshCw icon, Tooltip, archiveTasks)
- Updated KanbanBoardProps interface to remove onRefresh and isRefreshing props
- Updated DroppableColumnProps interface to remove archivedCount, showArchived, and onToggleArchived props
- Removed archived-related state and logic (archivedCount, filteredTasks, showArchived)
- Updated tasksByStatus to use tasks directly instead of filteredTasks
- Cleaned up App.tsx by removing unused isRefreshingTasks state and handleRefreshTasks function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…h and Show Archived buttons with tooltips, add tooltip to + button
…nglish and French

- Added refreshTasks and addNewProject keys to en/common.json
- Added refreshTasks and addNewProject keys to fr/common.json
- Tooltips will display for Refresh and Add Project buttons in tab bar

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…to ProjectTabBar

- Added showArchived state management to App component
- Created handleRefreshTasks handler to reload tasks from store
- Created handleToggleArchived handler to toggle archived visibility
- Added archivedCount calculation based on tasks with archivedAt metadata
- Updated ProjectTabBarWithContext interface to include new props
- Passed all new props (onRefresh, isRefreshing, showArchived, onToggleArchived, archivedCount) to ProjectTabBar

This completes the UI reorganization by lifting the refresh and archived state
management from KanbanBoard to the parent component and passing it through to
the ProjectTabBar where the controls now reside.
Fixes:
- Show Archived button now only appears when archivedCount > 0
- Changed icons from Eye/EyeOff to Archive
- Added badge with count on button (not in tooltip)
- Added active state styling (primary background when enabled)
- Added aria-pressed attribute for accessibility
- Fixed + button tooltip to use "Add new project" translation

Verified:
- All QA issues from QA_FIX_REQUEST.md addressed
- Implementation now matches spec requirements exactly

QA Fix Session: 1
Fixes:
- Show Archived button functionality: Added showArchived prop to KanbanBoard and filter archived tasks
- + icon positioning: Moved buttons into same flex container as tabs for proper alignment

Verified:
- Show Archived button now properly filters archived tasks
- Buttons (Refresh, Show Archived, +) appear directly to the right of tabs
- Added flex-shrink-0 to prevent button shrinking

QA Fix Session: 1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Reorganize ProjectTabBar layout so that Add Project button stays next
to the project tabs while Refresh Tasks and Show Archived buttons are
anchored to the right side of the bar. Also fixes refresh tooltip to
use correct translation key and adds missing archiveTasks import.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Follows established codebase pattern for cross-namespace translation access.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove redundant undefined check since archivedCount defaults to 0.

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

Resolved conflicts by:
- Keeping all new develop features (selection, collapse, resize, lock columns, bulk actions)
- Preserving our feature: Kanban controls moved to ProjectTabBar
- Removed archived-related props from Done column (moved to tab bar)
- Kept Expand All button, removed duplicate Refresh button from Kanban header
- Used isRefreshingTasks state for refresh spinner
- Updated to use filteredTasks for archive filtering
- Added Tooltip imports to KanbanBoard.tsx

Note: TypeScript errors for rehype-* modules will be resolved when dependencies
are installed in the main repository. These come from develop branch changes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Import Tooltip, TooltipContent, TooltipTrigger for column header buttons
- Add .secretsignore to allow test files and checksums in commits

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @fireapache, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly tidies up the Kanban board interface by reorganizing key UI elements. The 'Add Project' button is now more intuitively placed, and controls for refreshing tasks and viewing archived items have been elevated to the project tab bar. This change aims to streamline the user experience, making the Kanban board itself less cluttered while providing essential actions in a more accessible location.

Highlights

  • Kanban Board UI Refinements: The 'Add Project' button has been relocated to appear immediately after the last project tab, improving discoverability and workflow. Controls for refreshing tasks and toggling archived task visibility have been moved from the Kanban board header to the main project tab bar, centralizing these actions and freeing up Kanban board real estate.
  • Archived Task Visibility: A new feature allows users to toggle the visibility of archived tasks directly from the project tab bar, with a count indicating the number of archived tasks. This functionality is specific to the Kanban view.
  • Code Refactoring and Prop Management: The App.tsx component now manages the state and logic for refreshing tasks and showing archived tasks, passing relevant props down to ProjectTabBar. The KanbanBoard.tsx component has been simplified by removing its internal state and UI elements related to these features.
  • Internationalization Updates: New translation keys for 'refresh tasks' and 'add new project' have been added to both English and French locale files to support the updated UI elements.
  • New .secretsignore File: A new .secretsignore file has been added to prevent test files with mock credentials and scripts containing checksums from being treated as secrets.
Changelog
  • .secretsignore
    • Added a new file to specify patterns for ignoring test files with mock credentials and scripts with checksums from secret scanning.
  • apps/frontend/src/renderer/App.tsx
    • Updated ProjectTabBarWithContextProps to include new props for refresh and archived task controls.
    • Passed new refresh and archived task related props to the ProjectTabBar component.
    • Introduced showArchived state and handleToggleArchived function to manage archived task visibility.
    • Calculated archivedCount based on tasks with archivedAt metadata.
    • Conditionally rendered refresh and archived controls in ProjectTabBar only when the active view is 'kanban'.
    • Removed onRefresh and isRefreshing props from KanbanBoard component, and added showArchived prop.
  • apps/frontend/src/renderer/components/KanbanBoard.tsx
    • Removed useViewState import and related logic.
    • Updated KanbanBoardProps to remove onRefresh and isRefreshing, and added showArchived.
    • Removed the archived task toggle button from the 'done' column header.
    • Removed the refresh button from the Kanban board's main header.
    • Simplified prop passing to DroppableColumn by removing archived task related props.
  • apps/frontend/src/renderer/components/ProjectTabBar.tsx
    • Imported RefreshCw, Archive icons, and Tooltip components.
    • Extended ProjectTabBarProps with new properties for refresh and archived task controls.
    • Updated useTranslation to include the 'tasks' namespace.
    • Modified the layout to separate project tabs and controls into left and right sections.
    • Relocated the 'Add Project' button to the left side, next to the project tabs, with a tooltip.
    • Added a refresh button with a loading spinner and a 'Show Archived' button with a task count to the right side of the tab bar, both with tooltips.
  • apps/frontend/src/renderer/components/SortableProjectTab.tsx
    • Removed Settings2 icon import.
    • Removed the settings icon button from the active project tab controls.
  • apps/frontend/src/shared/i18n/locales/en/common.json
    • Added new translation keys: refreshTasks and addNewProject.
  • apps/frontend/src/shared/i18n/locales/fr/common.json
    • Added new translation keys: refreshTasks and addNewProject.
Activity
  • The pull request author, fireapache, has indicated that this PR introduces a new feature for the frontend.
  • The author has disclosed that AI-generated code was used and has been fully tested.
  • The author has confirmed that the changes have been synced with the develop branch, tested locally, follow code principles, and are focused.
  • Platform testing indicates that Windows has been tested, and no hardcoded paths were used.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

This PR refactors component state management by moving archive visibility to a shared ViewState context, removes per-component refresh UI from KanbanBoard, consolidates refresh and archive controls into ProjectTabBar, eliminates per-tab settings controls, and adds corresponding internationalization strings.

Changes

Cohort / File(s) Summary
Secret Scanning Configuration
.secretsignore
Added ignore patterns to exclude test files, mock credentials, scripts, and CI directories from secret scanning.
State Management Refactoring
apps/frontend/src/renderer/App.tsx
Integrated ViewState context via useViewState hook; updated ProjectTabBarWithContext to consume showArchived and toggleShowArchived from context; introduced kanban-specific props computation; updated component signatures to include tasks array and optional refresh callbacks.
Component API Simplification
apps/frontend/src/renderer/components/KanbanBoard.tsx, apps/frontend/src/renderer/components/SortableProjectTab.tsx
Removed onRefresh/isRefreshing props from KanbanBoard and refresh UI; removed onSettingsClick and settings button from SortableProjectTab; shifted archive visibility to context-driven approach.
Control Consolidation
apps/frontend/src/renderer/components/ProjectTabBar.tsx
Added new public props for refresh control and archive filtering; introduced UI buttons with tooltips for Refresh Tasks and Show/Hide Archived; reorganized layout with left-aligned tabs and right-aligned controls; expanded translation namespace.
Internationalization
apps/frontend/src/shared/i18n/locales/en/common.json, apps/frontend/src/shared/i18n/locales/fr/common.json
Added translation keys for new UI controls: refreshTasks and addNewProject in both English and French.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

feature, area/frontend, size/M

Suggested reviewers

  • MikeeBuilds
  • AndyMik90
  • AlexMadera

Poem

🐰 With context now shared, no more prop confusion,
Archive state flows through with seamless infusion,
Refresh buttons bloom in the bar at the top,
Settings dismissed—simplicity won't stop! ✨
One source of truth keeps our UI so clean.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Tidying up kanban board' accurately reflects the main objective of the PR, which is to clean up and reorganize the Kanban board UI by moving controls to the top bar and simplifying the board itself.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively tidies up the Kanban board and project tab bar by relocating the 'add project', 'refresh', and 'show archived' controls. The changes improve UI layout and visibility as intended.

My review includes a few suggestions for improvement:

  • Removing an unused variable in App.tsx.
  • Optimizing a calculation by using useMemo for better performance.
  • Cleaning up an unused prop in SortableProjectTab.tsx following the refactor.

These changes will help improve code clarity and performance. Overall, this is a good step forward for the UI.

const setActiveProject = useProjectStore((state) => state.setActiveProject);
const reorderTabs = useProjectStore((state) => state.reorderTabs);
const tasks = useTaskStore((state) => state.tasks);
const isLoadingTasks = useTaskStore((state) => state.isLoading);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The constant isLoadingTasks is declared but its value is never read. This unused variable should be removed to improve code clarity and maintainability.

Comment on lines +850 to +852
const archivedCount = tasks.filter(
(task) => task.metadata?.archivedAt
).length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To optimize performance, this calculation of archivedCount should be memoized using useMemo, similar to how it was implemented in KanbanBoard.tsx before this refactoring. This will prevent re-calculating on every render, which can be expensive if the tasks array is large. Please also remember to import useMemo from react.

Suggested change
const archivedCount = tasks.filter(
(task) => task.metadata?.archivedAt
).length;
const archivedCount = useMemo(() => tasks.filter(
(task) => task.metadata?.archivedAt
).length, [tasks]);

import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { useTranslation } from 'react-i18next';
import { Settings2 } from 'lucide-react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since the settings button and its usage via onSettingsClick have been removed from this component, the onSettingsClick prop is now unused. To improve code clarity, please remove the onSettingsClick prop from the SortableProjectTabProps interface (line 16) and from the component's destructuring (line 30). Also, remove it from the parent component ProjectTabBar.tsx where it's being passed to SortableProjectTab.

Fixes:
- Remove unused isLoadingTasks variable from App.tsx
- Memoize archivedCount calculation for performance optimization
- Remove unused onSettingsClick prop from SortableProjectTab and ProjectTabBar
- Remove unused AlertCircle and RefreshCw imports from KanbanBoard

Verified:
- TypeScript type checking passes
- All unused code removed per PR AndyMik90#1900 review comments

QA Fix Session: 0

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Contributor Author

@fireapache fireapache left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: 🔴 BLOCKED

🔴 Blocked - 2 CI check(s) failing. Fix CI before merge.

Blocked: 2 CI check(s) failing. Fix CI before merge.

Risk Assessment

Factor Level Notes
Complexity Medium Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

🚨 Blocking Issues (Must Fix)

  • CI Failed: CI Complete
  • CI Failed: test-frontend (windows-latest)

Findings Summary

  • High: 1 issue(s)
  • Low: 2 issue(s)

Generated by Auto Claude PR Review

Findings (3 selected of 3 total)

🟠 [cb1add393993] [HIGH] Duplicate showArchived state breaks ViewStateContext cross-view sync

📁 apps/frontend/src/renderer/App.tsx:158

The PR introduces a new useState(false) for showArchived in App.tsx (line 158), but the codebase already has ViewStateContext (contexts/ViewStateContext.tsx) which provides this exact state via useViewState(). The ViewStateProvider is still rendered in App.tsx (line 851), and the Ideation component (ideation/Ideation.tsx:22) still reads showArchived from useViewState(). This means KanbanBoard now uses the local App.tsx state while Ideation uses the ViewStateContext state — they are no longer synced. The ViewStateContext JSDoc explicitly states it manages 'view state that needs to be shared across different project pages (kanban, ideation, etc.)'. The PR should either use ViewStateContext consistently (passing its values to ProjectTabBar) or update Ideation to also use the new approach. | The showArchived state was moved from ViewStateContext to App.tsx local state (useState(false) at line 158). However, the Ideation component (Ideation.tsx:22) still reads showArchived from ViewStateContext via useViewState() (comment says 'Get showArchived from shared context for cross-page sync'). Since the kanban's archived toggle now controls App.tsx's local state instead of the context, the ViewStateContext's showArchived is permanently stuck at false — nothing ever calls toggleShowArchived() or setShowArchived() on it anymore. This means: (1) If Ideation was supposed to react to kanban's archived toggle, it won't. (2) The ViewStateProvider wrapping the entire app (App.tsx:851) is now dead code for its only purpose (showArchived). Either remove the context and manage archived state per-view independently, or keep using the context so state stays synced.

Suggested fix:

Either (a) continue using ViewStateContext by consuming `useViewState()` in the component that passes props to ProjectTabBar, or (b) remove ViewStateContext usage from Ideation and pipe the App.tsx state down. Option (a) is preferred as it preserves the existing architectural pattern.

🔵 [2a8034dd862b] [LOW] Repetitive ternary pattern for conditional prop passing

📁 apps/frontend/src/renderer/App.tsx:881

Five consecutive props use the same activeView === 'kanban' ? value : undefined ternary pattern. This is verbose and error-prone if new kanban-only controls are added later.

Suggested fix:

Consider computing `const isKanban = activeView === 'kanban';` once and using spread: `{...(isKanban && { onRefresh: handleRefreshTasks, isRefreshing: isRefreshingTasks, showArchived, onToggleArchived: handleToggleArchived, archivedCount })}`

🔵 [4eae1bc52317] [LOW] [NEEDS REVIEW] Archive All button lost showArchived guard, may re-archive tasks

📁 apps/frontend/src/renderer/components/KanbanBoard.tsx:514

The old code had !showArchived as a condition for showing the Archive All button in the Done column (line 514). This guard was removed. When showArchived=true, the Done column includes already-archived tasks (via filteredTasks at line 682-687 which returns all tasks when showArchived is true). The handleArchiveAll at line 870 archives ALL tasksByStatus.done tasks without checking if they're already archived. This means clicking 'Archive All' when archived tasks are visible will redundantly re-archive already-archived tasks. While likely idempotent, it's unnecessary API calls and could confuse users seeing an 'Archive All' button when viewing archived content.

Suggested fix:

Either restore the `!showArchived` guard on the button visibility, or filter out already-archived tasks in handleArchiveAll: `const doneTaskIds = tasksByStatus.done.filter(t => !t.metadata?.archivedAt).map(t => t.id);`

This review was generated by Auto Claude.

Fixes:
- Use ViewStateContext instead of local showArchived state for cross-view sync
- Simplify repetitive ternary pattern using spread operator
- Add showArchived guard to Archive All button to prevent re-archiving

Details:
1. HIGH: Duplicate showArchived state breaks ViewStateContext cross-view sync
   - Removed local showArchived state from App.tsx
   - Updated ProjectTabBarWithContext to use useViewState() hook
   - Updated KanbanBoard to use useViewState() instead of prop
   - Removed unused showArchived/onToggleArchived/archivedCount from DroppableColumnProps
   - Now KanbanBoard and Ideation share the same ViewStateContext state

2. LOW: Repetitive ternary pattern for conditional prop passing
   - Computed isKanban once and created kanbanOnlyProps object
   - Used spread operator {...kanbanOnlyProps} for cleaner code

3. LOW: Archive All button lost showArchived guard
   - Added useViewState() hook in DroppableColumn
   - Added !showArchived guard to Archive All button condition
   - Prevents re-archiving already-archived tasks

Verified:
- TypeScript type checking passes
- All PR review issues resolved

PR Review: AndyMik90#1900
QA Fix Session: 1

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@fireapache fireapache marked this pull request as ready for review February 25, 2026 13:39
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/frontend/src/renderer/App.tsx (1)

79-122: 🛠️ Refactor suggestion | 🟠 Major

Migrate showArchived state from React context to a Zustand store.

ProjectTabBarWithContext reads showArchived from ViewStateContext, a plain React context at apps/frontend/src/renderer/contexts/ViewStateContext.tsx. Per coding guidelines, all frontend state management must use Zustand stores in src/renderer/stores/. Since showArchived is cross-view shared state (used across Kanban, Ideation, and other views), it belongs in a domain store such as ui-store.ts or within an existing domain store like task-store.ts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/App.tsx` around lines 79 - 122, Replace the React
context usage in ProjectTabBarWithContext by reading and mutating the archived
flag from the Zustand UI/domain store instead of useViewState: remove the
useViewState() call and instead import and call the appropriate store hook
(e.g., useUiStore or useTaskStore) to select showArchived and the toggle action
(e.g., const { showArchived, toggleShowArchived } = useUiStore(s => ({
showArchived: s.showArchived, toggleShowArchived: s.toggleShowArchived }))).
Keep the archivedCount computation using tasks unchanged, and pass the
store-derived showArchived and toggleShowArchived into ProjectTabBar (props
showArchived and onToggleArchived). Ensure you add the selector shape/name that
matches the chosen store (create one if needed in the store file) so
ProjectTabBarWithContext references the correct functions/fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/frontend/src/renderer/App.tsx`:
- Line 73: Replace the relative import for the ViewState context with the
project path alias: change the import of ViewStateProvider and useViewState in
App.tsx to use the "@/..." alias (referencing the same module that currently
exports ViewStateProvider and useViewState) so imports use the renderer path
alias per tsconfig instead of a relative path.

In `@apps/frontend/src/renderer/components/KanbanBoard.tsx`:
- Around line 1393-1409: The Expand All button is only rendered when
collapsedColumnCount >= 3 so it’s hidden when 1–2 columns are collapsed; change
the conditional in the KanbanBoard JSX to use a lower threshold (e.g.,
collapsedColumnCount >= 1 or >= 2) so the Button (onClick={handleExpandAll},
label t('tasks:kanban.expandAll')) is shown earlier, and update the surrounding
comment string that currently says "appears when 3+ columns are collapsed" to
reflect the new threshold.

In `@apps/frontend/src/renderer/components/ProjectTabBar.tsx`:
- Line 40: Remove the unused 'tasks' namespace from the useTranslation call in
ProjectTabBar.tsx: update the useTranslation invocation (const { t } =
useTranslation(['common', 'tasks'])) to only request the 'common' namespace
since all t() usages are prefixed with 'common:' and 'tasks' is never
referenced; this will eliminate the unnecessary bundle import while leaving the
t binding and its existing calls unchanged.
- Around line 167-194: The toggle disappears when archivedCount === 0 but
showArchived may still be true; update the render condition in ProjectTabBar so
the Archived Button is shown if onToggleArchived is present and either
archivedCount > 0 or showArchived is true (i.e. replace the current conditional
with onToggleArchived && (archivedCount > 0 || showArchived)). Also ensure the
badge/number span renders only when archivedCount > 0 so it doesn't display "0"
when there are no archived items.

---

Outside diff comments:
In `@apps/frontend/src/renderer/App.tsx`:
- Around line 79-122: Replace the React context usage in
ProjectTabBarWithContext by reading and mutating the archived flag from the
Zustand UI/domain store instead of useViewState: remove the useViewState() call
and instead import and call the appropriate store hook (e.g., useUiStore or
useTaskStore) to select showArchived and the toggle action (e.g., const {
showArchived, toggleShowArchived } = useUiStore(s => ({ showArchived:
s.showArchived, toggleShowArchived: s.toggleShowArchived }))). Keep the
archivedCount computation using tasks unchanged, and pass the store-derived
showArchived and toggleShowArchived into ProjectTabBar (props showArchived and
onToggleArchived). Ensure you add the selector shape/name that matches the
chosen store (create one if needed in the store file) so
ProjectTabBarWithContext references the correct functions/fields.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60c4890 and 1f63c2e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (7)
  • .secretsignore
  • apps/frontend/src/renderer/App.tsx
  • apps/frontend/src/renderer/components/KanbanBoard.tsx
  • apps/frontend/src/renderer/components/ProjectTabBar.tsx
  • apps/frontend/src/renderer/components/SortableProjectTab.tsx
  • apps/frontend/src/shared/i18n/locales/en/common.json
  • apps/frontend/src/shared/i18n/locales/fr/common.json

import { ProjectTabBar } from './components/ProjectTabBar';
import { AddProjectModal } from './components/AddProjectModal';
import { ViewStateProvider } from './contexts/ViewStateContext';
import { ViewStateProvider, useViewState } from './contexts/ViewStateContext';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use the @/* path alias instead of a relative path.

Line 73 introduces a new relative import in the renderer. Per coding guidelines, all renderer imports should use the @/* path alias.

♻️ Proposed fix
-import { ViewStateProvider, useViewState } from './contexts/ViewStateContext';
+import { ViewStateProvider, useViewState } from '@/contexts/ViewStateContext';

As per coding guidelines: "Use path aliases from tsconfig.json in frontend code: @/* for renderer".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { ViewStateProvider, useViewState } from './contexts/ViewStateContext';
import { ViewStateProvider, useViewState } from '@/contexts/ViewStateContext';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/App.tsx` at line 73, Replace the relative import
for the ViewState context with the project path alias: change the import of
ViewStateProvider and useViewState in App.tsx to use the "@/..." alias
(referencing the same module that currently exports ViewStateProvider and
useViewState) so imports use the renderer path alias per tsconfig instead of a
relative path.

Comment on lines +1393 to 1409
{/* Kanban header with expand all button */}
{collapsedColumnCount >= 3 && (
<div className="flex items-center justify-between px-6 pt-4 pb-2">
<div className="flex items-center gap-2">
{/* Expand All button - appears when 3+ columns are collapsed */}
{collapsedColumnCount >= 3 && (
<Button
variant="outline"
size="sm"
onClick={handleExpandAll}
className="gap-2 text-muted-foreground hover:text-foreground"
>
<ChevronsRight className="h-4 w-4" />
{t('tasks:kanban.expandAll')}
</Button>
)}
</div>
<div className="flex items-center gap-2">
{onRefresh && (
<Button
variant="ghost"
size="sm"
onClick={onRefresh}
disabled={isRefreshing}
className="gap-2 text-muted-foreground hover:text-foreground"
>
<RefreshCw className={cn("h-4 w-4", isRefreshing && "animate-spin")} />
{isRefreshing ? t('common:buttons.refreshing') : t('tasks:refreshTasks')}
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={handleExpandAll}
className="gap-2 text-muted-foreground hover:text-foreground"
>
<ChevronsRight className="h-4 w-4" />
{t('tasks:kanban.expandAll')}
</Button>
</div>
</div>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor UX gap: "Expand All" is hidden when fewer than 3 columns are collapsed.

With 1 or 2 columns collapsed, collapsedColumnCount >= 3 evaluates to false and the entire header (including the only available "Expand All" shortcut) is hidden. Users must expand each collapsed column individually via the per-column button. Consider lowering the threshold to >= 1 or >= 2 to surface the convenience button earlier.

💡 Suggested threshold adjustment
-      {collapsedColumnCount >= 3 && (
+      {collapsedColumnCount >= 1 && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/components/KanbanBoard.tsx` around lines 1393 -
1409, The Expand All button is only rendered when collapsedColumnCount >= 3 so
it’s hidden when 1–2 columns are collapsed; change the conditional in the
KanbanBoard JSX to use a lower threshold (e.g., collapsedColumnCount >= 1 or >=
2) so the Button (onClick={handleExpandAll}, label t('tasks:kanban.expandAll'))
is shown earlier, and update the surrounding comment string that currently says
"appears when 3+ columns are collapsed" to reflect the new threshold.

archivedCount = 0
}: ProjectTabBarProps) {
const { t } = useTranslation('common');
const { t } = useTranslation(['common', 'tasks']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove the unused 'tasks' namespace from useTranslation.

Every t() call in this file uses the 'common:' prefix. The 'tasks' namespace is never referenced and adds an unnecessary bundle import.

♻️ Proposed fix
-  const { t } = useTranslation(['common', 'tasks']);
+  const { t } = useTranslation(['common']);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { t } = useTranslation(['common', 'tasks']);
const { t } = useTranslation(['common']);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/components/ProjectTabBar.tsx` at line 40, Remove
the unused 'tasks' namespace from the useTranslation call in ProjectTabBar.tsx:
update the useTranslation invocation (const { t } = useTranslation(['common',
'tasks'])) to only request the 'common' namespace since all t() usages are
prefixed with 'common:' and 'tasks' is never referenced; this will eliminate the
unnecessary bundle import while leaving the t binding and its existing calls
unchanged.

Comment on lines +167 to +194
{/* Show Archived button */}
{onToggleArchived && archivedCount > 0 && (
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className={cn(
"h-8 w-8 relative flex-shrink-0",
showArchived
? "text-primary bg-primary/10 hover:bg-primary/20"
: "hover:bg-muted-foreground/10 hover:text-muted-foreground"
)}
onClick={onToggleArchived}
aria-pressed={showArchived}
aria-label={t('common:accessibility.toggleShowArchivedAriaLabel')}
>
<Archive className="h-4 w-4" />
<span className="absolute -top-1 -right-1 text-[10px] font-medium bg-muted rounded-full min-w-[14px] h-[14px] flex items-center justify-center">
{archivedCount}
</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
<span>{showArchived ? t('common:projectTab.hideArchived') : t('common:projectTab.showArchived')}</span>
</TooltipContent>
</Tooltip>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

showArchived state persists invisibly when archivedCount drops to zero.

When showArchived is true (archived tasks are shown) but all archived tasks are then deleted or un-archived, archivedCount becomes 0, causing the toggle to disappear. The context state remains showArchived = true, but there is no visible control to reset it. If new tasks are later archived they will immediately be visible, which is the correct behavior — but the user has no affordance to opt out of archived mode while archivedCount === 0.

Consider either rendering the toggle regardless of archivedCount when showArchived is true, or resetting showArchived when archivedCount reaches zero.

💡 Option: always render when already active
-        {onToggleArchived && archivedCount > 0 && (
+        {onToggleArchived && (archivedCount > 0 || showArchived) && (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{/* Show Archived button */}
{onToggleArchived && archivedCount > 0 && (
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className={cn(
"h-8 w-8 relative flex-shrink-0",
showArchived
? "text-primary bg-primary/10 hover:bg-primary/20"
: "hover:bg-muted-foreground/10 hover:text-muted-foreground"
)}
onClick={onToggleArchived}
aria-pressed={showArchived}
aria-label={t('common:accessibility.toggleShowArchivedAriaLabel')}
>
<Archive className="h-4 w-4" />
<span className="absolute -top-1 -right-1 text-[10px] font-medium bg-muted rounded-full min-w-[14px] h-[14px] flex items-center justify-center">
{archivedCount}
</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
<span>{showArchived ? t('common:projectTab.hideArchived') : t('common:projectTab.showArchived')}</span>
</TooltipContent>
</Tooltip>
)}
{/* Show Archived button */}
{onToggleArchived && (archivedCount > 0 || showArchived) && (
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className={cn(
"h-8 w-8 relative flex-shrink-0",
showArchived
? "text-primary bg-primary/10 hover:bg-primary/20"
: "hover:bg-muted-foreground/10 hover:text-muted-foreground"
)}
onClick={onToggleArchived}
aria-pressed={showArchived}
aria-label={t('common:accessibility.toggleShowArchivedAriaLabel')}
>
<Archive className="h-4 w-4" />
<span className="absolute -top-1 -right-1 text-[10px] font-medium bg-muted rounded-full min-w-[14px] h-[14px] flex items-center justify-center">
{archivedCount}
</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
<span>{showArchived ? t('common:projectTab.hideArchived') : t('common:projectTab.showArchived')}</span>
</TooltipContent>
</Tooltip>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/components/ProjectTabBar.tsx` around lines 167 -
194, The toggle disappears when archivedCount === 0 but showArchived may still
be true; update the render condition in ProjectTabBar so the Archived Button is
shown if onToggleArchived is present and either archivedCount > 0 or
showArchived is true (i.e. replace the current conditional with onToggleArchived
&& (archivedCount > 0 || showArchived)). Also ensure the badge/number span
renders only when archivedCount > 0 so it doesn't display "0" when there are no
archived items.

@AndyMik90 AndyMik90 self-assigned this Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants