Skip to content

18073 trigger new or modified folders instant subfolder support #18091

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

luancazarine
Copy link
Collaborator

@luancazarine luancazarine commented Aug 18, 2025

Resolves #18073

Summary by CodeRabbit

  • New Features

    • New or Modified Folders source: add parent folder filter and optional subfolder inclusion, limit emitted results, and improve event timestamps/payloads.
    • Upload File action: smarter default filename, default multipart uploads, and MIME type validation to prevent mismatches.
  • Chores

    • Patch version bumps across many Google Drive actions and sources; behavior unchanged.
    • Minor import housekeeping and overall package version bump for Google Drive components.

- Bumped versions for multiple actions and sources to ensure compatibility and reflect recent changes.
- Enhanced the 'New or Modified Folders' source to include options for parent folder selection and subfolder inclusion.
- Improved event handling and filtering for various actions related to file and folder management.
@luancazarine luancazarine linked an issue Aug 18, 2025 that may be closed by this pull request
Copy link

vercel bot commented Aug 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Ignored Ignored Aug 18, 2025 1:12pm
pipedream-docs Ignored Ignored Aug 18, 2025 1:12pm
pipedream-docs-redirect-do-not-edit Ignored Ignored Aug 18, 2025 1:12pm

Copy link
Contributor

coderabbitai bot commented Aug 18, 2025

Walkthrough

Patch releases across Google Drive actions and sources with mostly version bumps and import reorders. One functional action change improves file upload handling. The “New or Modified Folders” source adds filtering by parent folder and optional subfolder inclusion, adjusts processing limits, and modifies event emission to use changed file objects.

Changes

Cohort / File(s) Summary
Actions — metadata updates
components/google_drive/actions/add-file-sharing-preference/add-file-sharing-preference.mjs, .../copy-file/copy-file.mjs, .../create-file-from-template/create-file-from-template.mjs, .../create-file-from-text/create-file-from-text.mjs, .../create-folder/create-folder.mjs, .../create-shared-drive/create-shared-drive.mjs, .../delete-file/delete-file.mjs, .../delete-shared-drive/delete-shared-drive.mjs, .../download-file/download-file.mjs, .../find-file/find-file.mjs, .../find-folder/find-folder.mjs, .../find-forms/find-forms.mjs, .../find-spreadsheets/find-spreadsheets.mjs, .../get-file-by-id/get-file-by-id.mjs, .../get-folder-id-for-path/get-folder-id-for-path.mjs, .../get-shared-drive/get-shared-drive.mjs, .../list-access-proposals/list-access-proposals.mjs, .../list-files/list-files.mjs, .../move-file-to-trash/move-file-to-trash.mjs, .../move-file/move-file.mjs, .../resolve-access-proposal/resolve-access-proposal.mjs, .../search-shared-drives/search-shared-drives.mjs, .../update-file/update-file.mjs, .../update-shared-drive/update-shared-drive.mjs
Version bumps and import reordering; no functional logic changes.
Action — Upload File functional changes
components/google_drive/actions/upload-file/upload-file.mjs
Uses getFileStreamAndMetadata, sets default multipart upload type, derives filename from source metadata, adds MIME validation (ConfigurationError), and increments version.
Sources — metadata updates
components/google_drive/sources/changes-to-specific-files-shared-drive/*.mjs, .../changes-to-specific-files/*.mjs, .../new-access-proposal/*.mjs, .../new-files-instant/*.mjs, .../new-files-shared-drive/*.mjs, .../new-or-modified-comments/*.mjs, .../new-or-modified-files/*.mjs, .../new-shared-drive/*.mjs, .../new-spreadsheet/*.mjs
Version bumps and minor import organization; no behavior changes.
Source — New or Modified Folders feature
components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs
Adds props folderId and includeSubfolders, introduces getAllParents, updates processChanges with filtering and maxResults, uses changed file for timing and emits, removes fixed pageSize; version to 0.2.0.
Package metadata
components/google_drive/package.json
Package version bumped 1.0.4 → 1.0.5.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Source as New/Modified Folders Source
  participant DriveAPI as Google Drive API
  participant Emitter

  User->>Source: Configure folderId, includeSubfolders
  Source->>DriveAPI: List recent changes
  DriveAPI-->>Source: Changed files/folders
  alt includeSubfolders = true
    Source->>DriveAPI: Traverse parents (getAllParents)
  end
  Source->>Source: Filter changes by folderId/root and type=folder
  Source->>Source: Truncate to maxResults
  Source->>Emitter: Emit event (file, meta from changed file)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Add Parent Folder filter to scope trigger to a specific folder [#18073]
Support monitoring subfolders beneath the specified Parent Folder [#18073]
Adjust trigger to emit only for new/modified folders under the selected scope [#18073]
Limit initial/deploy processing to a small, recent set of results [#18073]

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Functional updates to Upload File action (components/google_drive/actions/upload-file/upload-file.mjs) Not related to subfolder support for the “New or Modified Folders” trigger; modifies upload behavior and validation.

Possibly related PRs

  • Google Drive Access Proposals #16268 — Touches Google Drive access proposal actions; overlaps code surface updated here (list-access-proposals, resolve-access-proposal) with version bumps.

Suggested reviewers

  • jcortes

Poem

A rabbit hopped through folders’ trees,
Now peeking under roots with ease.
Parent picked, subpaths in tow,
Only the right new burrows show.
With uploads tidied, patches thrive—
Carrots versioned, code alive. 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 18073-trigger-new-or-modified-folders-instant---subfolder-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (4)
components/google_drive/actions/search-shared-drives/search-shared-drives.mjs (1)

15-16: Fix typo in user-facing description (“shard” → “shared”)

This appears in the action description and surfaced to users. Please correct.

Apply this diff:

-        "The [shared drives](https://support.google.com/a/users/answer/9310351) search query. See [query terms](https://developers.google.com/drive/api/v3/ref-search-terms#drive_properties) for a list of shard drive-specific query terms.",
+        "The [shared drives](https://support.google.com/a/users/answer/9310351) search query. See [query terms](https://developers.google.com/drive/api/v3/ref-search-terms#drive_properties) for a list of shared drive-specific query terms.",
components/google_drive/actions/list-files/list-files.mjs (1)

86-88: Preserve pagination by always including nextPageToken in fields.

If the user provides custom fields without nextPageToken, subsequent pages won't be fetched, silently truncating results. Ensure nextPageToken is present.

Apply this diff:

-    if (this.fields) {
-      opts.fields = this.fields;
-    }
+    if (this.fields) {
+      const baseFields = this.fields.trim();
+      opts.fields = /\bnextPageToken\b/.test(baseFields)
+        ? baseFields
+        : `nextPageToken, ${baseFields}`;
+    }
components/google_drive/actions/upload-file/upload-file.mjs (2)

91-97: Allow reassignment of mimeType for inferred defaults

To support inferring mimeType from the source (see next comment), we need mimeType to be mutable.

-    const {
-      parentId,
-      filePath,
-      name,
-      mimeType,
-    } = this;
+    let {
+      parentId,
+      filePath,
+      name,
+      mimeType,
+    } = this;

110-112: Avoid introducing a breaking change on MIME type handling

Throwing when metadata.mimeType is set but the mimeType prop is not provided breaks existing workflows that relied on setting conversion via metadata only. Previous behavior allowed conversion using metadata.mimeType alone. Prefer inferring the media mimeType from the source when not explicitly provided.

Replace the error with a safe fallback:

-    if (metadata?.mimeType && !mimeType) {
-      throw new ConfigurationError(`Please include the file's original MIME type in the \`Mime Type\` prop. File will be converted to \`${metadata.mimeType}\`.`);
-    }
+    if (!mimeType && fileMetadata?.mimeType) {
+      mimeType = fileMetadata.mimeType;
+    }

This preserves backward compatibility and still lets users control conversion via metadata.mimeType when desired.

🧹 Nitpick comments (16)
components/google_drive/actions/delete-file/delete-file.mjs (1)

38-38: Close the parenthesis in the summary message.

Cosmetic fix to improve UX of the run summary.

Apply this diff:

-    $.export("$summary", `Successfully deleted file (ID: ${fileId}`);
+    $.export("$summary", `Successfully deleted file (ID: ${fileId})`);
components/google_drive/actions/get-folder-id-for-path/get-folder-id-for-path.mjs (1)

35-43: Normalize the path to avoid empty segments (trailing/duplicate slashes).

Trailing or repeated slashes (e.g., "foo/bar/" or "foo//bar") will produce empty parts and cause an unnecessary lookup for a folder with an empty name. Normalize the path by trimming and filtering falsy segments.

Apply this diff:

-    const parts = this.path.split("/");
+    const parts = this.path
+      .split("/")
+      .map((p) => p.trim())
+      .filter(Boolean);
components/google_drive/actions/list-files/list-files.mjs (1)

74-80: Escape filter text to prevent malformed Drive queries and avoid accidental injection.

Unescaped single quotes or backslashes in filterText can break the q expression and trigger 400s from the Drive API. Escape them before building the query.

Apply this diff:

-    if (this.filterText) {
-      opts.q += `${opts.q
-        ? " AND "
-        : ""}name ${this.filterType === "CONTAINS"
-        ? "contains"
-        : "="} '${this.filterText}'`;
-    }
+    if (this.filterText) {
+      const escaped = String(this.filterText).replace(/(['\\])/g, "\\$1");
+      opts.q += `${opts.q
+        ? " AND "
+        : ""}name ${this.filterType === "CONTAINS"
+        ? "contains"
+        : "="} '${escaped}'`;
+    }
components/google_drive/actions/update-file/update-file.mjs (1)

144-144: Fix $summary to display the file name (not ID) when renaming.

The message currently outputs the file ID when a name is provided, which is confusing. Prefer the file name, optionally including the ID if desired.

Apply this diff:

-    $.export("$summary", `Successfully updated the file, "${name ? resp.id : resp.name}"`);
+    $.export("$summary", `Successfully updated the file, "${resp.name}"`);

Optional alternative (if you want both):

-    $.export("$summary", `Successfully updated the file, "${name ? resp.id : resp.name}"`);
+    $.export("$summary", `Successfully updated the file, "${resp.name}" (ID: ${resp.id})`);
components/google_drive/actions/move-file-to-trash/move-file-to-trash.mjs (1)

12-16: Nit: Alert copy references the wrong action name.

The link points to delete-file but the text says “Move File to Trash”. Suggest aligning the text to “Delete File”.

Apply this diff:

-      content: "If you want to **permanently** delete a file instead, use the **[Move File to Trash](https://pipedream.com/apps/google-drive/actions/delete-file)** action.",
+      content: "If you want to **permanently** delete a file instead, use the **[Delete File](https://pipedream.com/apps/google-drive/actions/delete-file)** action.",
components/google_drive/actions/create-folder/create-folder.mjs (1)

72-81: Escape folder names in Drive query to avoid malformed queries.

Building the query with an unescaped name can break when it contains ' or \ and may cause false negatives.

Apply this diff to escape the name before interpolation:

     if (createIfUnique) {
-      let q = `mimeType = '${GOOGLE_DRIVE_FOLDER_MIME_TYPE}' and name = '${name}' and trashed = false`;
+      const escapedName = String(name ?? "")
+        .replaceAll("\\", "\\\\")
+        .replaceAll("'", "\\'");
+      let q = `mimeType = '${GOOGLE_DRIVE_FOLDER_MIME_TYPE}' and name = '${escapedName}' and trashed = false`;
       if (parentId) {
         q += ` and '${parentId}' in parents`;
       } else if (drive === MY_DRIVE_VALUE) {
         q += " and 'root' in parents";
       } else {
         q += ` and '${driveId}' in parents`;
       }

If preferred, I can extract an escapeDriveQueryValue helper in common utils and replace usages across actions.

components/google_drive/sources/new-or-modified-files/new-or-modified-files.mjs (2)

139-147: Skip per-file parents fetch when no folder filter is set.

Minor optimization: you always fetch parents even when folders filter is empty (watchedFolders.size == 0 path), which isn’t needed.

For example:

// Before
file.parents = (await this.googleDrive.getFile(file.id, { fields: "parents" })).parents;

// After (only when filtering by folders)
if (this.folders?.length) {
  const { parents = [] } = await this.googleDrive.getFile(file.id, { fields: "parents" });
  file.parents = parents;
}

144-148: Remove debug logs or gate them behind a verbosity flag.

Unnecessary console logs can spam user logs for high-volume changes.

-        console.log(file); // see what file was processed
...
-          console.log(`Skipping file ${file.name}`);
components/google_drive/actions/find-folder/find-folder.mjs (1)

52-55: Throw an Error, not a string.

Re-throwing a string loses stack and type. Wrap the API error in an Error to preserve stack trace and structured handling.

-    } catch (error) {
-      console.log("Failed to find folders with query", error.response?.data?.error || error);
-      throw JSON.stringify(error.response?.data?.error, null, 2);
-    }
+    } catch (error) {
+      const details = error?.response?.data?.error || error;
+      console.log("Failed to find folders with query", details);
+      const message = typeof details === "string" ? details : JSON.stringify(details, null, 2);
+      throw new Error(message);
+    }
components/google_drive/actions/move-file/move-file.mjs (2)

28-38: Target folder should be required.

Moving a file without a destination folder likely errors or orphans the file. Consider making folderId required.

     folderId: {
       propDefinition: [
         googleDrive,
         "folderId",
         (c) => ({
           drive: c.drive,
         }),
       ],
       description: "The folder you want to move the file to",
-      optional: true,
+      optional: false,
     },

44-48: Guard against missing parents when removing.

If file.parents is undefined/empty, join(",") can throw or send an empty string. Guard accordingly.

-    const resp = await this.googleDrive.updateFile(this.fileId, {
-      fields: "*",
-      removeParents: file.parents.join(","),
-      addParents: this.folderId,
-    });
+    const removeParents = Array.isArray(file.parents) && file.parents.length
+      ? file.parents.join(",")
+      : undefined;
+    const resp = await this.googleDrive.updateFile(this.fileId, {
+      fields: "*",
+      removeParents,
+      addParents: this.folderId,
+    });
components/google_drive/actions/upload-file/upload-file.mjs (2)

100-105: Ensure a safe filename fallback

filename may be undefined if the source doesn’t provide a name (some URLs/streams). Consider a robust fallback to avoid API errors.

Apply this minimal diff to add a fallback:

-    const filename = name || fileMetadata.name;
+    const filename = name || fileMetadata?.name || `uploaded-file-${Date.now()}`;

If you’d prefer deriving the name from the provided path/URL, add this import and logic outside the selected range:

// at top-level imports
import { basename } from "node:path";
// replace the filename line with:
const filename = name
  || fileMetadata?.name
  || (filePath?.includes("://") ? new URL(filePath).pathname.split("/").pop() : basename(filePath || "")) 
  || `uploaded-file-${Date.now()}`;

120-125: Nit: remove uploadType from metadata-only update

uploadType is only relevant to media uploads. This call updates metadata after media is updated separately, so uploadType can be omitted to avoid confusion.

-      result = await this.googleDrive.updateFile(this.fileId, omitEmptyStringValues({
-        name: filename,
-        mimeType,
-        uploadType,
-        requestBody: metadata,
-      }));
+      result = await this.googleDrive.updateFile(this.fileId, omitEmptyStringValues({
+        name: filename,
+        mimeType,
+        requestBody: metadata,
+      }));
components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs (3)

28-48: Clarify “Parent Folder” semantics and set a safe default for recursion

Two points:

  • The current default of includeSubfolders is false. When no folderId is provided, this effectively limits events to top-level folders only, which likely deviates from the historical behavior (“watch the entire drive”). Consider defaulting to true to preserve prior breadth.
  • Tighten descriptions so users understand how “Parent Folder” and “Include Subfolders” interact.

Also, propDefinition closure relies on c.drive. Please confirm drive is defined on common.props and its value shape is compatible (string literal “My Drive” vs. drive ID).

Apply this diff to improve defaults and clarity:

       label: "Parent Folder",
-      description: "The ID of the parent folder which contains the folders. If not specified, it will watch all folders from the drive's top-level folder.",
+      description: "The ID of the parent folder to scope this source. If not specified, the source watches the entire Drive. Combine with “Include Subfolders” to control recursion.",
       optional: true,
     },
     includeSubfolders: {
       type: "boolean",
       label: "Include Subfolders",
-      description: "Whether to include subfolders of the parent folder in the changes.",
-      optional: true,
+      description: "When enabled, emits events for subfolders nested within the Parent Folder. If no Parent Folder is set, applies to the entire Drive.",
+      optional: true,
+      default: true,
     },

To verify drive is present and its value type, please run the script in the separate verification comment below.


81-98: Memoize or bound parent traversal to reduce API calls

getAllParents walks the chain with one API call per level. For deeply nested structures and bursts of changes, this can be chatty. Consider:

  • Caching ancestor results per folder ID within a single processChanges invocation.
  • Adding a sanity bound (e.g., max depth 50) to prevent pathological loops.

I can provide a lightweight memoization pattern scoped to processChanges if you want it baked in now.


157-160: Avoid post-loop array truncation; you’re already short-circuiting

Given the early break when maxResults is reached, post-loop truncation becomes redundant. If you’d rather keep the truncation pattern, remove the early break in favor of the existing slice/truncate; don’t do both.

Apply this diff if you keep the early break:

-      if (maxResults && filteredFiles.length >= maxResults) {
-        filteredFiles.length = maxResults;
-      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 84fa60f and 007543c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (36)
  • components/google_drive/actions/add-file-sharing-preference/add-file-sharing-preference.mjs (1 hunks)
  • components/google_drive/actions/copy-file/copy-file.mjs (1 hunks)
  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1 hunks)
  • components/google_drive/actions/create-file-from-text/create-file-from-text.mjs (1 hunks)
  • components/google_drive/actions/create-folder/create-folder.mjs (1 hunks)
  • components/google_drive/actions/create-shared-drive/create-shared-drive.mjs (1 hunks)
  • components/google_drive/actions/delete-file/delete-file.mjs (1 hunks)
  • components/google_drive/actions/delete-shared-drive/delete-shared-drive.mjs (1 hunks)
  • components/google_drive/actions/download-file/download-file.mjs (2 hunks)
  • components/google_drive/actions/find-file/find-file.mjs (1 hunks)
  • components/google_drive/actions/find-folder/find-folder.mjs (1 hunks)
  • components/google_drive/actions/find-forms/find-forms.mjs (1 hunks)
  • components/google_drive/actions/find-spreadsheets/find-spreadsheets.mjs (1 hunks)
  • components/google_drive/actions/get-file-by-id/get-file-by-id.mjs (1 hunks)
  • components/google_drive/actions/get-folder-id-for-path/get-folder-id-for-path.mjs (1 hunks)
  • components/google_drive/actions/get-shared-drive/get-shared-drive.mjs (1 hunks)
  • components/google_drive/actions/list-access-proposals/list-access-proposals.mjs (1 hunks)
  • components/google_drive/actions/list-files/list-files.mjs (1 hunks)
  • components/google_drive/actions/move-file-to-trash/move-file-to-trash.mjs (1 hunks)
  • components/google_drive/actions/move-file/move-file.mjs (1 hunks)
  • components/google_drive/actions/resolve-access-proposal/resolve-access-proposal.mjs (1 hunks)
  • components/google_drive/actions/search-shared-drives/search-shared-drives.mjs (1 hunks)
  • components/google_drive/actions/update-file/update-file.mjs (1 hunks)
  • components/google_drive/actions/update-shared-drive/update-shared-drive.mjs (1 hunks)
  • components/google_drive/actions/upload-file/upload-file.mjs (1 hunks)
  • components/google_drive/package.json (1 hunks)
  • components/google_drive/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs (2 hunks)
  • components/google_drive/sources/changes-to-specific-files/changes-to-specific-files.mjs (2 hunks)
  • components/google_drive/sources/new-access-proposal/new-access-proposal.mjs (1 hunks)
  • components/google_drive/sources/new-files-instant/new-files-instant.mjs (1 hunks)
  • components/google_drive/sources/new-files-shared-drive/new-files-shared-drive.mjs (1 hunks)
  • components/google_drive/sources/new-or-modified-comments/new-or-modified-comments.mjs (1 hunks)
  • components/google_drive/sources/new-or-modified-files/new-or-modified-files.mjs (2 hunks)
  • components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs (4 hunks)
  • components/google_drive/sources/new-shared-drive/new-shared-drive.mjs (1 hunks)
  • components/google_drive/sources/new-spreadsheet/new-spreadsheet.mjs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs (2)
components/google_drive/sources/new-or-modified-files/new-or-modified-files.mjs (5)
  • common (20-20)
  • filteredFiles (137-137)
  • changes (135-135)
  • eventToEmit (151-154)
  • meta (155-155)
components/google_drive/sources/new-or-modified-comments/new-or-modified-comments.mjs (3)
  • changes (106-106)
  • eventToEmit (125-128)
  • meta (129-129)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (54)
components/google_drive/package.json (2)

3-3: Version bump looks good.

Metadata-only update; no dependency changes. Safe to publish.


3-3: New or Modified Folders (Instant): Props and Logic Verified
All required changes are present in components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs:

  • Version bumped to 0.2.0 (line 23)
  • Parent folder selector (folderId) and Include Subfolders option defined (lines 30–47)
  • processChanges filters results by the selected parent (lines 144–152)
  • Descriptions for Parent Folder and Include Subfolders updated to reflect behavior (lines 37–46)

Please confirm that the call to this.getListFilesOpts(...) in run correctly includes the drive and includeItemsFromAllDrives (or equivalent) flags so shared-drive items are scoped properly.

components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)

11-11: Patch version bump approved.

No functional changes; safe to release.

components/google_drive/actions/get-file-by-id/get-file-by-id.mjs (1)

8-8: Patch version bump approved.

Runtime behavior unchanged.

components/google_drive/actions/delete-file/delete-file.mjs (1)

8-8: Patch version bump approved.

No logic changes; OK to publish.

components/google_drive/actions/get-shared-drive/get-shared-drive.mjs (1)

7-7: Patch version bump approved.

No behavior changes detected.

components/google_drive/actions/list-access-proposals/list-access-proposals.mjs (1)

7-7: Version bump looks good

Patch version increment only; no behavioral changes in this file. Safe to ship.

components/google_drive/actions/delete-shared-drive/delete-shared-drive.mjs (1)

7-7: Patch version update acknowledged

No logic changes; version bump aligns with PR’s patch-level updates across actions.

components/google_drive/actions/search-shared-drives/search-shared-drives.mjs (1)

7-7: Patch version bump approved

No runtime or API changes in this action; version metadata updated only.

components/google_drive/actions/add-file-sharing-preference/add-file-sharing-preference.mjs (1)

23-23: Version bump only; no functional changes

Looks consistent with the rest of the PR’s patch updates.

components/google_drive/actions/copy-file/copy-file.mjs (1)

7-7: Version increment acknowledged

Metadata-only change; behavior unchanged.

components/google_drive/actions/get-folder-id-for-path/get-folder-id-for-path.mjs (1)

15-15: Patch version bump only — LGTM

No functional changes; version bump is consistent with the broader patch release.

components/google_drive/actions/list-files/list-files.mjs (1)

2-2: Import reorder and patch version bump — LGTM

No runtime impact from import order; version bump aligns with related actions in this PR.

Also applies to: 8-8

components/google_drive/actions/create-file-from-text/create-file-from-text.mjs (1)

8-8: Patch version bump only — LGTM

No functional changes in this action. Implementation remains consistent.

components/google_drive/actions/update-file/update-file.mjs (1)

2-3: Import ordering and patch version bump — LGTM

Reordered imports are fine; version bump aligns with other actions.

Also applies to: 9-9

components/google_drive/actions/update-shared-drive/update-shared-drive.mjs (1)

7-7: Patch version bump only — LGTM

No functional changes; consistent with the broader patch release.

components/google_drive/actions/create-shared-drive/create-shared-drive.mjs (1)

7-7: Version bump only — LGTM

No functional changes. Patch version increment is appropriate.

components/google_drive/sources/new-or-modified-comments/new-or-modified-comments.mjs (2)

12-12: Import reorder — LGTM

Reordering imports has no runtime effect here and aligns with common style.


20-20: Patch version bump — LGTM

No behavioral changes in this source; version bump is appropriate.

components/google_drive/sources/new-access-proposal/new-access-proposal.mjs (2)

2-2: Import order change — LGTM

Moving the app import under the platform constant is harmless and consistent with the PR’s import tidy-ups.


9-9: Patch version bump — LGTM

No functional changes; version bump looks good.

components/google_drive/actions/download-file/download-file.mjs (2)

6-7: Import ordering — LGTM

Reordered imports are fine and do not affect behavior.


21-21: Patch version bump — LGTM

No runtime changes; version increment is appropriate.

components/google_drive/actions/find-forms/find-forms.mjs (2)

2-3: Import order adjustment — LGTM

Bringing getListFilesOpts up is fine and keeps usage close to its import.


9-9: Subfolder filtering in new-or-modified-folders.mjs verified

The PR’s main enhancement—support for subfolder filtering—has landed as intended:

  • New props present:
    • folderId (ln 30)
    • includeSubfolders (ln 42)
    • maxResults (ln 127)
  • Helper methods implemented:
    • getAllParents (ln 81)
    • processChanges (ln 127)
  • Filtering logic correctly checks parents:
    • Uses getAllParents when includeSubfolders is true (ln 144–152)
  • Source version updated to “0.2.0” (ln 23)

Patch version bump is fine.

components/google_drive/actions/move-file-to-trash/move-file-to-trash.mjs (1)

2-2: Patch-only changes look good (import order + version bump).

No runtime behavior change introduced. Safe to merge.

Also applies to: 8-8

components/google_drive/sources/new-shared-drive/new-shared-drive.mjs (1)

2-2: LGTM on import reorder and version bump.

No functional changes; deploy/run logic remains intact.

Also applies to: 8-8

components/google_drive/actions/create-folder/create-folder.mjs (1)

5-5: Minor metadata tweaks approved.

Import reordering and version bump are fine.

Also applies to: 9-10, 16-16

components/google_drive/actions/find-file/find-file.mjs (1)

2-3: Approved: import order adjustment and patch version bump.

No runtime semantics changed.

Also applies to: 9-9

components/google_drive/sources/new-spreadsheet/new-spreadsheet.mjs (1)

9-9: Version bump approved.

No logic changes; behavior unchanged.

components/google_drive/sources/new-or-modified-files/new-or-modified-files.mjs (3)

17-18: Re-introduced imports look correct and necessary.

Bringing back common and sampleEmit resolves downstream references (e.g., common.props and sampleEmit export). No behavioral concerns.


27-27: Version bump to 0.3.8 is fine.

Patch-level increment aligns with non-functional import adjustments. No further action needed.


22-28: New or Modified Folders (Instant) already includes correct folder filtering and descendant support.

  • The folderId prop is defined for parent‐folder filtering.
  • The optional includeSubfolders boolean is present.
  • In processChanges, when includeSubfolders is true, it calls getAllParents(file.id) to collect the entire ancestor chain and matches against folderId (or root.id), ensuring true descendant filtering rather than just direct parents.

No further action needed here.

components/google_drive/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs (2)

15-17: Import reordering is a no-op at runtime.

No behavior change. Safe patch.


30-30: Version bump to 0.2.8 is appropriate.

Consistent with sibling source bump.

components/google_drive/actions/find-folder/find-folder.mjs (2)

10-10: Version bump to 0.1.11 is fine.

Patch-level change aligns with import/source adjustments in this PR.


42-45: getListFilesOpts import and signature confirmed
The getListFilesOpts function is exported as a named export in components/google_drive/common/utils.mjs and its signature—function getListFilesOpts(drive, baseOpts = {})—matches how it’s called in find-folder.mjs. No changes needed.

components/google_drive/actions/move-file/move-file.mjs (1)

7-7: Version bump to 0.1.11 is fine.

No functional change in this action.

components/google_drive/sources/changes-to-specific-files/changes-to-specific-files.mjs (2)

6-6: Import reordering is benign.

No runtime impact. Ok to proceed.


19-19: Version bump to 0.2.8 is appropriate.

Consistent with shared-drive variant.

components/google_drive/sources/new-files-shared-drive/new-files-shared-drive.mjs (2)

1-1: Import placement cleanup looks good

Moving the DEFAULT_POLLING_SOURCE_TIMER_INTERVAL import to the top resolves duplication and aligns with common import-order conventions.


10-10: Patch version bump acknowledged

Version updated to 0.0.5 with no behavioral changes in this file. All good.

components/google_drive/sources/new-files-instant/new-files-instant.mjs (2)

5-6: Import reordering is fine

Reordering imports for common-webhook and test-event has no runtime effect and improves consistency.


13-13: Patch version bump acknowledged

Version updated to 0.1.16; no functional changes here.

components/google_drive/actions/find-spreadsheets/find-spreadsheets.mjs (2)

2-3: Import order tweak is safe

Switching the order of getListFilesOpts and googleDrive imports has no behavioral impact.


9-9: Patch version bump acknowledged

Version updated to 0.1.11; the run logic remains unchanged.

components/google_drive/actions/resolve-access-proposal/resolve-access-proposal.mjs (2)

2-2: Import order cleanup is fine

Moving googleDrive import after ConfigurationError is consistent with the rest of the codebase; no runtime change.


8-8: Patch version bump acknowledged

Version updated to 0.0.4; no API changes in this action.

components/google_drive/actions/upload-file/upload-file.mjs (2)

1-5: Good refactor: centralized helpers and constants

Using getFileStreamAndMetadata and the shared upload type constant simplifies file handling, supports both URLs and local files, and reduces duplication.


16-16: Patch version bump acknowledged

Version updated to 2.0.4. See note below regarding a potential breaking change introduced in this file.

components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs (4)

16-16: LGTM: import path/use of common-webhook

Importing common from ../common-webhook.mjs aligns with how other Drive sources wire props and hooks. No issues spotted.


23-23: Confirm version bump vs. behavior change

Default behavior appears to change when no Parent Folder is set (see filtering logic). If that’s intentional and potentially breaking for existing users, verify that 0.2.0 is the correct semver bump and consider documenting the change in the component’s changelog/description.

Would you like me to draft a concise changelog entry?


160-176: Ensure modifiedTime is always present; otherwise events will re-emit

You now rely on file.modifiedTime from the fetched file. If getFile doesn’t include it by default, Date.parse(undefined) yields NaN, and the equality check will never match, causing repeated emissions. The earlier diff forces modifiedTime into the selected fields, which addresses this.


139-151: Drive root resolution verified

The drive prop is defined via the googleDrive.watchedDrive dropdown, which returns either the literal "My Drive" or a shared-drive ID string. In the Drive API, a shared-drive’s ID is the same as its root‐folder ID, and our getFile(id) wrapper automatically sets supportsAllDrives. Therefore, passing "root" for My Drive or the shared-drive ID correctly retrieves the root folder—no changes needed here.

Comment on lines +127 to +156
async processChanges(changedFiles, headers, maxResults) {
const files = changedFiles.filter(
// API docs that define Google Drive folders:
// https://developers.google.com/drive/api/v3/folder
(file) => file.mimeType === "application/vnd.google-apps.folder",
);

const filteredFiles = [];
for (const file of files) {
// The changelog is updated each time a folder is opened. Check the
// folder's `modifiedTime` to see if the folder has been modified.
const fileInfo = await this.googleDrive.getFile(file.id);
const root = await this.googleDrive.getFile(this.drive === "My Drive"
? "root"
: this.drive);

const allParents = [];
if (this.includeSubfolders) {
allParents.push(...(await this.getAllParents(file.id)));
} else {
allParents.push(fileInfo.parents[0]);
}

if (!allParents.includes(this.folderId || root.id)) {
continue;
}

filteredFiles.push(fileInfo);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potentially drops all webhook-driven events: relying on changedFiles.mimeType before fetching file metadata

Webhooks often only provide IDs, not mimeType. Filtering folders prior to fetching metadata can make files empty, preventing any event emission. Also, root is fetched inside the loop, causing unnecessary repeated calls, and getFile doesn’t request explicit fields (risking modifiedTime being absent).

Refactor to:

  • Fetch fileInfo first (with explicit fields), then filter by mimeType.
  • Resolve the Drive root once, outside the loop.
  • Stop early when maxResults is reached.

Apply this diff:

-    async processChanges(changedFiles, headers, maxResults) {
-      const files = changedFiles.filter(
-        // API docs that define Google Drive folders:
-        // https://developers.google.com/drive/api/v3/folder
-        (file) => file.mimeType === "application/vnd.google-apps.folder",
-      );
-
-      const filteredFiles = [];
-      for (const file of files) {
+    async processChanges(changedFiles, headers, maxResults) {
+      // Resolve the Drive root once to avoid redundant requests inside the loop
+      const root = await this.googleDrive.getFile(
+        this.drive === "My Drive" ? "root" : this.drive,
+        { fields: "id" },
+      );
+      const filteredFiles = [];
+      for (const changed of changedFiles) {
         // The changelog is updated each time a folder is opened. Check the
         // folder's `modifiedTime` to see if the folder has been modified.
-        const fileInfo = await this.googleDrive.getFile(file.id);
-        const root = await this.googleDrive.getFile(this.drive === "My Drive"
-          ? "root"
-          : this.drive);
+        const fileInfo = await this.googleDrive.getFile(changed.id, {
+          fields: "id, name, mimeType, modifiedTime, parents",
+        });
+        // Filter to folders only, regardless of the shape of `changedFiles`
+        if (fileInfo.mimeType !== "application/vnd.google-apps.folder") {
+          continue;
+        }
 
-        const allParents = [];
-        if (this.includeSubfolders) {
-          allParents.push(...(await this.getAllParents(file.id)));
-        } else {
-          allParents.push(fileInfo.parents[0]);
-        }
+        const allParents = [];
+        if (this.includeSubfolders) {
+          allParents.push(...(await this.getAllParents(fileInfo.id)));
+        } else {
+          allParents.push(fileInfo.parents?.[0]);
+        }
 
-        if (!allParents.includes(this.folderId || root.id)) {
-          continue;
-        }
+        if (!allParents.includes(this.folderId || root.id)) {
+          continue;
+        }
 
-        filteredFiles.push(fileInfo);
-      }
+        filteredFiles.push(fileInfo);
+        if (maxResults && filteredFiles.length >= maxResults) {
+          break;
+        }
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async processChanges(changedFiles, headers, maxResults) {
const files = changedFiles.filter(
// API docs that define Google Drive folders:
// https://developers.google.com/drive/api/v3/folder
(file) => file.mimeType === "application/vnd.google-apps.folder",
);
const filteredFiles = [];
for (const file of files) {
// The changelog is updated each time a folder is opened. Check the
// folder's `modifiedTime` to see if the folder has been modified.
const fileInfo = await this.googleDrive.getFile(file.id);
const root = await this.googleDrive.getFile(this.drive === "My Drive"
? "root"
: this.drive);
const allParents = [];
if (this.includeSubfolders) {
allParents.push(...(await this.getAllParents(file.id)));
} else {
allParents.push(fileInfo.parents[0]);
}
if (!allParents.includes(this.folderId || root.id)) {
continue;
}
filteredFiles.push(fileInfo);
}
async processChanges(changedFiles, headers, maxResults) {
// Resolve the Drive root once to avoid redundant requests inside the loop
const root = await this.googleDrive.getFile(
this.drive === "My Drive" ? "root" : this.drive,
{ fields: "id" },
);
const filteredFiles = [];
for (const changed of changedFiles) {
// The changelog is updated each time a folder is opened. Check the
// folder's `modifiedTime` to see if the folder has been modified.
const fileInfo = await this.googleDrive.getFile(changed.id, {
fields: "id, name, mimeType, modifiedTime, parents",
});
// Filter to folders only, regardless of the shape of `changedFiles`
if (fileInfo.mimeType !== "application/vnd.google-apps.folder") {
continue;
}
const allParents = [];
if (this.includeSubfolders) {
allParents.push(...(await this.getAllParents(fileInfo.id)));
} else {
allParents.push(fileInfo.parents?.[0]);
}
if (!allParents.includes(this.folderId || root.id)) {
continue;
}
filteredFiles.push(fileInfo);
if (maxResults && filteredFiles.length >= maxResults) {
break;
}
}
// …rest of method…
}
🤖 Prompt for AI Agents
In
components/google_drive/sources/new-or-modified-folders/new-or-modified-folders.mjs
around lines 127 to 156, the current code filters by file.mimeType before
fetching metadata which can drop webhook-only events, fetches root inside the
loop, and never respects maxResults; change the loop to first call
this.googleDrive.getFile(file.id) requesting explicit fields (id, mimeType,
parents, modifiedTime), then skip non-folder mimeTypes, resolve the Drive root
once before the loop (root = await this.googleDrive.getFile(this.drive === "My
Drive" ? "root" : this.drive)), ensure fileInfo.parents is handled safely
(fallback if missing), push parents via includeSubfolders logic, stop processing
and break the loop when filteredFiles.length reaches maxResults, and push
fileInfo into filteredFiles only after these checks.

Copy link
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@vunguyenhung vunguyenhung merged commit 700d827 into master Aug 19, 2025
11 checks passed
@vunguyenhung vunguyenhung deleted the 18073-trigger-new-or-modified-folders-instant---subfolder-support branch August 19, 2025 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[TRIGGER] New or Modified Folders (Instant) - Subfolder Support
3 participants