mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-19 10:43:08 +00:00
refactor: Improve all git operations, add stash support, add improved pull request flow, add worktree file copy options, address code review comments, add cherry pick options
This commit is contained in:
@@ -335,6 +335,7 @@ const initialState: AppState = {
|
||||
defaultDeleteBranchByProject: {},
|
||||
autoDismissInitScriptIndicatorByProject: {},
|
||||
useWorktreesByProject: {},
|
||||
worktreeCopyFilesByProject: {},
|
||||
worktreePanelCollapsed: false,
|
||||
lastProjectDir: '',
|
||||
recentFolders: [],
|
||||
@@ -359,10 +360,15 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
removeProject: (projectId) =>
|
||||
removeProject: (projectId: string) => {
|
||||
set((state) => ({
|
||||
projects: state.projects.filter((p) => p.id !== projectId),
|
||||
})),
|
||||
currentProject: state.currentProject?.id === projectId ? null : state.currentProject,
|
||||
}));
|
||||
|
||||
// Persist to storage
|
||||
saveProjects(get().projects);
|
||||
},
|
||||
|
||||
moveProjectToTrash: (projectId: string) => {
|
||||
const project = get().projects.find((p) => p.id === projectId);
|
||||
@@ -2394,6 +2400,16 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
return projectOverride !== undefined ? projectOverride : get().useWorktrees;
|
||||
},
|
||||
|
||||
// Worktree Copy Files actions
|
||||
setWorktreeCopyFiles: (projectPath, files) =>
|
||||
set((state) => ({
|
||||
worktreeCopyFilesByProject: {
|
||||
...state.worktreeCopyFilesByProject,
|
||||
[projectPath]: files,
|
||||
},
|
||||
})),
|
||||
getWorktreeCopyFiles: (projectPath) => get().worktreeCopyFilesByProject[projectPath] ?? [],
|
||||
|
||||
// UI State actions
|
||||
setWorktreePanelCollapsed: (collapsed) => set({ worktreePanelCollapsed: collapsed }),
|
||||
setLastProjectDir: (dir) => set({ lastProjectDir: dir }),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { create } from 'zustand';
|
||||
import type { GeminiAuthStatus } from '@automaker/types';
|
||||
// Note: persist middleware removed - settings now sync via API (use-settings-sync.ts)
|
||||
|
||||
// CLI Installation Status
|
||||
@@ -127,21 +128,8 @@ export interface ZaiAuthStatus {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// Gemini Auth Method
|
||||
export type GeminiAuthMethod =
|
||||
| 'cli_login' // Gemini CLI is installed and authenticated
|
||||
| 'api_key_env' // GOOGLE_API_KEY or GEMINI_API_KEY environment variable
|
||||
| 'api_key' // Manually stored API key
|
||||
| 'none';
|
||||
|
||||
// Gemini Auth Status
|
||||
export interface GeminiAuthStatus {
|
||||
authenticated: boolean;
|
||||
method: GeminiAuthMethod;
|
||||
hasApiKey?: boolean;
|
||||
hasEnvApiKey?: boolean;
|
||||
error?: string;
|
||||
}
|
||||
// GeminiAuthStatus is imported from @automaker/types (method: 'google_login' | 'api_key' | 'vertex_ai' | 'none')
|
||||
export type { GeminiAuthStatus };
|
||||
|
||||
// Claude Auth Method - all possible authentication sources
|
||||
export type ClaudeAuthMethod =
|
||||
|
||||
@@ -341,6 +341,10 @@ export interface AppState {
|
||||
// undefined = use global setting, true/false = project-specific override
|
||||
useWorktreesByProject: Record<string, boolean | undefined>;
|
||||
|
||||
// Worktree Copy Files (per-project, keyed by project path)
|
||||
// List of relative file paths to copy from project root into new worktrees
|
||||
worktreeCopyFilesByProject: Record<string, string[]>;
|
||||
|
||||
// UI State (previously in localStorage, now synced via API)
|
||||
/** Whether worktree panel is collapsed in board view */
|
||||
worktreePanelCollapsed: boolean;
|
||||
@@ -756,6 +760,10 @@ export interface AppActions {
|
||||
getProjectUseWorktrees: (projectPath: string) => boolean | undefined; // undefined = using global
|
||||
getEffectiveUseWorktrees: (projectPath: string) => boolean; // Returns actual value (project or global fallback)
|
||||
|
||||
// Worktree Copy Files actions (per-project)
|
||||
setWorktreeCopyFiles: (projectPath: string, files: string[]) => void;
|
||||
getWorktreeCopyFiles: (projectPath: string) => string[];
|
||||
|
||||
// UI State actions (previously in localStorage, now synced via API)
|
||||
setWorktreePanelCollapsed: (collapsed: boolean) => void;
|
||||
setLastProjectDir: (dir: string) => void;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
|
||||
interface UICacheState {
|
||||
/** ID of the currently selected project */
|
||||
@@ -82,13 +83,27 @@ export function syncUICache(appState: {
|
||||
worktreePanelCollapsed?: boolean;
|
||||
collapsedNavSections?: Record<string, boolean>;
|
||||
}): void {
|
||||
useUICacheStore.getState().updateFromAppStore({
|
||||
cachedProjectId: appState.currentProject?.id ?? null,
|
||||
cachedSidebarOpen: appState.sidebarOpen ?? true,
|
||||
cachedSidebarStyle: appState.sidebarStyle ?? 'unified',
|
||||
cachedWorktreePanelCollapsed: appState.worktreePanelCollapsed ?? false,
|
||||
cachedCollapsedNavSections: appState.collapsedNavSections ?? {},
|
||||
});
|
||||
const update: Partial<UICacheState> = {};
|
||||
|
||||
if ('currentProject' in appState) {
|
||||
update.cachedProjectId = appState.currentProject?.id ?? null;
|
||||
}
|
||||
if ('sidebarOpen' in appState) {
|
||||
update.cachedSidebarOpen = appState.sidebarOpen;
|
||||
}
|
||||
if ('sidebarStyle' in appState) {
|
||||
update.cachedSidebarStyle = appState.sidebarStyle;
|
||||
}
|
||||
if ('worktreePanelCollapsed' in appState) {
|
||||
update.cachedWorktreePanelCollapsed = appState.worktreePanelCollapsed;
|
||||
}
|
||||
if ('collapsedNavSections' in appState) {
|
||||
update.cachedCollapsedNavSections = appState.collapsedNavSections;
|
||||
}
|
||||
|
||||
if (Object.keys(update).length > 0) {
|
||||
useUICacheStore.getState().updateFromAppStore(update);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +115,7 @@ export function syncUICache(appState: {
|
||||
* This is reconciled later when hydrateStoreFromSettings() overwrites
|
||||
* the app store with authoritative server data.
|
||||
*
|
||||
* @param appStoreSetState - The setState function from the app store (avoids circular import)
|
||||
* @param appStoreSetState - The setState function from the app store
|
||||
*/
|
||||
export function restoreFromUICache(
|
||||
appStoreSetState: (state: Record<string, unknown>) => void
|
||||
@@ -112,12 +127,29 @@ export function restoreFromUICache(
|
||||
return false;
|
||||
}
|
||||
|
||||
appStoreSetState({
|
||||
// Attempt to resolve the cached project ID to a full project object.
|
||||
// At early startup the projects array may be empty (server data not yet loaded),
|
||||
// but if projects are already in the store (e.g. optimistic hydration has run)
|
||||
// this will restore the project context immediately so tab-discard recovery
|
||||
// does not lose the selected project when cached settings are missing.
|
||||
const existingProjects = useAppStore.getState().projects;
|
||||
const cachedProject = existingProjects.find((p) => p.id === cache.cachedProjectId) ?? null;
|
||||
|
||||
const stateUpdate: Record<string, unknown> = {
|
||||
sidebarOpen: cache.cachedSidebarOpen,
|
||||
sidebarStyle: cache.cachedSidebarStyle,
|
||||
worktreePanelCollapsed: cache.cachedWorktreePanelCollapsed,
|
||||
collapsedNavSections: cache.cachedCollapsedNavSections,
|
||||
});
|
||||
};
|
||||
|
||||
// Restore the project context when the project object is available.
|
||||
// When projects are not yet loaded (empty array), currentProject remains
|
||||
// null and will be properly set later by hydrateStoreFromSettings().
|
||||
if (cachedProject !== null) {
|
||||
stateUpdate.currentProject = cachedProject;
|
||||
}
|
||||
|
||||
appStoreSetState(stateUpdate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user