mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-05 17:42:12 +00:00
parent
46b435a543
commit
c70da1b1c2
2 changed files with 106 additions and 20 deletions
|
|
@ -31,10 +31,22 @@ type FilterStatus =
|
||||||
|
|
||||||
function AllThreadsPageContent() {
|
function AllThreadsPageContent() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const limit = 25;
|
||||||
|
const [offset, setOffset] = useState(0);
|
||||||
const { currentInstallation, installationsLoading } = useGitHubAppProvider();
|
const { currentInstallation, installationsLoading } = useGitHubAppProvider();
|
||||||
const { threads, isLoading: threadsLoading } = useThreadsSWR({
|
const {
|
||||||
|
threads,
|
||||||
|
isLoading: threadsLoading,
|
||||||
|
hasMore,
|
||||||
|
} = useThreadsSWR({
|
||||||
assistantId: MANAGER_GRAPH_ID,
|
assistantId: MANAGER_GRAPH_ID,
|
||||||
currentInstallation,
|
currentInstallation,
|
||||||
|
pagination: {
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
sortBy: "updated_at",
|
||||||
|
sortOrder: "desc",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [statusFilter, setStatusFilter] = useState<FilterStatus>("all");
|
const [statusFilter, setStatusFilter] = useState<FilterStatus>("all");
|
||||||
|
|
@ -96,6 +108,11 @@ function AllThreadsPageContent() {
|
||||||
(statusFilter === "all"
|
(statusFilter === "all"
|
||||||
? Object.values(groupedThreads).flat().length === 0
|
? Object.values(groupedThreads).flat().length === 0
|
||||||
: filteredThreads.length === 0);
|
: filteredThreads.length === 0);
|
||||||
|
const showNoThreads =
|
||||||
|
filteredThreads.length === 0 &&
|
||||||
|
!threadsLoading &&
|
||||||
|
!statusLoading &&
|
||||||
|
!showThreadsLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-background flex h-screen flex-col">
|
<div className="bg-background flex h-screen flex-col">
|
||||||
|
|
@ -233,22 +250,18 @@ function AllThreadsPageContent() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{filteredThreads.length === 0 &&
|
{showNoThreads && (
|
||||||
!threadsLoading &&
|
<div className="py-12 text-center">
|
||||||
!statusLoading && (
|
<div className="text-muted-foreground mb-2">No threads found</div>
|
||||||
<div className="py-12 text-center">
|
<div className="text-muted-foreground/70 text-xs">
|
||||||
<div className="text-muted-foreground mb-2">
|
{!threads || threads.length === 0
|
||||||
No threads found
|
? "No threads have been created yet"
|
||||||
</div>
|
: searchQuery
|
||||||
<div className="text-muted-foreground/70 text-xs">
|
? "Try adjusting your search query"
|
||||||
{!threads || threads.length === 0
|
: "No threads match the selected filter"}
|
||||||
? "No threads have been created yet"
|
|
||||||
: searchQuery
|
|
||||||
? "Try adjusting your search query"
|
|
||||||
: "No threads match the selected filter"}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{showThreadsLoading && (
|
{showThreadsLoading && (
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -264,6 +277,16 @@ function AllThreadsPageContent() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!showNoThreads && hasMore && (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOffset((prev) => prev + limit)}
|
||||||
|
>
|
||||||
|
Load more
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ import { ManagerGraphState } from "@open-swe/shared/open-swe/manager/types";
|
||||||
import { PlannerGraphState } from "@open-swe/shared/open-swe/planner/types";
|
import { PlannerGraphState } from "@open-swe/shared/open-swe/planner/types";
|
||||||
import { ReviewerGraphState } from "@open-swe/shared/open-swe/reviewer/types";
|
import { ReviewerGraphState } from "@open-swe/shared/open-swe/reviewer/types";
|
||||||
import { GraphState } from "@open-swe/shared/open-swe/types";
|
import { GraphState } from "@open-swe/shared/open-swe/types";
|
||||||
import { useMemo } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import type { Installation } from "./useGitHubInstallations";
|
import type { Installation } from "./useGitHubInstallations";
|
||||||
|
|
||||||
|
type ThreadSortBy = "thread_id" | "status" | "created_at" | "updated_at";
|
||||||
|
type SortOrder = "asc" | "desc";
|
||||||
/**
|
/**
|
||||||
* Union type representing all possible graph states in the Open SWE system
|
* Union type representing all possible graph states in the Open SWE system
|
||||||
*/
|
*/
|
||||||
|
|
@ -25,6 +27,32 @@ interface UseThreadsSWROptions {
|
||||||
revalidateOnReconnect?: boolean;
|
revalidateOnReconnect?: boolean;
|
||||||
currentInstallation?: Installation | null;
|
currentInstallation?: Installation | null;
|
||||||
disableOrgFiltering?: boolean;
|
disableOrgFiltering?: boolean;
|
||||||
|
/**
|
||||||
|
* Pagination options
|
||||||
|
*/
|
||||||
|
pagination?: {
|
||||||
|
/**
|
||||||
|
* Maximum number of threads to return.
|
||||||
|
* @default 25
|
||||||
|
*/
|
||||||
|
limit?: number;
|
||||||
|
/**
|
||||||
|
* Offset to start from.
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
offset?: number;
|
||||||
|
/**
|
||||||
|
* Sort by.
|
||||||
|
* @default "updated_at"
|
||||||
|
*/
|
||||||
|
sortBy?: ThreadSortBy;
|
||||||
|
/**
|
||||||
|
* Sort order.
|
||||||
|
* Must be one of 'asc' or 'desc'.
|
||||||
|
* @default "desc"
|
||||||
|
*/
|
||||||
|
sortOrder?: SortOrder;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,12 +73,34 @@ export function useThreadsSWR<
|
||||||
revalidateOnReconnect = THREAD_SWR_CONFIG.revalidateOnReconnect,
|
revalidateOnReconnect = THREAD_SWR_CONFIG.revalidateOnReconnect,
|
||||||
currentInstallation,
|
currentInstallation,
|
||||||
disableOrgFiltering,
|
disableOrgFiltering,
|
||||||
|
pagination,
|
||||||
} = options;
|
} = options;
|
||||||
|
const [hasMoreState, setHasMoreState] = useState(true);
|
||||||
|
|
||||||
|
const paginationWithDefaults = {
|
||||||
|
limit: 25,
|
||||||
|
offset: 0,
|
||||||
|
sortBy: "updated_at" as ThreadSortBy,
|
||||||
|
sortOrder: "desc" as SortOrder,
|
||||||
|
...pagination,
|
||||||
|
};
|
||||||
|
|
||||||
const apiUrl: string | undefined = process.env.NEXT_PUBLIC_API_URL ?? "";
|
const apiUrl: string | undefined = process.env.NEXT_PUBLIC_API_URL ?? "";
|
||||||
|
|
||||||
// Create a unique key for SWR caching based on assistantId
|
// Create a unique key for SWR caching based on assistantId and pagination parameters
|
||||||
const swrKey = assistantId ? ["threads", assistantId] : ["threads", "all"];
|
const swrKey = useMemo(() => {
|
||||||
|
const baseKey = assistantId ? ["threads", assistantId] : ["threads", "all"];
|
||||||
|
if (pagination) {
|
||||||
|
return [
|
||||||
|
...baseKey,
|
||||||
|
paginationWithDefaults.limit,
|
||||||
|
paginationWithDefaults.offset,
|
||||||
|
paginationWithDefaults.sortBy,
|
||||||
|
paginationWithDefaults.sortOrder,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return baseKey;
|
||||||
|
}, [assistantId, paginationWithDefaults]);
|
||||||
|
|
||||||
const fetcher = async (): Promise<Thread<TGraphState>[]> => {
|
const fetcher = async (): Promise<Thread<TGraphState>[]> => {
|
||||||
if (!apiUrl) {
|
if (!apiUrl) {
|
||||||
|
|
@ -63,8 +113,11 @@ export function useThreadsSWR<
|
||||||
metadata: {
|
metadata: {
|
||||||
graph_id: assistantId,
|
graph_id: assistantId,
|
||||||
},
|
},
|
||||||
|
...(paginationWithDefaults ? paginationWithDefaults : {}),
|
||||||
}
|
}
|
||||||
: undefined;
|
: paginationWithDefaults
|
||||||
|
? paginationWithDefaults
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return await client.threads.search<TGraphState>(searchArgs);
|
return await client.threads.search<TGraphState>(searchArgs);
|
||||||
};
|
};
|
||||||
|
|
@ -89,7 +142,12 @@ export function useThreadsSWR<
|
||||||
return allThreads;
|
return allThreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allThreads.length) {
|
||||||
|
setHasMoreState(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!currentInstallation) {
|
if (!currentInstallation) {
|
||||||
|
setHasMoreState(false);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,11 +160,16 @@ export function useThreadsSWR<
|
||||||
});
|
});
|
||||||
}, [data, currentInstallation, disableOrgFiltering]);
|
}, [data, currentInstallation, disableOrgFiltering]);
|
||||||
|
|
||||||
|
const hasMore = useMemo(() => {
|
||||||
|
return hasMoreState && !!threads.length;
|
||||||
|
}, [threads, paginationWithDefaults]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
threads,
|
threads,
|
||||||
error,
|
error,
|
||||||
isLoading,
|
isLoading,
|
||||||
isValidating,
|
isValidating,
|
||||||
mutate,
|
mutate,
|
||||||
|
hasMore,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue