From 4a13f4b107b17fdcd06d6760722f89baad2b0b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Thu, 29 Feb 2024 16:58:00 +0100 Subject: [PATCH 1/4] Assistant Builder: Tree component for datasources --- .../DataSourceResourceSelectorTree.tsx | 21 +- .../components/assistant/SlackIntegration.tsx | 8 +- .../assistant_builder/ActionScreen.tsx | 39 +-- .../assistant_builder/AssistantBuilder.tsx | 7 +- .../AssistantBuilderDataSourceModal.tsx | 135 ++++++----- .../DataSourceSelectionSection.tsx | 224 +++++++++++------- .../server_side_props_helpers.ts | 14 +- front/components/assistant_builder/types.ts | 13 +- front/package-lock.json | 6 + types/src/front/lib/connectors_api.ts | 27 +++ 10 files changed, 281 insertions(+), 213 deletions(-) diff --git a/front/components/DataSourceResourceSelectorTree.tsx b/front/components/DataSourceResourceSelectorTree.tsx index 6984341231cc..77fc9882b478 100644 --- a/front/components/DataSourceResourceSelectorTree.tsx +++ b/front/components/DataSourceResourceSelectorTree.tsx @@ -6,7 +6,11 @@ import { DocumentTextIcon, Spinner, } from "@dust-tt/sparkle"; -import type { DataSourceType, WorkspaceType } from "@dust-tt/types"; +import type { + ConnectorNode, + DataSourceType, + WorkspaceType, +} from "@dust-tt/types"; import type { ConnectorNodeType, ConnectorPermission } from "@dust-tt/types"; import { CircleStackIcon, FolderIcon } from "@heroicons/react/20/solid"; import { useState } from "react"; @@ -29,7 +33,8 @@ export default function DataSourceResourceSelectorTree({ expandable: boolean; selectedParentIds: Set; onSelectChange: ( - resource: { resourceId: string; resourceName: string; parents: string[] }, + resource: ConnectorNode, + parents: string[], selected: boolean ) => void; parentsById: Record>; @@ -99,7 +104,8 @@ function DataSourceResourceSelectorChildren({ selectedParentIds: Set; parents: string[]; onSelectChange: ( - resource: { resourceId: string; resourceName: string; parents: string[] }, + resource: ConnectorNode, + parents: string[], selected: boolean ) => void; parentsById: Record>; @@ -201,14 +207,7 @@ function DataSourceResourceSelectorChildren({ checked={checkStatus === "checked"} partialChecked={checkStatus === "partial"} onChange={(checked) => - onSelectChange( - { - resourceId: r.internalId, - resourceName: r.title, - parents: parents, - }, - checked - ) + onSelectChange(r, parents, checked) } disabled={isChecked || fullySelected} /> diff --git a/front/components/assistant/SlackIntegration.tsx b/front/components/assistant/SlackIntegration.tsx index 223f12a7b3c2..639f16196b9e 100644 --- a/front/components/assistant/SlackIntegration.tsx +++ b/front/components/assistant/SlackIntegration.tsx @@ -71,7 +71,7 @@ export function SlackIntegration({ dataSource={slackDataSource} selectedParentIds={selectedChannelIds} parentsById={{}} - onSelectChange={({ resourceId, resourceName }, selected) => { + onSelectChange={(node, selected) => { setHasChanged(true); if (selected) { @@ -81,8 +81,8 @@ export function SlackIntegration({ finalState.push(...sel); } finalState.push({ - slackChannelId: resourceId, - slackChannelName: resourceName, + slackChannelId: node.internalId, + slackChannelName: node.title, }); return finalState; @@ -95,7 +95,7 @@ export function SlackIntegration({ } finalState.splice( finalState.findIndex( - (c) => c.slackChannelId === resourceId + (c) => c.slackChannelId === node.internalId ), 1 ); diff --git a/front/components/assistant_builder/ActionScreen.tsx b/front/components/assistant_builder/ActionScreen.tsx index 7c13e568e0ea..78419d41eeb6 100644 --- a/front/components/assistant_builder/ActionScreen.tsx +++ b/front/components/assistant_builder/ActionScreen.tsx @@ -30,7 +30,6 @@ import { TIME_FRAME_UNIT_TO_LABEL } from "@app/components/assistant_builder/shar import TablesSelectionSection from "@app/components/assistant_builder/TablesSelectionSection"; import type { ActionMode, - AssistantBuilderDataSourceConfiguration, AssistantBuilderState, } from "@app/components/assistant_builder/types"; import { tableKey } from "@app/lib/client/tables_query"; @@ -142,15 +141,9 @@ export default function ActionScreen({ timeFrameError: string | null; }) { const [showDataSourcesModal, setShowDataSourcesModal] = useState(false); - const [dataSourceToManage, setDataSourceToManage] = - useState(null); const [showDustAppsModal, setShowDustAppsModal] = useState(false); const [showTableModal, setShowTableModal] = useState(false); - const configurableDataSources = dataSources.filter( - (dataSource) => !builderState.dataSourceConfigurations[dataSource.name] - ); - const deleteDataSource = (name: string) => { setEdited(true); setBuilderState(({ dataSourceConfigurations, ...rest }) => { @@ -197,7 +190,7 @@ export default function ActionScreen({ }; const noDataSources = - configurableDataSources.length === 0 && + dataSources.length === 0 && Object.keys(builderState.dataSourceConfigurations).length === 0; const noDustApp = dustApps.length === 0; @@ -207,9 +200,6 @@ export default function ActionScreen({ isOpen={showDustAppsModal} setOpen={(isOpen) => { setShowDustAppsModal(isOpen); - if (!isOpen) { - setDataSourceToManage(null); - } }} dustApps={dustApps} onSave={({ app }) => { @@ -243,12 +233,9 @@ export default function ActionScreen({ isOpen={showDataSourcesModal} setOpen={(isOpen) => { setShowDataSourcesModal(isOpen); - if (!isOpen) { - setDataSourceToManage(null); - } }} owner={owner} - dataSources={configurableDataSources} + dataSources={dataSources} onSave={({ dataSource, selectedResources, isSelectAll }) => { setEdited(true); setBuilderState((state) => ({ @@ -263,7 +250,8 @@ export default function ActionScreen({ }, })); }} - dataSourceToManage={dataSourceToManage} + onDelete={deleteDataSource} + dataSourceConfigurations={builderState.dataSourceConfigurations} />
@@ -414,7 +402,6 @@ export default function ActionScreen({ {SEARCH_MODES.filter((key) => { const flag = SEARCH_MODE_SPECIFICATIONS[key].flag; - console.log(owner.flags); return flag === null || owner.flags.includes(flag); }).map((key) => ( { setShowDataSourcesModal(true); }} - canAddDataSource={configurableDataSources.length > 0} - onManageDataSource={(name) => { - setDataSourceToManage( - builderState.dataSourceConfigurations[name] - ); - setShowDataSourcesModal(true); - }} + canAddDataSource={dataSources.length > 0} onDelete={deleteDataSource} /> @@ -472,17 +454,12 @@ export default function ActionScreen({ } > { setShowDataSourcesModal(true); }} - canAddDataSource={configurableDataSources.length > 0} - onManageDataSource={(name) => { - setDataSourceToManage( - builderState.dataSourceConfigurations[name] - ); - setShowDataSourcesModal(true); - }} + canAddDataSource={dataSources.length > 0} onDelete={deleteDataSource} />
diff --git a/front/components/assistant_builder/AssistantBuilder.tsx b/front/components/assistant_builder/AssistantBuilder.tsx index 947c9294d1a0..2ddefaec40fd 100644 --- a/front/components/assistant_builder/AssistantBuilder.tsx +++ b/front/components/assistant_builder/AssistantBuilder.tsx @@ -603,7 +603,12 @@ async function submitForm({ workspaceId: owner.sId, filter: { parents: !isSelectAll - ? { in: Object.keys(selectedResources), not: [] } + ? { + in: selectedResources.map( + (resource) => resource.internalId + ), + not: [], + } : null, tags: null, }, diff --git a/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx b/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx index 50896fc7c93a..2ba00fbd957e 100644 --- a/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx +++ b/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx @@ -7,14 +7,21 @@ import { Searchbar, SliderToggle, } from "@dust-tt/sparkle"; -import type { ConnectorProvider, DataSourceType } from "@dust-tt/types"; +import type { + ConnectorNode, + ConnectorProvider, + DataSourceType, +} from "@dust-tt/types"; import type { WorkspaceType } from "@dust-tt/types"; import { assertNever } from "@dust-tt/types"; import { Transition } from "@headlessui/react"; import * as React from "react"; import { useCallback, useEffect, useState } from "react"; -import type { AssistantBuilderDataSourceConfiguration } from "@app/components/assistant_builder/types"; +import type { + AssistantBuilderDataSourceConfiguration, + AssistantBuilderDataSourceConfigurations, +} from "@app/components/assistant_builder/types"; import DataSourceResourceSelectorTree from "@app/components/DataSourceResourceSelectorTree"; import { orderDatasourceByImportance } from "@app/lib/assistant"; import { CONNECTOR_CONFIGURATIONS } from "@app/lib/connector_providers"; @@ -43,33 +50,27 @@ export default function AssistantBuilderDataSourceModal({ owner, dataSources, onSave, - dataSourceToManage, + onDelete, + dataSourceConfigurations, }: { isOpen: boolean; setOpen: (isOpen: boolean) => void; owner: WorkspaceType; dataSources: DataSourceType[]; onSave: (params: AssistantBuilderDataSourceConfiguration) => void; - dataSourceToManage: AssistantBuilderDataSourceConfiguration | null; + onDelete: (name: string) => void; + dataSourceConfigurations: AssistantBuilderDataSourceConfigurations; }) { const [selectedDataSource, setSelectedDataSource] = useState(null); - const [selectedResources, setSelectedResources] = useState< - Record - >({}); + const [selectedResources, setSelectedResources] = useState( + [] + ); const [isSelectAll, setIsSelectAll] = useState(false); - useEffect(() => { - if (dataSourceToManage) { - setSelectedDataSource(dataSourceToManage.dataSource); - setSelectedResources(dataSourceToManage.selectedResources); - setIsSelectAll(dataSourceToManage.isSelectAll); - } - }, [dataSourceToManage]); - const onReset = () => { setSelectedDataSource(null); - setSelectedResources({}); + setSelectedResources([]); setIsSelectAll(false); }; @@ -81,43 +82,48 @@ export default function AssistantBuilderDataSourceModal({ }; const onSaveLocal = ({ isSelectAll }: { isSelectAll: boolean }) => { - if ( - !selectedDataSource || - (Object.keys(selectedResources).length === 0 && !isSelectAll) - ) { + if (!selectedDataSource) { throw new Error("Cannot save an incomplete configuration"); } - onSave({ - dataSource: selectedDataSource, - selectedResources, - isSelectAll, - }); + if (selectedResources.length) { + onSave({ + dataSource: selectedDataSource, + selectedResources, + isSelectAll, + }); + } else { + onDelete(selectedDataSource.name); + } + onClose(); }; return ( onSaveLocal({ isSelectAll })} - hasChanged={ - !!selectedDataSource && - (Object.keys(selectedResources).length > 0 || isSelectAll) - } + hasChanged={selectedDataSource !== null} variant="full-screen" - title="Add data sources" + title="Manage data sources selection" >
{!selectedDataSource || !selectedDataSource.connectorProvider ? ( { setSelectedDataSource(ds); + setSelectedResources( + dataSourceConfigurations[ds.name]?.selectedResources || [] + ); + setIsSelectAll( + dataSourceConfigurations[ds.name]?.isSelectAll || false + ); if (!ds.connectorProvider) { onSave({ dataSource: ds, - selectedResources: {}, + selectedResources: [], isSelectAll: true, }); onClose(); @@ -126,22 +132,34 @@ export default function AssistantBuilderDataSourceModal({ /> ) : ( { - const newSelectedResources = { ...selectedResources }; - if (selected) { - newSelectedResources[resourceId] = resourceName; - } else { - delete newSelectedResources[resourceId]; - } - - setSelectedResources(newSelectedResources); + onSelectChange={(node, selected) => { + setSelectedResources((currentResources) => { + const isNodeAlreadySelected = currentResources.some( + (resource) => resource.internalId === node.internalId + ); + if (selected) { + if (!isNodeAlreadySelected) { + return [...currentResources, node]; + } + } else { + if (isNodeAlreadySelected) { + return currentResources.filter( + (resource) => resource.internalId !== node.internalId + ); + } + } + return currentResources; + }); }} toggleSelectAll={() => { const selectAll = !isSelectAll; + if (isSelectAll === false) { + setSelectedResources([]); + } setIsSelectAll(selectAll); }} /> @@ -208,12 +226,9 @@ function DataSourceResourceSelector({ }: { dataSource: DataSourceType | null; owner: WorkspaceType; - selectedResources: Record; + selectedResources: ConnectorNode[]; isSelectAll: boolean; - onSelectChange: ( - resource: { resourceId: string; resourceName: string }, - selected: boolean - ) => void; + onSelectChange: (resource: ConnectorNode, selected: boolean) => void; toggleSelectAll: () => void; }) { const [parentsById, setParentsById] = useState>>( @@ -235,7 +250,9 @@ function DataSourceResourceSelector({ "Content-Type": "application/json", }, body: JSON.stringify({ - internalIds: Object.keys(selectedResources), + internalIds: selectedResources.map((resource) => { + return resource.internalId; + }), }), } ); @@ -257,7 +274,7 @@ function DataSourceResourceSelector({ }, [owner, dataSource?.name, selectedResources]); const hasParentsById = Object.keys(parentsById || {}).length > 0; - const hasSelectedResources = Object.keys(selectedResources).length > 0; + const hasSelectedResources = selectedResources.length > 0; useEffect(() => { if (parentsAreLoading || parentsAreError) { @@ -316,21 +333,21 @@ function DataSourceResourceSelector({ dataSource.connectorProvider as ConnectorProvider ]?.isNested } - selectedParentIds={new Set(Object.keys(selectedResources))} + selectedParentIds={ + new Set( + selectedResources.map((resource) => resource.internalId) + ) + } parentsById={parentsById} - onSelectChange={( - { resourceId, resourceName, parents }, - selected - ) => { + onSelectChange={(node, parents, selected) => { const newParentsById = { ...parentsById }; if (selected) { - newParentsById[resourceId] = new Set(parents); + newParentsById[node.internalId] = new Set(parents); } else { - delete newParentsById[resourceId]; + delete newParentsById[node.internalId]; } - setParentsById(newParentsById); - onSelectChange({ resourceId, resourceName }, selected); + onSelectChange(node, selected); }} fullySelected={isSelectAll} /> diff --git a/front/components/assistant_builder/DataSourceSelectionSection.tsx b/front/components/assistant_builder/DataSourceSelectionSection.tsx index 469a342e431a..d630e395a214 100644 --- a/front/components/assistant_builder/DataSourceSelectionSection.tsx +++ b/front/components/assistant_builder/DataSourceSelectionSection.tsx @@ -1,122 +1,162 @@ -import { - Button, - CloudArrowDownIcon, - Cog6ToothIcon, - ContextItem, - TrashIcon, -} from "@dust-tt/sparkle"; +import { Button, Tree } from "@dust-tt/sparkle"; +import type { DataSourceType, WorkspaceType } from "@dust-tt/types"; +import { useState } from "react"; -import { CONNECTOR_PROVIDER_TO_RESOURCE_NAME } from "@app/components/assistant_builder/shared"; import type { AssistantBuilderDataSourceConfiguration } from "@app/components/assistant_builder/types"; +import { PermissionTreeChildren } from "@app/components/ConnectorPermissionsTree"; import { EmptyCallToAction } from "@app/components/EmptyCallToAction"; +import ManagedDataSourceDocumentModal from "@app/components/ManagedDataSourceDocumentModal"; import { CONNECTOR_CONFIGURATIONS } from "@app/lib/connector_providers"; import { getDisplayNameForDataSource } from "@app/lib/data_sources"; +import { useConnectorPermissions } from "@app/lib/swr"; export default function DataSourceSelectionSection({ + owner, dataSourceConfigurations, openDataSourceModal, canAddDataSource, - onManageDataSource, - onDelete, }: { + owner: WorkspaceType; dataSourceConfigurations: Record< string, AssistantBuilderDataSourceConfiguration >; openDataSourceModal: () => void; canAddDataSource: boolean; - onManageDataSource: (name: string) => void; onDelete?: (name: string) => void; }) { + const [expanded, setExpanded] = useState>({}); + const [documentToDisplay, setDocumentToDisplay] = useState( + null + ); + const [dataSourceToDisplay, setDataSourceToDisplay] = + useState(); + return ( -
-
-
- {Object.keys(dataSourceConfigurations).length > 0 && ( -
+
+ {!Object.keys(dataSourceConfigurations).length ? ( + - )} -
- {!Object.keys(dataSourceConfigurations).length ? ( - - ) : ( - - {Object.entries(dataSourceConfigurations).map( - ([key, { dataSource, selectedResources, isSelectAll }]) => { - const selectedParentIds = Object.keys(selectedResources); + ) : ( + + {Object.values(dataSourceConfigurations).map((dsConfig) => { + const LogoComponent = dsConfig.dataSource?.connectorProvider + ? CONNECTOR_CONFIGURATIONS[ + dsConfig.dataSource.connectorProvider + ].logoComponent + : null; return ( - { + setExpanded((prev) => ({ + ...prev, + [dsConfig.dataSource.id]: prev[dsConfig.dataSource.id] + ? false + : true, + })); + }} + type="node" + label={getDisplayNameForDataSource(dsConfig.dataSource)} visual={ - - } - action={ - -
+ })} + + )} +
+ ); } diff --git a/front/components/assistant_builder/server_side_props_helpers.ts b/front/components/assistant_builder/server_side_props_helpers.ts index 9d8543d1c562..b02c2cc37171 100644 --- a/front/components/assistant_builder/server_side_props_helpers.ts +++ b/front/components/assistant_builder/server_side_props_helpers.ts @@ -55,29 +55,23 @@ export async function buildInitialState({ if (!dataSource.connectorId || !ds.resources) { return { dataSource: dataSource, - selectedResources: {}, + selectedResources: [], isSelectAll: ds.isSelectAll, }; } const connectorsAPI = new ConnectorsAPI(logger); - const response = await connectorsAPI.getResourcesTitles({ + const response = await connectorsAPI.getContentNodes({ connectorId: dataSource.connectorId, - resourceInternalIds: ds.resources, + internalIds: ds.resources, }); if (response.isErr()) { throw response.error; } - // key: interalId, value: title - const selectedResources: Record = {}; - for (const resource of response.value.resources) { - selectedResources[resource.internalId] = resource.title; - } - return { dataSource: dataSource, - selectedResources, + selectedResources: response.value.nodes, isSelectAll: ds.isSelectAll, }; } diff --git a/front/components/assistant_builder/types.ts b/front/components/assistant_builder/types.ts index 467ff1f923b4..3857fc720810 100644 --- a/front/components/assistant_builder/types.ts +++ b/front/components/assistant_builder/types.ts @@ -1,6 +1,7 @@ import type { AgentConfigurationScope, AppType, + ConnectorNode, DataSourceType, SupportedModel, TimeframeUnit, @@ -18,7 +19,7 @@ export type ActionMode = (typeof ACTION_MODES)[number]; export type AssistantBuilderDataSourceConfiguration = { dataSource: DataSourceType; - selectedResources: Record; + selectedResources: ConnectorNode[]; isSelectAll: boolean; }; @@ -33,13 +34,15 @@ export type AssistantBuilderTableConfiguration = { tableName: string; }; +export type AssistantBuilderDataSourceConfigurations = Record< + string, + AssistantBuilderDataSourceConfiguration +>; + // Builder State export type AssistantBuilderState = { actionMode: ActionMode; - dataSourceConfigurations: Record< - string, - AssistantBuilderDataSourceConfiguration - >; + dataSourceConfigurations: AssistantBuilderDataSourceConfigurations; timeFrame: { value: number; unit: TimeframeUnit; diff --git a/front/package-lock.json b/front/package-lock.json index 12ea9b267476..526596e13dc1 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -10301,9 +10301,15 @@ "license": "Apache-2.0" }, "node_modules/@dust-tt/sparkle": { +<<<<<<< HEAD "version": "0.2.105", "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.105.tgz", "integrity": "sha512-HKeV8pPP/OyY/xJcnI0fZN5wVZZ+Mfyu5q1anuOhHL9O8Xy7SqQrsaFrY5NOsGpz+Qv0olRNvu6BsI/RpmpUfA==", +======= + "version": "0.2.103", + "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.103.tgz", + "integrity": "sha512-QKtBuVShj/WmtrTmkOkn/a6cy7wweh4aFjtx6CV87gAubI/mB4v/KVhjBnBHmbK25QreElKDUaH2/rQjtEO5/w==", +>>>>>>> 0b1041e8 (Assistant Builder: Tree component for datasources) "dependencies": { "@headlessui/react": "^1.7.17", "esbuild": "^0.20.0", diff --git a/types/src/front/lib/connectors_api.ts b/types/src/front/lib/connectors_api.ts index 7384f4b9355d..f4ee4c920009 100644 --- a/types/src/front/lib/connectors_api.ts +++ b/types/src/front/lib/connectors_api.ts @@ -394,6 +394,33 @@ export class ConnectorsAPI { return this._resultFromResponse(res); } + async getContentNodes({ + connectorId, + internalIds, + }: { + connectorId: string; + internalIds: string[]; + }): Promise< + ConnectorsAPIResponse<{ + nodes: ConnectorNode[]; + }> + > { + const res = await fetch( + `${CONNECTORS_API}/connectors/${encodeURIComponent( + connectorId + )}/content_nodes`, + { + method: "POST", + headers: this.getDefaultHeaders(), + body: JSON.stringify({ + internalIds, + }), + } + ); + + return this._resultFromResponse(res); + } + async linkSlackChannelsWithAgent({ connectorId, slackChannelIds, From 13c5f9189807eb1d3bc67a5fb98439c9cd1700ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Mon, 4 Mar 2024 17:07:11 +0100 Subject: [PATCH 2/4] Use new titleWithParentsContext as default title if set --- .../assistant_builder/DataSourceSelectionSection.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/front/components/assistant_builder/DataSourceSelectionSection.tsx b/front/components/assistant_builder/DataSourceSelectionSection.tsx index d630e395a214..5ba20ac91e11 100644 --- a/front/components/assistant_builder/DataSourceSelectionSection.tsx +++ b/front/components/assistant_builder/DataSourceSelectionSection.tsx @@ -131,7 +131,10 @@ export default function DataSourceSelectionSection({ : true, })); }} - label={selectedResource.title} + label={ + selectedResource.titleWithParentsContext ?? + selectedResource.title + } type={selectedResource.expandable ? "node" : "leaf"} variant={selectedResource.type} className="whitespace-nowrap" From db503ac6ce3ae3e066823c6a07287a3fc6cceef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Mon, 4 Mar 2024 20:44:39 +0100 Subject: [PATCH 3/4] Add urls to documents in tree --- .../ManagedDataSourceDocumentModal.tsx | 6 +- .../DataSourceSelectionSection.tsx | 92 +++++++++++++------ front/package-lock.json | 6 -- 3 files changed, 67 insertions(+), 37 deletions(-) diff --git a/front/components/ManagedDataSourceDocumentModal.tsx b/front/components/ManagedDataSourceDocumentModal.tsx index a0af953419d8..4d617f1f549d 100644 --- a/front/components/ManagedDataSourceDocumentModal.tsx +++ b/front/components/ManagedDataSourceDocumentModal.tsx @@ -10,7 +10,7 @@ export default function ManagedDataSourceDocumentModal({ setOpen, }: { owner: WorkspaceType; - dataSource: DataSourceType; + dataSource: DataSourceType | null; documentId: string | null; isOpen: boolean; setOpen: (open: boolean) => void; @@ -20,7 +20,7 @@ export default function ManagedDataSourceDocumentModal({ const [downloading, setDownloading] = useState(false); useEffect(() => { - if (documentId) { + if (documentId && dataSource?.name) { setDownloading(true); fetch( `/api/w/${owner.sId}/data_sources/${encodeURIComponent( @@ -42,7 +42,7 @@ export default function ManagedDataSourceDocumentModal({ }) .catch((e) => console.error(e)); } - }, [dataSource.name, documentId, owner.sId]); + }, [dataSource, documentId, owner.sId]); function closeModal() { setOpen(false); diff --git a/front/components/assistant_builder/DataSourceSelectionSection.tsx b/front/components/assistant_builder/DataSourceSelectionSection.tsx index 5ba20ac91e11..242eca368b7c 100644 --- a/front/components/assistant_builder/DataSourceSelectionSection.tsx +++ b/front/components/assistant_builder/DataSourceSelectionSection.tsx @@ -1,4 +1,10 @@ -import { Button, Tree } from "@dust-tt/sparkle"; +import { + BracesIcon, + Button, + ExternalLinkIcon, + IconButton, + Tree, +} from "@dust-tt/sparkle"; import type { DataSourceType, WorkspaceType } from "@dust-tt/types"; import { useState } from "react"; @@ -9,6 +15,7 @@ import ManagedDataSourceDocumentModal from "@app/components/ManagedDataSourceDoc import { CONNECTOR_CONFIGURATIONS } from "@app/lib/connector_providers"; import { getDisplayNameForDataSource } from "@app/lib/data_sources"; import { useConnectorPermissions } from "@app/lib/swr"; +import { classNames } from "@app/lib/utils"; export default function DataSourceSelectionSection({ owner, @@ -30,23 +37,22 @@ export default function DataSourceSelectionSection({ null ); const [dataSourceToDisplay, setDataSourceToDisplay] = - useState(); + useState(null); return ( <> - {dataSourceToDisplay && ( - { - if (!open) { - setDocumentToDisplay(null); - } - }} - /> - )} + { + if (!open) { + setDocumentToDisplay(null); + } + }} + /> +
@@ -116,33 +122,63 @@ export default function DataSourceSelectionSection({ useConnectorPermissionsHook={useConnectorPermissions} /> )} - {dsConfig.selectedResources.map((selectedResource) => { + {dsConfig.selectedResources.map((node) => { return ( { setExpanded((prev) => ({ ...prev, - [selectedResource.internalId]: prev[ - selectedResource.internalId - ] + [node.internalId]: prev[node.internalId] ? false : true, })); }} - label={ - selectedResource.titleWithParentsContext ?? - selectedResource.title - } - type={selectedResource.expandable ? "node" : "leaf"} - variant={selectedResource.type} + label={node.titleWithParentsContext ?? node.title} + type={node.expandable ? "node" : "leaf"} + variant={node.type} className="whitespace-nowrap" + actions={ +
+ { + if (node.sourceUrl) { + window.open(node.sourceUrl, "_blank"); + } + }} + className={classNames( + node.sourceUrl + ? "" + : "pointer-events-none opacity-0" + )} + disabled={!node.sourceUrl} + /> + { + if (node.dustDocumentId) { + setDataSourceToDisplay(dsConfig.dataSource); + setDocumentToDisplay(node.dustDocumentId); + } + }} + className={classNames( + node.dustDocumentId + ? "" + : "pointer-events-none opacity-0" + )} + disabled={!node.dustDocumentId} + /> +
+ } > { diff --git a/front/package-lock.json b/front/package-lock.json index 526596e13dc1..12ea9b267476 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -10301,15 +10301,9 @@ "license": "Apache-2.0" }, "node_modules/@dust-tt/sparkle": { -<<<<<<< HEAD "version": "0.2.105", "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.105.tgz", "integrity": "sha512-HKeV8pPP/OyY/xJcnI0fZN5wVZZ+Mfyu5q1anuOhHL9O8Xy7SqQrsaFrY5NOsGpz+Qv0olRNvu6BsI/RpmpUfA==", -======= - "version": "0.2.103", - "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.103.tgz", - "integrity": "sha512-QKtBuVShj/WmtrTmkOkn/a6cy7wweh4aFjtx6CV87gAubI/mB4v/KVhjBnBHmbK25QreElKDUaH2/rQjtEO5/w==", ->>>>>>> 0b1041e8 (Assistant Builder: Tree component for datasources) "dependencies": { "@headlessui/react": "^1.7.17", "esbuild": "^0.20.0", From 4f0712d785aae576bec5d65efcf96dc2a7971a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Tue, 5 Mar 2024 14:01:22 +0100 Subject: [PATCH 4/4] Fix isSelectAll logic --- .../assistant_builder/AssistantBuilderDataSourceModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx b/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx index 2ba00fbd957e..6e3d2148f214 100644 --- a/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx +++ b/front/components/assistant_builder/AssistantBuilderDataSourceModal.tsx @@ -85,7 +85,7 @@ export default function AssistantBuilderDataSourceModal({ if (!selectedDataSource) { throw new Error("Cannot save an incomplete configuration"); } - if (selectedResources.length) { + if (selectedResources.length || isSelectAll) { onSave({ dataSource: selectedDataSource, selectedResources,