mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
feat: implement backlog plan management and UI enhancements
- Added functionality to save, clear, and load backlog plans within the application. - Introduced a new API endpoint for clearing saved backlog plans. - Enhanced the backlog plan dialog to allow users to review and apply changes to their features. - Integrated dependency management features in the UI, allowing users to select parent and child dependencies for features. - Improved the graph view with options to manage plans and visualize dependencies effectively. - Updated the sidebar and settings to include provider visibility toggles for better user control over model selection. These changes aim to enhance the user experience by providing robust backlog management capabilities and improving the overall UI for feature planning.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { Plus, Bug, FolderOpen } from 'lucide-react';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { Plus, Bug, FolderOpen, BookOpen } from 'lucide-react';
|
||||
import { useNavigate, useLocation } from '@tanstack/react-router';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useAppStore, type ThemeMode } from '@/store/app-store';
|
||||
import { useOSDetection } from '@/hooks/use-os-detection';
|
||||
@@ -10,6 +10,7 @@ import { EditProjectDialog } from './components/edit-project-dialog';
|
||||
import { NewProjectModal } from '@/components/dialogs/new-project-modal';
|
||||
import { OnboardingDialog } from '@/components/layout/sidebar/dialogs';
|
||||
import { useProjectCreation, useProjectTheme } from '@/components/layout/sidebar/hooks';
|
||||
import { SIDEBAR_FEATURE_FLAGS } from '@/components/layout/sidebar/constants';
|
||||
import type { Project } from '@/lib/electron';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { initializeProject, hasAppSpec, hasAutomakerDir } from '@/lib/project-init';
|
||||
@@ -31,6 +32,9 @@ function getOSAbbreviation(os: string): string {
|
||||
|
||||
export function ProjectSwitcher() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { hideWiki } = SIDEBAR_FEATURE_FLAGS;
|
||||
const isWikiActive = location.pathname === '/wiki';
|
||||
const {
|
||||
projects,
|
||||
currentProject,
|
||||
@@ -124,6 +128,10 @@ export function ProjectSwitcher() {
|
||||
api.openExternalLink('https://github.com/AutoMaker-Org/automaker/issues');
|
||||
}, []);
|
||||
|
||||
const handleWikiClick = useCallback(() => {
|
||||
navigate({ to: '/wiki' });
|
||||
}, [navigate]);
|
||||
|
||||
/**
|
||||
* Opens the system folder selection dialog and initializes the selected project.
|
||||
*/
|
||||
@@ -405,8 +413,37 @@ export function ProjectSwitcher() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bug Report Button at the very bottom */}
|
||||
<div className="p-2 border-t border-border/40">
|
||||
{/* Wiki and Bug Report Buttons at the very bottom */}
|
||||
<div className="p-2 border-t border-border/40 space-y-2">
|
||||
{/* Wiki Button */}
|
||||
{!hideWiki && (
|
||||
<button
|
||||
onClick={handleWikiClick}
|
||||
className={cn(
|
||||
'w-full aspect-square rounded-xl flex items-center justify-center',
|
||||
'transition-all duration-200 ease-out',
|
||||
isWikiActive
|
||||
? [
|
||||
'bg-gradient-to-r from-brand-500/20 via-brand-500/15 to-brand-600/10',
|
||||
'text-foreground',
|
||||
'border border-brand-500/30',
|
||||
'shadow-md shadow-brand-500/10',
|
||||
]
|
||||
: [
|
||||
'text-muted-foreground hover:text-foreground',
|
||||
'hover:bg-accent/50 border border-transparent hover:border-border/40',
|
||||
'hover:shadow-sm hover:scale-105 active:scale-95',
|
||||
]
|
||||
)}
|
||||
title="Wiki"
|
||||
data-testid="wiki-button"
|
||||
>
|
||||
<BookOpen
|
||||
className={cn('w-5 h-5', isWikiActive && 'text-brand-500 drop-shadow-sm')}
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
{/* Bug Report Button */}
|
||||
<button
|
||||
onClick={handleBugReportClick}
|
||||
className={cn(
|
||||
|
||||
@@ -57,8 +57,7 @@ export function Sidebar() {
|
||||
} = useAppStore();
|
||||
|
||||
// Environment variable flags for hiding sidebar items
|
||||
const { hideTerminal, hideWiki, hideRunningAgents, hideContext, hideSpecEditor } =
|
||||
SIDEBAR_FEATURE_FLAGS;
|
||||
const { hideTerminal, hideRunningAgents, hideContext, hideSpecEditor } = SIDEBAR_FEATURE_FLAGS;
|
||||
|
||||
// Get customizable keyboard shortcuts
|
||||
const shortcuts = useKeyboardShortcutsConfig();
|
||||
@@ -297,7 +296,6 @@ export function Sidebar() {
|
||||
sidebarOpen={sidebarOpen}
|
||||
isActiveRoute={isActiveRoute}
|
||||
navigate={navigate}
|
||||
hideWiki={hideWiki}
|
||||
hideRunningAgents={hideRunningAgents}
|
||||
runningAgentsCount={runningAgentsCount}
|
||||
shortcuts={{ settings: shortcuts.settings }}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import type { NavigateOptions } from '@tanstack/react-router';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { formatShortcut } from '@/store/app-store';
|
||||
import { BookOpen, Activity, Settings } from 'lucide-react';
|
||||
import { Activity, Settings } from 'lucide-react';
|
||||
|
||||
interface SidebarFooterProps {
|
||||
sidebarOpen: boolean;
|
||||
isActiveRoute: (id: string) => boolean;
|
||||
navigate: (opts: NavigateOptions) => void;
|
||||
hideWiki: boolean;
|
||||
hideRunningAgents: boolean;
|
||||
runningAgentsCount: number;
|
||||
shortcuts: {
|
||||
@@ -19,7 +18,6 @@ export function SidebarFooter({
|
||||
sidebarOpen,
|
||||
isActiveRoute,
|
||||
navigate,
|
||||
hideWiki,
|
||||
hideRunningAgents,
|
||||
runningAgentsCount,
|
||||
shortcuts,
|
||||
@@ -34,66 +32,6 @@ export function SidebarFooter({
|
||||
'bg-gradient-to-t from-background/10 via-sidebar/50 to-transparent'
|
||||
)}
|
||||
>
|
||||
{/* Wiki Link */}
|
||||
{!hideWiki && (
|
||||
<div className="p-2 pb-0">
|
||||
<button
|
||||
onClick={() => navigate({ to: '/wiki' })}
|
||||
className={cn(
|
||||
'group flex items-center w-full px-3 py-2.5 rounded-xl relative overflow-hidden titlebar-no-drag',
|
||||
'transition-all duration-200 ease-out',
|
||||
isActiveRoute('wiki')
|
||||
? [
|
||||
'bg-gradient-to-r from-brand-500/20 via-brand-500/15 to-brand-600/10',
|
||||
'text-foreground font-medium',
|
||||
'border border-brand-500/30',
|
||||
'shadow-md shadow-brand-500/10',
|
||||
]
|
||||
: [
|
||||
'text-muted-foreground hover:text-foreground',
|
||||
'hover:bg-accent/50',
|
||||
'border border-transparent hover:border-border/40',
|
||||
'hover:shadow-sm',
|
||||
],
|
||||
sidebarOpen ? 'justify-start' : 'justify-center',
|
||||
'hover:scale-[1.02] active:scale-[0.97]'
|
||||
)}
|
||||
title={!sidebarOpen ? 'Wiki' : undefined}
|
||||
data-testid="wiki-link"
|
||||
>
|
||||
<BookOpen
|
||||
className={cn(
|
||||
'w-[18px] h-[18px] shrink-0 transition-all duration-200',
|
||||
isActiveRoute('wiki')
|
||||
? 'text-brand-500 drop-shadow-sm'
|
||||
: 'group-hover:text-brand-400 group-hover:scale-110'
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
'ml-3 font-medium text-sm flex-1 text-left',
|
||||
sidebarOpen ? 'block' : 'hidden'
|
||||
)}
|
||||
>
|
||||
Wiki
|
||||
</span>
|
||||
{!sidebarOpen && (
|
||||
<span
|
||||
className={cn(
|
||||
'absolute left-full ml-3 px-2.5 py-1.5 rounded-lg',
|
||||
'bg-popover text-popover-foreground text-xs font-medium',
|
||||
'border border-border shadow-lg',
|
||||
'opacity-0 group-hover:opacity-100',
|
||||
'transition-all duration-200 whitespace-nowrap z-50',
|
||||
'translate-x-1 group-hover:translate-x-0'
|
||||
)}
|
||||
>
|
||||
Wiki
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{/* Running Agents Link */}
|
||||
{!hideRunningAgents && (
|
||||
<div className="p-2 pb-0">
|
||||
|
||||
@@ -12,10 +12,20 @@ export function useRunningAgents() {
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (api.runningAgents) {
|
||||
logger.debug('Fetching running agents count');
|
||||
const result = await api.runningAgents.getAll();
|
||||
if (result.success && result.runningAgents) {
|
||||
logger.debug('Running agents count fetched', {
|
||||
count: result.runningAgents.length,
|
||||
});
|
||||
setRunningAgentsCount(result.runningAgents.length);
|
||||
} else {
|
||||
logger.debug('Running agents count fetch returned empty/failed', {
|
||||
success: result.success,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
logger.debug('Running agents API not available');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error fetching running agents count:', error);
|
||||
@@ -26,6 +36,7 @@ export function useRunningAgents() {
|
||||
useEffect(() => {
|
||||
const api = getElectronAPI();
|
||||
if (!api.autoMode) {
|
||||
logger.debug('Auto mode API not available for running agents hook');
|
||||
// If autoMode is not available, still fetch initial count
|
||||
fetchRunningAgentsCount();
|
||||
return;
|
||||
@@ -35,6 +46,9 @@ export function useRunningAgents() {
|
||||
fetchRunningAgentsCount();
|
||||
|
||||
const unsubscribe = api.autoMode.onEvent((event) => {
|
||||
logger.debug('Auto mode event for running agents hook', {
|
||||
type: event.type,
|
||||
});
|
||||
// When a feature starts, completes, or errors, refresh the count
|
||||
if (
|
||||
event.type === 'auto_mode_feature_complete' ||
|
||||
@@ -50,6 +64,22 @@ export function useRunningAgents() {
|
||||
};
|
||||
}, [fetchRunningAgentsCount]);
|
||||
|
||||
// Subscribe to backlog plan events to update running agents count
|
||||
useEffect(() => {
|
||||
const api = getElectronAPI();
|
||||
if (!api.backlogPlan) return;
|
||||
|
||||
fetchRunningAgentsCount();
|
||||
|
||||
const unsubscribe = api.backlogPlan.onEvent(() => {
|
||||
fetchRunningAgentsCount();
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [fetchRunningAgentsCount]);
|
||||
|
||||
return {
|
||||
runningAgentsCount,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user