Skip to content

Copy response text as both plain text and rich HTML#1878

Open
kyoto wants to merge 1 commit intoopenshift:mainfrom
kyoto:copy-rich-text
Open

Copy response text as both plain text and rich HTML#1878
kyoto wants to merge 1 commit intoopenshift:mainfrom
kyoto:copy-rich-text

Conversation

@kyoto
Copy link
Copy Markdown
Member

@kyoto kyoto commented Apr 28, 2026

When an OLS response is copied to the clipboard, write both text/plain (raw Markdown) and text/html (rendered HTML via marked) so that pasting into rich text editors preserves formatting, while plain text editors still receive the raw Markdown.

Also overrides the dompurify version to address a vulnerability in the version used by monaco-editor.

Made-with: Cursor

Summary by CodeRabbit

  • New Features

    • Clipboard copy now writes both plain text and sanitized HTML (Markdown-converted) for improved pasting fidelity.
  • Chores

    • Added Markdown parsing and HTML sanitization libraries; pinned sanitizer version for consistent resolution.
    • Updated TypeScript config to allow synthetic default imports.

@kyoto kyoto added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5a4c2b38-23de-4b3e-8d9c-cebadaeafe6b

📥 Commits

Reviewing files that changed from the base of the PR and between cc23e28 and 2737235.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json
  • src/clipboard.ts
  • tsconfig.json
✅ Files skipped from review due to trivial changes (2)
  • tsconfig.json
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/clipboard.ts

📝 Walkthrough

Walkthrough

Adds runtime dependencies (marked@14.0.0, dompurify@3.4.0), pins dompurify via overrides, enables allowSyntheticDefaultImports in tsconfig, and converts copyToClipboard to async to write both plain-text and sanitized HTML clipboard representations using marked + DOMPurify.

Changes

Cohort / File(s) Summary
Package manifest
package.json
Added runtime deps marked@14.0.0, dompurify@3.4.0 and an overrides entry to pin dompurify@3.4.0.
Clipboard enhancement
src/clipboard.ts
copyToClipboard signature changed to Promise<void>; now attempts rich clipboard write with text/plain and sanitized text/html rendered via marked + DOMPurify, falling back to navigator.clipboard.writeText with expanded error logging.
TypeScript config
tsconfig.json
Enabled compilerOptions.allowSyntheticDefaultImports to permit default-style imports (supports DOMPurify/marked import syntax).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibbled at the markdown stem,
I painted HTML on a whim,
I scrubbed it neat with gentle care,
I carried plain and rich to share,
Hooray — two formats in my tiny paw!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and accurately summarizes the main change: enabling clipboard writes with both plain text (Markdown) and rich HTML formats, which directly corresponds to the primary modifications in src/clipboard.ts and supporting dependency changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from joshuawilson and syedriko April 28, 2026 08:14
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Apr 28, 2026

[APPROVALNOTIFIER] This PR is APPROVED

Approval requirements bypassed by manually added approval.

This pull-request has been approved by:

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

1 similar comment
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Apr 28, 2026

[APPROVALNOTIFIER] This PR is APPROVED

Approval requirements bypassed by manually added approval.

This pull-request has been approved by:

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/clipboard.ts (1)

3-14: ⚠️ Potential issue | 🟠 Major

Propagate clipboard failures back to the caller.

This helper now returns a Promise, but the current callers in src/components/CopyAction.tsx and src/components/GeneralPage.tsx still fire-and-forget it and mark the UI as copied immediately. That can show success before the write completes or fails. Please either rethrow after logging or update the callers to await this helper before setting the copied state.

♻️ Minimal change inside this helper
   } catch (err) {
     // eslint-disable-next-line no-console
     console.error('Failed to copy to clipboard: ', err);
+    throw err;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clipboard.ts` around lines 3 - 14, The helper copyToClipboard currently
swallows errors, causing callers (CopyAction.tsx, GeneralPage.tsx) to show
success prematurely; modify copyToClipboard to propagate failures by rethrowing
the caught error (or remove the try/catch) after logging so callers can await
the Promise and only mark UI as copied on success; ensure the function signature
remains Promise<void> and keep the existing logging via console.error or
processLogger before rethrowing the error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/clipboard.ts`:
- Around line 3-14: The helper copyToClipboard currently swallows errors,
causing callers (CopyAction.tsx, GeneralPage.tsx) to show success prematurely;
modify copyToClipboard to propagate failures by rethrowing the caught error (or
remove the try/catch) after logging so callers can await the Promise and only
mark UI as copied on success; ensure the function signature remains
Promise<void> and keep the existing logging via console.error or processLogger
before rethrowing the error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4ea7e5b3-148e-44fb-8cf2-b0af5b234a09

📥 Commits

Reviewing files that changed from the base of the PR and between 130dfdd and c8bb23f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json
  • src/clipboard.ts

Copy link
Copy Markdown

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/clipboard.ts (1)

4-19: ⚠️ Potential issue | 🟠 Major

Propagate copy failures from the new async API.

Line 4 now exposes a Promise, but Lines 16-18 swallow every failure. That leaves callers unable to distinguish success from failure, and the current consumers already show the downstream problem: src/components/CopyAction.tsx:25-26 flips to “Copied” immediately, while src/components/GeneralPage.tsx:225 ignores the promise entirely. Please either rethrow/return a success flag here or keep this helper fire-and-forget so the contract matches reality.

Proposed direction
-export const copyToClipboard = async (value: string): Promise<void> => {
+export const copyToClipboard = async (value: string): Promise<boolean> => {
   try {
     if (typeof ClipboardItem !== 'undefined' && navigator.clipboard?.write) {
       const html = DOMPurify.sanitize(marked.parse(value) as string);
       const clipboardItem = new ClipboardItem({
         'text/plain': new Blob([value], { type: 'text/plain' }),
         'text/html': new Blob([html], { type: 'text/html' }),
       });
       await navigator.clipboard.write([clipboardItem]);
     } else {
       await navigator.clipboard.writeText(value);
     }
+    return true;
   } catch (err) {
     // eslint-disable-next-line no-console
     console.error('Failed to copy to clipboard: ', err);
+    return false;
   }
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clipboard.ts` around lines 4 - 19, copyToClipboard currently swallows all
errors in its try/catch, preventing callers from detecting failures; change it
to propagate failures by either removing the catch or rethrowing after logging
so the returned Promise rejects on error, e.g. keep the DOMPurify/ClipboardItem
logic inside try but after logging do "throw err" (or return a boolean success
flag from copyToClipboard and resolve true/false consistently), and ensure
callers of copyToClipboard (e.g., CopyAction component) await the Promise
instead of treating it as fire-and-forget so they can react to success/failure.
🧹 Nitpick comments (1)
src/clipboard.ts (1)

7-7: Remove the as string cast and await marked.parse() instead.

By default, marked.parse() returns string | Promise<string> in TypeScript's type definitions. The as string cast masks this union type, potentially hiding the mismatch if async mode is ever enabled. Since this function is already async, awaiting the result properly handles both cases and removes the unsafe cast.

Suggested fix
-      const html = DOMPurify.sanitize(marked.parse(value) as string);
+      const rendered = await marked.parse(value);
+      const html = DOMPurify.sanitize(rendered);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clipboard.ts` at line 7, In src/clipboard.ts, remove the unsafe "as
string" cast and await the possibly asynchronous marked.parse() call: call await
marked.parse(value) and pass its result into DOMPurify.sanitize so
DOMPurify.sanitize receives a definite string; update the declaration of html
(used where DOMPurify.sanitize is called) to use the awaited value rather than
casting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/clipboard.ts`:
- Around line 6-14: The rich clipboard write should be wrapped in a try/catch
and fall back to navigator.clipboard.writeText on any failure; before adding the
'text/html' blob, detect support with ClipboardItem.supports('text/html') and
only include the html entry when supported (otherwise construct the
ClipboardItem with only 'text/plain'), then attempt await
navigator.clipboard.write([clipboardItem]) inside the try block and on catch
call await navigator.clipboard.writeText(value) to ensure plain-text fallback;
update the code around ClipboardItem, navigator.clipboard.write and
navigator.clipboard.writeText and keep DOMPurify.sanitize(marked.parse(value))
for the html content.

---

Outside diff comments:
In `@src/clipboard.ts`:
- Around line 4-19: copyToClipboard currently swallows all errors in its
try/catch, preventing callers from detecting failures; change it to propagate
failures by either removing the catch or rethrowing after logging so the
returned Promise rejects on error, e.g. keep the DOMPurify/ClipboardItem logic
inside try but after logging do "throw err" (or return a boolean success flag
from copyToClipboard and resolve true/false consistently), and ensure callers of
copyToClipboard (e.g., CopyAction component) await the Promise instead of
treating it as fire-and-forget so they can react to success/failure.

---

Nitpick comments:
In `@src/clipboard.ts`:
- Line 7: In src/clipboard.ts, remove the unsafe "as string" cast and await the
possibly asynchronous marked.parse() call: call await marked.parse(value) and
pass its result into DOMPurify.sanitize so DOMPurify.sanitize receives a
definite string; update the declaration of html (used where DOMPurify.sanitize
is called) to use the awaited value rather than casting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 24e8d11f-02d3-4668-be7d-77a7a0099dc8

📥 Commits

Reviewing files that changed from the base of the PR and between c8bb23f and cc23e28.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json
  • src/clipboard.ts
  • tsconfig.json
✅ Files skipped from review due to trivial changes (1)
  • tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json

Comment thread src/clipboard.ts
When an OLS response is copied to the clipboard, write both text/plain
(raw Markdown) and text/html (rendered HTML via marked) so that pasting
into rich text editors preserves formatting, while plain text editors
still receive the raw Markdown.

Also overrides the dompurify version to address a vulnerability in the
version used by monaco-editor.

Made-with: Cursor
@kyoto
Copy link
Copy Markdown
Member Author

kyoto commented Apr 28, 2026

/cherry-pick release-4.19

@openshift-cherrypick-robot
Copy link
Copy Markdown

@kyoto: once the present PR merges, I will cherry-pick it on top of release-4.19 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick release-4.19

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants