mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-27 17:56:25 +02:00
feat: improve connector popup with grouped OAuth connectors
Active Connectors tab: - Group OAuth connectors by type (Gmail, Google Drive, etc.) - Show account count badge on grouped cards - Show most recent last indexed date across all accounts - Show non-OAuth connectors individually with active task messages All Connectors tab: - Show most recent last indexed date for OAuth connector types - Check if any account is indexing for OAuth types Accounts List View: - Remove document count from individual account cards - Back button returns to previous tab (not always All Connectors) General: - Update handleViewAccountsList to use (connectorType, connectorTitle) signature - Consistent behavior for viewing accounts from both tabs
This commit is contained in:
parent
9ad1348d6b
commit
3ff87a218d
6 changed files with 193 additions and 93 deletions
|
|
@ -205,7 +205,6 @@ export const ConnectorIndicator: FC = () => {
|
|||
connectors={(allConnectors || []) as SearchSourceConnector[]}
|
||||
indexingConnectorIds={indexingConnectorIds}
|
||||
logsSummary={logsSummary}
|
||||
documentTypeCounts={documentTypeCounts}
|
||||
onBack={handleBackFromAccountsList}
|
||||
onManage={handleStartEdit}
|
||||
onAddAccount={() => {
|
||||
|
|
@ -317,18 +316,19 @@ export const ConnectorIndicator: FC = () => {
|
|||
/>
|
||||
</TabsContent>
|
||||
|
||||
<ActiveConnectorsTab
|
||||
searchQuery={searchQuery}
|
||||
hasSources={hasSources}
|
||||
totalSourceCount={totalSourceCount}
|
||||
activeDocumentTypes={activeDocumentTypes}
|
||||
connectors={connectors as SearchSourceConnector[]}
|
||||
indexingConnectorIds={indexingConnectorIds}
|
||||
logsSummary={logsSummary}
|
||||
searchSpaceId={searchSpaceId}
|
||||
onTabChange={handleTabChange}
|
||||
onManage={handleStartEdit}
|
||||
/>
|
||||
<ActiveConnectorsTab
|
||||
searchQuery={searchQuery}
|
||||
hasSources={hasSources}
|
||||
totalSourceCount={totalSourceCount}
|
||||
activeDocumentTypes={activeDocumentTypes}
|
||||
connectors={connectors as SearchSourceConnector[]}
|
||||
indexingConnectorIds={indexingConnectorIds}
|
||||
logsSummary={logsSummary}
|
||||
searchSpaceId={searchSpaceId}
|
||||
onTabChange={handleTabChange}
|
||||
onManage={handleStartEdit}
|
||||
onViewAccountsList={handleViewAccountsList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Bottom fade shadow */}
|
||||
|
|
|
|||
|
|
@ -679,19 +679,20 @@ export const useConnectorDialog = () => {
|
|||
|
||||
// Handle viewing accounts list for OAuth connector type
|
||||
const handleViewAccountsList = useCallback(
|
||||
(connector: (typeof OAUTH_CONNECTORS)[number]) => {
|
||||
(connectorType: string, connectorTitle: string) => {
|
||||
if (!searchSpaceId) return;
|
||||
|
||||
setViewingAccountsType({
|
||||
connectorType: connector.connectorType,
|
||||
connectorTitle: connector.title,
|
||||
connectorType,
|
||||
connectorTitle,
|
||||
});
|
||||
|
||||
// Update URL to show accounts view
|
||||
// Update URL to show accounts view, preserving current tab
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("modal", "connectors");
|
||||
url.searchParams.set("view", "accounts");
|
||||
url.searchParams.set("connectorType", connector.connectorType);
|
||||
url.searchParams.set("connectorType", connectorType);
|
||||
// Keep the current tab in URL so we can go back to it
|
||||
window.history.pushState({ modal: true }, "", url.toString());
|
||||
},
|
||||
[searchSpaceId]
|
||||
|
|
@ -702,7 +703,7 @@ export const useConnectorDialog = () => {
|
|||
setViewingAccountsType(null);
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("modal", "connectors");
|
||||
url.searchParams.set("tab", "all");
|
||||
// Keep the current tab (don't change it) - just remove view-specific params
|
||||
url.searchParams.delete("view");
|
||||
url.searchParams.delete("connectorType");
|
||||
router.replace(url.pathname + url.search, { scroll: false });
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
|||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
import type { LogActiveTask, LogSummary } from "@/contracts/types/log.types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { OAUTH_CONNECTORS } from "../constants/connector-constants";
|
||||
import { getDocumentCountForConnector } from "../utils/connector-document-mapping";
|
||||
import { getConnectorDisplayName } from "./all-connectors-tab";
|
||||
|
||||
interface ActiveConnectorsTabProps {
|
||||
searchQuery: string;
|
||||
|
|
@ -25,6 +25,7 @@ interface ActiveConnectorsTabProps {
|
|||
searchSpaceId: string;
|
||||
onTabChange: (value: string) => void;
|
||||
onManage?: (connector: SearchSourceConnector) => void;
|
||||
onViewAccountsList?: (connectorType: string, connectorTitle: string) => void;
|
||||
}
|
||||
|
||||
export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
||||
|
|
@ -37,6 +38,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
searchSpaceId,
|
||||
onTabChange,
|
||||
onManage,
|
||||
onViewAccountsList,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
|
||||
|
|
@ -72,38 +74,24 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
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
|
||||
if (minutesAgo < 1) return "Just now";
|
||||
if (minutesAgo < 60) return `${minutesAgo} ${minutesAgo === 1 ? "minute" : "minutes"} ago`;
|
||||
if (isToday(date)) return `Today at ${format(date, "h:mm a")}`;
|
||||
if (isYesterday(date)) return `Yesterday at ${format(date, "h:mm a")}`;
|
||||
if (daysAgo < 7) return `${daysAgo} ${daysAgo === 1 ? "day" : "days"} ago`;
|
||||
return format(date, "MMM d, yyyy");
|
||||
};
|
||||
|
||||
// Document types that should be shown as cards (not from connectors)
|
||||
// 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)
|
||||
// Get most recent last indexed date from a list of connectors
|
||||
const getMostRecentLastIndexed = (connectorsList: SearchSourceConnector[]): string | undefined => {
|
||||
return connectorsList.reduce<string | undefined>((latest, c) => {
|
||||
if (!c.last_indexed_at) return latest;
|
||||
if (!latest) return c.last_indexed_at;
|
||||
return new Date(c.last_indexed_at) > new Date(latest) ? c.last_indexed_at : latest;
|
||||
}, undefined);
|
||||
};
|
||||
|
||||
// Document types that should be shown as standalone cards (not from connectors)
|
||||
const standaloneDocumentTypes = ["EXTENSION", "FILE", "NOTE", "YOUTUBE_VIDEO", "CRAWLED_URL"];
|
||||
|
||||
// Filter to only show standalone document types that have documents (count > 0)
|
||||
|
|
@ -119,8 +107,47 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
return doc.label.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
});
|
||||
|
||||
// Filter connectors based on search query
|
||||
const filteredConnectors = connectors.filter((connector) => {
|
||||
// Get OAuth connector types set for quick lookup
|
||||
const oauthConnectorTypes = new Set<string>(OAUTH_CONNECTORS.map((c) => c.connectorType));
|
||||
|
||||
// Separate OAuth and non-OAuth connectors
|
||||
const oauthConnectors = connectors.filter((c) => oauthConnectorTypes.has(c.connector_type));
|
||||
const nonOauthConnectors = connectors.filter((c) => !oauthConnectorTypes.has(c.connector_type));
|
||||
|
||||
// Group OAuth connectors by type
|
||||
const oauthConnectorsByType = oauthConnectors.reduce(
|
||||
(acc, connector) => {
|
||||
const type = connector.connector_type;
|
||||
if (!acc[type]) {
|
||||
acc[type] = [];
|
||||
}
|
||||
acc[type].push(connector);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, SearchSourceConnector[]>
|
||||
);
|
||||
|
||||
// Get display info for OAuth connector type
|
||||
const getOAuthConnectorTypeInfo = (connectorType: string) => {
|
||||
const oauthConnector = OAUTH_CONNECTORS.find((c) => c.connectorType === connectorType);
|
||||
return {
|
||||
title: oauthConnector?.title || connectorType.replace(/_/g, " ").replace(/connector/gi, "").trim(),
|
||||
};
|
||||
};
|
||||
|
||||
// Filter OAuth connector types based on search query
|
||||
const filteredOAuthConnectorTypes = Object.entries(oauthConnectorsByType).filter(([connectorType]) => {
|
||||
if (!searchQuery) return true;
|
||||
const searchLower = searchQuery.toLowerCase();
|
||||
const { title } = getOAuthConnectorTypeInfo(connectorType);
|
||||
return (
|
||||
title.toLowerCase().includes(searchLower) ||
|
||||
connectorType.toLowerCase().includes(searchLower)
|
||||
);
|
||||
});
|
||||
|
||||
// Filter non-OAuth connectors based on search query
|
||||
const filteredNonOAuthConnectors = nonOauthConnectors.filter((connector) => {
|
||||
if (!searchQuery) return true;
|
||||
const searchLower = searchQuery.toLowerCase();
|
||||
return (
|
||||
|
|
@ -129,18 +156,98 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
);
|
||||
});
|
||||
|
||||
const hasActiveConnectors = filteredOAuthConnectorTypes.length > 0 || filteredNonOAuthConnectors.length > 0;
|
||||
|
||||
return (
|
||||
<TabsContent value="active" className="m-0">
|
||||
{hasSources ? (
|
||||
<div className="space-y-6">
|
||||
{/* Active Connectors Section */}
|
||||
{filteredConnectors.length > 0 && (
|
||||
{hasActiveConnectors && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="text-sm font-semibold text-muted-foreground">Active Connectors</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
{filteredConnectors.map((connector) => {
|
||||
{/* OAuth Connectors - Grouped by Type */}
|
||||
{filteredOAuthConnectorTypes.map(([connectorType, typeConnectors]) => {
|
||||
const { title } = getOAuthConnectorTypeInfo(connectorType);
|
||||
const isAnyIndexing = typeConnectors.some(
|
||||
(c: SearchSourceConnector) => indexingConnectorIds.has(c.id)
|
||||
);
|
||||
const documentCount = getDocumentCountForConnector(
|
||||
connectorType,
|
||||
documentTypeCounts
|
||||
);
|
||||
const accountCount = typeConnectors.length;
|
||||
const mostRecentLastIndexed = getMostRecentLastIndexed(typeConnectors);
|
||||
|
||||
const handleManageClick = () => {
|
||||
if (onViewAccountsList) {
|
||||
onViewAccountsList(connectorType, title);
|
||||
} else if (onManage && typeConnectors[0]) {
|
||||
onManage(typeConnectors[0]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`oauth-type-${connectorType}`}
|
||||
className={cn(
|
||||
"relative flex items-center gap-4 p-4 rounded-xl border border-border transition-all",
|
||||
isAnyIndexing
|
||||
? "bg-primary/5 border-primary/20"
|
||||
: "bg-slate-400/5 dark:bg-white/5 hover:bg-slate-400/10 dark:hover:bg-white/10"
|
||||
)}
|
||||
>
|
||||
{/* Account count badge */}
|
||||
<div className="absolute -top-2 -right-2 flex h-5 items-center justify-center rounded-md bg-primary px-2 text-[10px] font-semibold text-primary-foreground whitespace-nowrap">
|
||||
{accountCount > 99 ? "99+" : accountCount} {accountCount === 1 ? "Account" : "Accounts"}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-12 w-12 items-center justify-center rounded-lg border shrink-0",
|
||||
isAnyIndexing
|
||||
? "bg-primary/10 border-primary/20"
|
||||
: "bg-slate-400/5 dark:bg-white/5 border-slate-400/5 dark:border-white/5"
|
||||
)}
|
||||
>
|
||||
{getConnectorIcon(connectorType, "size-6")}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-[14px] font-semibold leading-tight truncate">
|
||||
{title}
|
||||
</p>
|
||||
{isAnyIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
Indexing...
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[10px] text-muted-foreground mt-1 whitespace-nowrap">
|
||||
{mostRecentLastIndexed
|
||||
? `Last indexed: ${formatLastIndexedDate(mostRecentLastIndexed)}`
|
||||
: "Never indexed"}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-[10px] text-muted-foreground mt-0.5">
|
||||
{formatDocumentCount(documentCount)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="h-8 text-[11px] px-3 rounded-lg font-medium bg-white text-slate-700 hover:bg-slate-50 border-0 shadow-xs dark:bg-secondary dark:text-secondary-foreground dark:hover:bg-secondary/80 shrink-0"
|
||||
onClick={handleManageClick}
|
||||
>
|
||||
Manage
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Non-OAuth Connectors - Individual Cards */}
|
||||
{filteredNonOAuthConnectors.map((connector) => {
|
||||
const isIndexing = indexingConnectorIds.has(connector.id);
|
||||
const activeTask = logsSummary?.active_tasks?.find(
|
||||
(task: LogActiveTask) => task.connector_id === connector.id
|
||||
|
|
@ -162,7 +269,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-12 w-12 items-center justify-center rounded-lg border",
|
||||
"flex h-12 w-12 items-center justify-center rounded-lg border shrink-0",
|
||||
isIndexing
|
||||
? "bg-primary/10 border-primary/20"
|
||||
: "bg-slate-400/5 dark:bg-white/5 border-slate-400/5 dark:border-white/5"
|
||||
|
|
@ -172,7 +279,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-[14px] font-semibold leading-tight truncate">
|
||||
{getConnectorDisplayName(connector.name)}
|
||||
{connector.name}
|
||||
</p>
|
||||
{isIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
|
|
@ -198,7 +305,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="h-8 text-[11px] px-3 rounded-lg font-medium bg-white text-slate-700 hover:bg-slate-50 border-0 shadow-xs dark:bg-secondary dark:text-secondary-foreground dark:hover:bg-secondary/80"
|
||||
className="h-8 text-[11px] px-3 rounded-lg font-medium bg-white text-slate-700 hover:bg-slate-50 border-0 shadow-xs dark:bg-secondary dark:text-secondary-foreground dark:hover:bg-secondary/80 shrink-0"
|
||||
onClick={onManage ? () => onManage(connector) : undefined}
|
||||
>
|
||||
Manage
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ interface AllConnectorsTabProps {
|
|||
onCreateWebcrawler?: () => void;
|
||||
onCreateYouTubeCrawler?: () => void;
|
||||
onManage?: (connector: SearchSourceConnector) => void;
|
||||
onViewAccountsList?: (connector: (typeof OAUTH_CONNECTORS)[number]) => void;
|
||||
onViewAccountsList?: (connectorType: string, connectorTitle: string) => void;
|
||||
}
|
||||
|
||||
export const AllConnectorsTab: FC<AllConnectorsTabProps> = ({
|
||||
|
|
@ -102,25 +102,40 @@ export const AllConnectorsTab: FC<AllConnectorsTabProps> = ({
|
|||
{filteredOAuth.map((connector) => {
|
||||
const isConnected = connectedTypes.has(connector.connectorType);
|
||||
const isConnecting = connectingId === connector.id;
|
||||
// Find the actual connector object if connected
|
||||
const actualConnector =
|
||||
|
||||
// Find all connectors of this type
|
||||
const typeConnectors =
|
||||
isConnected && allConnectors
|
||||
? allConnectors.find(
|
||||
? allConnectors.filter(
|
||||
(c: SearchSourceConnector) =>
|
||||
c.connector_type === connector.connectorType
|
||||
)
|
||||
: undefined;
|
||||
: [];
|
||||
|
||||
// Get the most recent last_indexed_at across all accounts
|
||||
const mostRecentLastIndexed = typeConnectors.reduce<string | undefined>(
|
||||
(latest, c) => {
|
||||
if (!c.last_indexed_at) return latest;
|
||||
if (!latest) return c.last_indexed_at;
|
||||
return new Date(c.last_indexed_at) > new Date(latest) ? c.last_indexed_at : latest;
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
const documentCount = getDocumentCountForConnector(
|
||||
connector.connectorType,
|
||||
documentTypeCounts
|
||||
);
|
||||
const isIndexing =
|
||||
actualConnector &&
|
||||
indexingConnectorIds?.has(actualConnector.id);
|
||||
const activeTask = actualConnector
|
||||
? getActiveTaskForConnector(actualConnector.id)
|
||||
: undefined;
|
||||
|
||||
// Check if any account is currently indexing
|
||||
const isIndexing = typeConnectors.some(
|
||||
(c) => indexingConnectorIds?.has(c.id)
|
||||
);
|
||||
|
||||
// Get active task from any indexing account
|
||||
const activeTask = typeConnectors
|
||||
.map((c) => getActiveTaskForConnector(c.id))
|
||||
.find((task) => task !== undefined);
|
||||
|
||||
return (
|
||||
<ConnectorCard
|
||||
|
|
@ -132,13 +147,13 @@ export const AllConnectorsTab: FC<AllConnectorsTabProps> = ({
|
|||
isConnected={isConnected}
|
||||
isConnecting={isConnecting}
|
||||
documentCount={documentCount}
|
||||
lastIndexedAt={actualConnector?.last_indexed_at}
|
||||
lastIndexedAt={mostRecentLastIndexed}
|
||||
isIndexing={isIndexing}
|
||||
activeTask={activeTask}
|
||||
onConnect={() => onConnectOAuth(connector)}
|
||||
onManage={
|
||||
isConnected && onViewAccountsList
|
||||
? () => onViewAccountsList(connector)
|
||||
? () => onViewAccountsList(connector.connectorType, connector.title)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
|||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
import type { LogActiveTask, LogSummary } from "@/contracts/types/log.types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getDocumentCountForConnector } from "../utils/connector-document-mapping";
|
||||
import { getConnectorDisplayName } from "../tabs/all-connectors-tab";
|
||||
|
||||
interface ConnectorAccountsListViewProps {
|
||||
|
|
@ -17,27 +16,12 @@ interface ConnectorAccountsListViewProps {
|
|||
connectors: SearchSourceConnector[];
|
||||
indexingConnectorIds: Set<number>;
|
||||
logsSummary: LogSummary | undefined;
|
||||
documentTypeCounts?: Record<string, number>;
|
||||
onBack: () => void;
|
||||
onManage: (connector: SearchSourceConnector) => void;
|
||||
onAddAccount: () => void;
|
||||
isConnecting?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format document count (e.g., "1.2k docs", "500 docs", "1.5M docs")
|
||||
*/
|
||||
function formatDocumentCount(count: number | undefined): string {
|
||||
if (count === undefined || count === 0) return "0 docs";
|
||||
if (count < 1000) return `${count} docs`;
|
||||
if (count < 1000000) {
|
||||
const k = (count / 1000).toFixed(1);
|
||||
return `${k.replace(/\.0$/, "")}k docs`;
|
||||
}
|
||||
const m = (count / 1000000).toFixed(1);
|
||||
return `${m.replace(/\.0$/, "")}M docs`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format last indexed date with contextual messages
|
||||
*/
|
||||
|
|
@ -76,7 +60,6 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
connectors,
|
||||
indexingConnectorIds,
|
||||
logsSummary,
|
||||
documentTypeCounts,
|
||||
onBack,
|
||||
onManage,
|
||||
onAddAccount,
|
||||
|
|
@ -145,10 +128,6 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
const activeTask = logsSummary?.active_tasks?.find(
|
||||
(task: LogActiveTask) => task.connector_id === connector.id
|
||||
);
|
||||
const documentCount = getDocumentCountForConnector(
|
||||
connector.connector_type,
|
||||
documentTypeCounts
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -191,9 +170,6 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
: "Never indexed"}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-[10px] text-muted-foreground mt-0.5">
|
||||
{formatDocumentCount(documentCount)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue