diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx index e8abcae8..d889a89e 100644 --- a/apps/client/src/features/page/tree/components/space-tree.tsx +++ b/apps/client/src/features/page/tree/components/space-tree.tsx @@ -269,12 +269,15 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) { const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom); const prefetchPage = () => { - timerRef.current = setTimeout(() => { - queryClient.prefetchQuery({ - queryKey: ["pages", node.data.slugId], - queryFn: () => getPageById({ pageId: node.data.slugId }), + timerRef.current = setTimeout(async () => { + const page = await queryClient.fetchQuery({ + queryKey: ["pages", node.data.id], + queryFn: () => getPageById({ pageId: node.data.id }), staleTime: 5 * 60 * 1000, }); + if (page?.slugId) { + queryClient.setQueryData(["pages", page.slugId], page); + } }, 150); }; diff --git a/apps/client/src/features/share/components/share-modal.tsx b/apps/client/src/features/share/components/share-modal.tsx index a39effca..cf597e0a 100644 --- a/apps/client/src/features/share/components/share-modal.tsx +++ b/apps/client/src/features/share/components/share-modal.tsx @@ -8,7 +8,6 @@ import { Switch, Text, TextInput, - Tooltip, } from "@mantine/core"; import { IconExternalLink, IconWorld, IconLock } from "@tabler/icons-react"; import React, { useEffect, useMemo, useState } from "react"; @@ -21,12 +20,12 @@ import { import { Link, useNavigate, useParams } from "react-router-dom"; import { extractPageSlugId, getPageIcon } from "@/lib"; import { useTranslation } from "react-i18next"; +import { usePageQuery } from "@/features/page/queries/page-query.ts"; import CopyTextButton from "@/components/common/copy.tsx"; import { getAppUrl, isCloud } from "@/lib/config.ts"; import { buildPageUrl } from "@/features/page/page.utils.ts"; import classes from "@/features/share/components/share.module.css"; import useTrial from "@/ee/hooks/use-trial.tsx"; -import { getCheckoutLink } from "@/ee/billing/services/billing-service.ts"; interface ShareModalProps { readOnly: boolean; @@ -35,7 +34,9 @@ export default function ShareModal({ readOnly }: ShareModalProps) { const { t } = useTranslation(); const navigate = useNavigate(); const { pageSlug } = useParams(); - const pageId = extractPageSlugId(pageSlug); + const pageSlugId = extractPageSlugId(pageSlug); + const { data: page } = usePageQuery({ pageId: pageSlugId }); + const pageId = page?.id; const { data: share } = useShareForPageQuery(pageId); const { spaceSlug } = useParams(); const { isTrial } = useTrial(); diff --git a/apps/client/src/features/share/queries/share-query.ts b/apps/client/src/features/share/queries/share-query.ts index dea047bf..97ecff76 100644 --- a/apps/client/src/features/share/queries/share-query.ts +++ b/apps/client/src/features/share/queries/share-query.ts @@ -27,9 +27,7 @@ import { getShares, updateShare, } from "@/features/share/services/share-service.ts"; -import { IPage } from "@/features/page/types/page.types.ts"; import { IPagination, QueryParams } from "@/lib/types.ts"; -import { useEffect } from "react"; export function useGetSharesQuery( params?: QueryParams, @@ -72,7 +70,7 @@ export function useShareForPageQuery( queryKey: ["share-for-page", pageId], queryFn: () => getShareForPage(pageId), enabled: !!pageId, - staleTime: 0, + staleTime: 60 * 1000, retry: false, }); diff --git a/apps/server/src/core/share/share.service.ts b/apps/server/src/core/share/share.service.ts index d065f860..82b8660c 100644 --- a/apps/server/src/core/share/share.service.ts +++ b/apps/server/src/core/share/share.service.ts @@ -123,80 +123,82 @@ export class ShareService { .withRecursive('page_hierarchy', (cte) => cte .selectFrom('pages') + .leftJoin('shares', 'shares.pageId', 'pages.id') .select([ - 'id', - 'slugId', + 'pages.id', + 'pages.slugId', 'pages.title', 'pages.icon', - 'parentPageId', + 'pages.parentPageId', sql`0`.as('level'), + 'shares.id as shareId', + 'shares.key as shareKey', + 'shares.includeSubPages', + 'shares.searchIndexing', + 'shares.creatorId', + 'shares.spaceId', + 'shares.workspaceId', + 'shares.createdAt', ]) - .where(isValidUUID(pageId) ? 'id' : 'slugId', '=', pageId) - .where('deletedAt', 'is', null) - .unionAll((union) => - union - .selectFrom('pages as p') - .select([ - 'p.id', - 'p.slugId', - 'p.title', - 'p.icon', - 'p.parentPageId', - // Increase the level by 1 for each ancestor. - sql`ph.level + 1`.as('level'), - ]) - .innerJoin('page_hierarchy as ph', 'ph.parentPageId', 'p.id') - .where('p.deletedAt', 'is', null), + .where(isValidUUID(pageId) ? 'pages.id' : 'pages.slugId', '=', pageId) + .where('pages.deletedAt', 'is', null) + .unionAll( + (union) => + union + .selectFrom('pages as p') + .innerJoin('page_hierarchy as ph', 'ph.parentPageId', 'p.id') + .leftJoin('shares as s', 's.pageId', 'p.id') + .select([ + 'p.id', + 'p.slugId', + 'p.title', + 'p.icon', + 'p.parentPageId', + sql`ph.level + 1`.as('level'), + 's.id as shareId', + 's.key as shareKey', + 's.includeSubPages', + 's.searchIndexing', + 's.creatorId', + 's.spaceId', + 's.workspaceId', + 's.createdAt', + ]) + .where('p.deletedAt', 'is', null) + .where(sql`ph.share_id`, 'is', null) // stop if share found + .where(sql`ph.level`, '<', sql`25`), // prevent loop ), ) .selectFrom('page_hierarchy') - .leftJoin('shares', 'shares.pageId', 'page_hierarchy.id') - .select([ - 'page_hierarchy.id as sharedPageId', - 'page_hierarchy.slugId as sharedPageSlugId', - 'page_hierarchy.title as sharedPageTitle', - 'page_hierarchy.icon as sharedPageIcon', - 'page_hierarchy.level as level', - 'shares.id', - 'shares.key', - 'shares.pageId', - 'shares.includeSubPages', - 'shares.searchIndexing', - 'shares.creatorId', - 'shares.spaceId', - 'shares.workspaceId', - 'shares.createdAt', - 'shares.updatedAt', - ]) - .where('shares.id', 'is not', null) - .orderBy('page_hierarchy.level', 'asc') + .selectAll() + .where('shareId', 'is not', null) + .limit(1) .executeTakeFirst(); - if (!share || share.workspaceId != workspaceId) { + if (!share || share.workspaceId !== workspaceId) { return undefined; } - if (share.level === 1 && !share.includeSubPages) { - // we can only show a page if its shared ancestor permits it + if ((share.level as number) > 0 && !share.includeSubPages) { return undefined; } return { - id: share.id, - key: share.key, + id: share.shareId, + key: share.shareKey, includeSubPages: share.includeSubPages, searchIndexing: share.searchIndexing, - pageId: share.pageId, + pageId: share.id, creatorId: share.creatorId, spaceId: share.spaceId, workspaceId: share.workspaceId, createdAt: share.createdAt, level: share.level, sharedPage: { - id: share.sharedPageId, - slugId: share.sharedPageSlugId, - title: share.sharedPageTitle, - icon: share.sharedPageIcon, + id: share.id, + slugId: share.slugId, + title: share.title, + icon: share.icon, }, }; }