feat: Add auto-dismiss functionality for Init Script Indicator

This commit introduces an auto-dismiss feature for the Init Script Indicator, enhancing user experience by automatically hiding the indicator 5 seconds after the script completes. Key changes include:

1. **State Management**: Added `autoDismissInitScriptIndicatorByProject` to manage the auto-dismiss setting per project.
2. **UI Components**: Updated the WorktreesSection to include a toggle for enabling or disabling the auto-dismiss feature, allowing users to customize their experience.
3. **Indicator Logic**: Implemented logic in the SingleIndicator component to handle auto-dismiss based on the new setting.

These enhancements provide users with more control over the visibility of the Init Script Indicator, streamlining project management workflows.
This commit is contained in:
Kacper
2026-01-10 23:43:52 +01:00
parent d98ff16c8f
commit 09527b3b67
4 changed files with 83 additions and 1 deletions

View File

@@ -13,9 +13,16 @@ interface SingleIndicatorProps {
state: InitScriptState;
onDismiss: (key: string) => void;
isOnlyOne: boolean; // Whether this is the only indicator shown
autoDismiss: boolean; // Whether to auto-dismiss after completion
}
function SingleIndicator({ stateKey, state, onDismiss, isOnlyOne }: SingleIndicatorProps) {
function SingleIndicator({
stateKey,
state,
onDismiss,
isOnlyOne,
autoDismiss,
}: SingleIndicatorProps) {
const [showLogs, setShowLogs] = useState(false);
const logsEndRef = useRef<HTMLDivElement>(null);
@@ -35,6 +42,16 @@ function SingleIndicator({ stateKey, state, onDismiss, isOnlyOne }: SingleIndica
}
}, [status, isOnlyOne]);
// Auto-dismiss after completion (5 seconds)
useEffect(() => {
if (autoDismiss && (status === 'success' || status === 'failed')) {
const timer = setTimeout(() => {
onDismiss(stateKey);
}, 5000);
return () => clearTimeout(timer);
}
}, [status, autoDismiss, stateKey, onDismiss]);
if (status === 'idle') return null;
return (
@@ -123,8 +140,12 @@ function SingleIndicator({ stateKey, state, onDismiss, isOnlyOne }: SingleIndica
export function InitScriptIndicator({ projectPath }: InitScriptIndicatorProps) {
const getInitScriptStatesForProject = useAppStore((s) => s.getInitScriptStatesForProject);
const clearInitScriptState = useAppStore((s) => s.clearInitScriptState);
const getAutoDismissInitScriptIndicator = useAppStore((s) => s.getAutoDismissInitScriptIndicator);
const [dismissedKeys, setDismissedKeys] = useState<Set<string>>(new Set());
// Get auto-dismiss setting
const autoDismiss = getAutoDismissInitScriptIndicator(projectPath);
// Get all init script states for this project
const allStates = getInitScriptStatesForProject(projectPath);
@@ -180,6 +201,7 @@ export function InitScriptIndicator({ projectPath }: InitScriptIndicatorProps) {
state={state}
onDismiss={handleDismiss}
isOnlyOne={activeStates.length === 1}
autoDismiss={autoDismiss}
/>
))}
</div>

View File

@@ -37,6 +37,8 @@ export function WorktreesSection({ useWorktrees, onUseWorktreesChange }: Worktre
const setShowInitScriptIndicator = useAppStore((s) => s.setShowInitScriptIndicator);
const getDefaultDeleteBranch = useAppStore((s) => s.getDefaultDeleteBranch);
const setDefaultDeleteBranch = useAppStore((s) => s.setDefaultDeleteBranch);
const getAutoDismissInitScriptIndicator = useAppStore((s) => s.getAutoDismissInitScriptIndicator);
const setAutoDismissInitScriptIndicator = useAppStore((s) => s.setAutoDismissInitScriptIndicator);
const [scriptContent, setScriptContent] = useState('');
const [originalContent, setOriginalContent] = useState('');
const [scriptExists, setScriptExists] = useState(false);
@@ -54,6 +56,11 @@ export function WorktreesSection({ useWorktrees, onUseWorktreesChange }: Worktre
? getDefaultDeleteBranch(currentProject.path)
: false;
// Get the auto-dismiss setting
const autoDismiss = currentProject?.path
? getAutoDismissInitScriptIndicator(currentProject.path)
: true;
// Check if there are unsaved changes
const hasChanges = scriptContent !== originalContent;
@@ -233,6 +240,33 @@ export function WorktreesSection({ useWorktrees, onUseWorktreesChange }: Worktre
</div>
)}
{/* Auto-dismiss Init Script Indicator Toggle */}
{currentProject && showIndicator && (
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3 ml-6">
<Checkbox
id="auto-dismiss-indicator"
checked={autoDismiss}
onCheckedChange={(checked) => {
if (currentProject?.path) {
setAutoDismissInitScriptIndicator(currentProject.path, checked === true);
}
}}
className="mt-1"
/>
<div className="space-y-1.5">
<Label
htmlFor="auto-dismiss-indicator"
className="text-foreground cursor-pointer font-medium flex items-center gap-2"
>
Auto-dismiss After Completion
</Label>
<p className="text-xs text-muted-foreground/80 leading-relaxed">
Automatically hide the indicator 5 seconds after the script completes.
</p>
</div>
</div>
)}
{/* Default Delete Branch Toggle */}
{currentProject && (
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3">

View File

@@ -673,6 +673,10 @@ export interface AppState {
// Whether to default the "delete branch" checkbox when deleting a worktree (default: false)
defaultDeleteBranchByProject: Record<string, boolean>;
// Auto-dismiss Init Script Indicator (per-project, keyed by project path)
// Whether to auto-dismiss the indicator after completion (default: true)
autoDismissInitScriptIndicatorByProject: Record<string, boolean>;
// UI State (previously in localStorage, now synced via API)
/** Whether worktree panel is collapsed in board view */
worktreePanelCollapsed: boolean;
@@ -1094,6 +1098,10 @@ export interface AppActions {
setDefaultDeleteBranch: (projectPath: string, deleteBranch: boolean) => void;
getDefaultDeleteBranch: (projectPath: string) => boolean;
// Auto-dismiss Init Script Indicator actions (per-project)
setAutoDismissInitScriptIndicator: (projectPath: string, autoDismiss: boolean) => void;
getAutoDismissInitScriptIndicator: (projectPath: string) => boolean;
// UI State actions (previously in localStorage, now synced via API)
setWorktreePanelCollapsed: (collapsed: boolean) => void;
setLastProjectDir: (dir: string) => void;
@@ -1233,6 +1241,7 @@ const initialState: AppState = {
worktreePanelVisibleByProject: {},
showInitScriptIndicatorByProject: {},
defaultDeleteBranchByProject: {},
autoDismissInitScriptIndicatorByProject: {},
// UI State (previously in localStorage, now synced via API)
worktreePanelCollapsed: false,
lastProjectDir: '',
@@ -3179,6 +3188,21 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
return get().defaultDeleteBranchByProject[projectPath] ?? false;
},
// Auto-dismiss Init Script Indicator actions (per-project)
setAutoDismissInitScriptIndicator: (projectPath, autoDismiss) => {
set({
autoDismissInitScriptIndicatorByProject: {
...get().autoDismissInitScriptIndicatorByProject,
[projectPath]: autoDismiss,
},
});
},
getAutoDismissInitScriptIndicator: (projectPath) => {
// Default to true (auto-dismiss enabled) if not set
return get().autoDismissInitScriptIndicatorByProject[projectPath] ?? true;
},
// UI State actions (previously in localStorage, now synced via API)
setWorktreePanelCollapsed: (collapsed) => set({ worktreePanelCollapsed: collapsed }),
setLastProjectDir: (dir) => set({ lastProjectDir: dir }),

View File

@@ -601,6 +601,8 @@ export interface ProjectSettings {
// Worktree Behavior
/** Default value for "delete branch" checkbox when deleting a worktree (default: false) */
defaultDeleteBranchWithWorktree?: boolean;
/** Auto-dismiss init script indicator after completion (default: true) */
autoDismissInitScriptIndicator?: boolean;
// Session Tracking
/** Last chat session selected in this project */