Merge branch 'dev' into sur-73-impr-implement-new-main-app-ux

This commit is contained in:
CREDO23 2026-01-09 21:50:41 +02:00
commit 8255d158a8
47 changed files with 2632 additions and 33 deletions

View file

@ -7,7 +7,7 @@ import { cn } from "@/lib/utils";
export const Logo = ({ className }: { className?: string }) => {
return (
<Link href="/">
<Image src="/icon-128.png" className={cn(className)} alt="logo" width={128} height={128} />
<Image src="/icon-128.svg" className={cn("dark:invert", className)} alt="logo" width={128} height={128} />
</Link>
);
};

View file

@ -248,7 +248,8 @@ export const ConnectorIndicator: FC = () => {
onBack={handleBackFromEdit}
onQuickIndex={
editingConnector.connector_type !== "GOOGLE_DRIVE_CONNECTOR"
? () => handleQuickIndexConnector(editingConnector.id)
? () =>
handleQuickIndexConnector(editingConnector.id, editingConnector.connector_type)
: undefined
}
onConfigChange={setConnectorConfig}

View file

@ -0,0 +1,29 @@
"use client";
import { Info } from "lucide-react";
import type { FC } from "react";
import type { ConnectorConfigProps } from "../index";
export interface TeamsConfigProps extends ConnectorConfigProps {
onNameChange?: (name: string) => void;
}
export const TeamsConfig: FC<TeamsConfigProps> = () => {
return (
<div className="space-y-6">
<div className="rounded-xl border border-border bg-primary/5 p-4 flex items-start gap-3">
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10 shrink-0 mt-0.5">
<Info className="size-4" />
</div>
<div className="text-xs sm:text-sm">
<p className="font-medium text-xs sm:text-sm">Microsoft Teams Access</p>
<p className="text-muted-foreground mt-1 text-[10px] sm:text-sm">
SurfSense will index messages from Teams channels that you have access to. The app can
only read messages from teams and channels where you are a member. Make sure you're a
member of the teams you want to index before connecting.
</p>
</div>
</div>
</div>
);
};

View file

@ -17,6 +17,7 @@ import { LumaConfig } from "./components/luma-config";
import { SearxngConfig } from "./components/searxng-config";
import { SlackConfig } from "./components/slack-config";
import { TavilyApiConfig } from "./components/tavily-api-config";
import { TeamsConfig } from "./components/teams-config";
import { WebcrawlerConfig } from "./components/webcrawler-config";
export interface ConnectorConfigProps {
@ -52,6 +53,8 @@ export function getConnectorConfigComponent(
return SlackConfig;
case "DISCORD_CONNECTOR":
return DiscordConfig;
case "TEAMS_CONNECTOR":
return TeamsConfig;
case "CONFLUENCE_CONNECTOR":
return ConfluenceConfig;
case "BOOKSTACK_CONNECTOR":

View file

@ -51,6 +51,13 @@ export const OAUTH_CONNECTORS = [
connectorType: EnumConnectorName.SLACK_CONNECTOR,
authEndpoint: "/api/v1/auth/slack/connector/add/",
},
{
id: "teams-connector",
title: "Microsoft Teams",
description: "Search Teams messages",
connectorType: EnumConnectorName.TEAMS_CONNECTOR,
authEndpoint: "/api/v1/auth/teams/connector/add/",
},
{
id: "discord-connector",
title: "Discord",

View file

@ -15,6 +15,14 @@ import { EnumConnectorName } from "@/contracts/enums/connector";
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
import { searchSourceConnector } from "@/contracts/types/connector.types";
import { authenticatedFetch } from "@/lib/auth-utils";
import {
trackConnectorConnected,
trackConnectorDeleted,
trackIndexWithDateRangeOpened,
trackIndexWithDateRangeStarted,
trackPeriodicIndexingStarted,
trackQuickIndexClicked,
} from "@/lib/posthog/events";
import { cacheKeys } from "@/lib/query-client/cache-keys";
import { queryClient } from "@/lib/query-client/client";
import type { IndexingConfigState } from "../constants/connector-constants";
@ -309,6 +317,13 @@ export const useConnectorDialog = () => {
if (newConnector) {
const connectorValidation = searchSourceConnector.safeParse(newConnector);
if (connectorValidation.success) {
// Track connector connected event for OAuth connectors
trackConnectorConnected(
Number(searchSpaceId),
oauthConnector.connectorType,
newConnector.id
);
const config = validateIndexingConfigState({
connectorType: oauthConnector.connectorType,
connectorId: newConnector.id,
@ -419,6 +434,13 @@ export const useConnectorDialog = () => {
if (connector) {
const connectorValidation = searchSourceConnector.safeParse(connector);
if (connectorValidation.success) {
// Track webcrawler connector connected
trackConnectorConnected(
Number(searchSpaceId),
EnumConnectorName.WEBCRAWLER_CONNECTOR,
connector.id
);
const config = validateIndexingConfigState({
connectorType: EnumConnectorName.WEBCRAWLER_CONNECTOR,
connectorId: connector.id,
@ -514,6 +536,9 @@ export const useConnectorDialog = () => {
// Store connectingConnectorType before clearing it
const currentConnectorType = connectingConnectorType;
// Track connector connected event for non-OAuth connectors
trackConnectorConnected(Number(searchSpaceId), currentConnectorType, connector.id);
// Find connector title from constants
const connectorInfo = OTHER_CONNECTORS.find(
(c) => c.connectorType === currentConnectorType
@ -848,6 +873,27 @@ export const useConnectorDialog = () => {
});
}
// Track index with date range started event
trackIndexWithDateRangeStarted(
Number(searchSpaceId),
indexingConfig.connectorType,
indexingConfig.connectorId,
{
hasStartDate: !!startDate,
hasEndDate: !!endDate,
}
);
// Track periodic indexing started if enabled
if (periodicEnabled && indexingConfig.connectorType !== "GOOGLE_DRIVE_CONNECTOR") {
trackPeriodicIndexingStarted(
Number(searchSpaceId),
indexingConfig.connectorType,
indexingConfig.connectorId,
parseInt(frequencyMinutes, 10)
);
}
toast.success(`${indexingConfig.connectorTitle} indexing started`, {
description: periodicEnabled
? `Periodic sync enabled every ${getFrequencyLabel(frequencyMinutes)}.`
@ -914,6 +960,15 @@ export const useConnectorDialog = () => {
return;
}
// Track index with date range opened event
if (connector.is_indexable) {
trackIndexWithDateRangeOpened(
Number(searchSpaceId),
connector.connector_type,
connector.id
);
}
setEditingConnector(connector);
setConnectorName(connector.name);
// Load existing periodic sync settings (disabled for Google Drive and non-indexable connectors)
@ -1049,6 +1104,36 @@ export const useConnectorDialog = () => {
indexingDescription = "Re-indexing started with new date range.";
}
// Track indexing started if re-indexing was performed
if (
editingConnector.is_indexable &&
(indexingDescription.includes("Re-indexing") || indexingDescription.includes("indexing"))
) {
trackIndexWithDateRangeStarted(
Number(searchSpaceId),
editingConnector.connector_type,
editingConnector.id,
{
hasStartDate: !!startDateStr,
hasEndDate: !!endDateStr,
}
);
}
// Track periodic indexing if enabled (for non-Google Drive connectors)
if (
periodicEnabled &&
editingConnector.is_indexable &&
editingConnector.connector_type !== "GOOGLE_DRIVE_CONNECTOR"
) {
trackPeriodicIndexingStarted(
Number(searchSpaceId),
editingConnector.connector_type,
editingConnector.id,
frequency || parseInt(frequencyMinutes, 10)
);
}
toast.success(`${editingConnector.name} updated successfully`, {
description: periodicEnabled
? `Periodic sync ${frequency ? `enabled every ${getFrequencyLabel(frequencyMinutes)}` : "enabled"}. ${indexingDescription}`
@ -1101,6 +1186,13 @@ export const useConnectorDialog = () => {
id: editingConnector.id,
});
// Track connector deleted event
trackConnectorDeleted(
Number(searchSpaceId),
editingConnector.connector_type,
editingConnector.id
);
toast.success(`${editingConnector.name} disconnected successfully`);
// Update URL - the effect will handle closing the modal and clearing state
@ -1127,9 +1219,14 @@ export const useConnectorDialog = () => {
// Handle quick index (index without date picker, uses backend defaults)
const handleQuickIndexConnector = useCallback(
async (connectorId: number) => {
async (connectorId: number, connectorType?: string) => {
if (!searchSpaceId) return;
// Track quick index clicked event
if (connectorType) {
trackQuickIndexClicked(Number(searchSpaceId), connectorType, connectorId);
}
try {
await indexConnector({
connector_id: connectorId,

View file

@ -11,6 +11,7 @@
export const CONNECTOR_TO_DOCUMENT_TYPE: Record<string, string> = {
// Direct mappings (connector type matches document type)
SLACK_CONNECTOR: "SLACK_CONNECTOR",
TEAMS_CONNECTOR: "TEAMS_CONNECTOR",
NOTION_CONNECTOR: "NOTION_CONNECTOR",
GITHUB_CONNECTOR: "GITHUB_CONNECTOR",
LINEAR_CONNECTOR: "LINEAR_CONNECTOR",

View file

@ -54,7 +54,7 @@ const DesktopNav = ({ navItems, isScrolled }: any) => {
: "bg-transparent border border-transparent"
)}
>
<div className="flex flex-1 flex-row items-center gap-2">
<div className="flex flex-1 flex-row items-center gap-0.5">
<Logo className="h-8 w-8 rounded-md" />
<span className="dark:text-white/90 text-gray-800 text-lg font-bold">SurfSense</span>
</div>