diff --git a/front/components/data_source/DataSourceEdition.tsx b/front/components/data_source/DataSourceEdition.tsx index 722d4f07e2bd..e606947bf537 100644 --- a/front/components/data_source/DataSourceEdition.tsx +++ b/front/components/data_source/DataSourceEdition.tsx @@ -11,6 +11,7 @@ import { import type { ConnectorProvider, ConnectorType, + DataSourceType, EditedByUser, UpdateConnectorRequestBody, UserType, @@ -25,6 +26,7 @@ import React, { useContext, useState } from "react"; import { SendNotificationsContext } from "@app/components/sparkle/Notification"; import { CONNECTOR_CONFIGURATIONS } from "@app/lib/connector_providers"; import { formatTimestampToFriendlyDate } from "@app/lib/utils"; +import type { PostManagedDataSourceRequestBody } from "@app/pages/api/w/[wId]/data_sources/managed"; import { setupConnection } from "@app/pages/w/[wId]/builder/data-sources/managed"; export type DataSourceIntegration = { @@ -55,8 +57,24 @@ interface DataSourceEditionModalProps { dustClientFacingUrl: string; user: UserType; setIsRequestDataSourceModalOpen: (show: boolean) => void; + setDataSourceIntegrations: ( + integrations: (prev: DataSourceIntegration[]) => DataSourceIntegration[] + ) => void; + setIsLoadingByProvider: ( + providers: ( + prev: Record + ) => Record + ) => void; } +const REDIRECT_TO_EDIT_PERMISSIONS = [ + "confluence", + "google_drive", + "microsoft", + "slack", + "intercom", +]; + export function DataSourceEditionModal({ isOpen, owner, @@ -67,16 +85,18 @@ export function DataSourceEditionModal({ dustClientFacingUrl, user, setIsRequestDataSourceModalOpen, + setDataSourceIntegrations, + setIsLoadingByProvider, }: DataSourceEditionModalProps) { const sendNotification = useContext(SendNotificationsContext); const [showConfirmDialog, setShowConfirmDialog] = useState(false); - if (!connectorProvider) { + if (!connectorProvider || !dataSourceIntegration) { return; } const connectorConfiguration = CONNECTOR_CONFIGURATIONS[connectorProvider]; - const isSetup = !!dataSourceIntegration; + const isSetup = !!dataSourceIntegration?.connector; let dataSourceOwner: EditedByUser | null | undefined = null; let isDataSourceOwner: boolean = false; @@ -86,6 +106,87 @@ export function DataSourceEditionModal({ dataSourceIntegration?.editedByUser?.userId === user.sId; } + const handleEnableManagedDataSource = async ( + dataSourceIntegration: DataSourceIntegration + ) => { + try { + const provider = dataSourceIntegration.connectorProvider; + const suffix = dataSourceIntegration.setupWithSuffix; + const connectionIdRes = await setupConnection({ + dustClientFacingUrl, + owner, + provider, + }); + if (connectionIdRes.isErr()) { + throw connectionIdRes.error; + } + onClose(); + setIsLoadingByProvider((prev) => ({ ...prev, [provider]: true })); + + const res = await fetch( + suffix + ? `/api/w/${ + owner.sId + }/data_sources/managed?suffix=${encodeURIComponent(suffix)}` + : `/api/w/${owner.sId}/data_sources/managed`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + provider, + connectionId: connectionIdRes.value, + name: undefined, + configuration: null, + } satisfies PostManagedDataSourceRequestBody), + } + ); + + if (res.ok) { + const createdManagedDataSource: { + dataSource: DataSourceType; + connector: ConnectorType; + } = await res.json(); + setDataSourceIntegrations((prev) => + prev.map((ds) => { + return ds.connector === null && ds.connectorProvider == provider + ? { + ...ds, + connector: createdManagedDataSource.connector, + setupWithSuffix: null, + dataSourceName: createdManagedDataSource.dataSource.name, + } + : ds; + }) + ); + if (REDIRECT_TO_EDIT_PERMISSIONS.includes(provider)) { + void router.push( + `/w/${owner.sId}/builder/data-sources/${createdManagedDataSource.dataSource.name}?edit_permissions=true` + ); + } + } else { + const responseText = await res.text(); + sendNotification({ + type: "error", + title: `Failed to enable connection (${provider})`, + description: `Got: ${responseText}`, + }); + } + } catch (e) { + onClose(); + sendNotification({ + type: "error", + title: `Failed to enable connection (${dataSourceIntegration.connectorProvider})`, + }); + } finally { + setIsLoadingByProvider((prev) => ({ + ...prev, + [dataSourceIntegration.connectorProvider]: false, + })); + } + }; + const updateConnectorConnectionId = async ( newConnectionId: string, provider: string @@ -228,6 +329,9 @@ export function DataSourceEditionModal({ size="md" icon={CloudArrowLeftRightIcon} label="Make Connection" + onClick={async () => { + await handleEnableManagedDataSource(dataSourceIntegration); + }} /> )} diff --git a/front/pages/w/[wId]/builder/data-sources/managed.tsx b/front/pages/w/[wId]/builder/data-sources/managed.tsx index 8e92f46b77dd..ce71217d8cff 100644 --- a/front/pages/w/[wId]/builder/data-sources/managed.tsx +++ b/front/pages/w/[wId]/builder/data-sources/managed.tsx @@ -1,6 +1,5 @@ import { Avatar, - BookOpenIcon, Button, Chip, CloudArrowLeftRightIcon, @@ -18,7 +17,6 @@ import { } from "@dust-tt/sparkle"; import type { ConnectorProvider, - DataSourceType, EditedByUser, ManageDataSourcesLimitsType, Result, @@ -36,23 +34,18 @@ import { } from "@dust-tt/types"; import type { CellContext, ColumnDef } from "@tanstack/react-table"; import type { InferGetServerSidePropsType } from "next"; -import Link from "next/link"; import type { NextRouter } from "next/router"; import { useRouter } from "next/router"; import { useRef } from "react"; -import { useContext, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import * as React from "react"; -import type { - DataSourceIntegration} from "@app/components/data_source/DataSourceEdition"; -import { - DataSourceEditionModal -} from "@app/components/data_source/DataSourceEdition"; +import type { DataSourceIntegration } from "@app/components/data_source/DataSourceEdition"; +import { DataSourceEditionModal } from "@app/components/data_source/DataSourceEdition"; import ConnectorSyncingChip from "@app/components/data_source/DataSourceSyncChip"; import { RequestDataSourcesModal } from "@app/components/data_source/RequestDataSourcesModal"; import { subNavigationBuild } from "@app/components/navigation/config"; import AppLayout from "@app/components/sparkle/AppLayout"; -import { SendNotificationsContext } from "@app/components/sparkle/Notification"; import { getDataSourceUsage } from "@app/lib/api/agent_data_sources"; import config from "@app/lib/api/config"; import { getDataSources } from "@app/lib/api/data_sources"; @@ -61,7 +54,6 @@ import { withDefaultUserAuthRequirements } from "@app/lib/iam/session"; import { useAdmins } from "@app/lib/swr"; import { classNames, timeAgoFrom } from "@app/lib/utils"; import logger from "@app/logger/logger"; -import type { PostManagedDataSourceRequestBody } from "@app/pages/api/w/[wId]/data_sources/managed"; const { GA_TRACKING_ID = "" } = process.env; @@ -89,6 +81,11 @@ type GetTableRowParams = { readOnly: boolean; }; +type ShowIntegration = { + show: boolean; + dataSourceIntegration: DataSourceIntegration | null; +}; + type HandleConnectionClickParams = { integration: DataSourceIntegration; isAdmin: boolean; @@ -97,7 +94,7 @@ type HandleConnectionClickParams = { owner: WorkspaceType; limits: ManageDataSourcesLimitsType; setShowUpgradePopup: (show: boolean) => void; - setShowConfirmConnection: (integration: DataSourceIntegration | null) => void; + setShowEditionDataSourceModalOpen: (showIntegration: ShowIntegration) => void; setShowPreviewPopupForProvider: (providerPreview: { show: boolean; connector: ConnectorProvider | null; @@ -114,14 +111,6 @@ type ManagedSourceType = { usage: number | null; }; -const REDIRECT_TO_EDIT_PERMISSIONS = [ - "confluence", - "google_drive", - "microsoft", - "slack", - "intercom", -]; - export async function setupConnection({ dustClientFacingUrl, owner, @@ -323,132 +312,6 @@ export const getServerSideProps = withDefaultUserAuthRequirements<{ }; }); -function ConfirmationModal({ - dataSource, - show, - onClose, - onConfirm, -}: { - dataSource: DataSourceIntegration; - show: boolean; - onClose: () => void; - onConfirm: () => void; -}) { - const [isLoading, setIsLoading] = useState(false); - - return ( - -
- -
-
- Important -
-
- Resources shared with Dust will be made available to the entire - workspace{" "} - - irrespective of their granular permissions - {" "} - on {dataSource.name}. -
-
- - {dataSource.limitations && ( -
-
- Limitations -
-
- {dataSource.limitations} -
-
- )} - - {dataSource.connectorProvider === "google_drive" && ( - <> -
-
- Disclosure -
-
- Dust's use of information received from the Google APIs will - adhere to{" "} - - Google API Services User Data Policy - - , including the Limited Use requirements. -
-
- -
-
- Notice on data processing -
-
- By connecting Google Drive, you acknowledge and agree that - within your Google Drive, the data contained in the files and - folders that you choose to synchronize with Dust will be - transmitted to third-party entities, including but not limited - to Artificial Intelligence (AI) model providers, for the - purpose of processing and analysis. This process is an - integral part of the functionality of our service and is - subject to the terms outlined in our Privacy Policy and Terms - of Service. -
-
- - )} - -
- -
-
-
-
- ); -} - export default function DataSourcesView({ owner, subscription, @@ -460,7 +323,6 @@ export default function DataSourcesView({ dustClientFacingUrl, user, }: InferGetServerSidePropsType) { - const sendNotification = useContext(SendNotificationsContext); const [dataSourceIntegrations, setDataSourceIntegrations] = useState(integrations); const [isLoadingByProvider, setIsLoadingByProvider] = useState< @@ -474,13 +336,9 @@ export default function DataSourcesView({ show: false, connector: null, }); - const [showConfirmConnection, setShowConfirmConnection] = - useState(null); + const [showEditionDataSourceModalOpen, setShowEditionDataSourceModalOpen] = - useState<{ - show: boolean; - dataSourceIntegration: DataSourceIntegration | null; - }>({ + useState({ show: false, dataSourceIntegration: null, }); @@ -489,83 +347,6 @@ export default function DataSourcesView({ const { admins, isAdminsLoading } = useAdmins(owner); const planConnectionsLimits = plan.limits.connections; - const handleEnableManagedDataSource = async ( - provider: ConnectorProvider, - suffix: string | null - ) => { - try { - const connectionIdRes = await setupConnection({ - dustClientFacingUrl, - owner, - provider, - }); - if (connectionIdRes.isErr()) { - throw connectionIdRes.error; - } - - setShowConfirmConnection(null); - setIsLoadingByProvider((prev) => ({ ...prev, [provider]: true })); - - const res = await fetch( - suffix - ? `/api/w/${ - owner.sId - }/data_sources/managed?suffix=${encodeURIComponent(suffix)}` - : `/api/w/${owner.sId}/data_sources/managed`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - provider, - connectionId: connectionIdRes.value, - name: undefined, - configuration: null, - } satisfies PostManagedDataSourceRequestBody), - } - ); - - if (res.ok) { - const createdManagedDataSource: { - dataSource: DataSourceType; - connector: ConnectorType; - } = await res.json(); - setDataSourceIntegrations((prev) => - prev.map((ds) => { - return ds.connector === null && ds.connectorProvider == provider - ? { - ...ds, - connector: createdManagedDataSource.connector, - setupWithSuffix: null, - dataSourceName: createdManagedDataSource.dataSource.name, - } - : ds; - }) - ); - if (REDIRECT_TO_EDIT_PERMISSIONS.includes(provider)) { - void router.push( - `/w/${owner.sId}/builder/data-sources/${createdManagedDataSource.dataSource.name}?edit_permissions=true` - ); - } - } else { - const responseText = await res.text(); - sendNotification({ - type: "error", - title: `Failed to enable connection (${provider})`, - description: `Got: ${responseText}`, - }); - } - } catch (e) { - setShowConfirmConnection(null); - sendNotification({ - type: "error", - title: `Failed to enable connection (${provider})`, - }); - } finally { - setIsLoadingByProvider((prev) => ({ ...prev, [provider]: false })); - } - }; useEffect(() => { setDataSourceIntegrations(dataSourceIntegrations); @@ -675,19 +456,6 @@ export default function DataSourcesView({ )} - {showConfirmConnection && ( - setShowConfirmConnection(null)} - onConfirm={async () => { - await handleEnableManagedDataSource( - showConfirmConnection.connectorProvider as ConnectorProvider, - showConfirmConnection.setupWithSuffix - ); - }} - /> - )} {showUpgradePopup && ( @@ -1019,7 +789,7 @@ function handleConnectionClick({ isAdmin, isLoadingByProvider, setShowUpgradePopup, - setShowConfirmConnection, + setShowEditionDataSourceModalOpen, setShowPreviewPopupForProvider, router, owner, @@ -1040,7 +810,10 @@ function handleConnectionClick({ setShowUpgradePopup(true); } else { if (isBuilt) { - setShowConfirmConnection(integration); + setShowEditionDataSourceModalOpen({ + show: true, + dataSourceIntegration: integration, + }); } else { setShowPreviewPopupForProvider({ show: true,