From 74c7b10bc710243d9d9fb470f9da0417ef16b004 Mon Sep 17 00:00:00 2001
From: Chris Lu
Date: Sun, 25 Jan 2026 23:09:14 -0800
Subject: [PATCH 1/2] Fix Chrome dialog auto-dismiss with Bootstrap modals
- Add modal-alerts.js library with Bootstrap modal replacements
- Replace all 15 confirm() calls with showConfirm/showDeleteConfirm
- Auto-override window.alert() for all alert() calls
- Fixes Chrome 132+ aggressively blocking native dialogs
---
weed/admin/static/js/modal-alerts.js | 302 ++++++++++++++++++
weed/admin/view/app/cluster_ec_shards.templ | 4 +-
.../admin/view/app/cluster_ec_shards_templ.go | 2 +-
weed/admin/view/app/cluster_ec_volumes.templ | 4 +-
.../view/app/cluster_ec_volumes_templ.go | 2 +-
weed/admin/view/app/collection_details.templ | 4 +-
.../view/app/collection_details_templ.go | 2 +-
weed/admin/view/app/file_browser.templ | 4 +-
weed/admin/view/app/file_browser_templ.go | 2 +-
weed/admin/view/app/maintenance_config.templ | 4 +-
.../view/app/maintenance_config_schema.templ | 4 +-
.../app/maintenance_config_schema_templ.go | 2 +-
.../view/app/maintenance_config_templ.go | 2 +-
weed/admin/view/app/maintenance_workers.templ | 4 +-
.../view/app/maintenance_workers_templ.go | 2 +-
weed/admin/view/app/object_store_users.templ | 10 +-
.../view/app/object_store_users_templ.go | 2 +-
weed/admin/view/app/policies.templ | 6 +-
weed/admin/view/app/policies_templ.go | 2 +-
weed/admin/view/app/service_accounts.templ | 4 +-
weed/admin/view/app/service_accounts_templ.go | 2 +-
weed/admin/view/app/task_config.templ | 4 +-
weed/admin/view/app/task_config_schema.templ | 4 +-
.../view/app/task_config_schema_templ.go | 2 +-
weed/admin/view/app/task_config_templ.go | 2 +-
weed/admin/view/app/task_config_templ.templ | 4 +-
.../admin/view/app/task_config_templ_templ.go | 2 +-
weed/admin/view/app/task_detail.templ | 4 +-
weed/admin/view/app/task_detail_templ.go | 2 +-
weed/admin/view/layout/layout.templ | 2 +
weed/admin/view/layout/layout_templ.go | 8 +-
31 files changed, 357 insertions(+), 47 deletions(-)
create mode 100644 weed/admin/static/js/modal-alerts.js
diff --git a/weed/admin/static/js/modal-alerts.js b/weed/admin/static/js/modal-alerts.js
new file mode 100644
index 000000000..612bc1961
--- /dev/null
+++ b/weed/admin/static/js/modal-alerts.js
@@ -0,0 +1,302 @@
+/**
+ * Modal Alerts - Bootstrap Modal replacement for native alert() and confirm()
+ * Fixes Chrome auto-dismiss issue with native dialogs
+ *
+ * Usage:
+ * showAlert('Message', 'success');
+ * showConfirm('Delete this?', function() { });
+ */
+
+(function() {
+ 'use strict';
+
+ // Create and inject modal HTML into page if not already present
+ function ensureModalsExist() {
+ if (document.getElementById('globalAlertModal')) {
+ return; // Already exists
+ }
+
+ const modalsHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
Are you sure you want to delete this item?
+
+
This action cannot be undone.
+
+
+
+
+
+ `;
+
+ // Inject modals at end of body
+ document.body.insertAdjacentHTML('beforeend', modalsHTML);
+ }
+
+ /**
+ * Show an alert message using Bootstrap modal
+ * @param {string} message - The message to display
+ * @param {string} type - Type: 'success', 'error', 'warning', 'info' (default: 'info')
+ * @param {string} title - Optional custom title
+ */
+ window.showAlert = function(message, type, title) {
+ ensureModalsExist();
+
+ const modal = document.getElementById('globalAlertModal');
+ const header = document.getElementById('globalAlertModalHeader');
+ const titleEl = document.getElementById('globalAlertModalTitle');
+ const bodyEl = document.getElementById('globalAlertModalBody');
+ const iconEl = document.getElementById('globalAlertModalIcon');
+
+ // Configuration for different types
+ const types = {
+ 'success': {
+ title: 'Success',
+ icon: 'fa-check-circle',
+ headerClass: 'bg-success text-white',
+ btnClose: 'btn-close-white'
+ },
+ 'error': {
+ title: 'Error',
+ icon: 'fa-exclamation-triangle',
+ headerClass: 'bg-danger text-white',
+ btnClose: 'btn-close-white'
+ },
+ 'warning': {
+ title: 'Warning',
+ icon: 'fa-exclamation-circle',
+ headerClass: 'bg-warning text-dark',
+ btnClose: ''
+ },
+ 'info': {
+ title: 'Notice',
+ icon: 'fa-info-circle',
+ headerClass: 'bg-info text-white',
+ btnClose: 'btn-close-white'
+ }
+ };
+
+ const config = types[type] || types['info'];
+
+ // Update header styling
+ header.className = 'modal-header ' + config.headerClass;
+ const closeBtn = header.querySelector('.btn-close');
+ closeBtn.className = 'btn-close ' + config.btnClose;
+
+ // Update icon
+ iconEl.className = 'fas ' + config.icon + ' me-2';
+
+ // Update title
+ titleEl.textContent = title || config.title;
+
+ // Update body - support HTML or text
+ if (message.includes('<')) {
+ bodyEl.innerHTML = message;
+ } else {
+ bodyEl.innerHTML = '' + escapeHtml(message) + '
';
+ }
+
+ // Show modal
+ const bsModal = new bootstrap.Modal(modal);
+ bsModal.show();
+ };
+
+ /**
+ * Show a confirmation dialog using Bootstrap modal
+ * @param {string} message - The confirmation message
+ * @param {function} onConfirm - Callback function if user confirms
+ * @param {function} onCancel - Optional callback function if user cancels
+ * @param {string} title - Optional custom title
+ */
+ window.showConfirm = function(message, onConfirm, onCancel, title) {
+ ensureModalsExist();
+
+ const modalEl = document.getElementById('globalConfirmModal');
+ const bodyEl = document.getElementById('globalConfirmModalBody');
+ const titleEl = document.getElementById('globalConfirmModalLabel').querySelector('span');
+ const okBtn = document.getElementById('globalConfirmOkBtn');
+ const cancelBtn = document.getElementById('globalConfirmCancelBtn');
+
+ // Set title if provided
+ if (title) {
+ if (titleEl) {
+ titleEl.textContent = title;
+ } else {
+ document.getElementById('globalConfirmModalLabel').insertAdjacentHTML('beforeend', '' + escapeHtml(title) + '');
+ }
+ }
+
+ // Set message
+ if (message.includes('<')) {
+ bodyEl.innerHTML = message;
+ } else {
+ bodyEl.innerHTML = '' + escapeHtml(message) + '
';
+ }
+
+ // Remove old event listeners by cloning buttons
+ const newOkBtn = okBtn.cloneNode(true);
+ const newCancelBtn = cancelBtn.cloneNode(true);
+ okBtn.parentNode.replaceChild(newOkBtn, okBtn);
+ cancelBtn.parentNode.replaceChild(newCancelBtn, cancelBtn);
+
+ const modal = new bootstrap.Modal(modalEl);
+
+ // Add event listeners
+ newOkBtn.addEventListener('click', function() {
+ modal.hide();
+ if (typeof onConfirm === 'function') {
+ onConfirm();
+ }
+ });
+
+ newCancelBtn.addEventListener('click', function() {
+ modal.hide();
+ if (typeof onCancel === 'function') {
+ onCancel();
+ }
+ });
+
+ modal.show();
+ };
+
+ /**
+ * Show a delete confirmation dialog
+ * @param {string} itemName - Name of the item to delete
+ * @param {function} onConfirm - Callback function if user confirms deletion
+ * @param {string} message - Optional custom message (default: "Are you sure you want to delete this item?")
+ */
+ window.showDeleteConfirm = function(itemName, onConfirm, message) {
+ ensureModalsExist();
+
+ const modalEl = document.getElementById('globalDeleteModal');
+ const messageEl = document.getElementById('globalDeleteModalMessage');
+ const itemNameEl = document.getElementById('globalDeleteModalItemName');
+ const confirmBtn = document.getElementById('globalDeleteConfirmBtn');
+
+ // Set custom message if provided
+ if (message) {
+ messageEl.textContent = message;
+ } else {
+ messageEl.textContent = 'Are you sure you want to delete this item?';
+ }
+
+ // Set item name
+ itemNameEl.textContent = itemName;
+
+ // Remove old event listener by cloning button
+ const newConfirmBtn = confirmBtn.cloneNode(true);
+ confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
+
+ const modal = new bootstrap.Modal(modalEl);
+
+ // Add new event listener
+ newConfirmBtn.addEventListener('click', function() {
+ modal.hide();
+ if (typeof onConfirm === 'function') {
+ onConfirm();
+ }
+ });
+
+ modal.show();
+ };
+
+ /**
+ * Escape HTML to prevent XSS
+ */
+ function escapeHtml(text) {
+ const map = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+ return text.replace(/[&<>"']/g, function(m) { return map[m]; });
+ }
+
+ // Auto-initialize on DOMContentLoaded
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', ensureModalsExist);
+ } else {
+ ensureModalsExist();
+ }
+
+ /**
+ * AUTOMATIC OVERRIDE of native alert()
+ * This makes ALL existing alert() calls automatically use Bootstrap modals
+ */
+ window.alert = function(message) {
+ // Auto-detect message type from content
+ let type = 'info';
+ const msgLower = (message || '').toLowerCase();
+
+ if (msgLower.includes('success') || msgLower.includes('created') || msgLower.includes('updated') || msgLower.includes('saved')) {
+ type = 'success';
+ } else if (msgLower.includes('error') || msgLower.includes('failed') || msgLower.includes('invalid') || msgLower.includes('cannot')) {
+ type = 'error';
+ } else if (msgLower.includes('warning') || msgLower.includes('please') || msgLower.includes('required')) {
+ type = 'warning';
+ }
+
+ showAlert(message, type);
+ };
+
+ console.log('Modal Alerts library loaded - native alert() overridden');
+ console.log('For confirm(), use showConfirm() or showDeleteConfirm() instead of native confirm()');
+})();
diff --git a/weed/admin/view/app/cluster_ec_shards.templ b/weed/admin/view/app/cluster_ec_shards.templ
index 19f6fd2d6..d7180f2bb 100644
--- a/weed/admin/view/app/cluster_ec_shards.templ
+++ b/weed/admin/view/app/cluster_ec_shards.templ
@@ -387,7 +387,7 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
// Get data from the button element (not the icon inside it)
const button = event.target.closest('button');
const volumeId = button.getAttribute('data-volume-id');
- if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {
+ showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {
fetch(`/api/storage/volumes/${volumeId}/repair`, {
method: 'POST',
headers: {
@@ -406,7 +406,7 @@ templ ClusterEcShards(data dash.ClusterEcShardsData) {
.catch(error => {
alert('Error: ' + error.message);
});
- }
+ });
}
}
diff --git a/weed/admin/view/app/cluster_ec_shards_templ.go b/weed/admin/view/app/cluster_ec_shards_templ.go
index b7c169d1e..31cf8f9bd 100644
--- a/weed/admin/view/app/cluster_ec_shards_templ.go
+++ b/weed/admin/view/app/cluster_ec_shards_templ.go
@@ -663,7 +663,7 @@ func ClusterEcShards(data dash.ClusterEcShardsData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/cluster_ec_volumes.templ b/weed/admin/view/app/cluster_ec_volumes.templ
index 6e94443ae..de0f32168 100644
--- a/weed/admin/view/app/cluster_ec_volumes.templ
+++ b/weed/admin/view/app/cluster_ec_volumes.templ
@@ -378,7 +378,7 @@ templ ClusterEcVolumes(data dash.ClusterEcVolumesData) {
function repairVolume(event) {
const volumeId = event.target.closest('button').getAttribute('data-volume-id');
- if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {
+ showConfirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`, function() {
fetch(`/api/storage/ec-volumes/${volumeId}/repair`, {
method: 'POST',
headers: {
@@ -402,7 +402,7 @@ templ ClusterEcVolumes(data dash.ClusterEcVolumesData) {
.catch(error => {
alert('Error: ' + error.message);
});
- }
+ });
}
}
diff --git a/weed/admin/view/app/cluster_ec_volumes_templ.go b/weed/admin/view/app/cluster_ec_volumes_templ.go
index 9103607a8..1c83c51ba 100644
--- a/weed/admin/view/app/cluster_ec_volumes_templ.go
+++ b/weed/admin/view/app/cluster_ec_volumes_templ.go
@@ -757,7 +757,7 @@ func ClusterEcVolumes(data dash.ClusterEcVolumesData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/collection_details.templ b/weed/admin/view/app/collection_details.templ
index 296839b93..46075613c 100644
--- a/weed/admin/view/app/collection_details.templ
+++ b/weed/admin/view/app/collection_details.templ
@@ -372,10 +372,10 @@ templ CollectionDetails(data dash.CollectionDetailsData) {
// Repair EC Volume
function repairEcVolume(event) {
const volumeId = event.target.closest('button').getAttribute('data-volume-id');
- if (confirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`)) {
+ showConfirm(`Are you sure you want to repair missing shards for EC volume ${volumeId}?`, function() {
// TODO: Implement repair functionality
alert('Repair functionality will be implemented soon.');
- }
+ });
}
}
\ No newline at end of file
diff --git a/weed/admin/view/app/collection_details_templ.go b/weed/admin/view/app/collection_details_templ.go
index f2ff0ab13..762f3c391 100644
--- a/weed/admin/view/app/collection_details_templ.go
+++ b/weed/admin/view/app/collection_details_templ.go
@@ -575,7 +575,7 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/file_browser.templ b/weed/admin/view/app/file_browser.templ
index 6ae00b81b..a88f00488 100644
--- a/weed/admin/view/app/file_browser.templ
+++ b/weed/admin/view/app/file_browser.templ
@@ -365,9 +365,9 @@ templ FileBrowser(data dash.FileBrowserData) {
showFileProperties(path);
break;
case 'delete':
- if (confirm('Are you sure you want to delete "' + path + '"?')) {
+ showDeleteConfirm(path, function() {
deleteFile(path);
- }
+ }, 'Are you sure you want to delete this file?');
break;
}
});
diff --git a/weed/admin/view/app/file_browser_templ.go b/weed/admin/view/app/file_browser_templ.go
index 4a66ff026..ca787195c 100644
--- a/weed/admin/view/app/file_browser_templ.go
+++ b/weed/admin/view/app/file_browser_templ.go
@@ -700,7 +700,7 @@ func FileBrowser(data dash.FileBrowserData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "\">Preparing upload...
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "\">Preparing upload...
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/maintenance_config.templ b/weed/admin/view/app/maintenance_config.templ
index 65ef565af..4110486ba 100644
--- a/weed/admin/view/app/maintenance_config.templ
+++ b/weed/admin/view/app/maintenance_config.templ
@@ -251,7 +251,7 @@ templ MaintenanceConfig(data *maintenance.MaintenanceConfigData) {
}
function resetToDefaults() {
- if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {
+ showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {
// Reset form to defaults (matching DefaultMaintenanceConfig values)
document.getElementById('enabled').checked = false;
document.getElementById('scanInterval').value = '30';
@@ -261,7 +261,7 @@ templ MaintenanceConfig(data *maintenance.MaintenanceConfigData) {
document.getElementById('maxRetries').value = '3';
document.getElementById('retryDelay').value = '15';
document.getElementById('taskRetention').value = '7';
- }
+ });
}
}
\ No newline at end of file
diff --git a/weed/admin/view/app/maintenance_config_schema.templ b/weed/admin/view/app/maintenance_config_schema.templ
index ee89cab64..3e1d6ee1f 100644
--- a/weed/admin/view/app/maintenance_config_schema.templ
+++ b/weed/admin/view/app/maintenance_config_schema.templ
@@ -179,7 +179,7 @@ templ MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *m
}
function resetToDefaults() {
- if (confirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.')) {
+ showConfirm('Are you sure you want to reset to default configuration? This will overwrite your current settings.', function() {
fetch('/maintenance/config/defaults', {
method: 'POST',
headers: {
@@ -199,7 +199,7 @@ templ MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *m
console.error('Error:', error);
alert('Error resetting configuration: ' + error.message);
});
- }
+ });
}
}
diff --git a/weed/admin/view/app/maintenance_config_schema_templ.go b/weed/admin/view/app/maintenance_config_schema_templ.go
index b7046f3f9..b4d806fb6 100644
--- a/weed/admin/view/app/maintenance_config_schema_templ.go
+++ b/weed/admin/view/app/maintenance_config_schema_templ.go
@@ -46,7 +46,7 @@ func MaintenanceConfigSchema(data *maintenance.MaintenanceConfigData, schema *ma
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Reclaims disk space by removing deleted files from volumes.
ConfigureRedistributes volumes across servers to optimize storage utilization.
ConfigureConverts volumes to erasure coded format for improved durability.
Configure ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Reclaims disk space by removing deleted files from volumes.
ConfigureRedistributes volumes across servers to optimize storage utilization.
ConfigureConverts volumes to erasure coded format for improved durability.
Configure ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/maintenance_config_templ.go b/weed/admin/view/app/maintenance_config_templ.go
index 45e9b8ef1..75017b31d 100644
--- a/weed/admin/view/app/maintenance_config_templ.go
+++ b/weed/admin/view/app/maintenance_config_templ.go
@@ -273,7 +273,7 @@ func MaintenanceConfig(data *maintenance.MaintenanceConfigData) templ.Component
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/maintenance_workers.templ b/weed/admin/view/app/maintenance_workers.templ
index 00748e550..eb95c0d55 100644
--- a/weed/admin/view/app/maintenance_workers.templ
+++ b/weed/admin/view/app/maintenance_workers.templ
@@ -302,7 +302,7 @@ templ MaintenanceWorkers(data *dash.MaintenanceWorkersData) {
function pauseWorker(event) {
const workerID = event.target.closest('button').getAttribute('data-worker-id');
- if (confirm('Are you sure you want to pause this worker?')) {
+ showConfirm('Are you sure you want to pause this worker?', function() {
fetch('/api/maintenance/workers/' + workerID + '/pause', {
method: 'POST'
})
@@ -318,7 +318,7 @@ templ MaintenanceWorkers(data *dash.MaintenanceWorkersData) {
console.error('Error pausing worker:', error);
alert('Failed to pause worker');
});
- }
+ });
}
function formatDuration(nanoseconds) {
diff --git a/weed/admin/view/app/maintenance_workers_templ.go b/weed/admin/view/app/maintenance_workers_templ.go
index f1fd13ebb..12378b532 100644
--- a/weed/admin/view/app/maintenance_workers_templ.go
+++ b/weed/admin/view/app/maintenance_workers_templ.go
@@ -390,7 +390,7 @@ func MaintenanceWorkers(data *dash.MaintenanceWorkersData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/object_store_users.templ b/weed/admin/view/app/object_store_users.templ
index b3b7d92de..e80b9e7e7 100644
--- a/weed/admin/view/app/object_store_users.templ
+++ b/weed/admin/view/app/object_store_users.templ
@@ -802,7 +802,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
// Delete user function
async function deleteUser(username) {
- if (confirm(`Are you sure you want to delete user "${username}"? This action cannot be undone.`)) {
+ showDeleteConfirm(username, async function() {
try {
const response = await fetch(`/api/users/${username}`, {
method: 'DELETE'
@@ -819,6 +819,9 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
console.error('Error deleting user:', error);
showErrorMessage('Failed to delete user: ' + error.message);
}
+ }, 'Are you sure you want to delete this user? This action cannot be undone.');
+ }
+ }
}
}
@@ -1102,7 +1105,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
// Delete access key
async function deleteAccessKey(username, accessKey) {
- if (confirm('Are you sure you want to delete this access key?')) {
+ showDeleteConfirm(accessKey, async function() {
try {
const response = await fetch(`/api/users/${username}/access-keys/${accessKey}`, {
method: 'DELETE'
@@ -1121,6 +1124,9 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
console.error('Error deleting access key:', error);
showErrorMessage('Failed to delete access key: ' + error.message);
}
+ }, 'Are you sure you want to delete this access key?');
+ }
+ }
}
}
diff --git a/weed/admin/view/app/object_store_users_templ.go b/weed/admin/view/app/object_store_users_templ.go
index f03337207..08cc858d1 100644
--- a/weed/admin/view/app/object_store_users_templ.go
+++ b/weed/admin/view/app/object_store_users_templ.go
@@ -193,7 +193,7 @@ func ObjectStoreUsers(data dash.ObjectStoreUsersData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "Access Keys for
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "Access Keys for
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/policies.templ b/weed/admin/view/app/policies.templ
index e613d535e..a61ac6b55 100644
--- a/weed/admin/view/app/policies.templ
+++ b/weed/admin/view/app/policies.templ
@@ -635,7 +635,7 @@ templ Policies(data dash.PoliciesData) {
}
function deletePolicy(policyName) {
- if (confirm('Are you sure you want to delete policy "' + policyName + '"?')) {
+ showDeleteConfirm(policyName, function() {
fetch('/api/object-store/policies/' + encodeURIComponent(policyName), {
method: 'DELETE'
})
@@ -643,7 +643,7 @@ templ Policies(data dash.PoliciesData) {
.then(data => {
if (data.success) {
alert('Policy deleted successfully!');
- location.reload(); // Refresh the page
+ location.reload();
} else {
alert('Error deleting policy: ' + (data.error || 'Unknown error'));
}
@@ -652,7 +652,7 @@ templ Policies(data dash.PoliciesData) {
console.error('Error:', error);
alert('Error deleting policy: ' + error.message);
});
- }
+ }, 'Are you sure you want to delete this policy?');
}
}
\ No newline at end of file
diff --git a/weed/admin/view/app/policies_templ.go b/weed/admin/view/app/policies_templ.go
index 89aa83db5..30f92e158 100644
--- a/weed/admin/view/app/policies_templ.go
+++ b/weed/admin/view/app/policies_templ.go
@@ -193,7 +193,7 @@ func Policies(data dash.PoliciesData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "Loading...
Loading policy...
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "Loading...
Loading policy...
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/service_accounts.templ b/weed/admin/view/app/service_accounts.templ
index 5c85ac3ce..f0bb12b4c 100644
--- a/weed/admin/view/app/service_accounts.templ
+++ b/weed/admin/view/app/service_accounts.templ
@@ -373,7 +373,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
}
async function deleteSA(id) {
- if (confirm('Are you sure you want to delete this service account? This action cannot be undone.')) {
+ showDeleteConfirm(id, async function() {
try {
const response = await fetch(`/api/service-accounts/${id}`, {
method: 'DELETE'
@@ -390,7 +390,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {
console.error('Error deleting service account:', error);
showErrorMessage('Failed to delete: ' + error.message);
}
- }
+ }, 'Are you sure you want to delete this service account? This action cannot be undone.');
}
async function handleCreateServiceAccount() {
diff --git a/weed/admin/view/app/service_accounts_templ.go b/weed/admin/view/app/service_accounts_templ.go
index d4fa05b5e..960152edf 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
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
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
}
diff --git a/weed/admin/view/app/task_config.templ b/weed/admin/view/app/task_config.templ
index 81e089de6..41034cd09 100644
--- a/weed/admin/view/app/task_config.templ
+++ b/weed/admin/view/app/task_config.templ
@@ -104,13 +104,13 @@ templ TaskConfig(data *maintenance.TaskConfigData) {
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/task_config_templ.templ b/weed/admin/view/app/task_config_templ.templ
index 010f5782c..37d236868 100644
--- a/weed/admin/view/app/task_config_templ.templ
+++ b/weed/admin/view/app/task_config_templ.templ
@@ -121,9 +121,9 @@ templ TaskConfigTempl(data *TaskConfigTemplData) {
// Reset form function
function resetForm() {
- if (confirm('Are you sure you want to reset all changes?')) {
+ showConfirm('Are you sure you want to reset all changes?', function() {
location.reload();
- }
+ });
}
// Test configuration function
diff --git a/weed/admin/view/app/task_config_templ_templ.go b/weed/admin/view/app/task_config_templ_templ.go
index e037eb1cf..5b5d261b0 100644
--- a/weed/admin/view/app/task_config_templ_templ.go
+++ b/weed/admin/view/app/task_config_templ_templ.go
@@ -101,7 +101,7 @@ func TaskConfigTempl(data *TaskConfigTemplData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/task_detail.templ b/weed/admin/view/app/task_detail.templ
index 6045a5301..784e6dddf 100644
--- a/weed/admin/view/app/task_detail.templ
+++ b/weed/admin/view/app/task_detail.templ
@@ -1056,7 +1056,7 @@ templ TaskDetail(data *maintenance.TaskDetailData) {
}
function cancelTask(taskId) {
- if (confirm('Are you sure you want to cancel this task?')) {
+ showConfirm('Are you sure you want to cancel this task?', function() {
fetch(`/api/maintenance/tasks/${taskId}/cancel`, {
method: 'POST',
headers: {
@@ -1076,7 +1076,7 @@ templ TaskDetail(data *maintenance.TaskDetailData) {
console.error('Error:', error);
alert('Error cancelling task');
});
- }
+ });
}
function refreshTaskLogs(taskId) {
diff --git a/weed/admin/view/app/task_detail_templ.go b/weed/admin/view/app/task_detail_templ.go
index eec5ba29c..9d403c331 100644
--- a/weed/admin/view/app/task_detail_templ.go
+++ b/weed/admin/view/app/task_detail_templ.go
@@ -1617,7 +1617,7 @@ func TaskDetail(data *maintenance.TaskDetailData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\" onclick=\"exportTaskDetail(this.getAttribute('data-task-id'))\"> Export DetailsLoading logs...
Fetching logs from worker...
Task: | Worker: | Entries:
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\" onclick=\"exportTaskDetail(this.getAttribute('data-task-id'))\"> Export DetailsLoading logs...
Fetching logs from worker...
Task: | Worker: | Entries:
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/layout/layout.templ b/weed/admin/view/layout/layout.templ
index de74892f2..859984ca7 100644
--- a/weed/admin/view/layout/layout.templ
+++ b/weed/admin/view/layout/layout.templ
@@ -357,6 +357,8 @@ templ Layout(c *gin.Context, content templ.Component) {
+
+