mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-03 21:02:40 +02:00
feat: add connectorId support for multi-account OAuth connectors
Backend: - Add connectorId to OAuth redirect URLs in all 10 connector routes - Enables frontend to identify the specific connector created Frontend: - Update OAuth success handler to use connectorId for finding new connector - Set connectorId in URL when transitioning to configure view - Add connectorId support in URL sync effect for page refresh - Consolidate handleAddAccountOAuth into handleConnectOAuth - Update indexing config view to show connector type and display name
This commit is contained in:
parent
2508b37f4e
commit
9ad1348d6b
13 changed files with 48 additions and 62 deletions
|
|
@ -86,7 +86,6 @@ export const ConnectorIndicator: FC = () => {
|
|||
handleBackFromYouTube,
|
||||
handleViewAccountsList,
|
||||
handleBackFromAccountsList,
|
||||
handleAddAccountOAuth,
|
||||
handleQuickIndexConnector,
|
||||
connectorConfig,
|
||||
setConnectorConfig,
|
||||
|
|
@ -214,7 +213,7 @@ export const ConnectorIndicator: FC = () => {
|
|||
(c) => c.connectorType === viewingAccountsType.connectorType
|
||||
);
|
||||
if (oauthConnector) {
|
||||
handleAddAccountOAuth(oauthConnector);
|
||||
handleConnectOAuth(oauthConnector);
|
||||
}
|
||||
}}
|
||||
isConnecting={connectingId !== null}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
|||
import { cn } from "@/lib/utils";
|
||||
import { DateRangeSelector } from "../../components/date-range-selector";
|
||||
import { PeriodicSyncConfig } from "../../components/periodic-sync-config";
|
||||
import type { IndexingConfigState } from "../../constants/connector-constants";
|
||||
import { OAUTH_CONNECTORS, type IndexingConfigState } from "../../constants/connector-constants";
|
||||
import { getConnectorConfigComponent } from "../index";
|
||||
import { getConnectorTypeDisplay } from "@/lib/connectors/utils";
|
||||
import { getConnectorDisplayName } from "../../tabs/all-connectors-tab";
|
||||
|
||||
interface IndexingConfigurationViewProps {
|
||||
config: IndexingConfigState;
|
||||
|
|
@ -89,12 +91,14 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
|||
};
|
||||
}, [checkScrollState]);
|
||||
|
||||
const authConnector = OAUTH_CONNECTORS.find((c) => c.connectorType === connector?.connector_type);
|
||||
|
||||
return (
|
||||
<div className="flex-1 flex flex-col min-h-0 overflow-hidden">
|
||||
{/* Fixed Header */}
|
||||
<div
|
||||
className={cn(
|
||||
"flex-shrink-0 px-6 sm:px-12 pt-8 sm:pt-10 transition-shadow duration-200 relative z-10",
|
||||
"shrink-0 px-6 sm:px-12 pt-8 sm:pt-10 transition-shadow duration-200 relative z-10",
|
||||
isScrolled && "shadow-sm"
|
||||
)}
|
||||
>
|
||||
|
|
@ -111,14 +115,14 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
|||
)}
|
||||
|
||||
{/* Success header */}
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="flex gap-4 mb-6">
|
||||
<div className="flex h-14 w-14 items-center justify-center rounded-xl bg-green-500/10 border border-green-500/20">
|
||||
<Check className="size-7 text-green-500" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl sm:text-2xl font-semibold tracking-tight">
|
||||
{config.connectorTitle} Connected!
|
||||
</h2>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xl sm:text-2xl font-semibold tracking-tight text-wrap whitespace-normal wrap-break-word">{getConnectorTypeDisplay(connector?.connector_type || "")} Connected !</span> <span className="text-xl sm:text-xl font-semibold text-muted-foreground tracking-tight text-wrap whitespace-normal wrap-break-word">{getConnectorDisplayName(connector?.name || "")}</span>
|
||||
</div>
|
||||
<p className="text-xs sm:text-base text-muted-foreground mt-1">
|
||||
Configure when to start syncing your data
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -148,14 +148,22 @@ export const useConnectorDialog = () => {
|
|||
// YouTube view is active - no additional state needed
|
||||
}
|
||||
|
||||
if (params.view === "configure" && params.connector && !indexingConfig) {
|
||||
// Handle configure view (for page refresh support)
|
||||
if (params.view === "configure" && params.connector && !indexingConfig && allConnectors) {
|
||||
const oauthConnector = OAUTH_CONNECTORS.find((c) => c.id === params.connector);
|
||||
if (oauthConnector && allConnectors) {
|
||||
const existingConnector = allConnectors.find(
|
||||
(c: SearchSourceConnector) => c.connector_type === oauthConnector.connectorType
|
||||
);
|
||||
if (oauthConnector) {
|
||||
let existingConnector: SearchSourceConnector | undefined;
|
||||
if (params.connectorId) {
|
||||
const connectorId = parseInt(params.connectorId, 10);
|
||||
existingConnector = allConnectors.find(
|
||||
(c: SearchSourceConnector) => c.id === connectorId
|
||||
);
|
||||
} else {
|
||||
existingConnector = allConnectors.find(
|
||||
(c: SearchSourceConnector) => c.connector_type === oauthConnector.connectorType
|
||||
);
|
||||
}
|
||||
if (existingConnector) {
|
||||
// Validate connector data before setting state
|
||||
const connectorValidation = searchSourceConnector.safeParse(existingConnector);
|
||||
if (connectorValidation.success) {
|
||||
const config = validateIndexingConfigState({
|
||||
|
|
@ -253,11 +261,19 @@ export const useConnectorDialog = () => {
|
|||
refetchAllConnectors().then((result) => {
|
||||
if (!result.data) return;
|
||||
|
||||
const newConnector = result.data.find(
|
||||
(c: SearchSourceConnector) => c.connector_type === oauthConnector.connectorType
|
||||
);
|
||||
let newConnector: SearchSourceConnector | undefined;
|
||||
if (params.connectorId) {
|
||||
const connectorId = parseInt(params.connectorId, 10);
|
||||
newConnector = result.data.find(
|
||||
(c: SearchSourceConnector) => c.id === connectorId
|
||||
);
|
||||
} else {
|
||||
newConnector = result.data.find(
|
||||
(c: SearchSourceConnector) => c.connector_type === oauthConnector.connectorType
|
||||
);
|
||||
}
|
||||
|
||||
if (newConnector) {
|
||||
// Validate connector data before setting state
|
||||
const connectorValidation = searchSourceConnector.safeParse(newConnector);
|
||||
if (connectorValidation.success) {
|
||||
const config = validateIndexingConfigState({
|
||||
|
|
@ -271,6 +287,7 @@ export const useConnectorDialog = () => {
|
|||
setIsOpen(true);
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.delete("success");
|
||||
url.searchParams.set("connectorId", newConnector.id.toString());
|
||||
url.searchParams.set("view", "configure");
|
||||
window.history.replaceState({}, "", url.toString());
|
||||
} else {
|
||||
|
|
@ -691,39 +708,6 @@ export const useConnectorDialog = () => {
|
|||
router.replace(url.pathname + url.search, { scroll: false });
|
||||
}, [router]);
|
||||
|
||||
// Handle adding a new account for OAuth connector (from accounts list view)
|
||||
const handleAddAccountOAuth = useCallback(
|
||||
async (connector: (typeof OAUTH_CONNECTORS)[number]) => {
|
||||
if (!searchSpaceId || !connector.authEndpoint) return;
|
||||
|
||||
// Set connecting state
|
||||
setConnectingId(connector.id);
|
||||
|
||||
try {
|
||||
const response = await authenticatedFetch(
|
||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}${connector.authEndpoint}?space_id=${searchSpaceId}`,
|
||||
{ method: "GET" }
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to initiate ${connector.title} OAuth`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const validatedData = parseOAuthAuthResponse(data);
|
||||
window.location.href = validatedData.auth_url;
|
||||
} catch (error) {
|
||||
console.error(`Error connecting to ${connector.title}:`, error);
|
||||
if (error instanceof Error && error.message.includes("Invalid auth URL")) {
|
||||
toast.error(`Invalid response from ${connector.title} OAuth endpoint`);
|
||||
} else {
|
||||
toast.error(`Failed to connect to ${connector.title}`);
|
||||
}
|
||||
setConnectingId(null);
|
||||
}
|
||||
},
|
||||
[searchSpaceId]
|
||||
);
|
||||
|
||||
// Handle starting indexing
|
||||
const handleStartIndexing = useCallback(
|
||||
|
|
@ -1249,7 +1233,6 @@ export const useConnectorDialog = () => {
|
|||
handleBackFromYouTube,
|
||||
handleViewAccountsList,
|
||||
handleBackFromAccountsList,
|
||||
handleAddAccountOAuth,
|
||||
handleQuickIndexConnector,
|
||||
connectorConfig,
|
||||
setConnectorConfig,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue