feat(app): show archived agent callout with unarchive button
When viewing an archived agent, display a callout in place of the input area that matches the message input styling. The Unarchive button calls refreshAgent which auto-unarchives server-side.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { useState } from 'react'
|
||||
import { View, Text } from 'react-native'
|
||||
import { StyleSheet } from 'react-native-unistyles'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { FOOTER_HEIGHT, MAX_CONTENT_WIDTH } from '@/constants/layout'
|
||||
import { useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime'
|
||||
import { useKeyboardShiftStyle } from '@/hooks/use-keyboard-shift-style'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import type { Theme } from '@/styles/theme'
|
||||
|
||||
interface ArchivedAgentCalloutProps {
|
||||
serverId: string
|
||||
agentId: string
|
||||
}
|
||||
|
||||
export function ArchivedAgentCallout({ serverId, agentId }: ArchivedAgentCalloutProps) {
|
||||
const insets = useSafeAreaInsets()
|
||||
const client = useHostRuntimeClient(serverId)
|
||||
const isConnected = useHostRuntimeIsConnected(serverId)
|
||||
const [isUnarchiving, setIsUnarchiving] = useState(false)
|
||||
|
||||
const { style: keyboardAnimatedStyle } = useKeyboardShiftStyle({ mode: 'translate' })
|
||||
|
||||
async function handleUnarchive() {
|
||||
if (!client || !isConnected || isUnarchiving) return
|
||||
setIsUnarchiving(true)
|
||||
try {
|
||||
await client.refreshAgent(agentId)
|
||||
} catch (error) {
|
||||
console.error('[ArchivedAgentCallout] Failed to unarchive agent:', error)
|
||||
setIsUnarchiving(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[styles.container, { paddingBottom: insets.bottom }, keyboardAnimatedStyle]}
|
||||
>
|
||||
<View style={styles.inputAreaContainer}>
|
||||
<View style={styles.inputAreaContent}>
|
||||
<View style={styles.callout}>
|
||||
<Text style={styles.calloutText}>This agent is archived</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onPress={handleUnarchive}
|
||||
disabled={!isConnected || isUnarchiving}
|
||||
>
|
||||
Unarchive
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create(((theme: Theme) => ({
|
||||
container: {
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
},
|
||||
inputAreaContainer: {
|
||||
position: 'relative',
|
||||
minHeight: FOOTER_HEIGHT,
|
||||
marginHorizontal: 'auto',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
overflow: 'visible',
|
||||
padding: theme.spacing[4],
|
||||
},
|
||||
inputAreaContent: {
|
||||
width: '100%',
|
||||
maxWidth: MAX_CONTENT_WIDTH,
|
||||
},
|
||||
callout: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: theme.spacing[3],
|
||||
backgroundColor: theme.colors.surface1,
|
||||
borderWidth: theme.borderWidth[1],
|
||||
borderColor: theme.colors.borderAccent,
|
||||
borderRadius: theme.borderRadius['2xl'],
|
||||
paddingVertical: {
|
||||
xs: theme.spacing[3],
|
||||
md: theme.spacing[4],
|
||||
},
|
||||
paddingHorizontal: {
|
||||
xs: theme.spacing[4],
|
||||
md: theme.spacing[6],
|
||||
},
|
||||
},
|
||||
calloutText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.base,
|
||||
},
|
||||
})) as any) as Record<string, any>
|
||||
@@ -6,6 +6,7 @@ import { Bot } from "lucide-react-native";
|
||||
import invariant from "tiny-invariant";
|
||||
import { AgentStreamView, type AgentStreamViewHandle } from "@/components/agent-stream-view";
|
||||
import { AgentInputArea } from "@/components/agent-input-area";
|
||||
import { ArchivedAgentCallout } from "@/components/archived-agent-callout";
|
||||
import { FileDropZone } from "@/components/file-drop-zone";
|
||||
import type { ImageAttachment } from "@/components/message-input";
|
||||
import { ToastViewport, useToastHost } from "@/components/toast-host";
|
||||
@@ -825,6 +826,8 @@ function AgentPanelBody({
|
||||
streamViewRef.current?.scrollToBottom("message-sent");
|
||||
}}
|
||||
/>
|
||||
) : agentId && agent?.archivedAt ? (
|
||||
<ArchivedAgentCallout serverId={serverId} agentId={agentId} />
|
||||
) : null}
|
||||
|
||||
{viewState.tag === "ready" &&
|
||||
|
||||
Reference in New Issue
Block a user