-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Dropbox - new shared link components #18393
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
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughAdds shared-link functionality to the Dropbox component: new actions to list shared links, get shared link metadata, and fetch a file via a shared link; updates create/update share link to accept an audience for non-basic accounts; adds sharedLinkUrl and linkPassword propDefinitions and SDK wrapper methods; adjusts audience options and bumps multiple versions. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Action as Create/Update Share Link Action
participant App as Dropbox App
participant API as Dropbox API
User->>Action: Provide path (+ audience if non-basic)
Action->>App: createSharedLink(path, settings{audience?})
App->>API: sharing/list_shared_links (path)
API-->>App: existing links (links, cursor?)
App->>App: find link with path_lower match
alt Link exists
App->>API: sharing/create_shared_link_with_settings (update or reuse)
API-->>App: link
else No link
App->>API: sharing/create_shared_link_with_settings(settings)
API-->>App: link
end
App-->>Action: link
Action-->>User: Shared link URL
sequenceDiagram
autonumber
actor User
participant List as List Shared Links Action
participant Meta as Get Shared Link Metadata Action
participant File as Get Shared Link File Action
participant App as Dropbox App
participant API as Dropbox API
User->>List: Optional path
List->>App: listSharedLinks(args)
loop Paginate while has_more
App->>API: sharing/list_shared_links(args or cursor)
API-->>App: links, has_more, cursor
end
App-->>List: all links
List-->>User: array of links
User->>Meta: sharedLinkUrl (+ password?)
Meta->>App: getSharedLinkMetadata({url, link_password})
App->>API: sharing/get_shared_link_metadata
API-->>App: metadata
App-->>Meta: metadata
Meta-->>User: metadata
User->>File: sharedLinkUrl (+ password?)
File->>App: getSharedLinkFile({url, link_password})
App->>API: sharing/get_shared_link_file
API-->>App: file content
App-->>File: file content
File-->>User: file content
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
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. Comment |
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
components/dropbox/actions/download-file-to-tmp/download-file-to-tmp.mjs (1)
54-55
: Fix invalid regex in filename sanitizer (runtime syntax error).Character class includes unescaped
[]
, which prematurely closes the class and can throw. Use an allowlist or properly escape brackets.Apply:
- const cleanFileName = fileName.replace(/[?$#&{}[]<>\*!@:\+\\\/]/g, ""); + // Remove characters unsafe for filenames across platforms + const cleanFileName = fileName.replace(/[^a-zA-Z0-9._ -]/g, ""); + // If you prefer the denylist style: + // fileName.replace(/[?$#&{}\[\]<>*!@:+\\\/]/g, "")components/dropbox/actions/search-files-folders/search-files-folders.mjs (1)
89-93
: Fix inverted condition for include_highlights.Currently sets options when value is undefined and omits when defined.
- match_field_options: !isNil(includeHighlights) - ? undefined - : { - include_highlights: includeHighlights, - }, + match_field_options: isNil(includeHighlights) + ? undefined + : { + include_highlights: includeHighlights, + },components/dropbox/dropbox.app.mjs (1)
398-407
: Bug: isEmpty() mis-handles booleans; remove_expiration can never be true.isEmpty(true|false) returns true, forcing remove_expiration to false even when set to true.
Apply:
- remove_expiration: isEmpty(args.remove_expiration) - ? false - : args.remove_expiration, + remove_expiration: isNil(args.remove_expiration) + ? false + : args.remove_expiration,
🧹 Nitpick comments (16)
components/dropbox/actions/upload-file/upload-file.mjs (3)
33-38
: Fix copy: “folder” → “file” in Autorename description.This action uploads a file.
Apply:
- description: "If there's a conflict, have Dropbox try to autorename the folder to avoid the conflict.", + description: "If there's a conflict, have Dropbox try to autorename the file to avoid the conflict.",
65-75
: Remove unused clientModified field (not exposed as a prop).It’s always undefined; drop it to avoid confusion.
Apply:
- const { - filePath, - path, - name, - autorename, - mute, - strictConflict, - mode, - clientModified, - } = this; + const { + filePath, + path, + name, + autorename, + mute, + strictConflict, + mode, + } = this;- client_modified: clientModified,
Also applies to: 90-90
94-94
: Improve summary when path is empty.Show a friendly fallback for root uploads.
Apply:
- $.export("$summary", `File successfully uploaded to "${path?.label || path}"`); + $.export("$summary", `File successfully uploaded to "${path?.label || path || "root folder"}"`);components/dropbox/actions/move-file-folder/move-file-folder.mjs (1)
58-71
: Normalize destination path and avoid possible double slashes; minor naming tidy.Use
getNormalizedPath(..., true)
and buildto_path
once.Apply:
- let normalizedPathTo = this.dropbox.getPath(pathTo); + const normalizedPathTo = this.dropbox.getNormalizedPath(pathTo, true); const normalizedPathFrom = this.dropbox.getPath(pathFrom); - // Add file/folder name to end of pathTo - const splited = normalizedPathFrom.split("/"); - const fileName = splited[splited.length - 1]; - normalizedPathTo += `/${fileName}`; + // Add file/folder name to end of pathTo + const parts = normalizedPathFrom.split("/"); + const fileName = parts[parts.length - 1]; + const toPath = `${normalizedPathTo}${fileName}`; const res = await this.dropbox.filesMove({ from_path: normalizedPathFrom, - to_path: normalizedPathTo, + to_path: toPath, autorename, allow_ownership_transfer: allowOwnershipTransfer, });Please test moving into root to confirm no leading “//”.
components/dropbox/actions/create-folder/create-folder.mjs (1)
41-46
: Optional: guard against invalid folder names.Consider rejecting names containing “/” to prevent unintended nested paths.
Would you like a small validation patch here?
components/dropbox/actions/upload-multiple-files/upload-multiple-files.mjs (1)
28-28
: Fix grammar in filesPaths description.Apply:
- description: "Provide an array of either file URLs or paths to a files in the /tmp directory (for example, /tmp/myFile.pdf).", + description: "Provide an array of either file URLs or paths to files in the /tmp directory (for example, /tmp/myFile.pdf).",components/dropbox/package.json (1)
1-27
: Declare Node engine and prune redundant deps (stream, util)
- Add "engines": { "node": ">=16" } — got@^13 requires a modern Node runtime.
- Remove "stream" and "util" from components/dropbox/package.json — code imports Node core modules (e.g., components/dropbox/actions/download-file-to-tmp/download-file-to-tmp.mjs); confirm your build/tooling doesn't require npm polyfills before removing.
components/dropbox/actions/download-file-to-tmp/download-file-to-tmp.mjs (2)
43-43
: Avoid logging the temporary download link.Leaking signed URLs in logs is a security/privacy risk.
- console.log("linkResponse: ", linkResponse); + // Consider: $.export("$debug", { hasLink: !!linkResponse?.result?.link });
59-62
: Add timeouts to the download stream.Network hangs will stall the action; set conservative timeouts/retries.
- await pipeline( - got.stream(link), - fs.createWriteStream(tmpPath), - ); + await pipeline( + got.stream(link, { timeout: { request: 15000 }, retry: { limit: 2 } }), + fs.createWriteStream(tmpPath), + );components/dropbox/actions/rename-file-folder/rename-file-folder.mjs (1)
53-55
: Nit: rename variable for clarity.
splitedPath
→splitPath
.- const splitedPath = normalizedPathFrom.split("/"); - splitedPath[splitedPath.length - 1] = newName; + const splitPath = normalizedPathFrom.split("/"); + splitPath[splitPath.length - 1] = newName; const res = await this.dropbox.filesMove({ from_path: normalizedPathFrom, - to_path: splitedPath.join("/"), + to_path: splitPath.join("/"),components/dropbox/actions/create-update-share-link/create-update-share-link.mjs (2)
110-119
: Avoid sending undefined fields in settings.Passing undefined keys can cause brittle request bodies. Build settings conditionally.
Apply:
- const res = await this.dropbox.createSharedLink({ - path: this.dropbox.getPath(path), - settings: { - require_password: requirePassword, - link_password: linkPassword, - expires, - access, - allow_download: allowDownload, - audience, - }, - }); + const settings = { + ...(requirePassword !== undefined && { require_password: requirePassword }), + ...(linkPassword && { link_password: linkPassword }), + ...(expires && { expires }), + ...(access && { access }), + ...(allowDownload !== undefined && { allow_download: allowDownload }), + ...(audience && { audience }), + }; + const res = await this.dropbox.createSharedLink({ + path: this.dropbox.getPath(path), + settings, + });
106-108
: Validate timestamp format, not just chronology.Date.parse returns NaN for invalid strings; the current check lets invalid values through.
Apply:
- if (expires && Date.parse(expires) < Date.now()) { + if (expires) { + const t = Date.parse(expires); + if (Number.isNaN(t)) throw new Error("Invalid expires timestamp. Use ISO 8601, e.g. 2024-07-18T20:00:00Z"); + if (t < Date.now()) throw new Error("Expire date must be later than the current datetime"); + }components/dropbox/dropbox.app.mjs (2)
99-124
: Pagination for sharedLinkUrl options: honor has_more and guard empty links.Without checking has_more, UI may keep requesting pages. Also guard against falsy links.
Apply:
- async options({ prevContext }) { + async options({ prevContext }) { const { - result: { - links, cursor, - }, + result: { + links = [], cursor, has_more, + }, } = await this.listSharedLinks({ cursor: prevContext?.cursor, }); - const options = links?.map(({ + const options = links.map(({ url: value, name: label, }) => ({ value, label: `${label} - ${value}`, })) || []; return { options, context: { - cursor, + cursor: has_more ? cursor : null, }, }; },
392-413
: Optional: request direct-only links to avoid unrelated matches.Filtering with direct_only reduces noise if multiple links exist under the same path subtree.
Apply:
- const links = await dpx.sharingListSharedLinks({ - path: args.path, - }); + const links = await dpx.sharingListSharedLinks({ + path: args.path, + direct_only: true, + });components/dropbox/actions/list-shared-links/list-shared-links.mjs (2)
31-33
: Avoid passing undefined path in args.Only include path when provided to keep request bodies clean.
Apply:
- const args = { - path: this.path?.value || this.path, - }; + const args = {}; + if (this.path) args.path = this.path?.value || this.path;
34-43
: Guard against falsy links when spreading.Spreading undefined throws; be defensive.
Apply:
- sharedLinks.push(...links); + sharedLinks.push(...(links || []));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
components/dropbox/actions/create-a-text-file/create-a-text-file.mjs
(1 hunks)components/dropbox/actions/create-folder/create-folder.mjs
(1 hunks)components/dropbox/actions/create-or-append-to-a-text-file/create-or-append-to-a-text-file.mjs
(1 hunks)components/dropbox/actions/create-update-share-link/create-update-share-link.mjs
(4 hunks)components/dropbox/actions/delete-file-folder/delete-file-folder.mjs
(1 hunks)components/dropbox/actions/download-file-to-tmp/download-file-to-tmp.mjs
(1 hunks)components/dropbox/actions/get-shared-link-file/get-shared-link-file.mjs
(1 hunks)components/dropbox/actions/get-shared-link-metadata/get-shared-link-metadata.mjs
(1 hunks)components/dropbox/actions/list-file-folders-in-a-folder/list-file-folders-in-a-folder.mjs
(1 hunks)components/dropbox/actions/list-file-revisions/list-file-revisions.mjs
(1 hunks)components/dropbox/actions/list-shared-links/list-shared-links.mjs
(1 hunks)components/dropbox/actions/move-file-folder/move-file-folder.mjs
(1 hunks)components/dropbox/actions/rename-file-folder/rename-file-folder.mjs
(1 hunks)components/dropbox/actions/restore-a-file/restore-a-file.mjs
(1 hunks)components/dropbox/actions/search-files-folders/search-files-folders.mjs
(1 hunks)components/dropbox/actions/upload-file/upload-file.mjs
(1 hunks)components/dropbox/actions/upload-multiple-files/upload-multiple-files.mjs
(1 hunks)components/dropbox/common/consts.mjs
(0 hunks)components/dropbox/dropbox.app.mjs
(3 hunks)components/dropbox/package.json
(1 hunks)components/dropbox/sources/all-updates/all-updates.mjs
(1 hunks)components/dropbox/sources/new-file/new-file.mjs
(1 hunks)components/dropbox/sources/new-folder/new-folder.mjs
(1 hunks)
💤 Files with no reviewable changes (1)
- components/dropbox/common/consts.mjs
🧰 Additional context used
🧬 Code graph analysis (3)
components/dropbox/actions/list-shared-links/list-shared-links.mjs (1)
components/dropbox/dropbox.app.mjs (6)
args
(346-351)args
(480-488)links
(395-397)cursor
(288-297)cursor
(344-344)cursor
(478-478)
components/dropbox/dropbox.app.mjs (2)
components/dropbox/actions/list-shared-links/list-shared-links.mjs (2)
args
(30-32)args
(35-39)components/dropbox/actions/create-update-share-link/create-update-share-link.mjs (1)
dpx
(82-82)
components/dropbox/actions/get-shared-link-file/get-shared-link-file.mjs (1)
components/dropbox/actions/upload-multiple-files/upload-multiple-files.mjs (1)
dropbox
(99-110)
⏰ 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). (3)
- GitHub Check: Lint Code Base
- GitHub Check: Publish TypeScript components
- GitHub Check: Verify TypeScript components
🔇 Additional comments (20)
components/dropbox/package.json (1)
3-3
: Version bump LGTM.Minor release aligns with new shared link features.
components/dropbox/actions/restore-a-file/restore-a-file.mjs (1)
7-7
: Version bump LGTM.components/dropbox/sources/new-folder/new-folder.mjs (1)
10-10
: Version bump LGTM.components/dropbox/actions/upload-file/upload-file.mjs (1)
9-9
: Version bump LGTM.components/dropbox/actions/move-file-folder/move-file-folder.mjs (1)
7-7
: Version bump LGTM.components/dropbox/actions/create-folder/create-folder.mjs (1)
7-7
: Version bump LGTM.components/dropbox/sources/new-file/new-file.mjs (1)
10-10
: Version bump LGTM.components/dropbox/actions/upload-multiple-files/upload-multiple-files.mjs (1)
11-11
: Version bump LGTM.components/dropbox/actions/download-file-to-tmp/download-file-to-tmp.mjs (1)
12-12
: Version bump LGTM.components/dropbox/actions/search-files-folders/search-files-folders.mjs (1)
9-9
: Version bump LGTM.components/dropbox/actions/list-file-revisions/list-file-revisions.mjs (1)
8-8
: Version bump LGTM.components/dropbox/actions/create-a-text-file/create-a-text-file.mjs (1)
7-7
: Version bump LGTM.components/dropbox/actions/create-or-append-to-a-text-file/create-or-append-to-a-text-file.mjs (1)
7-7
: Version bump LGTM.components/dropbox/actions/rename-file-folder/rename-file-folder.mjs (1)
7-7
: Version bump LGTM.components/dropbox/actions/delete-file-folder/delete-file-folder.mjs (1)
7-7
: Version bump LGTM.components/dropbox/sources/all-updates/all-updates.mjs (1)
10-10
: Version bump LGTM — verification passed.New shared-link actions present (components/dropbox/actions/list-shared-links/, get-shared-link-metadata/, get-shared-link-file/); app methods/props added (listSharedLinks, getSharedLinkMetadata, getSharedLinkFile, sharedLinkUrl, linkPassword); CREATE_SHARED_LINK_AUDIENCE_OPTIONS present and plumbed through create-update-share-link; components/dropbox/package.json version = 1.1.0.
components/dropbox/actions/list-file-folders-in-a-folder/list-file-folders-in-a-folder.mjs (1)
7-7
: Version bump only — LGTM.No functional changes. Safe to merge.
components/dropbox/dropbox.app.mjs (1)
418-441
: New wrappers look good.Thin pass-throughs with centralized error normalization keep the surface consistent.
components/dropbox/actions/get-shared-link-metadata/get-shared-link-metadata.mjs (1)
25-31
: LGTM — correct arg names and summary.Consistent with Dropbox API; pairs with sharedLinkUrl/linkPassword props.
components/dropbox/actions/create-update-share-link/create-update-share-link.mjs (1)
69-75
: Audience prop: verified — values match Dropbox LinkAudience.
consts.CREATE_SHARED_LINK_AUDIENCE_OPTIONS (components/dropbox/common/consts.mjs) contains "public", "team", "no_one"; no changes required.
components/dropbox/actions/get-shared-link-file/get-shared-link-file.mjs
Show resolved
Hide resolved
* new components * remove console.log * versions * update
* Leonardo AI components * added unzoom image action * fixing link errors * more lint fixes * Merging pull request #18359 * fix: pagination prop and params struct * fix: no need for paginate here * chore: update version * chore: cleanup * chore: update package * feat: allow raw response * chore: bump package * fix: buffer response instead * Update components/google_drive/actions/download-file/download-file.mjs Co-authored-by: Jorge Cortes <jacortesmahmud@gmail.com> * versions * pnpm-lock.yaml * pnpm-lock.yaml * pnpm-lock.yaml * feat: add content selector * chore: bump package * fix: comments * chore: bump versions * chore: fix versions * fixes: QA fixes * feat: add cursor to req * package.json --------- Co-authored-by: joao <joao@coform.com> Co-authored-by: joaocoform <joao@usecoform.com> Co-authored-by: Jorge Cortes <jacortesmahmud@gmail.com> Co-authored-by: Michelle Bergeron <michelle.bergeron@gmail.com> Co-authored-by: Luan Cazarine <luanhc@gmail.com> * Merging pull request #18361 * update siteId prop * pnpm-lock.yaml * package.json version * Google Sheets - update row refresh fields (#18369) * change prop order and refresh fields * bump package.json * Pipedrive - fix app name (#18370) * use pipedriveApp instead of app * bump package.json * Pipedrive - pipelineId integer (#18372) * pipelineId - integer * bump versions * Adding app scaffolding for lightspeed_ecom_c_series * Adding app scaffolding for financial_data * Adding app scaffolding for microsoft_authenticator * Merging pull request #18345 * updates * versions * versions * Merging pull request #18368 * updates * remove console.log * versions * Coinbase Developer Platform - New Wallet Event (#18342) * new component * pnpm-lock.yaml * updates * updates * Hubspot - update search-crm (#18360) * update search-crm * limit results to one page * update version * package.json version * Merging pull request #18347 * widget props * fix version * Adding app scaffolding for rundeck * Merging pull request #18378 * Update Taiga component with new actions and sources - Bump version to 0.1.0 in package.json and add dependency on @pipedream/platform. - Introduce new actions for creating, updating, and deleting issues, tasks, and user stories. - Add sources for tracking changes and deletions of issues and tasks. - Implement utility functions for parsing and cleaning objects in common/utils.mjs. - Enhance prop definitions for better integration with Taiga API. * pnpm update * Refactor Taiga actions to utilize parseObject utility - Added parseObject utility for tags, watchers, and points in update-issue, update-task, and update-userstory actions. - Removed the update-project action as it is no longer needed. - Enhanced base source to include secret key validation for webhook security. * Merging pull request #18382 * add testSources prop * pnpm-lock.yaml * fix * Merging pull request #18323 * Added actions * Added actions * Added actions * Merging pull request #18377 * Added actions * Update components/weaviate/actions/create-class/create-class.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Luan Cazarine <luanhc@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Merging pull request #18376 * Adding app scaffolding for etrusted * Adding app scaffolding for intelliflo_office * Adding app scaffolding for thoughtspot * Adding app scaffolding for kordiam * Adding app scaffolding for ticketsauce * trustpilot fixes (#18152) * trustpilot fixes * more fixes * update versions * more version updates * fixes * Bump all Trustpilot actions to version 0.1.0 Major improvements and API updates across all actions: - Enhanced private API support with proper authentication - Improved parameter handling and validation - Better error handling and response structures - Added new conversation flow for product reviews - Fixed endpoint URLs to match latest API documentation - Streamlined request/response processing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * up version and clean up sources * merge * fix business ID * delete temp action * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * comments * Pagination * fixes * comments * missed some `$`'s * unduplicated * more fixes * final comments * more comments * . --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Adding app scaffolding for peekalink * 18314 twilio (#18350) * Update Twilio component versions and dependencies - Update Twilio Send Message action adding detailed description for 'from' prop and refactoring phone number validation logic. - Incremented action versions for several Twilio actions. * pnpm update * Updating LinkedIn API version (#18399) * Merging pull request #18394 * Databricks API - Jobs action components (#18371) * Notion property building improvements (#18381) * validate property types * versions * Google Business - add debug log (#18407) * add debug log * bump versions * Notion API Key - update @pipedream/notion version (#18409) * update @pipedream/notion dependency version * pnpm-lock.yaml * Adding app scaffolding for reduct_video * Adding app scaffolding for shopware * Adding app scaffolding for instamojo * Hubspot - bug fix to sources w/ property changes (#18379) * updates * versions * Google sheets type fix (#18411) * Fixing worksheetId prop type from string to integer * Version bumps --------- Co-authored-by: Leo Vu <vunguyenhung@outlook.com> * Merging pull request #18393 * new components * remove console.log * versions * update * Merging pull request #18408 * 403 error message * versions * update * Merging pull request #18419 * Changes per PR Review * Removes leonardo_ai_actions.mdc not indented for merging * synced lockfile after install * fully lock form-data for leonardo_ai * conflict solving * lint fixes * Chipped down Readme, implemented async options in gen motion --------- Co-authored-by: jocarino <45713006+jocarino@users.noreply.github.com> Co-authored-by: joao <joao@coform.com> Co-authored-by: joaocoform <joao@usecoform.com> Co-authored-by: Jorge Cortes <jacortesmahmud@gmail.com> Co-authored-by: Michelle Bergeron <michelle.bergeron@gmail.com> Co-authored-by: Luan Cazarine <luanhc@gmail.com> Co-authored-by: michelle0927 <michelle0927@users.noreply.github.com> Co-authored-by: Andrew Chuang <andrewjschuang@gmail.com> Co-authored-by: danhsiung <35384182+danhsiung@users.noreply.github.com> Co-authored-by: Lucas Caresia <lucascarezia@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Job <9075380+Afstkla@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com> Co-authored-by: Leo Vu <vunguyenhung@outlook.com>
Resolves #18364
Summary by CodeRabbit
New Features
Chores