From ea396036622a3f06db4cc2c80550c9787271ee8c Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Tue, 21 Jan 2025 11:43:54 +0100 Subject: [PATCH 01/35] fix: run upsert hooks for all workspsaces (#10118) Co-authored-by: Henry Fontanier --- front/lib/document_upsert_hooks/hooks/index.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/front/lib/document_upsert_hooks/hooks/index.ts b/front/lib/document_upsert_hooks/hooks/index.ts index d366415c845f..e7619a8f309a 100644 --- a/front/lib/document_upsert_hooks/hooks/index.ts +++ b/front/lib/document_upsert_hooks/hooks/index.ts @@ -1,13 +1,10 @@ import type { ConnectorProvider, UpsertContext } from "@dust-tt/types"; -import { isDevelopment } from "@dust-tt/types"; import type { Authenticator } from "@app/lib/auth"; import { trackerUpsertHook } from "@app/lib/document_upsert_hooks/hooks/tracker"; import { wakeLock } from "@app/lib/wake_lock"; import logger from "@app/logger/logger"; -const DUST_WORKSPACE = "0ec9852c2f"; - const _hooks = { tracker: trackerUpsertHook, } as const; @@ -30,11 +27,6 @@ export type DocumentUpsertHook = { export function runDocumentUpsertHooks( params: Parameters[0] ): void { - // TODO(document-tracker): remove this once we have a way to enable/disable - if (params.auth.workspace()?.sId !== DUST_WORKSPACE && !isDevelopment()) { - return; - } - if (params.upsertContext?.sync_type !== "incremental") { // Skip hooks for batch syncs return; From 79f6dcd6fa35e40db81f8e92e6fb25e3f1d3c5d2 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Tue, 21 Jan 2025 11:44:10 +0100 Subject: [PATCH 02/35] feat(poke): trackers view (#10116) Co-authored-by: Henry Fontanier --- front/components/poke/trackers/columns.tsx | 40 ++++++++++ front/components/poke/trackers/table.tsx | 24 ++++++ front/lib/resources/tracker_resource.ts | 1 + .../poke/workspaces/[wId]/trackers/[tId].ts | 74 ++++++++++++++++++ .../poke/workspaces/[wId]/trackers/index.ts | 65 ++++++++++++++++ front/pages/poke/[wId]/index.tsx | 2 + .../pages/poke/[wId]/trackers/[tId]/index.tsx | 76 +++++++++++++++++++ front/poke/swr/trackers.ts | 45 +++++++++++ types/src/front/lib/error.ts | 4 +- types/src/front/tracker.ts | 1 + 10 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 front/components/poke/trackers/columns.tsx create mode 100644 front/components/poke/trackers/table.tsx create mode 100644 front/pages/api/poke/workspaces/[wId]/trackers/[tId].ts create mode 100644 front/pages/api/poke/workspaces/[wId]/trackers/index.ts create mode 100644 front/pages/poke/[wId]/trackers/[tId]/index.tsx create mode 100644 front/poke/swr/trackers.ts diff --git a/front/components/poke/trackers/columns.tsx b/front/components/poke/trackers/columns.tsx new file mode 100644 index 000000000000..3d53dfa37ef2 --- /dev/null +++ b/front/components/poke/trackers/columns.tsx @@ -0,0 +1,40 @@ +import type { TrackerConfigurationType, WorkspaceType } from "@dust-tt/types"; +import type { ColumnDef } from "@tanstack/react-table"; +import Link from "next/link"; + +import { formatTimestampToFriendlyDate } from "@app/lib/utils"; + +export function makeColumnsForTrackers( + owner: WorkspaceType +): ColumnDef[] { + return [ + { + accessorKey: "name", + header: "Name", + cell: ({ row }) => ( + + {row.original.name} + + ), + }, + { + accessorKey: "frequency", + header: "Frequency", + }, + { + accessorKey: "status", + header: "Status", + }, + { + accessorKey: "createdAt", + header: "Created At", + cell: ({ row }) => + row.original + ? formatTimestampToFriendlyDate(row.original.createdAt) + : "N/A", + }, + ]; +} diff --git a/front/components/poke/trackers/table.tsx b/front/components/poke/trackers/table.tsx new file mode 100644 index 000000000000..f2dd4840940c --- /dev/null +++ b/front/components/poke/trackers/table.tsx @@ -0,0 +1,24 @@ +import type { WorkspaceType } from "@dust-tt/types"; + +import { PokeDataTableConditionalFetch } from "@app/components/poke/PokeConditionalDataTables"; +import { PokeDataTable } from "@app/components/poke/shadcn/ui/data_table"; +import { makeColumnsForTrackers } from "@app/components/poke/trackers/columns"; +import { usePokeTrackers } from "@app/poke/swr/trackers"; + +interface TrackerDataTableProps { + owner: WorkspaceType; +} + +export function TrackerDataTable({ owner }: TrackerDataTableProps) { + return ( + + {(data) => ( + + )} + + ); +} diff --git a/front/lib/resources/tracker_resource.ts b/front/lib/resources/tracker_resource.ts index 5b8e9d6e5404..31d38140f0dc 100644 --- a/front/lib/resources/tracker_resource.ts +++ b/front/lib/resources/tracker_resource.ts @@ -687,6 +687,7 @@ export class TrackerConfigurationResource extends ResourceWithSpace dsc.scope === "watched") .map(dataSourceToJSON), + createdAt: this.createdAt.getTime(), }; if (this.generations?.length) { diff --git a/front/pages/api/poke/workspaces/[wId]/trackers/[tId].ts b/front/pages/api/poke/workspaces/[wId]/trackers/[tId].ts new file mode 100644 index 000000000000..c630a398390e --- /dev/null +++ b/front/pages/api/poke/workspaces/[wId]/trackers/[tId].ts @@ -0,0 +1,74 @@ +import type { + TrackerConfigurationType, + WithAPIErrorResponse, +} from "@dust-tt/types"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { withSessionAuthentication } from "@app/lib/api/auth_wrappers"; +import { Authenticator } from "@app/lib/auth"; +import type { SessionWithUser } from "@app/lib/iam/provider"; +import { TrackerConfigurationResource } from "@app/lib/resources/tracker_resource"; +import { apiError } from "@app/logger/withlogging"; + +export type PokeFetchTrackerResponse = { + tracker: TrackerConfigurationType; +}; + +async function handler( + req: NextApiRequest, + res: NextApiResponse>, + session: SessionWithUser +): Promise { + const { wId, tId } = req.query; + if (typeof wId !== "string" || typeof tId !== "string") { + return apiError(req, res, { + status_code: 400, + api_error: { + type: "tracker_not_found", + message: "The tracker was not found.", + }, + }); + } + + const auth = await Authenticator.fromSuperUserSession(session, wId); + + const owner = auth.workspace(); + if (!owner || !auth.isDustSuperUser()) { + return apiError(req, res, { + status_code: 404, + api_error: { + type: "tracker_not_found", + message: "Could not find the tracker.", + }, + }); + } + + const tracker = await TrackerConfigurationResource.fetchById(auth, tId); + if (!tracker) { + return apiError(req, res, { + status_code: 404, + api_error: { + type: "tracker_not_found", + message: "Could not find the tracker.", + }, + }); + } + + switch (req.method) { + case "GET": + return res.status(200).json({ + tracker: tracker.toJSON(), + }); + + default: + return apiError(req, res, { + status_code: 405, + api_error: { + type: "method_not_supported_error", + message: "The method is not supported.", + }, + }); + } +} + +export default withSessionAuthentication(handler); diff --git a/front/pages/api/poke/workspaces/[wId]/trackers/index.ts b/front/pages/api/poke/workspaces/[wId]/trackers/index.ts new file mode 100644 index 000000000000..302202317b89 --- /dev/null +++ b/front/pages/api/poke/workspaces/[wId]/trackers/index.ts @@ -0,0 +1,65 @@ +import type { + TrackerConfigurationType, + WithAPIErrorResponse, +} from "@dust-tt/types"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { withSessionAuthentication } from "@app/lib/api/auth_wrappers"; +import { Authenticator } from "@app/lib/auth"; +import type { SessionWithUser } from "@app/lib/iam/provider"; +import { TrackerConfigurationResource } from "@app/lib/resources/tracker_resource"; +import { apiError } from "@app/logger/withlogging"; + +export type PokeListTrackers = { + trackers: TrackerConfigurationType[]; +}; + +async function handler( + req: NextApiRequest, + res: NextApiResponse>, + session: SessionWithUser +): Promise { + const { wId } = req.query; + if (typeof wId !== "string") { + return apiError(req, res, { + status_code: 400, + api_error: { + type: "workspace_not_found", + message: "The workspace was not found.", + }, + }); + } + + const auth = await Authenticator.fromSuperUserSession(session, wId); + + const owner = auth.workspace(); + if (!owner || !auth.isDustSuperUser()) { + return apiError(req, res, { + status_code: 404, + api_error: { + type: "tracker_not_found", + message: "Could not find trackers.", + }, + }); + } + + switch (req.method) { + case "GET": + const trackers = await TrackerConfigurationResource.listByWorkspace(auth); + + return res.status(200).json({ + trackers: trackers.map((t) => t.toJSON()), + }); + + default: + return apiError(req, res, { + status_code: 405, + api_error: { + type: "method_not_supported_error", + message: "The method is not supported.", + }, + }); + } +} + +export default withSessionAuthentication(handler); diff --git a/front/pages/poke/[wId]/index.tsx b/front/pages/poke/[wId]/index.tsx index da0730a1bb37..898da656b0b2 100644 --- a/front/pages/poke/[wId]/index.tsx +++ b/front/pages/poke/[wId]/index.tsx @@ -33,6 +33,7 @@ import { PluginList } from "@app/components/poke/plugins/PluginList"; import PokeNavbar from "@app/components/poke/PokeNavbar"; import { SpaceDataTable } from "@app/components/poke/spaces/table"; import { ActiveSubscriptionTable } from "@app/components/poke/subscriptions/table"; +import { TrackerDataTable } from "@app/components/poke/trackers/table"; import { WorkspaceInfoTable } from "@app/components/poke/workspace/table"; import config from "@app/lib/api/config"; import { getDataSources } from "@app/lib/api/data_sources"; @@ -275,6 +276,7 @@ const WorkspacePage = ({ owner={owner} whitelistableFeatures={whitelistableFeatures} /> + diff --git a/front/pages/poke/[wId]/trackers/[tId]/index.tsx b/front/pages/poke/[wId]/trackers/[tId]/index.tsx new file mode 100644 index 000000000000..e3c5eecf5383 --- /dev/null +++ b/front/pages/poke/[wId]/trackers/[tId]/index.tsx @@ -0,0 +1,76 @@ +import { ContextItem, Page, Spinner, TextArea } from "@dust-tt/sparkle"; +import type { WorkspaceType } from "@dust-tt/types"; +import { JsonViewer } from "@textea/json-viewer"; +import type { InferGetServerSidePropsType } from "next"; + +import PokeNavbar from "@app/components/poke/PokeNavbar"; +import { withSuperUserAuthRequirements } from "@app/lib/iam/session"; +import { formatTimestampToFriendlyDate } from "@app/lib/utils"; +import { usePokeTracker } from "@app/poke/swr/trackers"; + +export const getServerSideProps = withSuperUserAuthRequirements<{ + owner: WorkspaceType; + trackerId: string; +}>(async (context, auth) => { + const owner = auth.getNonNullableWorkspace(); + const { tId } = context.params || {}; + + if (typeof tId !== "string") { + return { notFound: true }; + } + + return { + props: { + owner, + trackerId: tId, + }, + }; +}); + +export default function TrackerDetailPage({ + owner, + trackerId, +}: InferGetServerSidePropsType) { + const { data, isLoading, isError } = usePokeTracker({ + owner, + tId: trackerId, + }); + + if (isLoading) { + return ; + } + + if (isError || !data) { + return
Error loading tracker
; + } + + return ( +
+ +
+ + + }> + +
+
+
Created At:
+
{formatTimestampToFriendlyDate(data.createdAt)}
+
+
+
Prompt:
+