From d19da68b50039549d7167e112c0170b96e4426e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Wed, 11 Dec 2024 16:29:54 +0100 Subject: [PATCH] Tracker Builder: Manage datasource config (#9284) * Tracker Builder: Manage datasource config * Apply feedback --- front/admin/db.ts | 4 +- .../DataSourceViewSelector.tsx | 3 +- front/components/trackers/TrackerBuilder.tsx | 170 ++++++++++---- .../TrackerBuilderDataSourceModal.tsx | 97 ++++++++ front/lib/models/doc_tracker.ts | 17 +- front/lib/resources/tracker_resource.ts | 210 +++++++++++++++--- .../spaces/[spaceId]/trackers/[tId]/index.ts | 114 ++++++++++ .../[wId]/spaces/[spaceId]/trackers/index.ts | 23 +- .../assistant/labs/trackers/[tId]/index.tsx | 135 ++++++++++- .../w/[wId]/assistant/labs/trackers/new.tsx | 3 +- types/src/front/tracker.ts | 17 +- 11 files changed, 697 insertions(+), 96 deletions(-) create mode 100644 front/components/trackers/TrackerBuilderDataSourceModal.tsx create mode 100644 front/pages/api/w/[wId]/spaces/[spaceId]/trackers/[tId]/index.ts diff --git a/front/admin/db.ts b/front/admin/db.ts index 044fc1a8f343..0645abad7a88 100644 --- a/front/admin/db.ts +++ b/front/admin/db.ts @@ -50,7 +50,7 @@ import { DocumentTrackerChangeSuggestion, TrackedDocument, TrackerConfigurationModel, - TrackerDataSouceConfigurationModel, + TrackerDataSourceConfigurationModel, TrackerGenerationModel, } from "@app/lib/models/doc_tracker"; import { FeatureFlag } from "@app/lib/models/feature_flag"; @@ -129,7 +129,7 @@ async function main() { await DocumentTrackerChangeSuggestion.sync({ alter: true }); await TrackerConfigurationModel.sync({ alter: true }); - await TrackerDataSouceConfigurationModel.sync({ alter: true }); + await TrackerDataSourceConfigurationModel.sync({ alter: true }); await TrackerGenerationModel.sync({ alter: true }); await Plan.sync({ alter: true }); diff --git a/front/components/data_source_view/DataSourceViewSelector.tsx b/front/components/data_source_view/DataSourceViewSelector.tsx index 514de9210255..d19c7c5d2768 100644 --- a/front/components/data_source_view/DataSourceViewSelector.tsx +++ b/front/components/data_source_view/DataSourceViewSelector.tsx @@ -90,7 +90,8 @@ interface DataSourceViewsSelectorProps { useCase: | "spaceDatasourceManagement" | "assistantBuilder" - | "transcriptsProcessing"; + | "transcriptsProcessing" + | "trackerBuilder"; dataSourceViews: DataSourceViewType[]; allowedSpaces?: SpaceType[]; selectionConfigurations: DataSourceViewSelectionConfigurations; diff --git a/front/components/trackers/TrackerBuilder.tsx b/front/components/trackers/TrackerBuilder.tsx index 2b46889775f9..2c01dbdf0508 100644 --- a/front/components/trackers/TrackerBuilder.tsx +++ b/front/components/trackers/TrackerBuilder.tsx @@ -11,12 +11,12 @@ import { useSendNotification, } from "@dust-tt/sparkle"; import type { + DataSourceViewSelectionConfiguration, DataSourceViewType, SpaceType, SubscriptionType, SupportedModel, TrackerConfigurationStateType, - TrackerConfigurationType, WorkspaceType, } from "@dust-tt/types"; import { @@ -28,7 +28,11 @@ import { useState } from "react"; import { AdvancedSettings } from "@app/components/assistant_builder/InstructionScreen"; import AppLayout from "@app/components/sparkle/AppLayout"; -import { AppLayoutSimpleSaveCancelTitle } from "@app/components/sparkle/AppLayoutTitle"; +import { + AppLayoutSimpleCloseTitle, + AppLayoutSimpleSaveCancelTitle, +} from "@app/components/sparkle/AppLayoutTitle"; +import TrackerBuilderDataSourceModal from "@app/components/trackers/TrackerBuilderDataSourceModal"; import { isEmailValid } from "@app/lib/utils"; export const TrackerBuilder = ({ @@ -36,46 +40,49 @@ export const TrackerBuilder = ({ subscription, globalSpace, dataSourceViews, - trackerToEdit, + initialTrackerState, + initialTrackerId, }: { owner: WorkspaceType; subscription: SubscriptionType; globalSpace: SpaceType; dataSourceViews: DataSourceViewType[]; - trackerToEdit: TrackerConfigurationType | null; + initialTrackerState: TrackerConfigurationStateType | null; + initialTrackerId: string | null; }) => { const router = useRouter(); const sendNotification = useSendNotification(); - const [isSubmitting, setIsSubmitting] = useState(false); - const [tracker, setTracker] = useState({ - name: trackerToEdit?.name ?? null, - nameError: null, - description: trackerToEdit?.description ?? null, - descriptionError: null, - prompt: trackerToEdit?.prompt ?? null, - promptError: null, - frequency: trackerToEdit?.frequency ?? "daily", - frequencyError: null, - recipients: trackerToEdit?.recipients?.join(", ") ?? null, - recipientsError: null, - modelId: - trackerToEdit?.modelId ?? CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.modelId, - providerId: - trackerToEdit?.providerId ?? - CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.providerId, - temperature: trackerToEdit?.temperature ?? 0.5, - }); + const [edited, setEdited] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const [showMaintainedDsModal, setShowMaintainedDsModal] = useState(false); + const [showWatchedDsModal, setShowWatchedDataSourcesModal] = useState(false); - void dataSourceViews; // todo: use this + const [tracker, setTracker] = useState( + initialTrackerState ?? { + name: null, + nameError: null, + description: null, + descriptionError: null, + prompt: null, + promptError: null, + frequency: "daily", + frequencyError: null, + recipients: "", + recipientsError: null, + modelId: CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.modelId, + providerId: CLAUDE_3_5_SONNET_DEFAULT_MODEL_CONFIG.providerId, + temperature: 0.5, + maintainedDataSources: {}, + watchedDataSources: {}, + } + ); const extractEmails = (text: string): string[] => [ ...new Set(text.split(/[\n,]+/).map((e) => e.trim())), ]; - const onSubmit = async () => { - // Validate the form - setIsSubmitting(true); + const validateForm = () => { let hasValidationError = false; if (!tracker.name) { setTracker((t) => ({ @@ -109,6 +116,33 @@ export const TrackerBuilder = ({ })); hasValidationError = true; } + return hasValidationError; + }; + + const dataSourceToPayload = ( + { + dataSourceView, + selectedResources, + isSelectAll, + }: DataSourceViewSelectionConfiguration, + workspaceId: string + ) => ({ + dataSourceViewId: dataSourceView.sId, + workspaceId, + filter: { + parents: !isSelectAll + ? { + in: selectedResources.map((r) => r.internalId), + not: [], + } + : null, + }, + }); + + // todo use submit function. + const onSubmit = async () => { + setIsSubmitting(true); + const hasValidationError = validateForm(); if (hasValidationError) { setIsSubmitting(false); return; @@ -117,8 +151,8 @@ export const TrackerBuilder = ({ let route = `/api/w/${owner.sId}/spaces/${globalSpace.sId}/trackers`; let method = "POST"; - if (trackerToEdit) { - route += `/${trackerToEdit.sId}`; + if (initialTrackerId) { + route += `/${initialTrackerId}`; method = "PATCH"; } @@ -133,6 +167,12 @@ export const TrackerBuilder = ({ temperature: tracker.temperature, frequency: tracker.frequency, recipients: tracker.recipients ? extractEmails(tracker.recipients) : [], + maintainedDataSources: Object.values(tracker.maintainedDataSources).map( + (ds) => dataSourceToPayload(ds, owner.sId) + ), + watchedDataSources: Object.values(tracker.watchedDataSources).map( + (ds) => dataSourceToPayload(ds, owner.sId) + ), }), headers: { "Content-Type": "application/json", @@ -143,7 +183,7 @@ export const TrackerBuilder = ({ if (!res.ok) { const resJson = await res.json(); sendNotification({ - title: trackerToEdit + title: initialTrackerId ? "Failed to update tracker" : "Failed to create tracker", description: resJson.error.message, @@ -154,8 +194,8 @@ export const TrackerBuilder = ({ } sendNotification({ - title: trackerToEdit ? "Tracker updated" : "Tracker Created", - description: trackerToEdit + title: initialTrackerId ? "Tracker updated" : "Tracker Created", + description: initialTrackerId ? "Tracker updated successfully" : "Tracker created successfully.", type: "success", @@ -170,18 +210,62 @@ export const TrackerBuilder = ({ subscription={subscription} hideSidebar isWideMode - pageTitle={trackerToEdit ? "Dust - Edit Tracker" : "Dust - New Tracker"} + pageTitle={ + initialTrackerId ? "Dust - Edit Tracker" : "Dust - New Tracker" + } titleChildren={ - { - await router.push(`/w/${owner.sId}/assistant/labs/trackers`); - }} - onSave={onSubmit} - isSaving={isSubmitting} - /> + !edited ? ( + { + void router.push(`/w/${owner.sId}/assistant/labs/trackers`); + }} + /> + ) : ( + { + void router.push(`/w/${owner.sId}/assistant/labs/trackers`); + }} + onSave={onSubmit} + isSaving={isSubmitting} + /> + ) } > + setShowMaintainedDsModal(isOpen)} + owner={owner} + onSave={async (dsConfigs) => { + setEdited(true); + setTracker((t) => ({ + ...t, + maintainedDataSources: dsConfigs, + })); + }} + dataSourceViews={dataSourceViews} + initialDataSourceConfigurations={tracker.maintainedDataSources} + allowedSpaces={[globalSpace]} + viewType="documents" + /> + setShowWatchedDataSourcesModal(isOpen)} + owner={owner} + onSave={async (dsConfigs) => { + setEdited(true); + setTracker((t) => ({ + ...t, + watchedDataSources: dsConfigs, + })); + }} + dataSourceViews={dataSourceViews} + initialDataSourceConfigurations={tracker.watchedDataSources} + allowedSpaces={[globalSpace]} + viewType="documents" + /> +
@@ -343,7 +427,7 @@ export const TrackerBuilder = ({