From 6bf0c16862baf284cc13276f3bac93311b51f217 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 8 Jan 2026 18:44:36 -0800 Subject: [PATCH] fix admin copy text functions --- weed/admin/static/js/admin.js | 56 +++++++++++++++---- weed/admin/view/app/service_accounts.templ | 42 ++++++++++---- weed/admin/view/app/service_accounts_templ.go | 2 +- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/weed/admin/static/js/admin.js b/weed/admin/static/js/admin.js index 805445024..5d74f6e40 100644 --- a/weed/admin/static/js/admin.js +++ b/weed/admin/static/js/admin.js @@ -660,14 +660,46 @@ function formatDate(date) { return new Date(date).toLocaleString(); } -// Copy text to clipboard -function copyToClipboard(text) { - navigator.clipboard.writeText(text).then(() => { - showAlert('success', 'Copied to clipboard!'); - }).catch(err => { - console.error('Failed to copy text: ', err); +// Copy text to clipboard with fallback for non-secure contexts +function adminCopyToClipboard(text) { + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(() => { + showAlert('success', 'Copied to clipboard!'); + }).catch(err => { + console.error('Failed to copy text: ', err); + fallbackCopyText(text); + }); + } else { + fallbackCopyText(text); + } +} + +function fallbackCopyText(text) { + const textArea = document.createElement("textarea"); + textArea.value = text; + + // Ensure textArea is not visible but part of the DOM + textArea.style.position = "fixed"; + textArea.style.left = "-9999px"; + textArea.style.top = "0"; + document.body.appendChild(textArea); + + textArea.focus(); + textArea.select(); + + try { + const successful = document.execCommand('copy'); + if (successful) { + showAlert('success', 'Copied to clipboard!'); + } else { + showAlert('danger', 'Failed to copy to clipboard'); + } + } catch (err) { + console.error('Fallback copy failed: ', err); showAlert('danger', 'Failed to copy to clipboard'); - }); + } + + document.body.removeChild(textArea); } // Dashboard refresh functionality @@ -2359,7 +2391,7 @@ function createAccessKeysManagementContent(accessKeys) { ${key.access_key} - @@ -2454,7 +2486,7 @@ function showSecretKey(accessKey, secretKey) {
-
@@ -2463,7 +2495,7 @@ function showSecretKey(accessKey, secretKey) {
-
@@ -2487,7 +2519,7 @@ function showNewAccessKeyModal(accessKeyData) {
-
@@ -2496,7 +2528,7 @@ function showNewAccessKeyModal(accessKeyData) {
-
diff --git a/weed/admin/view/app/service_accounts.templ b/weed/admin/view/app/service_accounts.templ index df7e1956d..5c85ac3ce 100644 --- a/weed/admin/view/app/service_accounts.templ +++ b/weed/admin/view/app/service_accounts.templ @@ -270,7 +270,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
-
@@ -280,7 +280,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
-
@@ -474,27 +474,25 @@ templ ServiceAccounts(data dash.ServiceAccountsData) { setTimeout(() => window.location.reload(), 500); } - function copyToClipboard(event, elementId) { + function copyCredentialToClipboard(button, elementId) { const element = document.getElementById(elementId); + const textToCopy = element.value; // Use modern Clipboard API if available - if (navigator.clipboard) { - navigator.clipboard.writeText(element.value).then(() => { - // Success feedback could be added here + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(textToCopy).then(() => { + showSuccessMessage('Copied to clipboard!'); }).catch(err => { console.warn('Clipboard API failed:', err); // Fallback - element.select(); - document.execCommand('copy'); + fallbackCopyTextToClipboard(element); }); } else { - // Fallback for older browsers - element.select(); - document.execCommand('copy'); + // Fallback for older browsers or non-secure contexts + fallbackCopyTextToClipboard(element); } // Visual feedback - const button = event.target.closest('button'); const originalHTML = button.innerHTML; button.innerHTML = ''; @@ -508,6 +506,26 @@ templ ServiceAccounts(data dash.ServiceAccountsData) { }, 1000); } + function fallbackCopyTextToClipboard(element) { + element.select(); + element.setSelectionRange(0, 99999); // For mobile devices + + try { + const successful = document.execCommand('copy'); + if (successful) { + showSuccessMessage('Copied to clipboard!'); + } else { + showErrorMessage('Failed to copy to clipboard'); + } + } catch (err) { + console.error('Fallback copy failed:', err); + showErrorMessage('Failed to copy to clipboard'); + } + + // Clear selection + window.getSelection().removeAllRanges(); + } + function createSADetailsContent(sa) { // Create DOM elements safely to prevent XSS diff --git a/weed/admin/view/app/service_accounts_templ.go b/weed/admin/view/app/service_accounts_templ.go index 3ac8392b2..d4fa05b5e 100644 --- a/weed/admin/view/app/service_accounts_templ.go +++ b/weed/admin/view/app/service_accounts_templ.go @@ -272,7 +272,7 @@ func ServiceAccounts(data dash.ServiceAccountsData) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, " The service account will inherit permissions from this user
Leave empty for no expiration
Service Account Details
Service Account Created Successfully
Important: This is the only time you will see the secret access key. Please save it securely.
AWS CLI Configuration

Use these credentials to configure AWS CLI or SDKs:

Example AWS CLI Usage:
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export AWS_ENDPOINT_URL=http://localhost:8333
# List buckets
aws s3 ls
# Upload a file
aws s3 cp myfile.txt s3://mybucket/
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, " The service account will inherit permissions from this user
Leave empty for no expiration
Service Account Details
Service Account Created Successfully
Important: This is the only time you will see the secret access key. Please save it securely.
AWS CLI Configuration

Use these credentials to configure AWS CLI or SDKs:

Example AWS CLI Usage:
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export AWS_ENDPOINT_URL=http://localhost:8333
# List buckets
aws s3 ls
# Upload a file
aws s3 cp myfile.txt s3://mybucket/
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }