refactor: use confirmDialog and unique draft agent IDs
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
|||||||
Image,
|
Image,
|
||||||
Platform,
|
Platform,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Alert,
|
|
||||||
StatusBar,
|
StatusBar,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
type GestureResponderEvent,
|
type GestureResponderEvent,
|
||||||
@@ -53,6 +52,7 @@ import { useToast } from '@/contexts/toast-context'
|
|||||||
import { useCheckoutGitActionsStore } from '@/stores/checkout-git-actions-store'
|
import { useCheckoutGitActionsStore } from '@/stores/checkout-git-actions-store'
|
||||||
import { buildSidebarShortcutModel } from '@/utils/sidebar-shortcuts'
|
import { buildSidebarShortcutModel } from '@/utils/sidebar-shortcuts'
|
||||||
import { hasVisibleOrderChanged, mergeWithRemainder } from '@/utils/sidebar-reorder'
|
import { hasVisibleOrderChanged, mergeWithRemainder } from '@/utils/sidebar-reorder'
|
||||||
|
import { confirmDialog } from '@/utils/confirm-dialog'
|
||||||
|
|
||||||
const PASEO_WORKTREE_PATH_MARKER = '/.paseo/worktrees'
|
const PASEO_WORKTREE_PATH_MARKER = '/.paseo/worktrees'
|
||||||
|
|
||||||
@@ -459,7 +459,6 @@ function WorkspaceRowInner({
|
|||||||
dragHandleProps,
|
dragHandleProps,
|
||||||
menuController,
|
menuController,
|
||||||
}: WorkspaceRowInnerProps) {
|
}: WorkspaceRowInnerProps) {
|
||||||
const { theme } = useUnistyles()
|
|
||||||
const createdAtLabel = resolveWorkspaceCreatedAtLabel(workspace)
|
const createdAtLabel = resolveWorkspaceCreatedAtLabel(workspace)
|
||||||
const interaction = useLongPressDragInteraction({
|
const interaction = useLongPressDragInteraction({
|
||||||
drag,
|
drag,
|
||||||
@@ -547,12 +546,6 @@ function WorkspaceRowInner({
|
|||||||
return (
|
return (
|
||||||
<View style={styles.workspaceRowContainer}>
|
<View style={styles.workspaceRowContainer}>
|
||||||
{content}
|
{content}
|
||||||
{isArchiving ? (
|
|
||||||
<View style={styles.workspaceArchivingOverlay} testID={`sidebar-workspace-archiving-${workspace.workspaceKey}`}>
|
|
||||||
<ActivityIndicator size="small" color={theme.colors.foregroundMuted} />
|
|
||||||
<Text style={styles.workspaceArchivingText}>Archiving</Text>
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -593,31 +586,28 @@ function WorkspaceRowWithMenu({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Alert.alert(
|
void (async () => {
|
||||||
'Archive worktree?',
|
const confirmed = await confirmDialog({
|
||||||
`Archive "${workspace.name}"?\n\nThis removes the worktree from the sidebar.`,
|
title: 'Archive worktree?',
|
||||||
[
|
message: `Archive "${workspace.name}"?\n\nThis removes the worktree from the sidebar.`,
|
||||||
{
|
confirmLabel: 'Archive',
|
||||||
text: 'Cancel',
|
cancelLabel: 'Cancel',
|
||||||
style: 'cancel',
|
destructive: true,
|
||||||
},
|
})
|
||||||
{
|
|
||||||
text: 'Archive',
|
if (!confirmed) {
|
||||||
style: 'destructive',
|
return
|
||||||
onPress: () => {
|
}
|
||||||
void archiveWorktree({
|
|
||||||
serverId: workspace.serverId,
|
void archiveWorktree({
|
||||||
cwd: workspace.workspaceId,
|
serverId: workspace.serverId,
|
||||||
worktreePath: workspace.workspaceId,
|
cwd: workspace.workspaceId,
|
||||||
}).catch((error) => {
|
worktreePath: workspace.workspaceId,
|
||||||
const message = error instanceof Error ? error.message : 'Failed to archive worktree'
|
}).catch((error) => {
|
||||||
toast.error(message)
|
const message = error instanceof Error ? error.message : 'Failed to archive worktree'
|
||||||
})
|
toast.error(message)
|
||||||
},
|
})
|
||||||
},
|
})()
|
||||||
],
|
|
||||||
{ cancelable: true }
|
|
||||||
)
|
|
||||||
}, [archiveWorktree, isArchiving, toast, workspace.name, workspace.serverId, workspace.workspaceId])
|
}, [archiveWorktree, isArchiving, toast, workspace.name, workspace.serverId, workspace.workspaceId])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -124,19 +124,19 @@ export function useAgentAutocomplete(input: UseAgentAutocompleteInput): AgentAut
|
|||||||
[draftConfig]
|
[draftConfig]
|
||||||
)
|
)
|
||||||
|
|
||||||
const isRealAgent = Boolean(agentId) && !agentId.startsWith('__')
|
const isDraftContext = normalizedDraftConfig !== undefined
|
||||||
const queryDraftConfig = isRealAgent ? undefined : normalizedDraftConfig
|
const queryDraftConfig = isDraftContext ? normalizedDraftConfig : undefined
|
||||||
const canLoadCommands = Boolean(serverId) && (isRealAgent || !!queryDraftConfig)
|
const canLoadCommands = Boolean(serverId) && (Boolean(agentId) || isDraftContext)
|
||||||
|
|
||||||
const agentCwd = useSessionStore(
|
const agentCwd = useSessionStore(
|
||||||
(state) => state.sessions[serverId]?.agents?.get(agentId)?.cwd ?? ''
|
(state) => state.sessions[serverId]?.agents?.get(agentId)?.cwd ?? ''
|
||||||
)
|
)
|
||||||
const autocompleteCwd = useMemo(() => {
|
const autocompleteCwd = useMemo(() => {
|
||||||
if (isRealAgent) {
|
if (isDraftContext) {
|
||||||
return agentCwd.trim()
|
return queryDraftConfig?.cwd ?? ''
|
||||||
}
|
}
|
||||||
return queryDraftConfig?.cwd ?? ''
|
return agentCwd.trim()
|
||||||
}, [agentCwd, isRealAgent, queryDraftConfig])
|
}, [agentCwd, isDraftContext, queryDraftConfig])
|
||||||
|
|
||||||
const { client, isConnected } = useHostRuntimeSession(serverId)
|
const { client, isConnected } = useHostRuntimeSession(serverId)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,30 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { canToggleFileExplorerShortcut } from "./keyboard-shortcut-routing";
|
import {
|
||||||
|
canToggleFileExplorerShortcut,
|
||||||
|
resolveSelectedOrRouteAgentKey,
|
||||||
|
} from "./keyboard-shortcut-routing";
|
||||||
|
|
||||||
describe("keyboard-shortcut-routing", () => {
|
describe("keyboard-shortcut-routing", () => {
|
||||||
|
describe("resolveSelectedOrRouteAgentKey", () => {
|
||||||
|
it("returns selected agent key when provided", () => {
|
||||||
|
const key = resolveSelectedOrRouteAgentKey({
|
||||||
|
selectedAgentId: "server-1:agent-1",
|
||||||
|
pathname: "/h/server-1/workspace/workspace-1/tab/draft_123",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(key).toBe("server-1:agent-1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("maps workspace draft tabs to the draft tab id key", () => {
|
||||||
|
const key = resolveSelectedOrRouteAgentKey({
|
||||||
|
pathname: "/h/server-1/workspace/workspace-1/tab/draft_123",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(key).toBe("server-1:draft_123");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("canToggleFileExplorerShortcut", () => {
|
describe("canToggleFileExplorerShortcut", () => {
|
||||||
const toggleFileExplorer = () => undefined;
|
const toggleFileExplorer = () => undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import {
|
|||||||
parseHostWorkspaceTabRouteFromPathname,
|
parseHostWorkspaceTabRouteFromPathname,
|
||||||
} from "@/utils/host-routes";
|
} from "@/utils/host-routes";
|
||||||
|
|
||||||
const DRAFT_AGENT_ID = "__new_agent__";
|
|
||||||
|
|
||||||
export function resolveSelectedOrRouteAgentKey(input: {
|
export function resolveSelectedOrRouteAgentKey(input: {
|
||||||
selectedAgentId?: string;
|
selectedAgentId?: string;
|
||||||
pathname: string;
|
pathname: string;
|
||||||
@@ -22,7 +20,7 @@ export function resolveSelectedOrRouteAgentKey(input: {
|
|||||||
return agentId ? `${workspaceTabRoute.serverId}:${agentId}` : null;
|
return agentId ? `${workspaceTabRoute.serverId}:${agentId}` : null;
|
||||||
}
|
}
|
||||||
if (tabId.startsWith("draft_")) {
|
if (tabId.startsWith("draft_")) {
|
||||||
return `${workspaceTabRoute.serverId}:${DRAFT_AGENT_ID}`;
|
return `${workspaceTabRoute.serverId}:${tabId}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import { useTauriDragHandlers } from '@/utils/tauri-window'
|
|||||||
import { useKeyboardShiftStyle } from '@/hooks/use-keyboard-shift-style'
|
import { useKeyboardShiftStyle } from '@/hooks/use-keyboard-shift-style'
|
||||||
import { normalizeAgentSnapshot } from '@/utils/agent-snapshots'
|
import { normalizeAgentSnapshot } from '@/utils/agent-snapshots'
|
||||||
|
|
||||||
const DRAFT_AGENT_ID = '__new_agent__'
|
|
||||||
const EMPTY_PENDING_PERMISSIONS = new Map()
|
const EMPTY_PENDING_PERMISSIONS = new Map()
|
||||||
const EMPTY_STREAM_ITEMS: StreamItem[] = []
|
const EMPTY_STREAM_ITEMS: StreamItem[] = []
|
||||||
const MAX_INITIAL_AGENT_TITLE_CHARS = 60
|
const MAX_INITIAL_AGENT_TITLE_CHARS = 60
|
||||||
@@ -252,6 +251,7 @@ function DraftAgentScreenContent({
|
|||||||
const tauriDragHandlers = useTauriDragHandlers()
|
const tauriDragHandlers = useTauriDragHandlers()
|
||||||
const isExplorerOpen = isMobile ? mobileView === 'file-explorer' : desktopFileExplorerOpen
|
const isExplorerOpen = isMobile ? mobileView === 'file-explorer' : desktopFileExplorerOpen
|
||||||
const draftIdRef = useRef(generateDraftId())
|
const draftIdRef = useRef(generateDraftId())
|
||||||
|
const draftAgentIdRef = useRef(generateDraftId())
|
||||||
|
|
||||||
const [worktreeMode, setWorktreeMode] = useState<'none' | 'create' | 'attach'>('none')
|
const [worktreeMode, setWorktreeMode] = useState<'none' | 'create' | 'attach'>('none')
|
||||||
const [baseBranch, setBaseBranch] = useState('')
|
const [baseBranch, setBaseBranch] = useState('')
|
||||||
@@ -866,7 +866,7 @@ function DraftAgentScreenContent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
serverId,
|
serverId,
|
||||||
id: DRAFT_AGENT_ID,
|
id: draftAgentIdRef.current,
|
||||||
provider,
|
provider,
|
||||||
status: 'running',
|
status: 'running',
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
@@ -1160,7 +1160,7 @@ function DraftAgentScreenContent({
|
|||||||
{machine.tag === 'creating' && draftAgent && selectedServerId ? (
|
{machine.tag === 'creating' && draftAgent && selectedServerId ? (
|
||||||
<View style={styles.streamContainer}>
|
<View style={styles.streamContainer}>
|
||||||
<AgentStreamView
|
<AgentStreamView
|
||||||
agentId={DRAFT_AGENT_ID}
|
agentId={draftAgentIdRef.current}
|
||||||
serverId={selectedServerId}
|
serverId={selectedServerId}
|
||||||
agent={draftAgent}
|
agent={draftAgent}
|
||||||
streamItems={optimisticStreamItems}
|
streamItems={optimisticStreamItems}
|
||||||
@@ -1346,7 +1346,7 @@ function DraftAgentScreenContent({
|
|||||||
</Animated.View>
|
</Animated.View>
|
||||||
<View style={styles.inputAreaWrapper}>
|
<View style={styles.inputAreaWrapper}>
|
||||||
<AgentInputArea
|
<AgentInputArea
|
||||||
agentId={DRAFT_AGENT_ID}
|
agentId={draftAgentIdRef.current}
|
||||||
serverId={selectedServerId ?? ''}
|
serverId={selectedServerId ?? ''}
|
||||||
onSubmitMessage={handleCreateFromInput}
|
onSubmitMessage={handleCreateFromInput}
|
||||||
isSubmitLoading={isSubmitting}
|
isSubmitLoading={isSubmitting}
|
||||||
|
|||||||
Reference in New Issue
Block a user