diff --git a/.design-system/src/App.tsx b/.design-system/src/App.tsx index 7dab6604..69391a10 100644 --- a/.design-system/src/App.tsx +++ b/.design-system/src/App.tsx @@ -53,11 +53,11 @@ export default function App() {
{/* Header */}
- +

Auto-Build Design System

-

+

A modern, friendly design system for building beautiful interfaces

@@ -118,8 +118,8 @@ export default function App() {

Color Palette

-

- Currently showing: {currentThemeInfo.name} theme +

+ Currently showing: {currentThemeInfo.name} theme

@@ -128,14 +128,14 @@ export default function App() {

Background

-
+

Primary

-

--bg-primary

+

--bg-primary

-
+

Secondary

-

--bg-secondary

+

--bg-secondary

@@ -144,19 +144,19 @@ export default function App() {

Accent

-
+

Primary

-

--accent

+

--accent

-
+

Hover

-

--accent-hover

+

--accent-hover

-
+

Light

-

--accent-light

+

--accent-light

@@ -165,24 +165,24 @@ export default function App() {

Semantic

-
+

Success

-

--success

+

--success

-
+

Warning

-

--warning

+

--warning

-
+

Error

-

--error

+

--error

-
+

Info

-

--info

+

--info

@@ -191,29 +191,29 @@ export default function App() {

Text

-
+

Primary

-

--text-primary

+

--text-primary

-
+

Secondary

-

--text-secondary

+

--text-secondary

-
+

Tertiary

-

--text-tertiary

+

--text-tertiary

{/* Theme-specific color values */} -
-

+

+

Note: Colors vary by theme and mode. Switch themes using the dropdown above to see different palettes. - For specific hex values, see the Themes tab or check design.json. + For specific hex values, see the Themes tab or check design.json.

@@ -226,36 +226,36 @@ export default function App() {

Typography Scale

-
-

Display Large • 36px / 700

+
+

Display Large • 36px / 700

The quick brown fox jumps

-
-

Display Medium • 30px / 700

+
+

Display Medium • 30px / 700

The quick brown fox jumps over

-
-

Heading Large • 24px / 600

+
+

Heading Large • 24px / 600

The quick brown fox jumps over the lazy dog

-
-

Heading Medium • 20px / 600

+
+

Heading Medium • 20px / 600

The quick brown fox jumps over the lazy dog

-
-

Heading Small • 16px / 600

+
+

Heading Small • 16px / 600

The quick brown fox jumps over the lazy dog

-
-

Body Large • 16px / 400

+
+

Body Large • 16px / 400

The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.

-
-

Body Medium • 14px / 400

+
+

Body Medium • 14px / 400

The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.

-

Body Small • 12px / 400

+

Body Small • 12px / 400

The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.

@@ -392,7 +392,7 @@ export default function App() {

Animations

-

+

Animation demos are available in the original file. Extract them to a separate AnimationsSection component for better organization.

@@ -404,26 +404,26 @@ export default function App() {
-
- +
+

Theme Gallery

-

+

{themes.length} color themes × 2 modes = {themes.length * 2} combinations

{/* Mode Toggle */} -
+

February, 2021

-
{days.map((day, i) => ( -
+
{day}
))} @@ -39,11 +39,11 @@ export function CalendarCard() {
-
@@ -42,19 +42,19 @@ export function NotificationsCard() {

Ashlynn George - · 1h + · 1h

-

+

changed status of task in "Magma project"

-
-
+
diff --git a/.design-system/src/demo-cards/ProfileCard.tsx b/.design-system/src/demo-cards/ProfileCard.tsx index 523ec986..1bfed023 100644 --- a/.design-system/src/demo-cards/ProfileCard.tsx +++ b/.design-system/src/demo-cards/ProfileCard.tsx @@ -5,14 +5,14 @@ export function ProfileCard() { return (
-

Christine Thompson

-

Project manager

+

Project manager

UI/UX Design Project management diff --git a/.design-system/src/demo-cards/ProjectStatusCard.tsx b/.design-system/src/demo-cards/ProjectStatusCard.tsx index 1e3266bc..84e96f05 100644 --- a/.design-system/src/demo-cards/ProjectStatusCard.tsx +++ b/.design-system/src/demo-cards/ProjectStatusCard.tsx @@ -6,13 +6,13 @@ export function ProjectStatusCard() {
-

Amber website redesign

-

+

In today's fast-paced digital landscape, our mission is to transform our website into a more intuitive, engaging, and user-friendly platfor...

diff --git a/.design-system/src/demo-cards/TeamMembersCard.tsx b/.design-system/src/demo-cards/TeamMembersCard.tsx index 97e13d80..111d8d93 100644 --- a/.design-system/src/demo-cards/TeamMembersCard.tsx +++ b/.design-system/src/demo-cards/TeamMembersCard.tsx @@ -11,25 +11,25 @@ export function TeamMembersCard() { return ( -
+
{members.map((member, i) => (

{member.name}

-

{member.role}

+

{member.role}

- -
))}
-
+
Stripe
VISA
PayPal
diff --git a/.design-system/src/theme/ThemeSelector.tsx b/.design-system/src/theme/ThemeSelector.tsx index 1006174b..e5e0b9cb 100644 --- a/.design-system/src/theme/ThemeSelector.tsx +++ b/.design-system/src/theme/ThemeSelector.tsx @@ -29,7 +29,7 @@ export function ThemeSelector({
@@ -48,7 +48,7 @@ export function ThemeSelector({ className="fixed inset-0 z-40" onClick={() => setIsOpen(false)} /> -
+
{themes.map((theme) => ( ))} @@ -90,13 +90,13 @@ export function ThemeSelector({ {/* Light/Dark Toggle */}
diff --git a/.github/workflows/discord-release.yml b/.github/workflows/discord-release.yml index f0714e5c..63460eda 100644 --- a/.github/workflows/discord-release.yml +++ b/.github/workflows/discord-release.yml @@ -21,3 +21,4 @@ jobs: footer_title: "Auto Claude Changelog" footer_timestamp: true reduce_headings: true + diff --git a/auto-claude-ui/src/main/ipc-handlers/ideation-handlers.ts b/auto-claude-ui/src/main/ipc-handlers/ideation-handlers.ts index 9fcfa731..984ff53e 100644 --- a/auto-claude-ui/src/main/ipc-handlers/ideation-handlers.ts +++ b/auto-claude-ui/src/main/ipc-handlers/ideation-handlers.ts @@ -21,6 +21,9 @@ import { updateIdeaStatus, dismissIdea, dismissAllIdeas, + archiveIdea, + deleteIdea, + deleteMultipleIdeas, startIdeationGeneration, refreshIdeationSession, stopIdeationGeneration, @@ -56,6 +59,21 @@ export function registerIdeationHandlers( dismissAllIdeas ); + ipcMain.handle( + IPC_CHANNELS.IDEATION_ARCHIVE, + archiveIdea + ); + + ipcMain.handle( + IPC_CHANNELS.IDEATION_DELETE, + deleteIdea + ); + + ipcMain.handle( + IPC_CHANNELS.IDEATION_DELETE_MULTIPLE, + deleteMultipleIdeas + ); + // Generation operations ipcMain.on( IPC_CHANNELS.IDEATION_GENERATE, diff --git a/auto-claude-ui/src/main/ipc-handlers/ideation/idea-manager.ts b/auto-claude-ui/src/main/ipc-handlers/ideation/idea-manager.ts index 6934195c..5782343b 100644 --- a/auto-claude-ui/src/main/ipc-handlers/ideation/idea-manager.ts +++ b/auto-claude-ui/src/main/ipc-handlers/ideation/idea-manager.ts @@ -142,3 +142,132 @@ export async function dismissAllIdeas( }; } } + +/** + * Archive a single idea (typically when converted to task) + */ +export async function archiveIdea( + _event: IpcMainInvokeEvent, + projectId: string, + ideaId: string +): Promise { + const project = projectStore.getProject(projectId); + if (!project) { + return { success: false, error: 'Project not found' }; + } + + const ideationPath = path.join( + project.path, + AUTO_BUILD_PATHS.IDEATION_DIR, + AUTO_BUILD_PATHS.IDEATION_FILE + ); + + const ideation = readIdeationFile(ideationPath); + if (!ideation) { + return { success: false, error: 'Ideation not found' }; + } + + try { + const idea = ideation.ideas?.find((i) => i.id === ideaId); + if (!idea) { + return { success: false, error: 'Idea not found' }; + } + + idea.status = 'archived'; + updateIdeationTimestamp(ideation); + writeIdeationFile(ideationPath, ideation); + + return { success: true }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to archive idea' + }; + } +} + +/** + * Delete a single idea permanently + */ +export async function deleteIdea( + _event: IpcMainInvokeEvent, + projectId: string, + ideaId: string +): Promise { + const project = projectStore.getProject(projectId); + if (!project) { + return { success: false, error: 'Project not found' }; + } + + const ideationPath = path.join( + project.path, + AUTO_BUILD_PATHS.IDEATION_DIR, + AUTO_BUILD_PATHS.IDEATION_FILE + ); + + const ideation = readIdeationFile(ideationPath); + if (!ideation) { + return { success: false, error: 'Ideation not found' }; + } + + try { + const ideaIndex = ideation.ideas?.findIndex((i) => i.id === ideaId); + if (ideaIndex === undefined || ideaIndex === -1) { + return { success: false, error: 'Idea not found' }; + } + + ideation.ideas?.splice(ideaIndex, 1); + updateIdeationTimestamp(ideation); + writeIdeationFile(ideationPath, ideation); + + return { success: true }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to delete idea' + }; + } +} + +/** + * Delete multiple ideas permanently + */ +export async function deleteMultipleIdeas( + _event: IpcMainInvokeEvent, + projectId: string, + ideaIds: string[] +): Promise { + const project = projectStore.getProject(projectId); + if (!project) { + return { success: false, error: 'Project not found' }; + } + + const ideationPath = path.join( + project.path, + AUTO_BUILD_PATHS.IDEATION_DIR, + AUTO_BUILD_PATHS.IDEATION_FILE + ); + + const ideation = readIdeationFile(ideationPath); + if (!ideation) { + return { success: false, error: 'Ideation not found' }; + } + + try { + const idsToDelete = new Set(ideaIds); + const originalCount = ideation.ideas?.length || 0; + + ideation.ideas = ideation.ideas?.filter((idea) => !idsToDelete.has(idea.id)) || []; + + const deletedCount = originalCount - (ideation.ideas?.length || 0); + updateIdeationTimestamp(ideation); + writeIdeationFile(ideationPath, ideation); + + return { success: true, data: { deletedCount } }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to delete ideas' + }; + } +} diff --git a/auto-claude-ui/src/main/ipc-handlers/ideation/task-converter.ts b/auto-claude-ui/src/main/ipc-handlers/ideation/task-converter.ts index 065eeeec..addc764c 100644 --- a/auto-claude-ui/src/main/ipc-handlers/ideation/task-converter.ts +++ b/auto-claude-ui/src/main/ipc-handlers/ideation/task-converter.ts @@ -258,8 +258,8 @@ export async function convertIdeaToTask( const metadataPath = path.join(specDir, 'task_metadata.json'); writeFileSync(metadataPath, JSON.stringify(metadata, null, 2)); - // Update idea status - idea.status = 'converted'; + // Update idea status to archived (converted ideas are archived) + idea.status = 'archived'; idea.linked_task_id = specId; updateIdeationTimestamp(ideation); writeIdeationFile(ideationPath, ideation); diff --git a/auto-claude-ui/src/main/log-service.ts b/auto-claude-ui/src/main/log-service.ts index edede01a..5fe51bfc 100644 --- a/auto-claude-ui/src/main/log-service.ts +++ b/auto-claude-ui/src/main/log-service.ts @@ -339,3 +339,4 @@ export class LogService { // Singleton instance export const logService = new LogService(); + diff --git a/auto-claude-ui/src/main/notification-service.ts b/auto-claude-ui/src/main/notification-service.ts index 8d6d1571..ad4fe010 100644 --- a/auto-claude-ui/src/main/notification-service.ts +++ b/auto-claude-ui/src/main/notification-service.ts @@ -162,3 +162,4 @@ class NotificationService { // Export singleton instance export const notificationService = new NotificationService(); + diff --git a/auto-claude-ui/src/main/python-env-manager.ts b/auto-claude-ui/src/main/python-env-manager.ts index 830a2616..0fc9d50f 100644 --- a/auto-claude-ui/src/main/python-env-manager.ts +++ b/auto-claude-ui/src/main/python-env-manager.ts @@ -362,3 +362,4 @@ export class PythonEnvManager extends EventEmitter { // Singleton instance export const pythonEnvManager = new PythonEnvManager(); + diff --git a/auto-claude-ui/src/main/release-service.ts b/auto-claude-ui/src/main/release-service.ts index b1a8173e..640c6d11 100644 --- a/auto-claude-ui/src/main/release-service.ts +++ b/auto-claude-ui/src/main/release-service.ts @@ -602,3 +602,4 @@ export class ReleaseService extends EventEmitter { // Export singleton instance export const releaseService = new ReleaseService(); + diff --git a/auto-claude-ui/src/preload/api/index.ts b/auto-claude-ui/src/preload/api/index.ts index 5b0d393d..73727b74 100644 --- a/auto-claude-ui/src/preload/api/index.ts +++ b/auto-claude-ui/src/preload/api/index.ts @@ -4,6 +4,7 @@ import { TaskAPI, createTaskAPI } from './task-api'; import { SettingsAPI, createSettingsAPI } from './settings-api'; import { FileAPI, createFileAPI } from './file-api'; import { AgentAPI, createAgentAPI } from './agent-api'; +import { IdeationAPI, createIdeationAPI } from './modules/ideation-api'; export interface ElectronAPI extends ProjectAPI, @@ -11,7 +12,8 @@ export interface ElectronAPI extends TaskAPI, SettingsAPI, FileAPI, - AgentAPI {} + AgentAPI, + IdeationAPI {} export const createElectronAPI = (): ElectronAPI => ({ ...createProjectAPI(), @@ -19,7 +21,8 @@ export const createElectronAPI = (): ElectronAPI => ({ ...createTaskAPI(), ...createSettingsAPI(), ...createFileAPI(), - ...createAgentAPI() + ...createAgentAPI(), + ...createIdeationAPI() }); // Export individual API creators for potential use in tests or specialized contexts @@ -29,7 +32,8 @@ export { createTaskAPI, createSettingsAPI, createFileAPI, - createAgentAPI + createAgentAPI, + createIdeationAPI }; export type { @@ -38,5 +42,6 @@ export type { TaskAPI, SettingsAPI, FileAPI, - AgentAPI + AgentAPI, + IdeationAPI }; diff --git a/auto-claude-ui/src/preload/api/modules/ideation-api.ts b/auto-claude-ui/src/preload/api/modules/ideation-api.ts index 68f305df..341e7e1c 100644 --- a/auto-claude-ui/src/preload/api/modules/ideation-api.ts +++ b/auto-claude-ui/src/preload/api/modules/ideation-api.ts @@ -23,6 +23,9 @@ export interface IdeationAPI { convertIdeaToTask: (projectId: string, ideaId: string) => Promise>; dismissIdea: (projectId: string, ideaId: string) => Promise; dismissAllIdeas: (projectId: string) => Promise; + archiveIdea: (projectId: string, ideaId: string) => Promise; + deleteIdea: (projectId: string, ideaId: string) => Promise; + deleteMultipleIdeas: (projectId: string, ideaIds: string[]) => Promise; // Event Listeners onIdeationProgress: ( @@ -77,6 +80,15 @@ export const createIdeationAPI = (): IdeationAPI => ({ dismissAllIdeas: (projectId: string): Promise => invokeIpc(IPC_CHANNELS.IDEATION_DISMISS_ALL, projectId), + archiveIdea: (projectId: string, ideaId: string): Promise => + invokeIpc(IPC_CHANNELS.IDEATION_ARCHIVE, projectId, ideaId), + + deleteIdea: (projectId: string, ideaId: string): Promise => + invokeIpc(IPC_CHANNELS.IDEATION_DELETE, projectId, ideaId), + + deleteMultipleIdeas: (projectId: string, ideaIds: string[]): Promise => + invokeIpc(IPC_CHANNELS.IDEATION_DELETE_MULTIPLE, projectId, ideaIds), + // Event Listeners onIdeationProgress: ( callback: (projectId: string, status: IdeationGenerationStatus) => void diff --git a/auto-claude-ui/src/renderer/components/RoadmapKanbanView.tsx b/auto-claude-ui/src/renderer/components/RoadmapKanbanView.tsx index d13d604c..e42f214e 100644 --- a/auto-claude-ui/src/renderer/components/RoadmapKanbanView.tsx +++ b/auto-claude-ui/src/renderer/components/RoadmapKanbanView.tsx @@ -77,7 +77,7 @@ function DroppablePhaseColumn({
{phase.order}
-

+

{phase.name}

@@ -330,7 +330,7 @@ export function RoadmapKanbanView({ {activeFeature ? (
- +
{activeFeature.title}

{activeFeature.description} diff --git a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx index fcd8e905..8eb5eae1 100644 --- a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx +++ b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx @@ -456,9 +456,9 @@ export function TaskCreationWizard({ showFileExplorer ? "sm:max-w-[900px]" : "sm:max-w-[550px]" )} > -

+
{/* Form content */} -
+
Create New Task @@ -500,6 +500,7 @@ export function TaskCreationWizard({ onPaste={handlePaste} rows={5} disabled={isCreating} + className="resize-y min-h-[120px] max-h-[400px]" />

Tip: Paste screenshots directly with {navigator.platform.includes('Mac') ? '⌘V' : 'Ctrl+V'} to add reference images. diff --git a/auto-claude-ui/src/renderer/components/github-issues/components/InvestigationDialog.tsx b/auto-claude-ui/src/renderer/components/github-issues/components/InvestigationDialog.tsx index 7ee6f76c..532f0894 100644 --- a/auto-claude-ui/src/renderer/components/github-issues/components/InvestigationDialog.tsx +++ b/auto-claude-ui/src/renderer/components/github-issues/components/InvestigationDialog.tsx @@ -25,12 +25,12 @@ export function InvestigationDialog({ - AI Investigation + Create Task from Issue {selectedIssue && ( - Investigating issue #{selectedIssue.number}: {selectedIssue.title} + Issue #{selectedIssue.number}: {selectedIssue.title} )} @@ -39,16 +39,15 @@ export function InvestigationDialog({ {investigationStatus.phase === 'idle' ? (

- The AI will analyze this issue, examine relevant code, and create a planned task in your Kanban board. + Create a task from this GitHub issue. The task will be added to your Kanban board in the Planned column.

-

What the AI will do:

+

The task will include:

    -
  • - Analyze the issue description and comments
  • -
  • - Identify affected files and components
  • -
  • - Estimate complexity and effort
  • -
  • - Create acceptance criteria
  • -
  • - Generate a task spec for implementation
  • +
  • • Issue title and description
  • +
  • • Link back to the GitHub issue
  • +
  • • Labels and metadata from the issue
  • +
  • • Ready to start when you move it to In Progress
@@ -71,7 +70,7 @@ export function InvestigationDialog({ {investigationStatus.phase === 'complete' && (
- Investigation complete! Task created in Kanban board. + Task created! View it in your Kanban board.
)}
@@ -85,14 +84,14 @@ export function InvestigationDialog({ )} {investigationStatus.phase !== 'idle' && investigationStatus.phase !== 'complete' && ( )} {investigationStatus.phase === 'complete' && ( diff --git a/auto-claude-ui/src/renderer/components/github-issues/components/IssueDetail.tsx b/auto-claude-ui/src/renderer/components/github-issues/components/IssueDetail.tsx index 981bb26d..fbb45423 100644 --- a/auto-claude-ui/src/renderer/components/github-issues/components/IssueDetail.tsx +++ b/auto-claude-ui/src/renderer/components/github-issues/components/IssueDetail.tsx @@ -79,17 +79,17 @@ export function IssueDetail({ issue, onInvestigate, investigationResult }: Issue
- {/* Investigation Result */} + {/* Task Created Result */} {investigationResult?.success && ( - Investigation Complete + Task Created diff --git a/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubInvestigation.ts b/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubInvestigation.ts index 28656505..54be9310 100644 --- a/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubInvestigation.ts +++ b/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubInvestigation.ts @@ -1,5 +1,6 @@ import { useEffect, useCallback } from 'react'; import { useGitHubStore, investigateGitHubIssue } from '../../../stores/github-store'; +import { loadTasks } from '../../../stores/task-store'; import type { GitHubIssue } from '../../../../shared/types'; export function useGitHubInvestigation(projectId: string | undefined) { @@ -27,6 +28,10 @@ export function useGitHubInvestigation(projectId: string | undefined) { (eventProjectId, result) => { if (eventProjectId === projectId) { setInvestigationResult(result); + // Refresh the task store so the new task appears on the Kanban board + if (result.success && result.taskId) { + loadTasks(projectId); + } } } ); diff --git a/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubIssues.ts b/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubIssues.ts index dd51c7f3..9229848b 100644 --- a/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubIssues.ts +++ b/auto-claude-ui/src/renderer/components/github-issues/hooks/useGitHubIssues.ts @@ -1,4 +1,4 @@ -import { useEffect, useCallback } from 'react'; +import { useEffect, useCallback, useRef } from 'react'; import { useGitHubStore, loadGitHubIssues, checkGitHubConnection } from '../../../stores/github-store'; import type { FilterState } from '../types'; @@ -16,16 +16,29 @@ export function useGitHubIssues(projectId: string | undefined) { getOpenIssuesCount } = useGitHubStore(); - // Load issues when project changes + // Track if we've checked connection for this mount + const hasCheckedRef = useRef(false); + + // Always check connection when component mounts or projectId changes useEffect(() => { if (projectId) { + // Always check connection on mount (in case settings changed) checkGitHubConnection(projectId); + hasCheckedRef.current = true; + } + }, [projectId]); + + // Load issues when filter changes or after connection is established + useEffect(() => { + if (projectId && syncStatus?.connected) { loadGitHubIssues(projectId, filterState); } - }, [projectId, filterState]); + }, [projectId, filterState, syncStatus?.connected]); const handleRefresh = useCallback(() => { if (projectId) { + // Re-check connection and reload issues + checkGitHubConnection(projectId); loadGitHubIssues(projectId, filterState); } }, [projectId, filterState]); diff --git a/auto-claude-ui/src/renderer/components/ideation/GenerationProgressScreen.tsx b/auto-claude-ui/src/renderer/components/ideation/GenerationProgressScreen.tsx index 45c20c1f..070ac243 100644 --- a/auto-claude-ui/src/renderer/components/ideation/GenerationProgressScreen.tsx +++ b/auto-claude-ui/src/renderer/components/ideation/GenerationProgressScreen.tsx @@ -191,10 +191,12 @@ export function GenerationProgressScreen({ onSelectIdea(selectedIdea?.id === idea.id ? null : idea)} onConvert={onConvert} onGoToTask={onGoToTask} onDismiss={onDismiss} + onToggleSelect={() => {/* Selection disabled during generation */}} /> ))} diff --git a/auto-claude-ui/src/renderer/components/ideation/IdeaCard.tsx b/auto-claude-ui/src/renderer/components/ideation/IdeaCard.tsx index b02da32d..f2816d3a 100644 --- a/auto-claude-ui/src/renderer/components/ideation/IdeaCard.tsx +++ b/auto-claude-ui/src/renderer/components/ideation/IdeaCard.tsx @@ -1,8 +1,9 @@ -import { ExternalLink, Play, X } from 'lucide-react'; +import { ExternalLink, Play, X, Check } from 'lucide-react'; import { Button } from '../ui/button'; import { Badge } from '../ui/badge'; import { Card } from '../ui/card'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; +import { Checkbox } from '../ui/checkbox'; import { IDEATION_TYPE_LABELS, IDEATION_TYPE_COLORS, @@ -36,25 +37,45 @@ import { interface IdeaCardProps { idea: Idea; + isSelected: boolean; onClick: () => void; onConvert: (idea: Idea) => void; onGoToTask?: (taskId: string) => void; onDismiss: (idea: Idea) => void; + onToggleSelect: (ideaId: string) => void; } -export function IdeaCard({ idea, onClick, onConvert, onGoToTask, onDismiss }: IdeaCardProps) { +export function IdeaCard({ idea, isSelected, onClick, onConvert, onGoToTask, onDismiss, onToggleSelect }: IdeaCardProps) { const isDismissed = idea.status === 'dismissed'; + const isArchived = idea.status === 'archived'; const isConverted = idea.status === 'converted'; + const isInactive = isDismissed || isArchived; return ( -
-
+
+ {/* Selection checkbox */} +
{ + e.stopPropagation(); + onToggleSelect(idea.id); + }} + > + onToggleSelect(idea.id)} + className="data-[state=checked]:bg-primary data-[state=checked]:border-primary" + /> +
+ +
+
@@ -96,67 +117,91 @@ export function IdeaCard({ idea, onClick, onConvert, onGoToTask, onDismiss }: Id )}
-

+

{idea.title}

{idea.description}

+
+ {/* Action buttons */} + {!isInactive && !isConverted && ( +
+ + + + + Convert to Task + + + + + + Dismiss + +
+ )} + {/* Archived ideas show link to task */} + {isArchived && idea.taskId && onGoToTask && ( +
+ + + + + Go to Task + +
+ )} + {/* Legacy: converted status also shows link to task */} + {isConverted && idea.taskId && onGoToTask && ( +
+ + + + + Go to Task + +
+ )}
- {!isDismissed && !isConverted && ( -
- - - - - Convert to Task - - - - - - Dismiss - -
- )} - {isConverted && idea.taskId && onGoToTask && ( -
- - - - - Go to Task - -
- )}
); diff --git a/auto-claude-ui/src/renderer/components/ideation/Ideation.tsx b/auto-claude-ui/src/renderer/components/ideation/Ideation.tsx index a79481b1..2c1022ba 100644 --- a/auto-claude-ui/src/renderer/components/ideation/Ideation.tsx +++ b/auto-claude-ui/src/renderer/components/ideation/Ideation.tsx @@ -27,6 +27,7 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { activeTab, showConfigDialog, showDismissed, + showArchived, showEnvConfigModal, showAddMoreDialog, typesToAdd, @@ -34,10 +35,12 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { isCheckingToken, summary, activeIdeas, + selectedIds, setSelectedIdea, setActiveTab, setShowConfigDialog, setShowDismissed, + setShowArchived, setShowEnvConfigModal, setShowAddMoreDialog, setTypesToAdd, @@ -46,6 +49,8 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { handleRefresh, handleStop, handleDismissAll, + handleDeleteSelected, + handleSelectAll, handleEnvConfigured, getAvailableTypesToAdd, handleAddMoreIdeas, @@ -54,6 +59,8 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { handleGoToTask, handleDismiss, toggleIdeationType, + toggleSelectIdea, + clearSelection, getIdeasByType } = useIdeation(projectId, { onGoToTask }); @@ -121,13 +128,19 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { totalIdeas={summary.totalIdeas} ideaCountByType={summary.byType} showDismissed={showDismissed} + showArchived={showArchived} + selectedCount={selectedIds.size} onToggleShowDismissed={() => setShowDismissed(!showDismissed)} + onToggleShowArchived={() => setShowArchived(!showArchived)} onOpenConfig={() => setShowConfigDialog(true)} onOpenAddMore={() => { setTypesToAdd([]); setShowAddMoreDialog(true); }} onDismissAll={handleDismissAll} + onDeleteSelected={handleDeleteSelected} + onSelectAll={() => handleSelectAll(activeIdeas)} + onClearSelection={clearSelection} onRefresh={handleRefresh} hasActiveIdeas={activeIdeas.length > 0} canAddMore={getAvailableTypesToAdd().length > 0} @@ -143,10 +156,12 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { setSelectedIdea(selectedIdea?.id === idea.id ? null : idea)} onConvert={handleConvertToTask} onGoToTask={handleGoToTask} onDismiss={handleDismiss} + onToggleSelect={toggleSelectIdea} /> ))} {activeIdeas.length === 0 && ( @@ -158,29 +173,36 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) { {/* Type-specific Views */} - {ALL_IDEATION_TYPES.map((type) => ( - -
-

- {IDEATION_TYPE_DESCRIPTIONS[type]} -

-
-
- {getIdeasByType(type) - .filter((idea) => showDismissed || idea.status !== 'dismissed') - .map((idea) => ( + {ALL_IDEATION_TYPES.map((type) => { + const typeIdeas = getIdeasByType(type).filter((idea) => { + if (!showDismissed && idea.status === 'dismissed') return false; + if (!showArchived && idea.status === 'archived') return false; + return true; + }); + return ( + +
+

+ {IDEATION_TYPE_DESCRIPTIONS[type]} +

+
+
+ {typeIdeas.map((idea) => ( setSelectedIdea(selectedIdea?.id === idea.id ? null : idea)} onConvert={handleConvertToTask} onGoToTask={handleGoToTask} onDismiss={handleDismiss} + onToggleSelect={toggleSelectIdea} /> ))} -
-
- ))} +
+
+ ); + })}
diff --git a/auto-claude-ui/src/renderer/components/ideation/IdeationHeader.tsx b/auto-claude-ui/src/renderer/components/ideation/IdeationHeader.tsx index 19f99753..bf6ae373 100644 --- a/auto-claude-ui/src/renderer/components/ideation/IdeationHeader.tsx +++ b/auto-claude-ui/src/renderer/components/ideation/IdeationHeader.tsx @@ -1,4 +1,4 @@ -import { Lightbulb, Eye, EyeOff, Settings2, Plus, Trash2, RefreshCw } from 'lucide-react'; +import { Lightbulb, Eye, EyeOff, Settings2, Plus, Trash2, RefreshCw, Archive, CheckSquare, Square, X } from 'lucide-react'; import { Button } from '../ui/button'; import { Badge } from '../ui/badge'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; @@ -10,10 +10,16 @@ interface IdeationHeaderProps { totalIdeas: number; ideaCountByType: Record; showDismissed: boolean; + showArchived: boolean; + selectedCount: number; onToggleShowDismissed: () => void; + onToggleShowArchived: () => void; onOpenConfig: () => void; onOpenAddMore: () => void; onDismissAll: () => void; + onDeleteSelected: () => void; + onSelectAll: () => void; + onClearSelection: () => void; onRefresh: () => void; hasActiveIdeas: boolean; canAddMore: boolean; @@ -23,14 +29,21 @@ export function IdeationHeader({ totalIdeas, ideaCountByType, showDismissed, + showArchived, + selectedCount, onToggleShowDismissed, + onToggleShowArchived, onOpenConfig, onOpenAddMore, onDismissAll, + onDeleteSelected, + onSelectAll, + onClearSelection, onRefresh, hasActiveIdeas, canAddMore }: IdeationHeaderProps) { + const hasSelection = selectedCount > 0; return (
@@ -45,10 +58,62 @@ export function IdeationHeader({

+ {/* Selection controls */} + {hasSelection ? ( + <> + + {selectedCount} selected + + + + + + Delete selected ideas + + + + + + Clear selection + +
+ + ) : ( + hasActiveIdeas && ( + + + + + Select all + + ) + )} + + {/* View toggles */} + + + {showArchived ? 'Hide archived' : 'Show archived'} + +