mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-15 18:25:18 +02:00
refactor: improve connector popup UI and date formatting
- Adjusted the height of the dialog content in the connector popup for better layout. - Enhanced the last indexed date display with a new function for contextual formatting, providing clearer time references. - Updated various text sizes for consistency across the connector card and dialog header components. - Minor layout adjustments in the connector dialog header and active connectors tab for improved spacing.
This commit is contained in:
parent
0b7816850e
commit
d576607d67
4 changed files with 103 additions and 16 deletions
|
|
@ -189,7 +189,7 @@ export const ConnectorIndicator: FC = () => {
|
||||||
)}
|
)}
|
||||||
</TooltipIconButton>
|
</TooltipIconButton>
|
||||||
|
|
||||||
<DialogContent className="max-w-3xl w-[95vw] sm:w-full h-[90vh] sm:h-[85vh] flex flex-col p-0 gap-0 overflow-hidden border border-border bg-muted text-foreground [&>button]:right-6 sm:[&>button]:right-12 [&>button]:top-8 sm:[&>button]:top-10 [&>button]:opacity-80 hover:[&>button]:opacity-100 [&>button_svg]:size-5">
|
<DialogContent className="max-w-3xl w-[95vw] sm:w-full h-[75vh] sm:h-[85vh] flex flex-col p-0 gap-0 overflow-hidden border border-border bg-muted text-foreground [&>button]:right-4 sm:[&>button]:right-12 [&>button]:top-6 sm:[&>button]:top-10 [&>button]:opacity-80 hover:[&>button]:opacity-100 [&>button_svg]:size-5">
|
||||||
{/* YouTube Crawler View - shown when adding YouTube videos */}
|
{/* YouTube Crawler View - shown when adding YouTube videos */}
|
||||||
{isYouTubeView && searchSpaceId ? (
|
{isYouTubeView && searchSpaceId ? (
|
||||||
<YouTubeCrawlerView searchSpaceId={searchSpaceId} onBack={handleBackFromYouTube} />
|
<YouTubeCrawlerView searchSpaceId={searchSpaceId} onBack={handleBackFromYouTube} />
|
||||||
|
|
@ -272,7 +272,7 @@ export const ConnectorIndicator: FC = () => {
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="flex-1 min-h-0 relative overflow-hidden">
|
<div className="flex-1 min-h-0 relative overflow-hidden">
|
||||||
<div className="h-full overflow-y-auto" onScroll={handleScroll}>
|
<div className="h-full overflow-y-auto" onScroll={handleScroll}>
|
||||||
<div className="px-6 sm:px-12 py-6 sm:py-8 pb-16 sm:pb-16">
|
<div className="px-4 sm:px-12 py-4 sm:py-8 pb-12 sm:pb-16">
|
||||||
<TabsContent value="all" className="m-0">
|
<TabsContent value="all" className="m-0">
|
||||||
<AllConnectorsTab
|
<AllConnectorsTab
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { IconBrandYoutube } from "@tabler/icons-react";
|
import { IconBrandYoutube } from "@tabler/icons-react";
|
||||||
import { format } from "date-fns";
|
import {
|
||||||
|
differenceInDays,
|
||||||
|
differenceInMinutes,
|
||||||
|
format,
|
||||||
|
isToday,
|
||||||
|
isYesterday,
|
||||||
|
} from "date-fns";
|
||||||
import { FileText, Loader2 } from "lucide-react";
|
import { FileText, Loader2 } from "lucide-react";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -49,6 +55,45 @@ function formatDocumentCount(count: number | undefined): string {
|
||||||
return `${m.replace(/\.0$/, "")}M docs`;
|
return `${m.replace(/\.0$/, "")}M docs`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format last indexed date with contextual messages
|
||||||
|
* Examples: "Just now", "10 minutes ago", "Today at 2:30 PM", "Yesterday at 3:45 PM", "3 days ago", "Jan 15, 2026"
|
||||||
|
*/
|
||||||
|
function formatLastIndexedDate(dateString: string): string {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const now = new Date();
|
||||||
|
const minutesAgo = differenceInMinutes(now, date);
|
||||||
|
const daysAgo = differenceInDays(now, date);
|
||||||
|
|
||||||
|
// Just now (within last minute)
|
||||||
|
if (minutesAgo < 1) {
|
||||||
|
return "Just now";
|
||||||
|
}
|
||||||
|
|
||||||
|
// X minutes ago (less than 1 hour)
|
||||||
|
if (minutesAgo < 60) {
|
||||||
|
return `${minutesAgo} ${minutesAgo === 1 ? "minute" : "minutes"} ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Today at [time]
|
||||||
|
if (isToday(date)) {
|
||||||
|
return `Today at ${format(date, "h:mm a")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yesterday at [time]
|
||||||
|
if (isYesterday(date)) {
|
||||||
|
return `Yesterday at ${format(date, "h:mm a")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// X days ago (less than 7 days)
|
||||||
|
if (daysAgo < 7) {
|
||||||
|
return `${daysAgo} ${daysAgo === 1 ? "day" : "days"} ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full date for older entries
|
||||||
|
return format(date, "MMM d, yyyy");
|
||||||
|
}
|
||||||
|
|
||||||
export const ConnectorCard: FC<ConnectorCardProps> = ({
|
export const ConnectorCard: FC<ConnectorCardProps> = ({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -86,13 +131,13 @@ export const ConnectorCard: FC<ConnectorCardProps> = ({
|
||||||
// Show last indexed date for connected connectors
|
// Show last indexed date for connected connectors
|
||||||
if (lastIndexedAt) {
|
if (lastIndexedAt) {
|
||||||
return (
|
return (
|
||||||
<span className="whitespace-nowrap">
|
<span className="whitespace-nowrap text-[10px]">
|
||||||
Last indexed: {format(new Date(lastIndexedAt), "MMM d, yyyy")}
|
Last indexed: {formatLastIndexedDate(lastIndexedAt)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Fallback for connected but never indexed
|
// Fallback for connected but never indexed
|
||||||
return <span className="whitespace-nowrap">Never indexed</span>;
|
return <span className="whitespace-nowrap text-[10px]">Never indexed</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return description;
|
return description;
|
||||||
|
|
@ -113,9 +158,9 @@ export const ConnectorCard: FC<ConnectorCardProps> = ({
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-[14px] font-semibold leading-tight">{title}</span>
|
<span className="text-[14px] font-semibold leading-tight">{title}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[11px] text-muted-foreground mt-1">{getStatusContent()}</div>
|
<div className="text-[10px] text-muted-foreground mt-1">{getStatusContent()}</div>
|
||||||
{isConnected && documentCount !== undefined && (
|
{isConnected && documentCount !== undefined && (
|
||||||
<p className="text-[11px] text-muted-foreground mt-0.5">
|
<p className="text-[10px] text-muted-foreground mt-0.5">
|
||||||
{formatDocumentCount(documentCount)}
|
{formatDocumentCount(documentCount)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -24,20 +24,20 @@ export const ConnectorDialogHeader: FC<ConnectorDialogHeaderProps> = ({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex-shrink-0 px-6 sm:px-12 pt-8 sm:pt-10 transition-shadow duration-200 relative z-10",
|
"flex-shrink-0 px-4 sm:px-12 pt-5 sm:pt-10 transition-shadow duration-200 relative z-10",
|
||||||
isScrolled && "shadow-xl bg-muted/50 backdrop-blur-md"
|
isScrolled && "shadow-xl bg-muted/50 backdrop-blur-md"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-2xl sm:text-3xl font-semibold tracking-tight">
|
<DialogTitle className="text-xl sm:text-3xl font-semibold tracking-tight">
|
||||||
Connectors
|
Connectors
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription className="text-sm sm:text-base text-muted-foreground/80 mt-1 sm:mt-1.5">
|
<DialogDescription className="text-xs sm:text-base text-muted-foreground/80 mt-1 sm:mt-1.5">
|
||||||
Search across all your apps and data in one place.
|
Search across all your apps and data in one place.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="flex flex-col-reverse sm:flex-row sm:items-end justify-between gap-6 sm:gap-8 mt-6 sm:mt-8 border-b border-border/80 dark:border-white/5">
|
<div className="flex flex-col-reverse sm:flex-row sm:items-end justify-between gap-4 sm:gap-8 mt-4 sm:mt-8 border-b border-border/80 dark:border-white/5">
|
||||||
<TabsList className="bg-transparent p-0 gap-4 sm:gap-8 h-auto w-full sm:w-auto justify-center sm:justify-start">
|
<TabsList className="bg-transparent p-0 gap-4 sm:gap-8 h-auto w-full sm:w-auto justify-center sm:justify-start">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="all"
|
value="all"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { format } from "date-fns";
|
import {
|
||||||
|
differenceInDays,
|
||||||
|
differenceInMinutes,
|
||||||
|
format,
|
||||||
|
isToday,
|
||||||
|
isYesterday,
|
||||||
|
} from "date-fns";
|
||||||
import { ArrowRight, Cable, Loader2 } from "lucide-react";
|
import { ArrowRight, Cable, Loader2 } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
|
|
@ -64,6 +70,42 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
||||||
return `${m.replace(/\.0$/, "")}M docs`;
|
return `${m.replace(/\.0$/, "")}M docs`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Format last indexed date with contextual messages
|
||||||
|
const formatLastIndexedDate = (dateString: string): string => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const now = new Date();
|
||||||
|
const minutesAgo = differenceInMinutes(now, date);
|
||||||
|
const daysAgo = differenceInDays(now, date);
|
||||||
|
|
||||||
|
// Just now (within last minute)
|
||||||
|
if (minutesAgo < 1) {
|
||||||
|
return "Just now";
|
||||||
|
}
|
||||||
|
|
||||||
|
// X minutes ago (less than 1 hour)
|
||||||
|
if (minutesAgo < 60) {
|
||||||
|
return `${minutesAgo} ${minutesAgo === 1 ? "minute" : "minutes"} ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Today at [time]
|
||||||
|
if (isToday(date)) {
|
||||||
|
return `Today at ${format(date, "h:mm a")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yesterday at [time]
|
||||||
|
if (isYesterday(date)) {
|
||||||
|
return `Yesterday at ${format(date, "h:mm a")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// X days ago (less than 7 days)
|
||||||
|
if (daysAgo < 7) {
|
||||||
|
return `${daysAgo} ${daysAgo === 1 ? "day" : "days"} ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full date for older entries
|
||||||
|
return format(date, "MMM d, yyyy");
|
||||||
|
};
|
||||||
|
|
||||||
// Document types that should be shown as cards (not from connectors)
|
// Document types that should be shown as cards (not from connectors)
|
||||||
// These are: EXTENSION (browser extension), FILE (uploaded files), NOTE (editor notes),
|
// These are: EXTENSION (browser extension), FILE (uploaded files), NOTE (editor notes),
|
||||||
// YOUTUBE_VIDEO (YouTube videos), and CRAWLED_URL (web pages - shown separately even though it can come from WEBCRAWLER_CONNECTOR)
|
// YOUTUBE_VIDEO (YouTube videos), and CRAWLED_URL (web pages - shown separately even though it can come from WEBCRAWLER_CONNECTOR)
|
||||||
|
|
@ -148,13 +190,13 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-[11px] text-muted-foreground mt-1">
|
<p className="text-[10px] text-muted-foreground mt-1 whitespace-nowrap">
|
||||||
{connector.last_indexed_at
|
{connector.last_indexed_at
|
||||||
? `Last indexed: ${format(new Date(connector.last_indexed_at), "MMM d, yyyy")}`
|
? `Last indexed: ${formatLastIndexedDate(connector.last_indexed_at)}`
|
||||||
: "Never indexed"}
|
: "Never indexed"}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<p className="text-[11px] text-muted-foreground mt-0.5">
|
<p className="text-[10px] text-muted-foreground mt-0.5">
|
||||||
{formatDocumentCount(documentCount)}
|
{formatDocumentCount(documentCount)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue