diff --git a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs index 6470701d7a..9c6d33bf85 100644 --- a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs +++ b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Aspire.Dashboard.Extensions; @@ -7,12 +7,15 @@ internal static class FluentUIExtensions { public static Dictionary GetClipboardCopyAdditionalAttributes(string? text, string? precopy, string? postcopy, params (string Attribute, object Value)[] additionalAttributes) { + // No onclick attribute is added here. The CSP restricts inline scripts, including onclick. + // Instead, a click event listener is added to the document and clicking the button is bubbled up to the event. + // The document click listener looks for a button element and these attributes. var attributes = new Dictionary { { "data-text", text ?? string.Empty }, { "data-precopy", precopy ?? string.Empty }, { "data-postcopy", postcopy ?? string.Empty }, - { "onclick", $"buttonCopyTextToClipboard(this)" } + { "data-copybutton", "true" } }; foreach (var (attribute, value) in additionalAttributes) diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index 9624bb5f6f..b2121ed8ff 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -14,6 +14,15 @@ if (firstUndefinedElement) { document.body.classList.remove("before-upgrade"); } +// Register a global click event listener to handle copy button clicks. +// Required because an "onclick" attribute is denied by CSP. +document.addEventListener("click", function (e) { + if (e.target.type === "button" && e.target.getAttribute("data-copybutton")) { + buttonCopyTextToClipboard(e.target); + e.stopPropagation(); + } +}); + let isScrolledToContent = false; let lastScrollHeight = null;