mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Update files
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
||||
import { router, usePathname } from "expo-router";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { useQueries, useQueryClient, type UseQueryOptions } from "@tanstack/react-query";
|
||||
import { ChevronDown, ChevronRight } from "lucide-react-native";
|
||||
import { ChevronDown, ChevronRight, Plus } from "lucide-react-native";
|
||||
import { formatTimeAgo } from "@/utils/time";
|
||||
import {
|
||||
groupAgents,
|
||||
@@ -51,6 +51,8 @@ interface SectionData {
|
||||
firstAgentServerId?: string;
|
||||
/** For project sections, the first agent's id (to lookup checkout status) */
|
||||
firstAgentId?: string;
|
||||
/** Working directory for the project (from first agent) */
|
||||
workingDir?: string;
|
||||
}
|
||||
|
||||
interface GroupedAgentListProps {
|
||||
@@ -66,14 +68,17 @@ interface SectionHeaderProps {
|
||||
section: SectionData;
|
||||
isCollapsed: boolean;
|
||||
onToggle: () => void;
|
||||
onCreateAgent: (workingDir: string) => void;
|
||||
}
|
||||
|
||||
function SectionHeader({
|
||||
section,
|
||||
isCollapsed,
|
||||
onToggle,
|
||||
onCreateAgent,
|
||||
}: SectionHeaderProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
// For project sections, try to get repo name from checkout status
|
||||
const checkoutQuery = useCheckoutStatusCacheOnly({
|
||||
@@ -98,13 +103,26 @@ function SectionHeader({
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreatePress = useCallback(
|
||||
(e: { stopPropagation: () => void }) => {
|
||||
e.stopPropagation();
|
||||
if (section.workingDir) {
|
||||
onCreateAgent(section.workingDir);
|
||||
}
|
||||
},
|
||||
[onCreateAgent, section.workingDir]
|
||||
);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={({ hovered }) => [
|
||||
style={[
|
||||
styles.sectionHeader,
|
||||
hovered && styles.sectionHeaderHovered,
|
||||
isHovered && styles.sectionHeaderHovered,
|
||||
!isCollapsed && styles.sectionHeaderExpanded,
|
||||
]}
|
||||
onPress={onToggle}
|
||||
onHoverIn={() => setIsHovered(true)}
|
||||
onHoverOut={() => setIsHovered(false)}
|
||||
>
|
||||
<View style={styles.sectionHeaderLeft}>
|
||||
<Text style={styles.sectionTitle} numberOfLines={1}>
|
||||
@@ -112,6 +130,24 @@ function SectionHeader({
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.sectionHeaderRight}>
|
||||
{section.workingDir && (
|
||||
<Pressable
|
||||
style={[
|
||||
styles.createAgentButton,
|
||||
{ opacity: isHovered ? 1 : 0 },
|
||||
]}
|
||||
onPress={handleCreatePress}
|
||||
onHoverIn={() => setIsHovered(true)}
|
||||
onHoverOut={() => setIsHovered(true)}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<Plus
|
||||
size={14}
|
||||
color={hovered ? theme.colors.foreground : theme.colors.foregroundMuted}
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
)}
|
||||
{isCollapsed ? (
|
||||
<ChevronRight size={14} color={theme.colors.foregroundMuted} />
|
||||
) : (
|
||||
@@ -206,6 +242,13 @@ export function GroupedAgentList({
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleCreateAgentInProject = useCallback(
|
||||
(workingDir: string) => {
|
||||
router.push(`/agent?workingDir=${encodeURIComponent(workingDir)}` as any);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
// Subscribe to checkout status cache entries so project grouping can react
|
||||
// to remote URL updates (e.g. git worktrees in different directories).
|
||||
const checkoutCacheQueries = useQueries({
|
||||
@@ -260,6 +303,7 @@ export function GroupedAgentList({
|
||||
data: isCollapsed ? [] : group.agents,
|
||||
firstAgentServerId: firstAgent?.serverId,
|
||||
firstAgentId: firstAgent?.id,
|
||||
workingDir: firstAgent?.cwd,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -386,10 +430,11 @@ export function GroupedAgentList({
|
||||
section={section}
|
||||
isCollapsed={isCollapsed}
|
||||
onToggle={() => toggleSection(section.key)}
|
||||
onCreateAgent={handleCreateAgentInProject}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[collapsedSections, toggleSection]
|
||||
[collapsedSections, toggleSection, handleCreateAgentInProject]
|
||||
);
|
||||
|
||||
const keyExtractor = useCallback(
|
||||
@@ -495,14 +540,17 @@ const styles = StyleSheet.create((theme) => ({
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingHorizontal: theme.spacing[4] + theme.spacing[2],
|
||||
marginHorizontal: -theme.spacing[4],
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
marginHorizontal: -theme.spacing[2],
|
||||
marginTop: theme.spacing[2],
|
||||
borderRadius: theme.borderRadius.md,
|
||||
},
|
||||
sectionHeaderHovered: {
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
sectionHeaderExpanded: {
|
||||
marginBottom: theme.spacing[1],
|
||||
},
|
||||
sectionHeaderLeft: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
@@ -511,13 +559,21 @@ const styles = StyleSheet.create((theme) => ({
|
||||
minWidth: 0,
|
||||
},
|
||||
sectionHeaderRight: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: theme.spacing[2],
|
||||
marginLeft: theme.spacing[2],
|
||||
},
|
||||
createAgentButton: {
|
||||
width: 14,
|
||||
height: 14,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontWeight: "500",
|
||||
fontWeight: "normal",
|
||||
color: theme.colors.foregroundMuted,
|
||||
flex: 1,
|
||||
textAlign: "left",
|
||||
@@ -525,6 +581,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
agentItem: {
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
marginHorizontal: -theme.spacing[2],
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
marginBottom: theme.spacing[1],
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ import Animated, {
|
||||
} from "react-native-reanimated";
|
||||
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { ChevronRight, Plus, Settings } from "lucide-react-native";
|
||||
import { Plus, Settings, Users } from "lucide-react-native";
|
||||
import { router } from "expo-router";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
import { GroupedAgentList } from "./grouped-agent-list";
|
||||
@@ -170,20 +170,6 @@ export function SlidingSidebar({ selectedAgentId }: SlidingSidebarProps) {
|
||||
pointerEvents: backdropOpacity.value > 0.01 ? "auto" : "none",
|
||||
}));
|
||||
|
||||
const viewMoreButton = (
|
||||
<View style={styles.viewMoreContainer}>
|
||||
<Pressable
|
||||
style={({ hovered, pressed }) => [
|
||||
styles.viewMoreButton,
|
||||
(hovered || pressed) && styles.viewMoreButtonHovered,
|
||||
]}
|
||||
onPress={handleViewMore}
|
||||
>
|
||||
<Text style={styles.viewMoreButtonText}>All agents</Text>
|
||||
<ChevronRight size={16} color={theme.colors.foregroundMuted} />
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
|
||||
// Render mobile sidebar
|
||||
// On web, use "auto" instead of "box-none" because web's pointer-events: none blocks scroll
|
||||
@@ -228,17 +214,30 @@ export function SlidingSidebar({ selectedAgentId }: SlidingSidebarProps) {
|
||||
onRefresh={handleRefresh}
|
||||
selectedAgentId={selectedAgentId}
|
||||
onAgentSelect={handleAgentSelectMobile}
|
||||
listFooterComponent={viewMoreButton}
|
||||
/>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.sidebarFooter}>
|
||||
<Pressable
|
||||
style={styles.settingsButton}
|
||||
style={styles.footerButton}
|
||||
onPress={handleViewMore}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<>
|
||||
<Users size={18} color={hovered ? theme.colors.foreground : theme.colors.foregroundMuted} />
|
||||
<Text style={[styles.footerButtonText, hovered && styles.footerButtonTextHovered]}>
|
||||
All agents
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Pressable>
|
||||
<Pressable
|
||||
style={styles.footerIconButton}
|
||||
onPress={handleSettingsMobile}
|
||||
>
|
||||
<Settings size={20} color={theme.colors.foregroundMuted} />
|
||||
<Text style={styles.settingsButtonText}>Settings</Text>
|
||||
{({ hovered }) => (
|
||||
<Settings size={20} color={hovered ? theme.colors.foreground : theme.colors.foregroundMuted} />
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
@@ -279,17 +278,30 @@ export function SlidingSidebar({ selectedAgentId }: SlidingSidebarProps) {
|
||||
isRefreshing={isManualRefresh && isRevalidating}
|
||||
onRefresh={handleRefresh}
|
||||
selectedAgentId={selectedAgentId}
|
||||
listFooterComponent={viewMoreButton}
|
||||
/>
|
||||
|
||||
{/* Footer: Settings button */}
|
||||
{/* Footer */}
|
||||
<View style={styles.sidebarFooter}>
|
||||
<Pressable
|
||||
style={styles.settingsButton}
|
||||
style={styles.footerButton}
|
||||
onPress={handleViewMore}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<>
|
||||
<Users size={18} color={hovered ? theme.colors.foreground : theme.colors.foregroundMuted} />
|
||||
<Text style={[styles.footerButtonText, hovered && styles.footerButtonTextHovered]}>
|
||||
All agents
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Pressable>
|
||||
<Pressable
|
||||
style={styles.footerIconButton}
|
||||
onPress={handleSettingsDesktop}
|
||||
>
|
||||
<Settings size={20} color={theme.colors.foregroundMuted} />
|
||||
<Text style={styles.settingsButtonText}>Settings</Text>
|
||||
{({ hovered }) => (
|
||||
<Settings size={20} color={hovered ? theme.colors.foreground : theme.colors.foregroundMuted} />
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
@@ -349,47 +361,32 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
viewMoreContainer: {
|
||||
paddingTop: theme.spacing[2],
|
||||
},
|
||||
viewMoreButton: {
|
||||
sidebarFooter: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: theme.spacing[1],
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingHorizontal: 0,
|
||||
borderWidth: 0,
|
||||
backgroundColor: "transparent",
|
||||
alignSelf: "flex-start",
|
||||
transitionProperty: "opacity",
|
||||
transitionDuration: "150ms",
|
||||
},
|
||||
viewMoreButtonHovered: {
|
||||
opacity: 0.8,
|
||||
},
|
||||
viewMoreButtonText: {
|
||||
fontSize: theme.fontSize.base,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
sidebarFooter: {
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: theme.spacing[4],
|
||||
paddingTop: theme.spacing[2],
|
||||
paddingBottom: theme.spacing[4],
|
||||
paddingVertical: theme.spacing[3],
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: theme.colors.border,
|
||||
},
|
||||
settingsButton: {
|
||||
footerButton: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingHorizontal: theme.spacing[2],
|
||||
gap: theme.spacing[2],
|
||||
paddingVertical: theme.spacing[1],
|
||||
paddingHorizontal: theme.spacing[1],
|
||||
},
|
||||
settingsButtonText: {
|
||||
footerIconButton: {
|
||||
paddingVertical: theme.spacing[1],
|
||||
paddingHorizontal: theme.spacing[1],
|
||||
},
|
||||
footerButtonText: {
|
||||
fontSize: theme.fontSize.base,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
footerButtonTextHovered: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user