mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-03 18:08:58 +02:00
Egnyte connector (#3420)
This commit is contained in:
BIN
web/public/Egnyte.png
Normal file
BIN
web/public/Egnyte.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@@ -49,6 +49,7 @@ import { useRouter } from "next/navigation";
|
||||
import CardSection from "@/components/admin/CardSection";
|
||||
import { prepareOAuthAuthorizationRequest } from "@/lib/oauth_utils";
|
||||
import { EE_ENABLED, NEXT_PUBLIC_CLOUD_ENABLED } from "@/lib/constants";
|
||||
import { getConnectorOauthRedirectUrl } from "@/lib/connectors/oauth";
|
||||
export interface AdvancedConfig {
|
||||
refreshFreq: number;
|
||||
pruneFreq: number;
|
||||
@@ -442,11 +443,19 @@ export default function AddConnector({
|
||||
{/* Button to pop up a form to manually enter credentials */}
|
||||
<button
|
||||
className="mt-6 text-sm bg-background-900 px-2 py-1.5 flex text-text-200 flex-none rounded mr-4"
|
||||
onClick={() =>
|
||||
setCreateConnectorToggle(
|
||||
(createConnectorToggle) => !createConnectorToggle
|
||||
)
|
||||
}
|
||||
onClick={async () => {
|
||||
const redirectUrl =
|
||||
await getConnectorOauthRedirectUrl(connector);
|
||||
// if redirect is supported, just use it
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl;
|
||||
} else {
|
||||
setCreateConnectorToggle(
|
||||
(createConnectorToggle) =>
|
||||
!createConnectorToggle
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Create New
|
||||
</button>
|
||||
|
50
web/src/app/connector/oauth/callback/[source]/route.tsx
Normal file
50
web/src/app/connector/oauth/callback/[source]/route.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { INTERNAL_URL } from "@/lib/constants";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
// TODO: deprecate this and just go directly to the backend via /api/...
|
||||
// For some reason Egnyte doesn't work when using /api, so leaving this as is for now
|
||||
// If we do try and remove this, make sure we test the Egnyte connector oauth flow
|
||||
export async function GET(request: NextRequest) {
|
||||
if (process.env.NODE_ENV !== "development") {
|
||||
return NextResponse.json(
|
||||
{ message: "This API is only available in development mode." },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const backendUrl = new URL(INTERNAL_URL);
|
||||
// Copy path and query parameters from incoming request
|
||||
backendUrl.pathname = request.nextUrl.pathname;
|
||||
backendUrl.search = request.nextUrl.search;
|
||||
|
||||
const response = await fetch(backendUrl, {
|
||||
method: "GET",
|
||||
headers: request.headers,
|
||||
body: request.body,
|
||||
signal: request.signal,
|
||||
// @ts-ignore
|
||||
duplex: "half",
|
||||
});
|
||||
|
||||
const responseData = await response.json();
|
||||
if (responseData.redirect_url) {
|
||||
return NextResponse.redirect(responseData.redirect_url);
|
||||
}
|
||||
|
||||
return new NextResponse(JSON.stringify(responseData), {
|
||||
status: response.status,
|
||||
headers: response.headers,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.error("Proxy error:", error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: "Proxy error",
|
||||
error:
|
||||
error instanceof Error ? error.message : "An unknown error occurred",
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ import {
|
||||
ConfluenceCredentialJson,
|
||||
Credential,
|
||||
} from "@/lib/connectors/credentials";
|
||||
import { getConnectorOauthRedirectUrl } from "@/lib/connectors/oauth";
|
||||
|
||||
export default function CredentialSection({
|
||||
ccPair,
|
||||
@@ -38,9 +39,14 @@ export default function CredentialSection({
|
||||
sourceType: ValidSources;
|
||||
refresh: () => void;
|
||||
}) {
|
||||
const makeShowCreateCredential = () => {
|
||||
setShowModifyCredential(false);
|
||||
setShowCreateCredential(true);
|
||||
const makeShowCreateCredential = async () => {
|
||||
const redirectUrl = await getConnectorOauthRedirectUrl(sourceType);
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl;
|
||||
} else {
|
||||
setShowModifyCredential(false);
|
||||
setShowCreateCredential(true);
|
||||
}
|
||||
};
|
||||
|
||||
const { data: credentials } = useSWR<Credential<ConfluenceCredentialJson>[]>(
|
||||
@@ -150,9 +156,6 @@ export default function CredentialSection({
|
||||
title="Update Credentials"
|
||||
>
|
||||
<ModifyCredential
|
||||
showCreate={() => {
|
||||
setShowCreateCredential(true);
|
||||
}}
|
||||
close={closeModifyCredential}
|
||||
source={sourceType}
|
||||
attachedConnector={ccPair.connector}
|
||||
|
@@ -144,15 +144,12 @@ export default function ModifyCredential({
|
||||
attachedConnector,
|
||||
credentials,
|
||||
editableCredentials,
|
||||
source,
|
||||
defaultedCredential,
|
||||
|
||||
onSwap,
|
||||
onSwitch,
|
||||
onCreateNew = () => null,
|
||||
onEditCredential,
|
||||
onDeleteCredential,
|
||||
showCreate,
|
||||
onCreateNew,
|
||||
}: {
|
||||
close?: () => void;
|
||||
showIfEmpty?: boolean;
|
||||
@@ -161,13 +158,11 @@ export default function ModifyCredential({
|
||||
credentials: Credential<any>[];
|
||||
editableCredentials: Credential<any>[];
|
||||
source: ValidSources;
|
||||
|
||||
onSwitch?: (newCredential: Credential<any>) => void;
|
||||
onSwap?: (newCredential: Credential<any>, connectorId: number) => void;
|
||||
onCreateNew?: () => void;
|
||||
onDeleteCredential: (credential: Credential<any | null>) => void;
|
||||
onEditCredential?: (credential: Credential<ConfluenceCredentialJson>) => void;
|
||||
showCreate?: () => void;
|
||||
}) {
|
||||
const [selectedCredential, setSelectedCredential] =
|
||||
useState<Credential<any> | null>(null);
|
||||
@@ -244,10 +239,10 @@ export default function ModifyCredential({
|
||||
|
||||
{!showIfEmpty && (
|
||||
<div className="flex mt-8 justify-between">
|
||||
{showCreate ? (
|
||||
{onCreateNew ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
showCreate();
|
||||
onCreateNew();
|
||||
}}
|
||||
className="bg-neutral-500 disabled:border-transparent
|
||||
transition-colors duration-150 ease-in disabled:bg-neutral-300
|
||||
|
@@ -62,6 +62,7 @@ import document360Icon from "../../../public/Document360.png";
|
||||
import googleSitesIcon from "../../../public/GoogleSites.png";
|
||||
import zendeskIcon from "../../../public/Zendesk.svg";
|
||||
import dropboxIcon from "../../../public/Dropbox.png";
|
||||
import egnyteIcon from "../../../public/Egnyte.png";
|
||||
import slackIcon from "../../../public/Slack.png";
|
||||
|
||||
import s3Icon from "../../../public/S3.png";
|
||||
@@ -2725,3 +2726,17 @@ export const UserIcon = ({
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const EgnyteIcon = ({
|
||||
size = 16,
|
||||
className = defaultTailwindCSS,
|
||||
}: IconProps) => {
|
||||
return (
|
||||
<div
|
||||
style={{ width: `${size}px`, height: `${size}px` }}
|
||||
className={`w-[${size}px] h-[${size}px] ` + className}
|
||||
>
|
||||
<Image src={egnyteIcon} alt="Egnyte" width="96" height="96" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -1050,6 +1050,21 @@ For example, specifying .*-support.* as a "channel" will cause the connector to
|
||||
values: [],
|
||||
advanced_values: [],
|
||||
},
|
||||
egnyte: {
|
||||
description: "Configure Egnyte connector",
|
||||
values: [
|
||||
{
|
||||
type: "text",
|
||||
query: "Enter folder path to index:",
|
||||
label: "Folder Path",
|
||||
name: "folder_path",
|
||||
optional: true,
|
||||
description:
|
||||
"The folder path to index (e.g., '/Shared/Documents'). Leave empty to index everything.",
|
||||
},
|
||||
],
|
||||
advanced_values: [],
|
||||
},
|
||||
};
|
||||
export function createConnectorInitialValues(
|
||||
connector: ConfigurableSources
|
||||
|
@@ -195,6 +195,11 @@ export interface FirefliesCredentialJson {
|
||||
export interface MediaWikiCredentialJson {}
|
||||
export interface WikipediaCredentialJson extends MediaWikiCredentialJson {}
|
||||
|
||||
export interface EgnyteCredentialJson {
|
||||
domain: string;
|
||||
access_token: string;
|
||||
}
|
||||
|
||||
export const credentialTemplates: Record<ValidSources, any> = {
|
||||
github: { github_access_token: "" } as GithubCredentialJson,
|
||||
gitlab: {
|
||||
@@ -298,6 +303,10 @@ export const credentialTemplates: Record<ValidSources, any> = {
|
||||
fireflies: {
|
||||
fireflies_api_key: "",
|
||||
} as FirefliesCredentialJson,
|
||||
egnyte: {
|
||||
domain: "",
|
||||
access_token: "",
|
||||
} as EgnyteCredentialJson,
|
||||
xenforo: null,
|
||||
google_sites: null,
|
||||
file: null,
|
||||
|
19
web/src/lib/connectors/oauth.ts
Normal file
19
web/src/lib/connectors/oauth.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ValidSources } from "../types";
|
||||
|
||||
export async function getConnectorOauthRedirectUrl(
|
||||
connector: ValidSources
|
||||
): Promise<string | null> {
|
||||
const response = await fetch(
|
||||
`/api/connector/oauth/authorize/${connector}?desired_return_url=${encodeURIComponent(
|
||||
window.location.href
|
||||
)}`
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Failed to fetch OAuth redirect URL for ${connector}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.redirect_url as string;
|
||||
}
|
@@ -38,6 +38,7 @@ import {
|
||||
XenforoIcon,
|
||||
FreshdeskIcon,
|
||||
FirefliesIcon,
|
||||
EgnyteIcon,
|
||||
} from "@/components/icons/icons";
|
||||
import { ValidSources } from "./types";
|
||||
import {
|
||||
@@ -304,6 +305,12 @@ export const SOURCE_METADATA_MAP: SourceMap = {
|
||||
displayName: "Not Applicable",
|
||||
category: SourceCategory.Other,
|
||||
},
|
||||
egnyte: {
|
||||
icon: EgnyteIcon,
|
||||
displayName: "Egnyte",
|
||||
category: SourceCategory.Storage,
|
||||
docs: "https://docs.danswer.dev/connectors/egnyte",
|
||||
},
|
||||
} as SourceMap;
|
||||
|
||||
function fillSourceMetadata(
|
||||
|
@@ -309,6 +309,7 @@ export enum ValidSources {
|
||||
IngestionApi = "ingestion_api",
|
||||
Freshdesk = "freshdesk",
|
||||
Fireflies = "fireflies",
|
||||
Egnyte = "egnyte",
|
||||
}
|
||||
|
||||
export const validAutoSyncSources = [
|
||||
|
Reference in New Issue
Block a user