Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
307c6e3
feat(pages): paginate and search page.list instead of returning the w…
harshithmullapudi Sep 14, 2026
b129b84
fix(pages): stop a failed drain batch from blanking the page grid
harshithmullapudi Sep 14, 2026
30375bf
docs(page-skill): document --search, --limit and --cursor on pages list
harshithmullapudi Sep 14, 2026
b6dcf4d
feat(pages): say so when the background sweep stops short
harshithmullapudi Sep 14, 2026
0f96021
docs(page-skill): scope the output-shape note to --json
harshithmullapudi Sep 14, 2026
eee83f3
Merge remote-tracking branch 'origin/main' into superset-pages-pagina…
harshithmullapudi Sep 20, 2026
4f913b0
Merge remote-tracking branch 'origin/main' into superset-pages-pagina…
harshithmullapudi Sep 20, 2026
846b443
docs(page-skill): drop the em dash the prose rule forbids
harshithmullapudi Sep 20, 2026
52b28df
feat(pages): surface which workspace a page was published from
harshithmullapudi Sep 21, 2026
bd7a80b
fix(pages): name cloud workspaces in the pages list too
harshithmullapudi Sep 22, 2026
6653998
fix(pages): pick a named workspace link, and show the filter at one o…
harshithmullapudi Sep 22, 2026
cace2e8
refactor(pages): move pagesListInput beside the other dashboard utils
harshithmullapudi Sep 23, 2026
de9d56f
fix(pages): filter page.list on the server, and key it on created_at
harshithmullapudi Sep 23, 2026
a01e9b3
refactor(pages): answer the comment sweep in one query, and stop over…
harshithmullapudi Sep 23, 2026
8c0eb67
fix(pages): keep the menu's invalidation matching its query, and stop…
harshithmullapudi Sep 23, 2026
3a5cfe0
fix(pages): do not narrow a picker by the dimension it offers, and dr…
harshithmullapudi Sep 23, 2026
3a6fff0
fix(db): drop the pages updated_at index the list no longer reads
saddlepaddle Sep 23, 2026
0a6e204
fix(pages): shared load-more spinner, 48-page batches, centered empty…
saddlepaddle Sep 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Trans } from "@lingui/react/macro";
import type { RefObject } from "react";
import { LuRefreshCw } from "react-icons/lu";
import { LuLoader } from "react-icons/lu";

interface LoadMoreSentinelProps {
sentinelRef: RefObject<HTMLDivElement | null>;
Expand All @@ -24,12 +23,7 @@ export function LoadMoreSentinel({
className="flex items-center justify-center gap-2 py-3 text-xs text-muted-foreground"
>
{isFetchingNextPage && (
<>
<LuRefreshCw className="size-3.5 animate-spin motion-reduce:animate-none" />
<span>
<Trans>Loading more…</Trans>
</span>
</>
<LuLoader className="size-4 animate-spin motion-reduce:animate-none" />
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { usePagesList } from "./usePagesList";
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useMemo, useRef } from "react";
import { cloudTrpc } from "renderer/lib/cloud-trpc";
import {
type PagesListFilter,
pagesListInput,
} from "renderer/routes/_authenticated/_dashboard/utils/pagesListInput";

/**
* One batch per scroll. Attach `scrollRef` to the scroll container and
* `sentinelRef` to an element after the last row; nothing fetches ahead of
* what the viewer has reached.
*/
export function usePagesList(
filter: PagesListFilter = {},
options: { enabled?: boolean; staleTime?: number } = {},
) {
const query = cloudTrpc.page.list.useInfiniteQuery(pagesListInput(filter), {
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
...options,
});

const {
hasNextPage,
isFetchingNextPage,
isFetchNextPageError,
fetchNextPage,
} = query;

const scrollRef = useRef<HTMLDivElement>(null);
const sentinelRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const sentinel = sentinelRef.current;
const root = scrollRef.current;
// React Query derives `hasNextPage` from the last successful fetch, so a
// failed batch leaves it true — observing again would spin. The caller
// offers a retry instead.
if (
!sentinel ||
!root ||
!hasNextPage ||
isFetchingNextPage ||
isFetchNextPageError
) {
return;
}
const observer = new IntersectionObserver(
(entries) => {
if (entries[0]?.isIntersecting) void fetchNextPage();
},
{ root, rootMargin: "200px" },
);
observer.observe(sentinel);
return () => observer.disconnect();
}, [hasNextPage, isFetchingNextPage, isFetchNextPageError, fetchNextPage]);

const items = useMemo(
() => query.data?.pages.flatMap((page) => page.items) ?? [],
[query.data],
);

return { ...query, items, scrollRef, sentinelRef };
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function PagesGrid({

if (pages.length === 0) {
return (
<Empty className="my-auto min-h-80 items-start border-0 px-0 py-20 text-left max-w-md mx-auto w-full md:px-0 md:py-20">
<EmptyHeader className="items-start text-left">
<Empty className="my-auto min-h-80 border-0 py-20 md:py-20">
<EmptyHeader>
<EmptyMedia variant="icon">
{hasFilters ? (
<LuSearchX className="size-5" />
Expand All @@ -103,7 +103,12 @@ export function PagesGrid({
</EmptyDescription>
</EmptyHeader>
{!hasFilters && (
<Button size="sm" onClick={onCreate} disabled={isCreating}>
<Button
size="sm"
variant="secondary"
onClick={onCreate}
disabled={isCreating}
>
<LuPlus className="size-3.5" />
<Trans>Create with AI</Trans>
</Button>
Expand Down
Loading
Loading