mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-21 18:55:16 +02:00
Merge remote-tracking branch 'upstream/dev' into feat/ui-revamp
This commit is contained in:
commit
9b1b5a504e
148 changed files with 19460 additions and 2708 deletions
|
|
@ -120,45 +120,22 @@ interface LayoutShellProps {
|
|||
|
||||
function MainContentPanel({
|
||||
isChatPage,
|
||||
isSidebarCollapsed,
|
||||
onTabSwitch,
|
||||
onNewChat,
|
||||
leftActions,
|
||||
showResizeHandle = false,
|
||||
onResizeMouseDown,
|
||||
children,
|
||||
}: {
|
||||
isChatPage: boolean;
|
||||
isSidebarCollapsed: boolean;
|
||||
onTabSwitch?: (tab: Tab) => void;
|
||||
onNewChat?: () => void;
|
||||
leftActions?: React.ReactNode;
|
||||
showResizeHandle?: boolean;
|
||||
onResizeMouseDown?: (e: React.MouseEvent) => void;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const activeTab = useAtomValue(activeTabAtom);
|
||||
const isDocumentTab = activeTab?.type === "document";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex flex-1 flex-col min-w-0 -ml-2",
|
||||
isSidebarCollapsed ? "" : "border-l border-border/60"
|
||||
)}
|
||||
>
|
||||
{showResizeHandle && onResizeMouseDown && (
|
||||
<div
|
||||
role="slider"
|
||||
aria-label="Resize sidebar"
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={50}
|
||||
tabIndex={0}
|
||||
onMouseDown={onResizeMouseDown}
|
||||
className="absolute left-0 top-0 hidden md:block h-full w-2 -translate-x-1/2 cursor-col-resize z-30 focus:outline-none"
|
||||
/>
|
||||
)}
|
||||
<div className="relative isolate flex flex-1 flex-col min-w-0">
|
||||
<TabBar
|
||||
onTabSwitch={onTabSwitch}
|
||||
onNewChat={onNewChat}
|
||||
|
|
@ -538,14 +515,26 @@ export function LayoutShell({
|
|||
</SidebarSlideOutPanel>
|
||||
</div>
|
||||
|
||||
{/* Resize handle — negative margins eat the flex gap so spacing stays unchanged */}
|
||||
{!isCollapsed && (
|
||||
<div
|
||||
role="slider"
|
||||
aria-label="Resize sidebar"
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={50}
|
||||
tabIndex={0}
|
||||
onMouseDown={onResizeMouseDown}
|
||||
className="hidden md:block h-full cursor-col-resize z-30 focus:outline-none"
|
||||
style={{ width: 8, marginLeft: -8, marginRight: -8 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Main content panel */}
|
||||
<MainContentPanel
|
||||
isChatPage={isChatPage}
|
||||
isSidebarCollapsed={isCollapsed}
|
||||
onTabSwitch={onTabSwitch}
|
||||
onNewChat={onNewChat}
|
||||
showResizeHandle={!isCollapsed}
|
||||
onResizeMouseDown={onResizeMouseDown}
|
||||
leftActions={
|
||||
isCollapsed ? (
|
||||
<SidebarCollapseButton isCollapsed={isCollapsed} onToggle={toggleCollapsed} />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery } from "@rocicorp/zero/react";
|
||||
import { useIsAnonymous } from "@/contexts/anonymous-mode";
|
||||
import { queries } from "@/zero/queries";
|
||||
import { PageUsageDisplay } from "./PageUsageDisplay";
|
||||
|
||||
export function AuthenticatedPageUsageDisplay() {
|
||||
const isAnonymous = useIsAnonymous();
|
||||
const [me] = useQuery(queries.user.me({}));
|
||||
|
||||
if (isAnonymous || !me) return null;
|
||||
|
||||
return <PageUsageDisplay pagesUsed={me.pagesUsed} pagesLimit={me.pagesLimit} />;
|
||||
}
|
||||
|
|
@ -23,9 +23,7 @@ import { useTranslations } from "next-intl";
|
|||
import type React from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
mentionedDocumentsAtom,
|
||||
} from "@/atoms/chat/mentioned-documents.atom";
|
||||
import { mentionedDocumentsAtom } from "@/atoms/chat/mentioned-documents.atom";
|
||||
import { connectorDialogOpenAtom } from "@/atoms/connector-dialog/connector-dialog.atoms";
|
||||
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||
import { deleteDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms";
|
||||
|
|
@ -74,12 +72,12 @@ import type { DocumentTypeEnum } from "@/contracts/types/document.types";
|
|||
import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { useElectronAPI, usePlatform } from "@/hooks/use-platform";
|
||||
import { getMentionDocKey } from "@/lib/chat/mention-doc-key";
|
||||
import { anonymousChatApiService } from "@/lib/apis/anonymous-chat-api.service";
|
||||
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
||||
import { foldersApiService } from "@/lib/apis/folders-api.service";
|
||||
import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service";
|
||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||
import { getMentionDocKey } from "@/lib/chat/mention-doc-key";
|
||||
import { uploadFolderScan } from "@/lib/folder-sync-upload";
|
||||
import { getSupportedExtensionsSet } from "@/lib/supported-extensions";
|
||||
import { queries } from "@/zero/queries/index";
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useQuery } from "@rocicorp/zero/react";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import { useIsAnonymous } from "@/contexts/anonymous-mode";
|
||||
import { stripeApiService } from "@/lib/apis/stripe-api.service";
|
||||
import { queries } from "@/zero/queries";
|
||||
|
||||
export function PremiumTokenUsageDisplay() {
|
||||
const isAnonymous = useIsAnonymous();
|
||||
const { data: tokenStatus } = useQuery({
|
||||
queryKey: ["token-status"],
|
||||
queryFn: () => stripeApiService.getTokenStatus(),
|
||||
staleTime: 60_000,
|
||||
enabled: !isAnonymous,
|
||||
});
|
||||
const [me] = useQuery(queries.user.me({}));
|
||||
|
||||
if (!tokenStatus) return null;
|
||||
if (isAnonymous || !me) return null;
|
||||
|
||||
const usagePercentage = Math.min(
|
||||
(tokenStatus.premium_tokens_used / Math.max(tokenStatus.premium_tokens_limit, 1)) * 100,
|
||||
(me.premiumTokensUsed / Math.max(me.premiumTokensLimit, 1)) * 100,
|
||||
100
|
||||
);
|
||||
|
||||
|
|
@ -31,8 +26,7 @@ export function PremiumTokenUsageDisplay() {
|
|||
<div className="space-y-1.5">
|
||||
<div className="flex justify-between items-center text-xs">
|
||||
<span className="text-muted-foreground">
|
||||
{formatTokens(tokenStatus.premium_tokens_used)} /{" "}
|
||||
{formatTokens(tokenStatus.premium_tokens_limit)} tokens
|
||||
{formatTokens(me.premiumTokensUsed)} / {formatTokens(me.premiumTokensLimit)} tokens
|
||||
</span>
|
||||
<span className="font-medium">{usagePercentage.toFixed(0)}%</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import { useIsAnonymous } from "@/contexts/anonymous-mode";
|
|||
import { cn } from "@/lib/utils";
|
||||
import { SIDEBAR_MIN_WIDTH } from "../../hooks/useSidebarResize";
|
||||
import type { ChatItem, NavItem, PageUsage, SearchSpace, User } from "../../types/layout.types";
|
||||
import { AuthenticatedPageUsageDisplay } from "./AuthenticatedPageUsageDisplay";
|
||||
import { ChatListItem } from "./ChatListItem";
|
||||
import { NavSection } from "./NavSection";
|
||||
import { PageUsageDisplay } from "./PageUsageDisplay";
|
||||
import { PremiumTokenUsageDisplay } from "./PremiumTokenUsageDisplay";
|
||||
import { SidebarButton } from "./SidebarButton";
|
||||
import { SidebarCollapseButton } from "./SidebarCollapseButton";
|
||||
|
|
@ -342,9 +342,7 @@ function SidebarUsageFooter({
|
|||
return (
|
||||
<div className="px-3 py-3 border-t border-border/60 space-y-3">
|
||||
<PremiumTokenUsageDisplay />
|
||||
{pageUsage && (
|
||||
<PageUsageDisplay pagesUsed={pageUsage.pagesUsed} pagesLimit={pageUsage.pagesLimit} />
|
||||
)}
|
||||
<AuthenticatedPageUsageDisplay />
|
||||
<div className="space-y-0.5">
|
||||
<Link
|
||||
href={`/dashboard/${searchSpaceId}/more-pages`}
|
||||
|
|
|
|||
|
|
@ -316,10 +316,10 @@ export function DocumentTabContent({ documentId, searchSpaceId, title }: Documen
|
|||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<MarkdownViewer content={doc.source_markdown} />
|
||||
<MarkdownViewer content={doc.source_markdown} enableCitations />
|
||||
</>
|
||||
) : (
|
||||
<MarkdownViewer content={doc.source_markdown} />
|
||||
<MarkdownViewer content={doc.source_markdown} enableCitations />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue