feat: implement daemon connectivity updates and relay protocol versioning
This commit is contained in:
@@ -43,8 +43,8 @@ import {
|
||||
import { projectIconQueryKey } from "@/hooks/use-project-icon-query";
|
||||
import {
|
||||
type SidebarAgentListEntry,
|
||||
type SidebarProjectOption,
|
||||
} from "@/hooks/use-sidebar-agents-grouped";
|
||||
type SidebarProjectFilterOption,
|
||||
} from "@/hooks/use-sidebar-agents-list";
|
||||
import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
|
||||
import { getIsTauri } from "@/constants/layout";
|
||||
import { AgentStatusDot } from "@/components/agent-status-dot";
|
||||
@@ -59,9 +59,9 @@ type EntryData = SidebarAgentListEntry;
|
||||
|
||||
interface SidebarAgentListProps {
|
||||
entries: SidebarAgentListEntry[];
|
||||
projectOptions: SidebarProjectOption[];
|
||||
selectedProjectKeys: string[];
|
||||
onSelectedProjectKeysChange: (keys: string[]) => void;
|
||||
projectFilterOptions: SidebarProjectFilterOption[];
|
||||
selectedProjectFilterKeys: string[];
|
||||
onSelectedProjectFilterKeysChange: (keys: string[]) => void;
|
||||
isRefreshing?: boolean;
|
||||
onRefresh?: () => void;
|
||||
selectedAgentId?: string;
|
||||
@@ -72,7 +72,7 @@ interface SidebarAgentListProps {
|
||||
}
|
||||
|
||||
interface ProjectFilterOptionRowProps {
|
||||
option: SidebarProjectOption;
|
||||
option: SidebarProjectFilterOption;
|
||||
selected: boolean;
|
||||
iconDataUri: string | null;
|
||||
displayName: string;
|
||||
@@ -381,15 +381,15 @@ function deriveShortcutIndexByAgentKey(sidebarShortcutAgentKeys: string[]) {
|
||||
}
|
||||
|
||||
function resolveSelectedProjectLabel(input: {
|
||||
selectedProjectKeys: string[];
|
||||
projectOptions: SidebarProjectOption[];
|
||||
selectedProjectFilterKeys: string[];
|
||||
projectFilterOptions: SidebarProjectFilterOption[];
|
||||
}): string {
|
||||
if (input.selectedProjectKeys.length === 0) {
|
||||
if (input.selectedProjectFilterKeys.length === 0) {
|
||||
return "Project";
|
||||
}
|
||||
if (input.selectedProjectKeys.length === 1) {
|
||||
const selected = input.projectOptions.find(
|
||||
(option) => option.projectKey === input.selectedProjectKeys[0]
|
||||
if (input.selectedProjectFilterKeys.length === 1) {
|
||||
const selected = input.projectFilterOptions.find(
|
||||
(option) => option.projectKey === input.selectedProjectFilterKeys[0]
|
||||
);
|
||||
if (selected) {
|
||||
return deriveProjectDisplayName({
|
||||
@@ -399,7 +399,7 @@ function resolveSelectedProjectLabel(input: {
|
||||
});
|
||||
}
|
||||
return deriveProjectDisplayName({
|
||||
projectKey: input.selectedProjectKeys[0] ?? "",
|
||||
projectKey: input.selectedProjectFilterKeys[0] ?? "",
|
||||
projectName: "",
|
||||
remoteUrl: null,
|
||||
});
|
||||
@@ -444,9 +444,9 @@ function deriveProjectDisplayName(input: {
|
||||
|
||||
export function SidebarAgentList({
|
||||
entries,
|
||||
projectOptions,
|
||||
selectedProjectKeys,
|
||||
onSelectedProjectKeysChange,
|
||||
projectFilterOptions,
|
||||
selectedProjectFilterKeys,
|
||||
onSelectedProjectFilterKeysChange,
|
||||
isRefreshing = false,
|
||||
onRefresh,
|
||||
selectedAgentId,
|
||||
@@ -479,23 +479,23 @@ export function SidebarAgentList({
|
||||
);
|
||||
|
||||
const selectedProjectLabel = useMemo(
|
||||
() => resolveSelectedProjectLabel({ selectedProjectKeys, projectOptions }),
|
||||
[projectOptions, selectedProjectKeys]
|
||||
() => resolveSelectedProjectLabel({ selectedProjectFilterKeys, projectFilterOptions }),
|
||||
[projectFilterOptions, selectedProjectFilterKeys]
|
||||
);
|
||||
|
||||
const selectedProjectOption = useMemo(() => {
|
||||
if (selectedProjectKeys.length !== 1) {
|
||||
if (selectedProjectFilterKeys.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
projectOptions.find((option) => option.projectKey === selectedProjectKeys[0]) ?? null
|
||||
projectFilterOptions.find((option) => option.projectKey === selectedProjectFilterKeys[0]) ?? null
|
||||
);
|
||||
}, [projectOptions, selectedProjectKeys]);
|
||||
const showProjectFilters = projectOptions.length > 0;
|
||||
}, [projectFilterOptions, selectedProjectFilterKeys]);
|
||||
const showProjectFilters = projectFilterOptions.length > 0;
|
||||
|
||||
const projectIconRequests = useMemo(() => {
|
||||
const unique = new Map<string, { serverId: string; cwd: string }>();
|
||||
for (const option of projectOptions) {
|
||||
for (const option of projectFilterOptions) {
|
||||
if (!option.serverId || !option.workingDir) {
|
||||
continue;
|
||||
}
|
||||
@@ -513,7 +513,7 @@ export function SidebarAgentList({
|
||||
unique.set(`${serverId}:${cwd}`, { serverId, cwd });
|
||||
}
|
||||
return Array.from(unique.values());
|
||||
}, [entries, projectOptions]);
|
||||
}, [entries, projectFilterOptions]);
|
||||
|
||||
const projectIconQueries = useQueries({
|
||||
queries: projectIconRequests.map((request) => ({
|
||||
@@ -559,7 +559,7 @@ export function SidebarAgentList({
|
||||
|
||||
const projectIconByProjectKey = useMemo(() => {
|
||||
const map = new Map<string, string | null>();
|
||||
for (const option of projectOptions) {
|
||||
for (const option of projectFilterOptions) {
|
||||
map.set(
|
||||
option.projectKey,
|
||||
projectIconByQueryKey.get(`${option.serverId}:${option.workingDir}`) ?? null
|
||||
@@ -577,7 +577,7 @@ export function SidebarAgentList({
|
||||
);
|
||||
}
|
||||
return map;
|
||||
}, [entries, projectIconByQueryKey, projectOptions]);
|
||||
}, [entries, projectIconByQueryKey, projectFilterOptions]);
|
||||
|
||||
const selectedProjectIconUri = useMemo(() => {
|
||||
if (!selectedProjectOption) {
|
||||
@@ -588,20 +588,20 @@ export function SidebarAgentList({
|
||||
|
||||
const handleToggleProject = useCallback(
|
||||
(projectKey: string) => {
|
||||
const next = new Set(selectedProjectKeys);
|
||||
const next = new Set(selectedProjectFilterKeys);
|
||||
if (next.has(projectKey)) {
|
||||
next.delete(projectKey);
|
||||
} else {
|
||||
next.add(projectKey);
|
||||
}
|
||||
onSelectedProjectKeysChange(Array.from(next));
|
||||
onSelectedProjectFilterKeysChange(Array.from(next));
|
||||
},
|
||||
[onSelectedProjectKeysChange, selectedProjectKeys]
|
||||
[onSelectedProjectFilterKeysChange, selectedProjectFilterKeys]
|
||||
);
|
||||
|
||||
const handleClearProjectFilter = useCallback(() => {
|
||||
onSelectedProjectKeysChange([]);
|
||||
}, [onSelectedProjectKeysChange]);
|
||||
onSelectedProjectFilterKeysChange([]);
|
||||
}, [onSelectedProjectFilterKeysChange]);
|
||||
|
||||
const handleAgentPress = useCallback(
|
||||
(entry: SidebarAgentListEntry) => {
|
||||
@@ -755,7 +755,7 @@ export function SidebarAgentList({
|
||||
ref={projectFilterAnchorRef}
|
||||
style={({ hovered = false, pressed }) => [
|
||||
styles.filterTrigger,
|
||||
(selectedProjectKeys.length > 0 || hovered || pressed) &&
|
||||
(selectedProjectFilterKeys.length > 0 || hovered || pressed) &&
|
||||
styles.filterTriggerActive,
|
||||
]}
|
||||
onPress={() => setIsProjectFilterOpen(true)}
|
||||
@@ -763,20 +763,20 @@ export function SidebarAgentList({
|
||||
{({ hovered = false, pressed }) => {
|
||||
const isInteracting = hovered || pressed;
|
||||
const showActiveForeground =
|
||||
selectedProjectKeys.length > 0 || isInteracting;
|
||||
selectedProjectFilterKeys.length > 0 || isInteracting;
|
||||
return (
|
||||
<>
|
||||
{selectedProjectKeys.length === 1 && selectedProjectIconUri ? (
|
||||
{selectedProjectFilterKeys.length === 1 && selectedProjectIconUri ? (
|
||||
<Image
|
||||
source={{
|
||||
uri: selectedProjectIconUri,
|
||||
}}
|
||||
style={styles.selectedProjectIcon}
|
||||
/>
|
||||
) : selectedProjectKeys.length > 1 ? (
|
||||
) : selectedProjectFilterKeys.length > 1 ? (
|
||||
<View style={styles.projectCountBadge}>
|
||||
<Text style={styles.projectCountBadgeText}>
|
||||
{selectedProjectKeys.length}
|
||||
{selectedProjectFilterKeys.length}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
@@ -802,7 +802,7 @@ export function SidebarAgentList({
|
||||
}}
|
||||
</Pressable>
|
||||
|
||||
{selectedProjectKeys.length > 0 ? (
|
||||
{selectedProjectFilterKeys.length > 0 ? (
|
||||
<Pressable style={styles.clearFilterButton} onPress={handleClearProjectFilter}>
|
||||
<Text style={styles.clearFilterText}>Clear</Text>
|
||||
</Pressable>
|
||||
@@ -821,14 +821,14 @@ export function SidebarAgentList({
|
||||
anchorRef={projectFilterAnchorRef}
|
||||
>
|
||||
<View style={styles.filterOptionsList}>
|
||||
{projectOptions.length === 0 ? (
|
||||
{projectFilterOptions.length === 0 ? (
|
||||
<Text style={styles.filterEmptyText}>No projects</Text>
|
||||
) : (
|
||||
projectOptions.map((option) => (
|
||||
projectFilterOptions.map((option) => (
|
||||
<ProjectFilterOptionRow
|
||||
key={option.projectKey}
|
||||
option={option}
|
||||
selected={selectedProjectKeys.includes(option.projectKey)}
|
||||
selected={selectedProjectFilterKeys.includes(option.projectKey)}
|
||||
iconDataUri={projectIconByProjectKey.get(option.projectKey) ?? null}
|
||||
displayName={deriveProjectDisplayName({
|
||||
projectKey: option.projectKey,
|
||||
|
||||
Reference in New Issue
Block a user