Skip to content

Added support for Admitions and code copy button in serviceDoc panel#27732

Open
Rohit0301 wants to merge 5 commits intomainfrom
fix-27705
Open

Added support for Admitions and code copy button in serviceDoc panel#27732
Rohit0301 wants to merge 5 commits intomainfrom
fix-27705

Conversation

@Rohit0301
Copy link
Copy Markdown
Contributor

@Rohit0301 Rohit0301 commented Apr 25, 2026

Describe your changes:

Fixes #27705

I worked on ... because ...

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.

Summary by Gitar

  • UI Enhancements:
    • Added AdmonitionNode support with visual styles for note, warning, danger, info, tip, and caution.
    • Implemented CodeBlockWithCopy using CodeBlockComponent to provide a copy-to-clipboard feature in ServiceDocPanel.
  • Logic Updates:
    • Updated ServiceUtils.tsx to include convertAdmonitionsToHtml for processing markdown-based admonition syntax.

This will update automatically on new commits.

@Rohit0301 Rohit0301 self-assigned this Apr 25, 2026
@Rohit0301 Rohit0301 requested a review from a team as a code owner April 25, 2026 11:31
@Rohit0301 Rohit0301 added the safe to test Add this label to run secure Github workflows on PRs label Apr 25, 2026
Comment thread openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx
Comment thread openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx Outdated
return {
type: {
default: 'note',
parseHTML: (element) => element.getAttribute('data-admonition') ?? 'note',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Security: AdmonitionNode type attribute is not validated on parse

In AdmonitionNode.ts, the parseHTML handler reads data-admonition from the DOM element without validating it against the known admonition types (line 25). Since this attribute value is interpolated into a CSS class name (admonition-${node.attrs.type}) in renderHTML (line 41), a crafted document could inject arbitrary class names (e.g., data-admonition="foo bar"class="admonition admonition-foo bar"). Consider validating the attribute against the allowed types set.

Suggested fix:

const VALID_TYPES = new Set(['note', 'warning', 'danger', 'info', 'tip', 'caution']);

parseHTML: (element) => {
  const type = element.getAttribute('data-admonition') ?? 'note';
  return VALID_TYPES.has(type) ? type : 'note';
},

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 25, 2026

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 61%
61.93% (61782/99752) 42.06% (33028/78522) 45.06% (9763/21662)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 25, 2026

🟡 Playwright Results — all passed (18 flaky)

✅ 3955 passed · ❌ 0 failed · 🟡 18 flaky · ⏭️ 86 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 296 0 3 4
🟡 Shard 2 754 0 5 8
🟡 Shard 3 731 0 1 7
✅ Shard 4 759 0 0 18
🟡 Shard 5 686 0 1 41
🟡 Shard 6 729 0 8 8
🟡 18 flaky test(s) (passed on retry)
  • Flow/Tour.spec.ts › Tour should work from welcome screen (shard 1, 1 retry)
  • Flow/Tour.spec.ts › Tour should work from URL directly (shard 1, 1 retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/ActivityAPI.spec.ts › Activity event is created when description is updated (shard 2, 1 retry)
  • Features/ActivityAPI.spec.ts › Activity event shows the actor who made the change (shard 2, 1 retry)
  • Features/ColumnBulkOperations.spec.ts › should expand STRUCT column to show nested fields (shard 2, 1 retry)
  • Features/DomainFilterQueryFilter.spec.ts › Domain filter should work with different asset types (shard 2, 1 retry)
  • Features/DomainFilterQueryFilter.spec.ts › Quick filters should persist when domain filter is applied and cleared (shard 2, 1 retry)
  • Features/RTL.spec.ts › Verify Following widget functionality (shard 3, 1 retry)
  • Pages/EntityDataSteward.spec.ts › Tier Add, Update and Remove (shard 5, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › verify create lineage for entity - Container (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › Column lineage for dashboard -> topic (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › Column lineage for dashboardDataModel -> apiEndpoint (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab IS visible for supported type: searchIndex (shard 6, 1 retry)
  • Pages/ServiceListing.spec.ts › should render the service listing page (shard 6, 1 retry)
  • Pages/Users.spec.ts › Create and Delete user (shard 6, 1 retry)
  • Pages/Users.spec.ts › Admin soft & hard delete and restore user (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Apr 26, 2026

Code Review 👍 Approved with suggestions 4 resolved / 5 findings

ServiceDoc panel now supports admonitions and a code copy button, resolving issues with redundant type sets, improper content rendering, and memory leaks. Ensure the AdmonitionNode type attribute is validated during parsing to prevent malformed node injection.

💡 Security: AdmonitionNode type attribute is not validated on parse

📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/AdmonitionNode.ts:25 📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/AdmonitionNode.ts:41

In AdmonitionNode.ts, the parseHTML handler reads data-admonition from the DOM element without validating it against the known admonition types (line 25). Since this attribute value is interpolated into a CSS class name (admonition-${node.attrs.type}) in renderHTML (line 41), a crafted document could inject arbitrary class names (e.g., data-admonition="foo bar"class="admonition admonition-foo bar"). Consider validating the attribute against the allowed types set.

Suggested fix
const VALID_TYPES = new Set(['note', 'warning', 'danger', 'info', 'tip', 'caution']);

parseHTML: (element) => {
  const type = element.getAttribute('data-admonition') ?? 'note';
  return VALID_TYPES.has(type) ? type : 'note';
},
✅ 4 resolved
Bug: Admonition content is double-converted through markdown-to-HTML

📄 openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx:693-705 📄 openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx:720-734
convertAdmonitionsToHtml converts the inner markdown content to HTML via MarkdownToHTMLConverter.makeHtml (line 700) and wraps it in a <div>. Then in processDocMarkdown, the entire result (including those already-converted HTML divs) is passed through MarkdownToHTMLConverter.makeHtml again (lines 723-724, 735-737, 744). While showdown generally passes through raw HTML blocks, this double-processing can cause issues:

  • Paragraph wrapping (<p>) may be added around or inside the div
  • Edge cases with inline markdown syntax inside the already-converted HTML

The fix is to not pre-convert admonition content to HTML in convertAdmonitionsToHtml. Instead, just replace the $$type ... $$ markers with the <div> wrapper while leaving the inner content as raw markdown, so it gets converted once by the section processing loop.

Bug: contentRef will always be null — NodeViewContent doesn't forward refs

📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/CodeBlock/CodeBlockComponent.tsx:21 📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/CodeBlock/CodeBlockComponent.tsx:24 📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/CodeBlock/CodeBlockComponent.tsx:36
Tiptap's NodeViewContent does not forward refs (known limitation, see tiptap#6150). This means contentRef.current on line 24 will always be null, and the copy fallback node.textContent will always be used. While the fallback works, it silently defeats the purpose of the ref. If node.textContent ever diverges from the rendered DOM text (e.g., decorated content), copying will be incorrect.

A more reliable approach is to use a wrapper <pre> ref and query the <code> element from it, or simply rely on node.textContent intentionally and remove the misleading ref.

Edge Case: setTimeout in handleCopy not cleared on unmount

📄 openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/CodeBlock/CodeBlockComponent.tsx:28
The setTimeout(() => setCopied(false), 2000) on line 28 is not cleaned up if the component unmounts before the timeout fires. This can cause a React "state update on unmounted component" warning. Use a ref to track the timeout and clear it in a cleanup effect.

Quality: ADMONITION_TYPES set is redundant — regex already constrains values

📄 openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx:681-688 📄 openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx:690-691 📄 openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtils.tsx:699
The ADMONITION_TYPES Set on line 681 duplicates the types already hard-coded in ADMONITION_BLOCK_REGEX. Since the regex only matches note|warning|danger|info|tip|caution, the ADMONITION_TYPES.has(type) check on line 699 is always true, making the fallback 'note' unreachable. Either remove the Set and the guard, or derive the regex from the Set to keep a single source of truth.

🤖 Prompt for agents
Code Review: ServiceDoc panel now supports admonitions and a code copy button, resolving issues with redundant type sets, improper content rendering, and memory leaks. Ensure the AdmonitionNode type attribute is validated during parsing to prevent malformed node injection.

1. 💡 Security: AdmonitionNode type attribute is not validated on parse
   Files: openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/AdmonitionNode.ts:25, openmetadata-ui/src/main/resources/ui/src/components/BlockEditor/Extensions/AdmonitionNode.ts:41

   In `AdmonitionNode.ts`, the `parseHTML` handler reads `data-admonition` from the DOM element without validating it against the known admonition types (line 25). Since this attribute value is interpolated into a CSS class name (`admonition-${node.attrs.type}`) in `renderHTML` (line 41), a crafted document could inject arbitrary class names (e.g., `data-admonition="foo bar"` → `class="admonition admonition-foo bar"`). Consider validating the attribute against the allowed types set.

   Suggested fix:
   const VALID_TYPES = new Set(['note', 'warning', 'danger', 'info', 'tip', 'caution']);
   
   parseHTML: (element) => {
     const type = element.getAttribute('data-admonition') ?? 'note';
     return VALID_TYPES.has(type) ? type : 'note';
   },

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link
Copy Markdown

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

Labels

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Notes style and code copy button is not visible on service doc panel

1 participant