diff --git a/packages/visual-editor/src/a2/google-drive/configurator.ts b/packages/visual-editor/src/a2/google-drive/configurator.ts index f499b31b0ec..5b9f3cec585 100644 --- a/packages/visual-editor/src/a2/google-drive/configurator.ts +++ b/packages/visual-editor/src/a2/google-drive/configurator.ts @@ -2,7 +2,9 @@ * @fileoverview Add a description for your module here. */ +import { Schema } from "@breadboard-ai/types"; import { createConfigurator } from "../a2/connector-manager.js"; +import { SLIDES_MIME_TYPE } from "./slides.js"; import type { ConnectorConfiguration } from "./types.js"; export { invoke as default, describe }; @@ -18,17 +20,43 @@ const { invoke, describe } = createConfigurator< return { title: "Untitled Drive File", configuration: {} }; }, read: async (_caps, { id: _id, configuration }) => { + const properties: Record = { + file: { + type: "object", + title: "Google Drive File", + description: "Select Google Drive File", + behavior: ["google-drive-file-id"], + }, + }; + + if (configuration.file?.mimeType === SLIDES_MIME_TYPE) { + properties["editEachTime"] = { + type: "string", + title: "Edit each time", + enum: ["New slide deck", "Same slide deck"], + default: "New slide deck", + behavior: ["hint-advanced", "reactive"], + }; + + if (configuration.editEachTime === "Same slide deck") { + properties["writeMode"] = { + type: "string", + title: "Write mode", + enum: [ + { id: "Prepend", title: "Prepend", info: "Add to the beginning" }, + { id: "Append", title: "Append", info: "Add to the end" }, + { id: "Overwrite", title: "Overwrite", info: "Replace everything" }, + ], + default: "Prepend", + behavior: ["hint-advanced"], + }; + } + } + return { schema: { type: "object", - properties: { - file: { - type: "object", - title: "Google Drive File", - description: "Select Google Drive File", - behavior: ["google-drive-file-id"], - }, - }, + properties, }, values: configuration, }; diff --git a/packages/visual-editor/src/a2/google-drive/connector-save.ts b/packages/visual-editor/src/a2/google-drive/connector-save.ts index e7c69d906bd..d939d502419 100644 --- a/packages/visual-editor/src/a2/google-drive/connector-save.ts +++ b/packages/visual-editor/src/a2/google-drive/connector-save.ts @@ -9,6 +9,7 @@ import { Schema, } from "@breadboard-ai/types"; import { err, ok } from "../a2/utils.js"; +import { SlidesRequest } from "./api.js"; import { appendSpreadsheetValues, create, @@ -81,6 +82,12 @@ async function invoke( return { context: contextFromId(id, DOC_MIME_TYPE) }; } case SLIDES_MIME_TYPE: { + const editEachTime = + info?.configuration?.editEachTime || "New slide deck"; + const writeMode = info?.configuration?.writeMode || "Prepend"; + const forceNew = editEachTime === "New slide deck"; + const fileId = forceNew ? undefined : info?.configuration?.file?.id; + const [gettingCollector, result] = await Promise.all([ getCollector( moduleArgs, @@ -88,18 +95,38 @@ async function invoke( graphId, title ?? "Untitled Presentation", SLIDES_MIME_TYPE, - info?.configuration?.file?.id + fileId, + forceNew ), inferSlideStructure(caps, moduleArgs, context), ]); if (!ok(gettingCollector)) return gettingCollector; if (!ok(result)) return result; const { id, end, last } = gettingCollector; + + let insertionIndex: number | undefined = undefined; + let deleteRequests: SlidesRequest[] = []; + if (editEachTime === "Same slide deck") { + if (writeMode === "Overwrite") { + const presentation = await getPresentation(moduleArgs, id); + if (ok(presentation)) { + deleteRequests = + presentation.slides?.map((s) => ({ + deleteObject: { objectId: s.objectId! }, + })) || []; + insertionIndex = 0; + } + } else if (writeMode === "Prepend") { + insertionIndex = 0; + } + } + const slideBuilder = new SimpleSlideBuilder(end, last); for (const slide of result.slides) { slideBuilder.addSlide(slide); } - const requests = slideBuilder.build([]); + const requests = slideBuilder.build([], insertionIndex); + requests.push(...deleteRequests); console.log("REQUESTS", requests); const updating = await updatePresentation(moduleArgs, id, { requests }); if (!ok(updating)) return updating; @@ -165,18 +192,23 @@ async function getCollector( graphId: string, title: string, mimeType: string, - fileId?: string + fileId?: string, + forceNew?: boolean ): Promise> { let id; if (!fileId) { + let foundId: string | undefined; const fileKey = `${getTypeKey(mimeType)}${connectorId}${graphId}`; - const findFile = await moduleArgs.shell.getDriveCollectorFile( - mimeType, - connectorId, - graphId - ); - if (!findFile.ok) return err(findFile.error); - id = findFile.id; + if (!forceNew) { + const findFile = await moduleArgs.shell.getDriveCollectorFile( + mimeType, + connectorId, + graphId + ); + if (!findFile.ok) return err(findFile.error); + foundId = findFile.id || undefined; + } + id = foundId; if (!id) { const createdFile = await create(moduleArgs, { name: title, diff --git a/packages/visual-editor/src/a2/google-drive/slides.ts b/packages/visual-editor/src/a2/google-drive/slides.ts index 6070e670beb..e7a0536d26e 100644 --- a/packages/visual-editor/src/a2/google-drive/slides.ts +++ b/packages/visual-editor/src/a2/google-drive/slides.ts @@ -118,10 +118,10 @@ class SlideBuilder { return this.#images; } - build(imageUrls: string[]) { + build(imageUrls: string[], insertionIndex?: number) { this.#finalizeSlide(); console.log("SLIDES", this.#slides); - const requests = slidesToRequests(this.#slides, imageUrls); + const requests = slidesToRequests(this.#slides, imageUrls, insertionIndex); if (this.#objectToDelete) { requests.unshift({ deleteObject: { @@ -264,15 +264,19 @@ class SlideBuilder { function slidesToRequests( slides: Slide[], - imageUrls: string[] + imageUrls: string[], + insertionIndex?: number ): SlidesRequest[] { const requests: SlidesRequest[] = []; - slides.forEach((slide) => { + slides.forEach((slide, index) => { const request: SlidesCreateSlideRequest = { objectId: slide.objectId, slideLayoutReference: { predefinedLayout: slide.layout }, placeholderIdMappings: mapPlaceholders(slide.objectId, slide.layout), }; + if (typeof insertionIndex === "number") { + request.insertionIndex = insertionIndex + index; + } requests.push({ createSlide: request }); if (slide.title) { requests.push({ @@ -377,9 +381,9 @@ class SimpleSlideBuilder { } } - build(imageUrls: string[]) { + build(imageUrls: string[], insertionIndex?: number) { console.log("SLIDES", this.#slides); - const requests = slidesToRequests(this.#slides, imageUrls); + const requests = slidesToRequests(this.#slides, imageUrls, insertionIndex); if (this.#objectToDelete) { requests.unshift({ deleteObject: { diff --git a/packages/visual-editor/src/a2/google-drive/types.ts b/packages/visual-editor/src/a2/google-drive/types.ts index 1d2ac347e4e..f0c30df5bd7 100644 --- a/packages/visual-editor/src/a2/google-drive/types.ts +++ b/packages/visual-editor/src/a2/google-drive/types.ts @@ -4,6 +4,8 @@ export type ConnectorConfiguration = { id: string; mimeType: string; }; + editEachTime?: string; + writeMode?: string; }; export type SimpleSlide = {