Skip to content

Conversation

@michelle0927
Copy link
Collaborator

@michelle0927 michelle0927 commented Jan 20, 2025

Note to QA: Go to Autodesk Fusion (pipedream.autodesk360.com) to view folders & files.

Resolves #15211.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added functionality for creating folders in Autodesk projects.
    • Implemented file upload capabilities to Autodesk.
    • Introduced webhook and polling mechanisms for tracking Autodesk events.
    • Added event sources for new folders, projects, and file versions.
  • Improvements

    • Enhanced Autodesk app integration with new API methods.
    • Improved project and folder management capabilities.
  • Version Update

    • Bumped package version from 0.0.1 to 0.1.0.

@michelle0927 michelle0927 added the ai-assisted Content generated by AI, with human refinement and modification label Jan 20, 2025
@vercel
Copy link

vercel bot commented Jan 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Ignored (Inspect) Visit Preview Jan 27, 2025 9:25pm
pipedream-docs ⬜️ Ignored (Inspect) Jan 27, 2025 9:25pm
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) Jan 27, 2025 9:25pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2025

Walkthrough

This pull request introduces new modules for creating folders and uploading files in Autodesk projects, along with webhook sources for monitoring project and file events. Enhancements to the Autodesk app module include improved property definitions and API interaction methods. Additionally, a polling mechanism for event handling is established, allowing for structured retrieval of project and folder data. Overall, the changes expand the capabilities for managing Autodesk resources programmatically.

Changes

File Change Summary
components/autodesk/actions/create-folder/create-folder.mjs New module for creating folders in Autodesk projects
components/autodesk/actions/upload-file/upload-file.mjs New module for uploading files to Autodesk
components/autodesk/autodesk.app.mjs Enhancements to API interaction methods, prop definitions for hubId, projectId, and folderId
components/autodesk/package.json Version updated to 0.1.0; added dependency on @pipedream/platform
components/autodesk/sources/common/base-polling.mjs New polling mechanism for handling Autodesk API events
components/autodesk/sources/common/base-webhook.mjs New component for integrating Autodesk webhooks
components/autodesk/sources/new-folder-instant/new-folder-instant.mjs Webhook source for folder creation events
components/autodesk/sources/new-project-created/new-project-created.mjs Source for new project creation events with polling
components/autodesk/sources/new-version-instant/new-version-instant.mjs Webhook source for file version events

Assessment against linked issues

Objective Addressed Explanation
Emit new event when a new project is created
Emit new event when a new file is uploaded
Emit new event when a new version of a file is created
Create a new project in Autodesk No implementation for creating projects is included in this PR.
Upload a new file to a specified project or folder

Possibly related PRs

Suggested reviewers

  • GTFalcao

Poem

🐰 In Autodesk's digital realm so bright,
Folders dance and files take flight,
Webhooks chirp with coding glee,
A rabbit's integration spree!
Pipedream's magic makes it right! 🚀


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e074b5 and 611c97e.

📒 Files selected for processing (2)
  • components/autodesk/actions/create-folder/create-folder.mjs (1 hunks)
  • components/autodesk/actions/upload-file/upload-file.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/autodesk/actions/create-folder/create-folder.mjs
  • components/autodesk/actions/upload-file/upload-file.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

@michelle0927 michelle0927 marked this pull request as ready for review January 21, 2025 18:52
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: 15

🧹 Nitpick comments (13)
components/autodesk/sources/new-version-instant/new-version-instant.mjs (2)

9-9: Consider starting with version 0.1.0 instead of 0.0.1

Following semantic versioning best practices, initial public releases typically start at 0.1.0 to indicate the first minor version.

-  version: "0.0.1",
+  version: "0.1.0",

17-23: Consider using event timestamp instead of parse time

The createdTime is parsed using Date.parse(), which might not preserve timezone information. Consider using the native Date object or a robust date handling library like date-fns.

     generateMeta(payload) {
       return {
         id: payload.source,
         summary: `New File Version for File: ${payload.name}`,
-        ts: Date.parse(payload.createdTime),
+        ts: new Date(payload.createdTime).getTime(),
       };
     },
components/autodesk/sources/new-project-created/new-project-created.mjs (1)

9-9: Maintain version consistency across components

For consistency with other components, consider using the same version number.

-  version: "0.0.1",
+  version: "0.1.0",
components/autodesk/sources/new-folder-instant/test-event.mjs (2)

2-2: Use realistic dates in test events

The test event contains future dates (2025). Consider using recent past dates for more realistic test scenarios.

-  "modifiedTime": "2025-01-20T21:24:41+0000",
+  "modifiedTime": "2024-01-20T21:24:41+0000",
-  "createdTime": "2025-01-20T21:24:41+0000",
+  "createdTime": "2024-01-20T21:24:41+0000",

Also applies to: 15-15


3-3: Use placeholder values for sensitive IDs

Consider using obvious placeholder values for user IDs in test data to prevent any confusion with real data.

-  "creator": "7QNJ9NNCKNKRJ8ZU",
+  "creator": "TEST_USER_ID",
   "user_info": {
-    "id": "7QNJ9NNCKNKRJ8ZU"
+    "id": "TEST_USER_ID"

Also applies to: 9-10

components/autodesk/sources/common/base-polling.mjs (1)

33-41: Add JSDoc comments for abstract methods

Add JSDoc comments to clearly document the expected implementation of abstract methods.

+    /**
+     * @abstract
+     * @returns {Function} Function to be used for pagination
+     * @throws {Error} When not implemented by child class
+     */
     getFn() {
       throw new Error("getFn is not implemented");
     },
+    /**
+     * @abstract
+     * @returns {Object} Arguments to be passed to the pagination function
+     */
     getArgs() {
       return {};
     },
+    /**
+     * @abstract
+     * @param {Object} data The data to generate metadata from
+     * @returns {Object} Metadata object with id, summary, and ts
+     * @throws {Error} When not implemented by child class
+     */
     generateMeta() {
       throw new Error("generateMeta is not implemented");
     },
components/autodesk/sources/new-project-created/test-event.mjs (1)

13-13: Consider using environment variables or constants for API URLs.

The hardcoded API URLs contain version numbers that could become outdated. Consider extracting these into environment variables or constants for easier maintenance.

Also applies to: 20-20, 31-31, 42-42, 49-49

components/autodesk/sources/new-version-instant/test-event.mjs (1)

3-3: Use a consistent date format with realistic timestamps.

The test event uses future dates (2025). Consider using a more recent or relative timestamp to avoid confusion.

Also applies to: 26-26, 29-29, 34-34

components/autodesk/actions/update-file-metadata/update-file-metadata.mjs (1)

48-52: Enhance metadata input validation.

Consider adding a custom validation function to ensure the metadata object has the correct structure before processing.

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

43-53: Improve documentation for extension types.

The description could be enhanced with more details about when to use each folder type and their implications.

components/autodesk/actions/upload-file/upload-file.mjs (3)

8-8: Consider starting with version 0.1.0.

Following semantic versioning best practices, consider starting with version 0.1.0 for the initial release instead of 0.0.1.


42-46: Enhance filePath documentation.

The description could be more specific about:

  1. Accepted file path formats
  2. Size limits
  3. Supported file types

96-103: Add error handling for upload request.

Consider adding error handling and progress tracking for large file uploads:

-    await this.autodesk._makeRequest({
+    try {
+      await this.autodesk._makeRequest({
         $,
         url: signedUrl,
         data: fileStream,
         headers: {
           "Content-Type": "application/octet-stream",
         },
-      });
+      });
+    } catch (error) {
+      throw new Error(`Failed to upload file: ${error.message}`);
+    }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ac79b00 and f83ba4b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • components/autodesk/actions/create-folder/create-folder.mjs (1 hunks)
  • components/autodesk/actions/update-file-metadata/update-file-metadata.mjs (1 hunks)
  • components/autodesk/actions/upload-file/upload-file.mjs (1 hunks)
  • components/autodesk/autodesk.app.mjs (1 hunks)
  • components/autodesk/package.json (2 hunks)
  • components/autodesk/sources/common/base-polling.mjs (1 hunks)
  • components/autodesk/sources/common/base-webhook.mjs (1 hunks)
  • components/autodesk/sources/new-folder-instant/new-folder-instant.mjs (1 hunks)
  • components/autodesk/sources/new-folder-instant/test-event.mjs (1 hunks)
  • components/autodesk/sources/new-project-created/new-project-created.mjs (1 hunks)
  • components/autodesk/sources/new-project-created/test-event.mjs (1 hunks)
  • components/autodesk/sources/new-version-instant/new-version-instant.mjs (1 hunks)
  • components/autodesk/sources/new-version-instant/test-event.mjs (1 hunks)
🔇 Additional comments (7)
components/autodesk/sources/common/base-webhook.mjs (4)

38-58: Well-structured activate method with proper error handling

The activate method effectively creates a webhook and handles potential errors by checking the presence of the location header and throwing an error if it's missing. The extraction and storage of hookId is correctly implemented.


59-66: Clean deactivate method that safely handles webhook deletion

The deactivate method appropriately retrieves the stored hookId and attempts to delete the webhook if it exists. This prevents unnecessary API calls and handles cases where the hookId may not be set.


75-80: Abstract methods correctly defined for extensibility

The getEvent and generateMeta methods are intentionally left unimplemented, throwing errors to ensure that any subclass provides the necessary implementations. This is an effective technique for creating an extensible base class.


82-94: Efficient event handling in the run method

The run method correctly handles incoming events by responding with a 200 status and emitting the payload with generated metadata. It assumes that generateMeta is implemented in derived classes, which aligns with the abstract method design.

components/autodesk/sources/new-folder-instant/new-folder-instant.mjs (2)

17-23: Proper implementation of generateMeta method

The generateMeta method correctly constructs metadata for emitted events, including a unique ID, summary, and timestamp. This ensures that each event can be uniquely identified and processed downstream.


13-16: Correct event type specified in getEvent method

The getEvent method returns the correct event type "dm.folder.added" for detecting when a new folder is created. This aligns with Autodesk's webhook event types and ensures the source functions as intended.

components/autodesk/package.json (1)

Line range hint 3-18: LGTM! Version bump and dependency addition look appropriate.

The version bump to 0.1.0 aligns with semantic versioning for initial releases, and the @pipedream/platform dependency is correctly specified.

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: 2

♻️ Duplicate comments (1)
components/autodesk/autodesk.app.mjs (1)

7-20: 🛠️ Refactor suggestion

Add error handling in the hubId options method.

The async options method should include error handling to prevent unhandled promise rejections.

 async options() {
-  const { data } = await this.listHubs();
-  return data?.map(({
-    id, attributes,
-  }) => ({
-    label: attributes.name,
-    value: id,
-  })) || [];
+  try {
+    const { data } = await this.listHubs();
+    return data?.map(({
+      id, attributes,
+    }) => ({
+      label: attributes.name,
+      value: id,
+    })) || [];
+  } catch (error) {
+    console.error("Error fetching hubs:", error);
+    return [];
+  }
 },
🧹 Nitpick comments (2)
components/autodesk/autodesk.app.mjs (2)

123-141: Consider adding request timeout and retries in _makeRequest.

The base request method could benefit from timeout and retry mechanisms for better reliability.

 _makeRequest({
   $ = this,
   path,
   headers,
+  timeout = 10000,
+  maxRetries = 3,
   ...otherOpts
 }) {
+  let retries = 0;
+  const makeRequestWithRetry = async () => {
+    try {
       return axios($, {
         url: `${this._baseUrl()}${path}`,
         headers: {
           "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
           "Content-Type": "application/json",
           ...headers,
         },
+        timeout,
         ...otherOpts,
       });
+    } catch (error) {
+      if (retries < maxRetries && error.response?.status >= 500) {
+        retries++;
+        await new Promise(resolve => setTimeout(resolve, 1000 * retries));
+        return makeRequestWithRetry();
+      }
+      throw error;
+    }
+  };
+  return makeRequestWithRetry();
 },

243-268: Verify pagination implementation in the paginate method.

The pagination implementation looks correct with the page increment fix, but consider adding error handling.

 async *paginate({
   fn,
   args,
   max,
 }) {
+  try {
     let hasMore = true;
     let count = 0;
     args = {
       ...args,
       params: {
         ...args?.params,
         "page[number]": 0,
         "page[limit]": 200,
       },
     };
     while (hasMore) {
+      try {
         const { data } = await fn(args);
         for (const item of data) {
           yield item;
           if (max && ++count >= max) {
             return;
           }
         }
         hasMore = data?.length === args.params["page[limit]"];
         args.params["page[number]"] += 1;
+      } catch (error) {
+        console.error("Error during pagination:", error);
+        break;
+      }
     }
+  } catch (error) {
+    console.error("Error initializing pagination:", error);
+    throw error;
+  }
 },
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f83ba4b and c2256f3.

📒 Files selected for processing (1)
  • components/autodesk/autodesk.app.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (3)
components/autodesk/autodesk.app.mjs (3)

1-6: LGTM! Basic app setup looks good.

The import statement and app definition follow the standard pattern for Pipedream components.


21-44: 🛠️ Refactor suggestion

Add error handling and verify pagination in the projectId options method.

The method handles pagination but needs error handling. Also, ensure the page parameter is properly typed.

 async options({
   hubId, page,
 }) {
+  try {
     if (!hubId) {
       return [];
     }
     const { data } = await this.listProjects({
       hubId,
       params: {
-        "page[number]": page,
+        "page[number]": parseInt(page) || 0,
       },
     });
     return data?.map(({
       id, attributes,
     }) => ({
       label: attributes.name,
       value: id,
     })) || [];
+  } catch (error) {
+    console.error("Error fetching projects:", error);
+    return [];
+  }
 },

Likely invalid or redundant comment.


96-120: 🛠️ Refactor suggestion

Add error handling and consider additional file filtering options.

The file listing implementation needs error handling and could benefit from additional filtering options.

 async options({
   projectId, folderId,
 }) {
+  try {
     if (!projectId || !folderId) {
       return [];
     }
     const { data } = await this.getFolderContent({
       projectId,
       folderId,
       params: {
         "filter[type]": "items",
+        "filter[extension.type]": "items:autodesk.core:File",
       },
     });
     return data?.map(({
       id, attributes,
     }) => ({
       label: attributes.displayName,
       value: id,
     })) || [];
+  } catch (error) {
+    console.error("Error fetching files:", error);
+    return [];
+  }
 },

Likely invalid or redundant comment.

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: 3

♻️ Duplicate comments (2)
components/autodesk/autodesk.app.mjs (2)

11-19: ⚠️ Potential issue

Add error handling to prevent unhandled promise rejections.

The options method needs error handling to gracefully manage API failures.

 async options() {
+  try {
     const { data } = await this.listHubs();
     return data?.map(({
       id, attributes,
     }) => ({
       label: attributes.name,
       value: id,
     })) || [];
+  } catch (error) {
+    console.error("Error fetching hubs:", error);
+    return [];
+  }
 },

117-125: ⚠️ Potential issue

Add input validation for webhook parameters.

The createWebhook method should validate required parameters before making the request.

 createWebhook({
   system, event, ...opts
 }) {
+  if (!system || !event) {
+    throw new Error("system and event parameters are required");
+  }
   return this._makeRequest({
     method: "POST",
     path: `/webhooks/v1/systems/${system}/events/${event}/hooks`,
     ...opts,
   });
 },
🧹 Nitpick comments (1)
components/autodesk/autodesk.app.mjs (1)

66-89: Optimize recursive folder fetching with parallel processing.

The current implementation fetches folders sequentially. Using Promise.all would improve performance.

 const fetchFoldersRecursively = async (folderId, depth = 0, maxDepth = 10) => {
   if (depth > maxDepth) {
     return;
   }
   try {
     const { data } = await this.getFolderContent({
       projectId,
       folderId,
       params: {
         "filter[type]": "folders",
       },
     });
     const folders = data?.map(({
       id, attributes,
     }) => ({
       label: attributes.name,
       value: id,
     })) || [];

     options.push(...folders);

-    for (const folder of folders) {
-      await fetchFoldersRecursively(folder.value, depth + 1, maxDepth);
-    }
+    await Promise.all(
+      folders.map(folder => 
+        fetchFoldersRecursively(folder.value, depth + 1, maxDepth)
+      )
+    );
   } catch (error) {
     console.error(`Error fetching subfolders for ${folderId}:`, error);
   }
 };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c2256f3 and fc0edd0.

📒 Files selected for processing (2)
  • components/autodesk/actions/upload-file/upload-file.mjs (1 hunks)
  • components/autodesk/autodesk.app.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/autodesk/actions/upload-file/upload-file.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (1)
components/autodesk/autodesk.app.mjs (1)

1-6: LGTM!

The basic structure follows Pipedream's app module pattern.

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fc0edd0 and 1e074b5.

📒 Files selected for processing (1)
  • components/autodesk/autodesk.app.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (8)
components/autodesk/autodesk.app.mjs (8)

1-6: LGTM!

The import statement and app definition are correctly implemented.


11-19: Add error handling in the hubId options method.

The method should handle API failures gracefully to prevent unhandled promise rejections.


25-43: Add error handling and pagination validation in the projectId options method.

The method needs to handle API failures and validate the page parameter.


49-95: Improve folder fetching robustness.

While the recursive implementation includes a depth limit, it needs error handling and could benefit from parallel processing improvements.


98-116: LGTM!

The base URL and request helper methods are well implemented with proper authorization and content type headers.


117-125: Add input validation for webhook creation.

The createWebhook method should validate required parameters before making the request.


148-156: Add error handling for empty response in getProjectTopFolderId.

The method assumes the response will always contain data[0].id, which might not be true.


218-243: LGTM! Pagination implementation looks good.

The pagination logic is well implemented with:

  • Proper initialization of pagination parameters
  • Correct page increment logic
  • Proper handling of max items limit

GTFalcao
GTFalcao previously approved these changes Jan 27, 2025
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!

Comment on lines 48 to 49
"folders:autodesk.core:Folder",
"folders:autodesk.bim360:Folder",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could those have a label? Such as BIM 360 Docs folders and Other folders

@michelle0927
Copy link
Collaborator Author

/approve

@michelle0927 michelle0927 merged commit efb7584 into master Feb 3, 2025
11 checks passed
@michelle0927 michelle0927 deleted the issue-15211 branch February 3, 2025 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Content generated by AI, with human refinement and modification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Components] autodesk

2 participants