-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Devin - new components #18324
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
Devin - new components #18324
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughAdds a Devin integration: a complete app client with API wrappers and propDefinitions, plus actions for sessions (create, list, get, send message, update tags), knowledge (list, create, update, delete), file upload, and package metadata/dependency updates. (49 words) Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Action as Pipedream Action
participant DevinApp as Devin App Client
participant DevinAPI as Devin API
rect rgba(235,245,255,0.9)
note right of Action: Create Session flow
User->>Action: invoke create-session (prompt, options)
Action->>DevinApp: createSession(data, $)
DevinApp->>DevinAPI: POST /sessions
DevinAPI-->>DevinApp: 201 { session }
DevinApp-->>Action: session response
Action-->>User: $summary with session_id
end
sequenceDiagram
autonumber
actor User
participant Action as Pipedream Action
participant DevinApp as Devin App Client
participant DevinAPI as Devin API
rect rgba(235,255,235,0.9)
note right of Action: Knowledge create/update/delete
User->>Action: create-knowledge (body, name, ...)
Action->>DevinApp: createKnowledge(data, $)
DevinApp->>DevinAPI: POST /knowledge
DevinAPI-->>DevinApp: 201 { knowledge }
DevinApp-->>Action: response
Action-->>User: $summary
par Update path
User->>Action: update-knowledge (knowledgeId, fields)
Action->>DevinApp: listKnowledge($)
DevinApp->>DevinAPI: GET /knowledge
DevinAPI-->>DevinApp: 200 knowledge[]
Action->>DevinApp: updateKnowledge(id, mergedData, $)
DevinApp->>DevinAPI: PUT /knowledge/{id}
DevinAPI-->>DevinApp: 200 updated
DevinApp-->>Action: response
Action-->>User: $summary
and Delete path
User->>Action: delete-knowledge (knowledgeId)
Action->>DevinApp: deleteKnowledge(knowledgeId, $)
DevinApp->>DevinAPI: DELETE /knowledge/{id}
DevinAPI-->>DevinApp: 204
DevinApp-->>Action: response
Action-->>User: $summary
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Pre-merge checks (3 passed, 2 warnings)❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Poem
✨ Finishing touches
🧪 Generate unit tests
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: 4
🧹 Nitpick comments (17)
components/devin/devin.app.mjs (3)
85-89: Nit: clean up pinnedRepo descriptionDuplicate “owner/repo” and wording is a bit long.
- description: "Pin knowledge to specific repositories. Valid values: `null`: No pinning (default), `all`: Pin to all repositories, `owner/repo`: Pin to specific repository, `owner/repo`: Pin to specific repository", + description: "Pin knowledge to specific repositories. Valid values: `null` (no pinning, default), `all` (pin to all repos), or `owner/repo` (pin to a specific repo).",
95-106: Add sane defaults to HTTP client (timeout, baseURL, Accept)Avoid indefinite hangs and rely on axios baseURL.
- return axios($, { - url: `${this._baseUrl()}${path}`, - headers: { - ...headers, - Authorization: `Bearer ${this.$auth.api_key}`, - }, - ...opts, - }); + return axios($, { + baseURL: this._baseUrl(), + url: path, + timeout: 30000, + headers: { + Accept: "application/json", + ...headers, + Authorization: `Bearer ${this.$auth.api_key}`, + }, + ...opts, + });
149-155: Add download attachments helper to cover requested endpointsIssue #18250 includes “GET: Download attachment files.” Add a wrapper for completeness.
// Inside methods: { ... } downloadAttachment({ attachmentId, responseType = "arraybuffer", ...opts }) { return this._makeRequest({ path: `/attachments/${attachmentId}`, responseType, ...opts, }); }components/devin/actions/list-knowledge/list-knowledge.mjs (1)
3-20: Support pagination inputs (limit/offset) to handle large result setsOptional props keep backward compatibility and help users page through knowledge.
export default { key: "devin-list-knowledge", name: "List Knowledge", description: "Retrieve a list of all knowledge objects. [See the documentation](https://docs.devin.ai/api-reference/knowledge/list-knowledge)", version: "0.0.1", type: "action", props: { devin, + limit: { + type: "integer", + label: "Limit", + description: "Max number of items to return", + optional: true, + default: 100, + }, + offset: { + type: "integer", + label: "Offset", + description: "Number of items to skip before starting to collect the result set", + optional: true, + default: 0, + }, }, async run({ $ }) { - const response = await this.devin.listKnowledge({ - $, - }); + const response = await this.devin.listKnowledge({ + $, + params: { + limit: this.limit, + offset: this.offset, + }, + }); $.export("$summary", `Successfully retrieved ${response.knowledge?.length || 0} knowledge objects`); return response; }, };If the endpoint returns a paginated container (e.g.,
next_offset,total), consider exporting pagination metadata in$summary.components/devin/actions/get-session/get-session.mjs (1)
24-25: More robust summary fallback.If the API doesn’t return title, include id before falling back to the input.
- $.export("$summary", `Successfully retrieved session: ${response.title || this.sessionId}`); + $.export("$summary", `Successfully retrieved session: ${response.title ?? response.id ?? this.sessionId}`);components/devin/actions/delete-knowledge/delete-knowledge.mjs (1)
18-26: Handle 204/empty responses gracefully.Delete endpoints often return 204 No Content. Returning a fallback object improves UX.
const response = await this.devin.deleteKnowledge({ $, knowledgeId: this.knowledgeId, }); $.export("$summary", `Successfully deleted knowledge object: ${this.knowledgeId}`); - return response; + return response ?? { success: true, knowledgeId: this.knowledgeId };components/devin/actions/upload-file/upload-file.mjs (2)
19-34: Harden input and avoid forcing knownLength; allow large uploads.
- Enforce http(s) URL or /tmp path.
- Only set knownLength when size is finite.
- Allow large files via axios options.
async run({ $ }) { + // Basic input hardening + if (!/^https?:\/\//i.test(this.filePathOrUrl) && !this.filePathOrUrl.startsWith("/tmp/")) { + throw new Error("filePathOrUrl must be an http(s) URL or a path under /tmp"); + } const { stream, metadata, } = await getFileStreamAndMetadata(this.filePathOrUrl); - const form = new FormData(); - form.append("file", stream, { - contentType: metadata.contentType, - knownLength: metadata.size, - filename: metadata.name, - }); + const form = new FormData(); + const appendOpts = { + filename: metadata.name, + contentType: metadata.contentType, + }; + if (Number.isFinite(metadata.size)) { + appendOpts.knownLength = metadata.size; + } + form.append("file", stream, appendOpts); const response = await this.devin.uploadFile({ $, headers: form.getHeaders(), - data: form, + data: form, + // Allow large uploads + maxBodyLength: Infinity, + maxContentLength: Infinity, });
5-11: Confirm coverage for “Download attachment files.”Issue #18250 requires a download attachments endpoint. I don’t see a corresponding action in this PR.
Want me to add a “Download Attachment” action (accepting attachmentId, streaming to /tmp, and returning local path)?
components/devin/actions/update-session-tags/update-session-tags.mjs (2)
32-33: Include tag count in summary for quick feedback.- $.export("$summary", `Successfully updated tags for session ${this.sessionId}`); + $.export("$summary", `Successfully updated tags for session ${this.sessionId} (${this.tags?.length ?? 0} tags)`);
17-21: Replacing tags vs. merging — confirm intent.This overwrites existing tags. If clearing or accidental empty arrays are not desired, consider a merge mode or a guard.
components/devin/actions/send-message-to-session/send-message-to-session.mjs (1)
23-26: Guard against empty messages.async run({ $ }) { + if (!this.message?.trim()) { + throw new Error("Message cannot be empty"); + } const response = await this.devin.sendMessageToSession({ $, sessionId: this.sessionId,components/devin/actions/create-session/create-session.mjs (2)
47-56: Verify multi-select propDefinition for knowledge IDs.You reference propDefinition "knowledgeId" while declaring type "string[]". Ensure the underlying devin prop supports multi-select, or expose a dedicated "knowledgeIds" propDefinition.
66-67: Avoid Pythonism in user-facing text.- description: "Custom title for the session. If None, a title will be generated automatically", + description: "Custom title for the session. If not provided, a title will be generated automatically",components/devin/actions/list-sessions/list-sessions.mjs (2)
6-6: Description nit: remove “all” to avoid implying auto-pagination.- description: "Retrieve a list of all sessions. [See the documentation](https://docs.devin.ai/api-reference/sessions/list-sessions)", + description: "Retrieve a list of sessions. [See the documentation](https://docs.devin.ai/api-reference/sessions/list-sessions)",
42-43: Make summary resilient to varying response shapes.- $.export("$summary", `Successfully retrieved ${response.sessions?.length || 0} sessions`); + const count = Array.isArray(response.sessions) + ? response.sessions.length + : (response.results?.length ?? response.data?.length ?? 0); + $.export("$summary", `Successfully retrieved ${count} sessions`);components/devin/actions/update-knowledge/update-knowledge.mjs (2)
43-45: Fix prop description to reflect update, not createMinor copy edit for clarity.
- description: "The ID of the folder to create the knowledge in", + description: "The ID of the parent folder for this knowledge object",
63-73: Optional: Send only fields the user provided if the API supports partial updatesAvoids an extra read and reduces payload surface. If Devin’s API accepts partial updates, build
datafrom provided props only and skip the pre-fetch.If supported, you could do:
const data = {}; if (typeof this.body !== "undefined") data.body = this.body; if (typeof this.name !== "undefined") data.name = this.name; if (typeof this.triggerDescription !== "undefined") data.trigger_description = this.triggerDescription; if (typeof this.parentFolderId !== "undefined") data.parent_folder_id = this.parentFolderId; if (typeof this.pinnedRepo !== "undefined") data.pinned_repo = this.pinnedRepo; const response = await this.devin.updateKnowledge({ $, knowledgeId: this.knowledgeId, data });Please confirm via docs or devin.app.mjs whether PUT supports partial updates or if a full resource is required.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
components/devin/actions/create-knowledge/create-knowledge.mjs(1 hunks)components/devin/actions/create-session/create-session.mjs(1 hunks)components/devin/actions/delete-knowledge/delete-knowledge.mjs(1 hunks)components/devin/actions/get-session/get-session.mjs(1 hunks)components/devin/actions/list-knowledge/list-knowledge.mjs(1 hunks)components/devin/actions/list-sessions/list-sessions.mjs(1 hunks)components/devin/actions/send-message-to-session/send-message-to-session.mjs(1 hunks)components/devin/actions/update-knowledge/update-knowledge.mjs(1 hunks)components/devin/actions/update-session-tags/update-session-tags.mjs(1 hunks)components/devin/actions/upload-file/upload-file.mjs(1 hunks)components/devin/devin.app.mjs(1 hunks)components/devin/package.json(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-12-12T19:23:09.039Z
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.
Applied to files:
components/devin/package.json
🧬 Code graph analysis (10)
components/devin/actions/delete-knowledge/delete-knowledge.mjs (3)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
response(47-56)components/devin/actions/list-knowledge/list-knowledge.mjs (1)
response(13-15)components/devin/actions/update-knowledge/update-knowledge.mjs (1)
response(63-73)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
components/devin/actions/update-knowledge/update-knowledge.mjs (1)
response(63-73)
components/devin/actions/list-sessions/list-sessions.mjs (3)
components/devin/actions/get-session/get-session.mjs (1)
response(19-22)components/devin/actions/list-knowledge/list-knowledge.mjs (1)
response(13-15)components/devin/actions/update-session-tags/update-session-tags.mjs (1)
response(24-30)
components/devin/actions/upload-file/upload-file.mjs (3)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
response(47-56)components/devin/actions/list-sessions/list-sessions.mjs (1)
response(33-40)components/devin/actions/send-message-to-session/send-message-to-session.mjs (1)
response(24-30)
components/devin/actions/update-session-tags/update-session-tags.mjs (3)
components/devin/actions/get-session/get-session.mjs (1)
response(19-22)components/devin/actions/list-sessions/list-sessions.mjs (1)
response(33-40)components/devin/actions/send-message-to-session/send-message-to-session.mjs (1)
response(24-30)
components/devin/actions/list-knowledge/list-knowledge.mjs (4)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
response(47-56)components/devin/actions/delete-knowledge/delete-knowledge.mjs (1)
response(19-22)components/devin/actions/list-sessions/list-sessions.mjs (1)
response(33-40)components/devin/actions/update-knowledge/update-knowledge.mjs (1)
response(63-73)
components/devin/actions/update-knowledge/update-knowledge.mjs (2)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
response(47-56)components/devin/actions/list-knowledge/list-knowledge.mjs (1)
response(13-15)
components/devin/actions/send-message-to-session/send-message-to-session.mjs (2)
components/devin/actions/get-session/get-session.mjs (1)
response(19-22)components/devin/actions/update-session-tags/update-session-tags.mjs (1)
response(24-30)
components/devin/actions/get-session/get-session.mjs (3)
components/devin/actions/list-sessions/list-sessions.mjs (1)
response(33-40)components/devin/actions/send-message-to-session/send-message-to-session.mjs (1)
response(24-30)components/devin/actions/update-session-tags/update-session-tags.mjs (1)
response(24-30)
components/devin/devin.app.mjs (1)
components/microsoft_outlook/microsoft_outlook.app.mjs (2)
DEFAULT_LIMIT(4-4)folders(157-162)
⏰ 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: Verify TypeScript components
- GitHub Check: Lint Code Base
- GitHub Check: Publish TypeScript components
- GitHub Check: pnpm publish
🔇 Additional comments (10)
components/devin/package.json (1)
3-3: Version bump and deps look good
- Matches the new actions’ needs; no built-in Node modules added (good per our past guidance).
Also applies to: 15-18
components/devin/devin.app.mjs (4)
121-132: RemovegetKnowledgesuggestion – no downstream usage detected
Search forgetKnowledge(returned no matches; adding this method is unnecessary.Likely an incorrect or invalid review comment.
12-24: Remove unnecessary fallback mapping
The List Sessions API returnssession_id(notid) alongsidetitle, so the existing destructuring (session_id→value,title→label) already covers all cases. No fallback toidis needed—keep the current mapping.
59-67: No action needed:secret_idandsecret_nameare correct keys
Mapping matches the Devin API response; no changes required.Likely an incorrect or invalid review comment.
41-54: listKnowledge correctly returns folders
Confirmed via Devin API docs that GET /v1/knowledge responds with bothknowledgeandfoldersarrays, so usingthis.listKnowledge()to populatefolderId.options()is valid—no separatelistFolderswrapper needed.components/devin/actions/get-session/get-session.mjs (1)
3-17: LGTM — action scaffold and props look correct.components/devin/actions/send-message-to-session/send-message-to-session.mjs (1)
3-22: LGTM — props and call pattern are consistent with other actions.components/devin/actions/create-session/create-session.mjs (1)
70-84: Field mapping looks correct; confirm API names.Please double-check these keys (snapshot_id, max_acu_limit, secret_ids, knowledge_ids) against the Devin API to avoid silent ignores.
components/devin/actions/list-sessions/list-sessions.mjs (1)
35-39: Confirm query param shapes.Verify whether the API expects tags as an array or comma-separated string, and that limit/offset names match the spec.
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
46-55: LGTM — payload mapping matches props; action reads cleanly.
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
♻️ Duplicate comments (3)
components/devin/actions/update-knowledge/update-knowledge.mjs (3)
56-59: Account for pagination or use a get-by-id endpoint.Listing once may miss the target item if paginated. Prefer a dedicated retrieval endpoint if available.
#!/bin/bash # Inspect wrappers to confirm pagination + any get-by-id method rg -nC3 'listKnowledge\\s*\\(' components/devin/devin.app.mjs rg -nC2 -e 'cursor|page|limit|next|offset' components/devin/devin.app.mjs rg -nC3 -e 'getKnowledge\\s*\\(|retrieveKnowledge\\s*\\(' components/devin/devin.app.mjs # Check return shape for `knowledge` vs `items` rg -nC2 '\\bknowledge\\b|\\bitems\\b' components/devin/devin.app.mjs | head -n 50
60-61: Guard when the knowledge item isn’t found.Avoid dereferencing
currentif not found.- const current = knowledge.find(({ id }) => id === this.knowledgeId); + const current = knowledge.find(({ id }) => id === this.knowledgeId); + if (!current) { + throw new Error(`Knowledge item not found for id: ${this.knowledgeId}`); + }
66-71: Preserve intentional falsy updates; avoid||in merges.Use undefined checks so empty string/false/null can overwrite existing values.
- body: this.body || current.body, - name: this.name || current.name, - trigger_description: this.triggerDescription || current.trigger_description, - parent_folder_id: this.parentFolderId || current.parent_folder_id, - pinned_repo: this.pinnedRepo || current.pinned_repo, + body: typeof this.body !== "undefined" ? this.body : current.body, + name: typeof this.name !== "undefined" ? this.name : current.name, + trigger_description: typeof this.triggerDescription !== "undefined" ? this.triggerDescription : current.trigger_description, + parent_folder_id: typeof this.parentFolderId !== "undefined" ? this.parentFolderId : current.parent_folder_id, + pinned_repo: typeof this.pinnedRepo !== "undefined" ? this.pinnedRepo : current.pinned_repo,
🧹 Nitpick comments (2)
components/devin/actions/update-knowledge/update-knowledge.mjs (2)
55-59: Require at least one updatable field.Fail fast if no fields are provided.
async run({ $ }) { + if ( + typeof this.body === "undefined" && + typeof this.name === "undefined" && + typeof this.triggerDescription === "undefined" && + typeof this.parentFolderId === "undefined" && + typeof this.pinnedRepo === "undefined" + ) { + throw new Error("No fields to update: provide at least one of body, name, triggerDescription, parentFolderId, or pinnedRepo."); + }
74-74: Make the summary more informative.Include the name when available.
- $.export("$summary", `Successfully updated knowledge object: ${this.knowledgeId}`); + $.export("$summary", `Successfully updated knowledge: ${current?.name ?? this.knowledgeId}`);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
components/devin/actions/update-knowledge/update-knowledge.mjs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
components/devin/actions/update-knowledge/update-knowledge.mjs (2)
components/devin/actions/create-knowledge/create-knowledge.mjs (1)
response(47-56)components/devin/actions/list-knowledge/list-knowledge.mjs (1)
response(13-15)
⏰ 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: Lint Code Base
- GitHub Check: pnpm publish
- GitHub Check: Verify TypeScript components
- GitHub Check: Publish TypeScript components
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: 3
♻️ Duplicate comments (2)
components/devin/devin.app.mjs (2)
145-146: Use correct Send Message path:/session/{id}/message(not plural)Per docs, the send message endpoint is singular. Update to avoid 404s. (docs.devin.ai)
- path: `/sessions/${sessionId}/message`, + path: `/session/${sessionId}/message`,
111-113: Fix Get Session path: singular/session/{id}Docs specify
GET /session/{session_id}, not/sessions/{id}. Current path will 404. (docs.devin.ai)- path: `/sessions/${sessionId}`, + path: `/session/${sessionId}`,
🧹 Nitpick comments (4)
components/devin/actions/list-sessions/list-sessions.mjs (2)
33-39: Pass tags as query params to leverage server-side filtering and avoid pagination missesThe API supports a
tagsquery param; sending it reduces payloads and prevents missing matches beyond the current page. Keep the client-side filter as a defensive fallback. (docs.devin.ai)- const response = await this.devin.listSessions({ - $, - params: { - limit: this.limit, - offset: this.offset, - }, - }); + const response = await this.devin.listSessions({ + $, + params: { + limit: this.limit, + offset: this.offset, + ...(this.tags?.length ? { tags: this.tags } : {}), + }, + });
17-30: Constrain limit/offset to documented rangesAdds basic validation in the UI to match API:
1 <= limit <= 1000,offset >= 0. (docs.devin.ai)limit: { type: "integer", label: "Limit", description: "Maximum number of sessions to retrieve", optional: true, default: 100, + min: 1, + max: 1000, }, offset: { type: "integer", label: "Offset", description: "Number of sessions to skip", optional: true, default: 0, + min: 0, },components/devin/devin.app.mjs (2)
19-24: Add a fallback label for sessions without a titleSome sessions may have a null/empty
title. Usesession_idas a fallback to keep the dropdown usable. (docs.devin.ai)- return sessions?.map(({ - session_id: value, title: label, - }) => ({ - label, - value, - })) || []; + return sessions?.map(({ + session_id: value, title, + }) => ({ + label: title || value, + value, + })) || [];
85-89: Tighten pinnedRepo description to remove duplicationMinor copy tweak for clarity.
- description: "Pin knowledge to specific repositories. Valid values: `null`: No pinning (default), `all`: Pin to all repositories, `owner/repo`: Pin to specific repository, `owner/repo`: Pin to specific repository", + description: "Pin knowledge to repositories. Valid values: `null` (no pinning, default), `all` (pin to all), or `owner/repo` (pin to a specific repo).",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
components/devin/actions/list-sessions/list-sessions.mjs(1 hunks)components/devin/devin.app.mjs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
components/devin/actions/list-sessions/list-sessions.mjs (3)
components/devin/actions/create-session/create-session.mjs (1)
response(71-84)components/devin/actions/list-knowledge/list-knowledge.mjs (1)
response(13-15)components/devin/actions/update-session-tags/update-session-tags.mjs (1)
response(24-30)
components/devin/devin.app.mjs (2)
components/microsoft_outlook/microsoft_outlook.app.mjs (1)
DEFAULT_LIMIT(4-4)components/devin/actions/list-sessions/list-sessions.mjs (1)
sessions(41-41)
⏰ 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
|
/approve |
Resolves #18250
Summary by CodeRabbit