From 98ee672eeb8a8d4def243495a4cd368a84e32ee7 Mon Sep 17 00:00:00 2001 From: Sophie <29382425+sophietheking@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:37:02 +0200 Subject: [PATCH 1/6] [2026-06-30] Code Coverage PR merge protection rule [Public Preview] (#61942) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../concepts/about-code-quality.md | 2 +- .../how-tos/maintain-quality-code/index.md | 1 + .../restrict-code-coverage.md | 39 +++++++++++++++++++ .../set-up-code-coverage.md | 1 + .../maintain-quality-code/unblock-your-pr.md | 25 ++++++++++-- .../available-rules-for-rulesets.md | 14 +++++++ 6 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 content/code-security/how-tos/maintain-quality-code/restrict-code-coverage.md diff --git a/content/code-security/concepts/about-code-quality.md b/content/code-security/concepts/about-code-quality.md index ae7556ec3f66..9ce394b43df1 100644 --- a/content/code-security/concepts/about-code-quality.md +++ b/content/code-security/concepts/about-code-quality.md @@ -29,7 +29,7 @@ With {% data variables.product.prodname_code_quality_short %}, you can: * Review clear explanations for findings and apply one-click **{% data variables.product.prodname_copilot_short %}-powered autofixes**. * Use **repository dashboards** to track reliability and maintainability scores, identify areas needing attention, and prioritize remediation. * Monitor **organization dashboards** to understand the code health of your repositories at a glance and determine which repositories to investigate further. -* Set up **rulesets** for pull requests to enforce code quality standards and block changes that do not meet your criteria. +* Set up **rulesets** for pull requests to enforce code quality standards and block changes that do not meet your criteria. You can also enforce coverage thresholds with rulesets to block pull requests that don't meet a minimum coverage percentage or that cause coverage to drop by more than the allowed amount. * Upload **code coverage** reports to see test coverage metrics directly on pull requests, helping reviewers identify untested code. * Easily assign remediation work to **{% data variables.copilot.copilot_cloud_agent %}**, if you have a {% data variables.product.prodname_copilot_short %} license. diff --git a/content/code-security/how-tos/maintain-quality-code/index.md b/content/code-security/how-tos/maintain-quality-code/index.md index f2a3447e2f1a..173c5f812ddd 100644 --- a/content/code-security/how-tos/maintain-quality-code/index.md +++ b/content/code-security/how-tos/maintain-quality-code/index.md @@ -12,6 +12,7 @@ children: - /set-up-code-coverage - /interpret-results - /set-pr-thresholds + - /restrict-code-coverage - /unblock-your-pr redirect_from: - /code-security/code-quality/how-tos diff --git a/content/code-security/how-tos/maintain-quality-code/restrict-code-coverage.md b/content/code-security/how-tos/maintain-quality-code/restrict-code-coverage.md new file mode 100644 index 000000000000..9af90a811783 --- /dev/null +++ b/content/code-security/how-tos/maintain-quality-code/restrict-code-coverage.md @@ -0,0 +1,39 @@ +--- +title: Restricting code coverage on pull requests +shortTitle: Restrict code coverage +intro: Protect your test coverage by automatically blocking pull requests that fall below the coverage levels your team requires. +versions: + feature: code-quality +permissions: '{% data reusables.permissions.code-quality-repo-enable %}' +contentType: how-tos +category: + - Improve code quality +--- + +> [!NOTE] +> This feature is in {% data variables.release-phases.public_preview %} and subject to change. + +## Prerequisites + +* {% data variables.product.prodname_code_quality %} is enabled on the repository. +* Code coverage data is uploaded to {% data variables.product.github %} for the pull request branch. See [AUTOTITLE](/code-security/how-tos/maintain-quality-code/set-up-code-coverage). + +## Creating a coverage threshold rule + +{% data reusables.repositories.navigate-to-repo %} +{% data reusables.repositories.sidebar-settings %} +{% data reusables.repositories.repo-rulesets-settings %} +1. Create a new branch ruleset or click an existing one to edit it. +1. Under "Branch rules", select **Restrict code coverage**. +1. Expand **Additional settings** to configure thresholds. A value of 0 means that the threshold is disabled. + + * **Minimum coverage percentage**: enter a value to block pull requests where aggregated coverage falls below this percentage. + * **Maximum coverage drop**: enter a value to block pull requests where coverage drops by more than this many percentage points relative to the default branch. + +1. Click **Create** or **Save changes**. + +{% ifversion repo-rules-enterprise %} + +> [!TIP] +> Consider setting your ruleset to **Evaluate** mode before switching to **Active**. This lets you observe which pull requests would have been blocked without enforcing the rule, giving you a chance to calibrate your thresholds. +{% endif %} diff --git a/content/code-security/how-tos/maintain-quality-code/set-up-code-coverage.md b/content/code-security/how-tos/maintain-quality-code/set-up-code-coverage.md index 51d909e34a20..121ea4f890f9 100644 --- a/content/code-security/how-tos/maintain-quality-code/set-up-code-coverage.md +++ b/content/code-security/how-tos/maintain-quality-code/set-up-code-coverage.md @@ -127,3 +127,4 @@ jobs: ## Next steps * **Interpret results:** Understand coverage metrics and per-file breakdowns on your pull requests. See [AUTOTITLE](/code-security/how-tos/maintain-quality-code/interpret-results). +* **Enforce coverage thresholds:** Block pull requests that don't meet a minimum coverage percentage or that cause coverage to drop. See [AUTOTITLE](/code-security/how-tos/maintain-quality-code/restrict-code-coverage). diff --git a/content/code-security/how-tos/maintain-quality-code/unblock-your-pr.md b/content/code-security/how-tos/maintain-quality-code/unblock-your-pr.md index d9e67f8ea40b..2cfdc6c9ef59 100644 --- a/content/code-security/how-tos/maintain-quality-code/unblock-your-pr.md +++ b/content/code-security/how-tos/maintain-quality-code/unblock-your-pr.md @@ -1,7 +1,7 @@ --- title: Resolving a block on your pull request shortTitle: Unblock your PR -intro: Identify and resolve a code quality block on your pull request so you can merge your changes. +intro: Identify and resolve a code quality or coverage threshold block on your pull request so you can merge your changes. versions: feature: code-quality permissions: '{% data reusables.permissions.code-quality-see-repo-findings %}' @@ -16,10 +16,14 @@ category: ## Understanding why your pull request is blocked -Repository administrators can set code quality gates for maintainability and reliability using {% data variables.product.prodname_code_quality %}. When you open a pull request, a scan automatically runs to check your changes against these standards. +Repository administrators can set quality gates using {% data variables.product.prodname_code_quality %}. When you open a pull request, checks automatically run to evaluate your changes against these standards. -If your pull request introduces code that falls below the required quality threshold, you’ll see a merge block banner at the bottom of the pull request in the Checks section: -"Merging is blocked: Code quality findings were detected." +There are two types of blocks: + +* **Code quality findings**: your changes introduce issues that fall below the required quality threshold. +* **Coverage threshold**: your changes cause code coverage to fall below a required minimum, or cause coverage to drop by more than a permitted amount relative to the default branch. + +If your pull request introduces code that falls below the required quality threshold, you'll see a merge block banner at the bottom of the pull request in the "Checks" section: "Merging is blocked: Code quality findings were detected." ![Screenshot of the merge block banner in the Checks section of a pull request.](/assets/images/help/code-quality/code-quality-merge-block.png) @@ -64,6 +68,19 @@ In order to unblock your pull request, you need to resolve each required finding To see if you've met the code quality requirements, look at the "Checks" section at the bottom of your pull request. The merge block banner should no longer be present, and you should be able to merge your changes as usual. +## Resolving a coverage threshold block + +If your pull request is blocked by a coverage threshold rule, you'll see a merge block banner in the "Checks" section with a message describing which threshold was not met. For example: + +* "Coverage 22.0% is below minimum 50.0%": your pull request branch coverage is below the minimum coverage percentage configured in the ruleset. +* "Coverage decreased by 2.5%, maximum allowed drop is 1.0%": your changes caused coverage to drop by more than the permitted amount relative to the default branch. + +To unblock your pull request, you need to add or modify tests so that more of the codebase is executed: + +1. Review the coverage summary comment on your pull request to identify which files or areas lack coverage. +1. Add or update tests to increase execution coverage. +1. Push your changes. The coverage check will re-run automatically. + ## Next steps Reduce technical debt by fixing findings in recently changed files. See [AUTOTITLE](/code-security/code-quality/tutorials/improve-recent-merges). diff --git a/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md b/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md index fc6b92ca6f82..ddfa3d8746de 100644 --- a/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md +++ b/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md @@ -212,6 +212,20 @@ If your repositories are configured with {% data variables.product.prodname_code For more information, see [AUTOTITLE](/code-security/code-quality/concepts/about-code-quality) and [AUTOTITLE](/code-security/code-quality/how-tos/set-pr-thresholds). +## Restrict code coverage + +> [!NOTE] +> This feature is in {% data variables.release-phases.public_preview %} and subject to change. + +If your repository has {% data variables.product.prodname_code_quality %} enabled and code coverage data is being uploaded, you can use rulesets to prevent pull requests from being merged based on code coverage thresholds. For more information about uploading coverage data, see [AUTOTITLE](/code-security/how-tos/maintain-quality-code/set-up-code-coverage). + +This rule blocks a pull request from being merged when either of two code coverage thresholds is not met: + +* **Minimum coverage percentage**: the aggregated code coverage for the pull request branch is below the configured percentage. +* **Maximum coverage drop**: code coverage drops by more than the configured number of percentage points relative to the default branch. + +For how to configure the thresholds, the prerequisite for uploading coverage data, and how to roll the rule out safely, see [AUTOTITLE](/code-security/how-tos/maintain-quality-code/restrict-code-coverage). + {% endif %} {% ifversion repo-rules-required-workflows %} From 83e5755d31a64b3f636ff75f19ccc86170d058a3 Mon Sep 17 00:00:00 2001 From: hubwriter Date: Tue, 30 Jun 2026 16:38:12 +0100 Subject: [PATCH 2/6] Copilot CLI: Update session sharing options (#61971) --- .../copilot-cli/use-copilot-cli/chronicle.md | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/content/copilot/how-tos/copilot-cli/use-copilot-cli/chronicle.md b/content/copilot/how-tos/copilot-cli/use-copilot-cli/chronicle.md index eb4fbdf5a07f..3702153baed8 100644 --- a/content/copilot/how-tos/copilot-cli/use-copilot-cli/chronicle.md +++ b/content/copilot/how-tos/copilot-cli/use-copilot-cli/chronicle.md @@ -49,9 +49,20 @@ To remame a session: ## Sharing a session -You can save the content of the current session as either a Markdown file or a private gist on {% data variables.product.prodname_dotcom_the_website %}. This allows you to share your prompts and {% data variables.product.prodname_copilot_short %}'s responses with others, or store a record of your work outside of the CLI. +You can share the content of the current session as a shareable link to the session on {% data variables.product.prodname_dotcom_the_website %}, a Markdown file, an interactive HTML file, or a private gist on {% data variables.product.prodname_dotcom_the_website %}. This allows you to share your prompts and {% data variables.product.prodname_copilot_short %}'s responses with others, or store a record of your work outside of the CLI. -To share a session as a gist, type the following in an interactive session: +> [!NOTE] +> You can use `/export` as an alias for `/share` in any of the commands below. + +To share the session to {% data variables.product.github %} and print a shareable link, type the following in an interactive session: + +```copilot copy +/share +``` + +To stop sharing the session, type `/share off`. + +To share a session as a gist, type: ```copilot copy /share gist @@ -65,6 +76,19 @@ To export the session conversation as a Markdown file, type: If you don't specify a file path, the Markdown file is saved in the current working directory with the name `copilot-session-SESSIONID.md`. +> [!NOTE] +> Gists are not available to {% data variables.product.prodname_emus %}, or if you use {% data variables.product.prodname_ghe_cloud %} with data residency (*.ghe.com). + +To export the session as an interactive HTML file, type: + +```copilot copy +/share html [PATH-TO-FILE] +``` + +As with Markdown export, if you don't specify a file path the file is saved in the current working directory, with the name `copilot-session-SESSIONID.html`. + +If you have used the `/research` slash command in the current session, you can also use the `/share` command to share a research report. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/research#viewing-and-sharing-a-research-report). + ## Using the `/chronicle` slash command The `/chronicle` slash command provides a set of subcommands that generate specific types of insights from your session history. While you can ask {% data variables.product.prodname_copilot_short %} free-form questions about your sessions at any time, `/chronicle` subcommands provide a quick way to get specific insights. From 90cf8f17690dfb3c10541ecb445e58a51c394a82 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Tue, 30 Jun 2026 09:46:29 -0700 Subject: [PATCH 3/6] Use .rc chatops to confirm GHES deprecation date and DRI in Step 1 (#61982) Co-authored-by: Tim Reimherr <16481702+timreimherr@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ghes-releases/lib/deprecation-steps.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ghes-releases/lib/deprecation-steps.md b/src/ghes-releases/lib/deprecation-steps.md index bcf03f1507c7..1a4f7606a65b 100644 --- a/src/ghes-releases/lib/deprecation-steps.md +++ b/src/ghes-releases/lib/deprecation-steps.md @@ -24,11 +24,16 @@ Throughout, `{{ release-number }}` stands for the version being deprecated. When ## Step 1: Confirm the deprecation date -Look up `{{ release-number }}` in the [release date list](https://github.com/github/enterprise-releases/blob/master/releases.json), find the corresponding `prp` owner, and draft a short Slack message asking them to confirm the deprecation date. +The release controller's Slack chatops are the authoritative source for both the deprecation date and the DRI (directly responsible individual): -🛑 **HUMAN**: Send a Slack message. If there is no `prp` owner, ask in #docs-content-enterprise or #ghes-releases instead. +* `.rc get-cycle {{ release-number }}` returns the release cycle for `{{ release-number }}`, including the deprecation date. +* `.rc release-dates` returns the current DRI for each release. Run it in either `#ghes-releases` or `#ghes-release-ops`. -* If the date is being pushed out, ask the `prp` to update the release date list, update this issue's target date, and pause until the new date arrives. +Draft both chatops and a follow-up confirmation message for the human, who runs the chatops in Slack and posts the confirmation. Cross-check the date returned by `.rc get-cycle` against the one in this issue's title and in `src/ghes-releases/lib/enterprise-dates.json`. + +🛑 **HUMAN**: Run `.rc get-cycle {{ release-number }}` and `.rc release-dates` in `#ghes-releases` (or `#ghes-release-ops`). Post a short message in `#ghes-releases` `@`-mentioning the DRI returned by `.rc release-dates` asking them to confirm the deprecation date, and add a comment on this issue linking to that Slack message for posterity. If `.rc release-dates` doesn't return a DRI for `{{ release-number }}`, ask in `#docs-content-enterprise` or `#ghes-releases` instead. + +* If the date is being pushed out, ask the DRI to update the [release date list](https://github.com/github/enterprise-releases/blob/master/releases.json), update this issue's target date, and pause until the new date arrives. * The release date list is often not updated. If it isn't, our copy in `src/ghes-releases/lib/enterprise-dates.json` may also be wrong. You fix that in Step 6. ## Step 2: Remove the version from the github/docs-content release tracker From 5eaa04c3c97e4bf0430268ad1d29ed489d6a5aa2 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Tue, 30 Jun 2026 09:46:42 -0700 Subject: [PATCH 4/6] Add RenderedHTML foundation for removing dangerouslySetInnerHTML (#61956) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package-lock.json | 91 +++++++++---------- package.json | 1 + .../ui/MarkdownContent/MarkdownContent.tsx | 44 +-------- .../ui/MarkdownContent/markdownComponents.tsx | 44 +++++++++ .../ui/RenderedHTML/RenderedHTML.tsx | 48 ++++++++++ src/frame/components/ui/RenderedHTML/index.ts | 3 + .../ui/RenderedHTML/render-html-string.ts | 17 ++++ .../ui/RenderedHTML/tests/rendered-html.ts | 81 +++++++++++++++++ 8 files changed, 240 insertions(+), 89 deletions(-) create mode 100644 src/frame/components/ui/MarkdownContent/markdownComponents.tsx create mode 100644 src/frame/components/ui/RenderedHTML/RenderedHTML.tsx create mode 100644 src/frame/components/ui/RenderedHTML/index.ts create mode 100644 src/frame/components/ui/RenderedHTML/render-html-string.ts create mode 100644 src/frame/components/ui/RenderedHTML/tests/rendered-html.ts diff --git a/package-lock.json b/package-lock.json index 6b903418d312..8e35a6e3a80f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "flat": "^6.0.1", "github-slugger": "^2.0.0", "glob": "13.0.2", + "hast-util-from-html": "^2.0.3", "hast-util-from-parse5": "^8.0.3", "hast-util-to-jsx-runtime": "^2.3.6", "hast-util-to-string": "^3.0.1", @@ -7834,18 +7835,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cheerio/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/cheerio/node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -8780,6 +8769,18 @@ "version": "1.1.1", "license": "ISC" }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -10602,6 +10603,36 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html/node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/hast-util-from-parse5": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", @@ -10702,18 +10733,6 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", "integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==" }, - "node_modules/hast-util-raw/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/hast-util-raw/node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -14764,18 +14783,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -14800,18 +14807,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-parser-stream/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parse5-parser-stream/node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", diff --git a/package.json b/package.json index 36df7e3d1cce..b966c75bf65b 100644 --- a/package.json +++ b/package.json @@ -212,6 +212,7 @@ "flat": "^6.0.1", "github-slugger": "^2.0.0", "glob": "13.0.2", + "hast-util-from-html": "^2.0.3", "hast-util-from-parse5": "^8.0.3", "hast-util-to-jsx-runtime": "^2.3.6", "hast-util-to-string": "^3.0.1", diff --git a/src/frame/components/ui/MarkdownContent/MarkdownContent.tsx b/src/frame/components/ui/MarkdownContent/MarkdownContent.tsx index ef2102c7aaef..77acd14a2abc 100644 --- a/src/frame/components/ui/MarkdownContent/MarkdownContent.tsx +++ b/src/frame/components/ui/MarkdownContent/MarkdownContent.tsx @@ -1,14 +1,11 @@ import { memo, ReactNode } from 'react' -import type { ComponentProps, JSX } from 'react' +import type { JSX } from 'react' import { Fragment, jsx, jsxs } from 'react/jsx-runtime' -import { toJsxRuntime, type Components } from 'hast-util-to-jsx-runtime' +import { toJsxRuntime } from 'hast-util-to-jsx-runtime' import type { Root as HastRoot } from 'hast' import cx from 'classnames' -import { CopyButton } from '@/frame/components/CopyButton' -import { CodeTabsGroup } from '@/frame/components/CodeTabsGroup' -import { ToggleableContent } from '@/tools/components/ToggleableContent' -import { isToggleClass } from '@/tools/components/SelectionContext' +import { markdownComponents } from './markdownComponents' import styles from './MarkdownContent.module.scss' export type MarkdownContentPropsT = { @@ -18,41 +15,6 @@ export type MarkdownContentPropsT = { as?: keyof JSX.IntrinsicElements } -// Map specific elements in the HTML AST to interactive React components instead -// of inert markup enhanced by post-hydration DOM mutation (#6619). This only -// applies to the hast rendering path; the dangerouslySetInnerHTML string path is -// untouched. The same map runs during SSR and on the client, so hydration matches. -const markdownComponents = { - button(props: ComponentProps<'button'>) { - const classes = String(props.className || '').split(/\s+/) - if (classes.includes('js-btn-copy')) { - return - } - return