diff --git a/src/backend/src/modules/puterai/AIChatService.js b/src/backend/src/modules/puterai/AIChatService.js index 9bfd6259c7..e1a1050ab7 100644 --- a/src/backend/src/modules/puterai/AIChatService.js +++ b/src/backend/src/modules/puterai/AIChatService.js @@ -336,7 +336,7 @@ class AIChatService extends BaseService { model, error: e, }); - while ( !! error ) { + while ( error ) { const fallback = this.get_fallback_model({ model, tried, }); diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index ddc8358805..adfc2d9d18 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -27,17 +27,17 @@ class PuterAIModule extends AdvancedBase { // TODO: services should govern their own availability instead of // the module deciding what to register - if ( !! config?.services?.['aws-textract']?.aws ) { + if ( config?.services?.['aws-textract']?.aws ) { const { AWSTextractService } = require('./AWSTextractService'); services.registerService('aws-textract', AWSTextractService); } - if ( !! config?.services?.['aws-polly']?.aws ) { + if ( config?.services?.['aws-polly']?.aws ) { const { AWSPollyService } = require('./AWSPollyService'); services.registerService('aws-polly', AWSPollyService); } - if ( !! config?.openai ) { + if ( config?.openai ) { const { OpenAICompletionService } = require('./OpenAICompletionService'); services.registerService('openai-completion', OpenAICompletionService); @@ -45,27 +45,27 @@ class PuterAIModule extends AdvancedBase { services.registerService('openai-image-generation', OpenAIImageGenerationService); } - if ( !! config?.services?.claude ) { + if ( config?.services?.claude ) { const { ClaudeService } = require('./ClaudeService'); services.registerService('claude', ClaudeService); } - if ( !! config?.services?.['together-ai'] ) { + if ( config?.services?.['together-ai'] ) { const { TogetherAIService } = require('./TogetherAIService'); services.registerService('together-ai', TogetherAIService); } - if ( !! config?.services?.['mistral'] ) { + if ( config?.services?.['mistral'] ) { const { MistralAIService } = require('./MistralAIService'); services.registerService('mistral', MistralAIService); } - if ( !! config?.services?.['groq'] ) { + if ( config?.services?.['groq'] ) { const { GroqAIService } = require('./GroqAIService'); services.registerService('groq', GroqAIService); } - if ( !! config?.services?.['xai'] ) { + if ( config?.services?.['xai'] ) { const { XAIService } = require('./XAIService'); services.registerService('xai', XAIService); diff --git a/src/backend/src/modules/web/WebServerService.js b/src/backend/src/modules/web/WebServerService.js index 9012a863e8..aef801f3fd 100644 --- a/src/backend/src/modules/web/WebServerService.js +++ b/src/backend/src/modules/web/WebServerService.js @@ -261,7 +261,7 @@ class WebServerService extends BaseService { * * @returns {Promise} A promise that resolves when the server is started. */ - // eslint-disable-next-line no-unused-vars + WebServerService.prototype.__on_start_webserver = async function () { // ... }; diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index bd8132dad5..018ed3b9b5 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1261,7 +1261,10 @@ const ipc_listener = async (event, handled) => { success: function(res){ }, error: function(err){ - UIAlert(err && err.message ? err.message : "Download failed."); + UIAlert({ + type: 'error', + message: err && err.message ? err.message : "Download failed." + }); } }); item_with_same_name_already_exists = false; diff --git a/src/gui/src/UI/UIAlert.js b/src/gui/src/UI/UIAlert.js index 82f2a7b0af..68baf9834a 100644 --- a/src/gui/src/UI/UIAlert.js +++ b/src/gui/src/UI/UIAlert.js @@ -19,57 +19,156 @@ import UIWindow from './UIWindow.js' -function UIAlert(options){ +// Alert type to icon mapping +const ALERT_TYPE_ICONS = { + 'info': 'bell.svg', + 'success': 'c-check.svg', + 'warning': 'warning-sign.svg', + 'error': 'danger.svg', + 'question': 'reminder.svg' +}; + +/** + * Validates and retrieves an icon with fallback logic + * @param {string} customIcon - The custom icon name/path to validate + * @param {string} alertType - The alert type for fallback icon + * @returns {string} The validated icon path or fallback icon + */ +function validateAndGetIcon(customIcon, alertType) { + // First, try to get the custom icon + if (customIcon && window.icons && window.icons[customIcon]) { + return window.icons[customIcon]; + } + + // If custom icon is a direct path/URL, validate it exists + if (customIcon && (customIcon.startsWith('/') || customIcon.startsWith('http') || customIcon.includes('.'))) { + // For direct paths, we'll trust they exist and return them + // The browser will handle broken images gracefully + return customIcon; + } + + // Fallback to type-based icon + const typeIcon = ALERT_TYPE_ICONS[alertType] || ALERT_TYPE_ICONS['warning']; + return window.icons[typeIcon] || window.icons[ALERT_TYPE_ICONS['warning']]; +} + +/** + * Sanitizes HTML content to prevent XSS attacks while allowing safe HTML elements + * @param {string|HTMLElement} content - The content to sanitize + * @returns {string} The sanitized HTML content + */ +function sanitizeCustomUI(content) { + if (!content) return ''; + + // If content is an HTMLElement, get its outerHTML + if (content instanceof HTMLElement) { + content = content.outerHTML; + } + + // Convert to string if not already + content = String(content); + + // Create a temporary div to parse and sanitize the HTML + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = content; + + // Define allowed tags and attributes for basic HTML sanitization + const allowedTags = ['div', 'span', 'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'ul', 'ol', 'li', 'a', 'img', 'button', 'input', 'textarea', 'select', 'option', 'label', 'form']; + const allowedAttributes = ['class', 'id', 'style', 'href', 'src', 'alt', 'title', 'type', 'value', 'name', 'placeholder', 'data-*']; + + // Remove script tags and event handlers + const scripts = tempDiv.querySelectorAll('script'); + scripts.forEach(script => script.remove()); + + // Remove event handler attributes (onclick, onload, etc.) + const allElements = tempDiv.querySelectorAll('*'); + allElements.forEach(element => { + // Remove event handler attributes + Array.from(element.attributes).forEach(attr => { + if (attr.name.startsWith('on')) { + element.removeAttribute(attr.name); + } + }); + + // Remove javascript: URLs + if (element.href && element.href.startsWith('javascript:')) { + element.removeAttribute('href'); + } + if (element.src && element.src.startsWith('javascript:')) { + element.removeAttribute('src'); + } + }); + + return tempDiv.innerHTML; +} + +function UIAlert(options) { // set sensible defaults - if(arguments.length > 0){ + if (arguments.length > 0) { // if first argument is a string, then assume it is the message - if(window.isString(arguments[0])){ + if (window.isString(arguments[0])) { options = {}; options.message = arguments[0]; } // if second argument is an array, then assume it is the buttons - if(arguments[1] && Array.isArray(arguments[1])){ + if (arguments[1] && Array.isArray(arguments[1])) { options.buttons = arguments[1]; } } + // ensure options is an object + options = options || {}; + return new Promise(async (resolve) => { // provide an 'OK' button if no buttons are provided - if(!options.buttons || options.buttons.length === 0){ + if (!options.buttons || options.buttons.length === 0) { options.buttons = [ - {label: i18n('ok'), value: true, type: 'primary'} + { label: i18n('ok'), value: true, type: 'primary' } ] } - // set body icon - options.body_icon = options.body_icon ?? window.icons['warning-sign.svg']; - if(options.type === 'success') - options.body_icon = window.icons['c-check.svg']; + // set default type if not provided (for backward compatibility) + if (!options.type) { + options.type = 'warning'; + } - let santized_message = html_encode(options.message); + // validate alert type and fallback to warning if invalid + if (!ALERT_TYPE_ICONS[options.type]) { + options.type = 'warning'; + } + + // set body icon based on type or custom icon override + if (options.icon) { + // custom icon override with validation and fallback + options.body_icon = validateAndGetIcon(options.icon, options.type); + } else { + // use type-based icon + options.body_icon = window.icons[ALERT_TYPE_ICONS[options.type]]; + } + let h = ''; + + let santized_message = html_encode(options.message); // replace sanitized with santized_message = santized_message.replace(/<strong>/g, ''); santized_message = santized_message.replace(/<\/strong>/g, ''); - // replace sanitized

with

santized_message = santized_message.replace(/<p>/g, '

'); santized_message = santized_message.replace(/<\/p>/g, '

'); - let h = ''; // icon h += ``; // message h += `
${santized_message}
`; + // buttons if(options.buttons && options.buttons.length > 0){ h += `
`; for(let y=0; y${html_encode(options.buttons[y].label)}`; + h += ``; } h += `
`; } @@ -106,19 +205,57 @@ function UIAlert(options){ 'backdrop-filter': 'blur(3px)', } }); + // focus to primary btn $(el_window).find('.button-primary').focus(); // -------------------------------------------------------- // Button pressed // -------------------------------------------------------- - $(el_window).find('.alert-resp-button').on('click', async function(event){ - event.preventDefault(); + $(el_window).find('.alert-resp-button').on('click', async function (event) { + event.preventDefault(); event.stopPropagation(); - resolve($(this).attr('data-value')); + + const buttonIndex = parseInt($(this).attr('data-button-index')); + const buttonConfig = options.buttons[buttonIndex]; + const buttonValue = $(this).attr('data-value'); + + // Execute callback function if provided + if (buttonConfig && typeof buttonConfig.callback === 'function') { + try { + // Execute the callback function + const callbackResult = await buttonConfig.callback(); + + // If callback returns a value, use it; otherwise use the button value + const resolveValue = callbackResult !== undefined ? callbackResult : buttonValue; + resolve(resolveValue); + } catch (error) { + console.error('Error executing button callback:', error); + // On callback error, still resolve with button value for backward compatibility + resolve(buttonValue); + } + } else { + // No callback - use existing behavior for backward compatibility + resolve(buttonValue); + } + $(el_window).close(); return false; - }) + }); + + // -------------------------------------------------------- + // Custom UI support - provide methods to close dialog programmatically + // -------------------------------------------------------- + if (options.customUI) { + // Add a close method to the window element for custom UI to use + el_window.closeAlert = function (value) { + resolve(value); + $(el_window).close(); + }; + + // Also make it available globally for custom UI scripts + window.currentAlertWindow = el_window; + } }) } diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 4c7d1637e2..5d9d4f4751 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -927,8 +927,9 @@ span.header-sort-icon img { } .device-phone .window-alert, .device-tablet .window-alert { - min-width: 90%; - max-width: 300px; + min-width: 160px !important; + max-width: calc(100vw - 20px) !important; + max-height: calc(100vh - 40px) !important; position: absolute; left: 50% !important; top: 50% !important; @@ -1457,28 +1458,429 @@ span.header-sort-icon img { } .window-alert-message, .window-prompt-message { - font-size: 15px; + font-size: 13px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #414650; text-shadow: 1px 1px #ffffff52; - margin-top: 10px; + margin-top: 8px; word-break: break-word; } +/* Alert sizing with resize constraints */ +.window-alert { + min-width: 200px !important; + max-width: 500px !important; + min-height: 120px !important; + max-height: 400px !important; +} + +/* Compact alert window header */ +.window-alert .window-head { + height: 24px !important; + min-height: 24px !important; + padding: 2px 6px !important; +} + +.window-alert .window-head .window-title { + font-size: 11px !important; + line-height: 20px !important; +} + +.window-alert .window-head .window-close-btn { + width: 16px !important; + height: 16px !important; + font-size: 10px !important; + line-height: 14px !important; +} + +/* Compact alert body */ +.window-alert .window-body { + min-height: auto !important; +} + +/* Compact button styling for alerts */ +.window-alert-buttons-compact { + flex-wrap: wrap !important; + min-height: 28px !important; +} + +.window-alert-buttons-compact .button { + margin: 0 !important; + font-weight: 500 !important; + height: 28px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + cursor: pointer !important; + transition: all 0.2s ease !important; + white-space: nowrap !important; +} + +.window-alert-buttons-compact .button:hover { + transform: translateY(-1px) !important; + box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important; +} + +/* Responsive button layout for resized alerts */ +.window-alert .window-alert-buttons-compact { + margin-top: auto !important; +} + +/* Content area flexibility */ +.window-alert .window-body { + display: flex !important; + flex-direction: column !important; + overflow: hidden !important; +} + +.window-alert-message-compact { + overflow-y: auto !important; + max-height: 200px !important; +} + .window-alert-message { text-align: center; } .window-alert-icon { - width: 64px; - margin: 10px auto 20px; + width: 32px; + margin: 6px auto 10px; display: block; } +/* Alert type-specific styling */ +.window-alert-info { + /* Info alert styling - blue theme */ + border-left: 4px solid #2196f3; +} + +.window-alert-info .window-alert-message { + color: #1976d2; +} + +.window-alert-info .window-alert-icon { + filter: hue-rotate(200deg) saturate(1.2); +} + +.window-alert-success { + /* Success alert styling - green theme */ + border-left: 4px solid #4caf50; +} + +.window-alert-success .window-alert-message { + color: #388e3c; +} + +.window-alert-success .window-alert-icon { + filter: hue-rotate(120deg) saturate(1.1); +} + +.window-alert-warning { + /* Warning alert styling - orange theme (default) */ + border-left: 4px solid #ff9800; +} + +.window-alert-warning .window-alert-message { + color: #f57c00; +} + +.window-alert-warning .window-alert-icon { + filter: hue-rotate(30deg) saturate(1.1); +} + +.window-alert-error { + /* Error alert styling - red theme */ + border-left: 4px solid #f44336; +} + +.window-alert-error .window-alert-message { + color: #d32f2f; +} + +.window-alert-error .window-alert-icon { + filter: hue-rotate(0deg) saturate(1.3); +} + +.window-alert-question { + /* Question alert styling - purple theme */ + border-left: 4px solid #9c27b0; +} + +.window-alert-question .window-alert-message { + color: #7b1fa2; +} + +.window-alert-question .window-alert-icon { + filter: hue-rotate(280deg) saturate(1.2); +} + +/* Enhanced alert type styling with backgrounds and shadows */ +.window-alert-info { + background: linear-gradient(135deg, rgba(33, 150, 243, 0.05) 0%, rgba(33, 150, 243, 0.02) 100%); + box-shadow: 0 2px 8px rgba(33, 150, 243, 0.15); +} + +.window-alert-success { + background: linear-gradient(135deg, rgba(76, 175, 80, 0.05) 0%, rgba(76, 175, 80, 0.02) 100%); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.15); +} + +.window-alert-warning { + background: linear-gradient(135deg, rgba(255, 152, 0, 0.05) 0%, rgba(255, 152, 0, 0.02) 100%); + box-shadow: 0 2px 8px rgba(255, 152, 0, 0.15); +} + +.window-alert-error { + background: linear-gradient(135deg, rgba(244, 67, 54, 0.05) 0%, rgba(244, 67, 54, 0.02) 100%); + box-shadow: 0 2px 8px rgba(244, 67, 54, 0.15); +} + +.window-alert-question { + background: linear-gradient(135deg, rgba(156, 39, 176, 0.05) 0%, rgba(156, 39, 176, 0.02) 100%); + box-shadow: 0 2px 8px rgba(156, 39, 176, 0.15); +} + +/* Enhanced icon styling for better visual hierarchy */ +.window-alert-icon { + transition: transform 0.2s ease-in-out; + border-radius: 50%; + padding: 8px; + background: rgba(255, 255, 255, 0.8); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.window-alert-icon:hover { + transform: scale(1.05); +} + +/* Message styling enhancements */ +.window-alert-message { + font-weight: 500; + line-height: 1.3; + margin: 8px 0; + font-size: 14px; +} + +/* Responsive design considerations */ +@media (max-width: 480px) { + .window-alert { + margin: 6px; + min-width: 160px !important; + max-width: calc(100vw - 20px) !important; + max-height: calc(100vh - 40px) !important; + } + + .window-alert-icon-compact { + width: 20px !important; + height: 20px !important; + } + + .window-alert-message-compact { + font-size: 12px !important; + } + + .window-alert-buttons-compact .button { + padding: 5px 10px !important; + font-size: 11px !important; + min-width: 50px !important; + height: 26px !important; + } + + /* Stack buttons vertically on very small screens when resized */ + @media (max-width: 320px) { + .window-alert-buttons-compact { + flex-direction: column !important; + gap: 4px !important; + } + + .window-alert-buttons-compact .button { + width: 100% !important; + } + } +} + +@media (max-width: 320px) { + .window-alert-icon { + width: 40px; + margin: 6px auto 12px; + } + + .window-alert-message { + font-size: 13px; + margin: 10px 0; + } +} + +/* High contrast mode support */ +@media (prefers-contrast: high) { + .window-alert-info { + border-left-width: 6px; + background: rgba(33, 150, 243, 0.1); + } + + .window-alert-success { + border-left-width: 6px; + background: rgba(76, 175, 80, 0.1); + } + + .window-alert-warning { + border-left-width: 6px; + background: rgba(255, 152, 0, 0.1); + } + + .window-alert-error { + border-left-width: 6px; + background: rgba(244, 67, 54, 0.1); + } + + .window-alert-question { + border-left-width: 6px; + background: rgba(156, 39, 176, 0.1); + } +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + .window-alert-icon { + transition: none; + } + + .window-alert-icon:hover { + transform: none; + } +} + +/* Custom UI content styling */ +.window-alert-custom-content { + width: 100%; + min-height: 50px; +} + +.window-alert-custom-content * { + box-sizing: border-box; +} + +/* Button container styling */ +.window-alert-buttons { + overflow: hidden; + margin-top: 20px; +} + .alert-resp-button { width: 100%; margin-top: 10px; + transition: all 0.2s ease-in-out; + border-radius: 6px; + font-weight: 500; +} + +/* Alert type-specific button styling */ +.window-alert-info .alert-resp-button.button-primary { + background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%); + border-color: #1976d2; +} + +.window-alert-info .alert-resp-button.button-primary:hover { + background: linear-gradient(135deg, #1976d2 0%, #1565c0 100%); + border-color: #1565c0; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(33, 150, 243, 0.3); +} + +.window-alert-success .alert-resp-button.button-primary { + background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%); + border-color: #388e3c; +} + +.window-alert-success .alert-resp-button.button-primary:hover { + background: linear-gradient(135deg, #388e3c 0%, #2e7d32 100%); + border-color: #2e7d32; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(76, 175, 80, 0.3); +} + +.window-alert-warning .alert-resp-button.button-primary { + background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%); + border-color: #f57c00; +} + +.window-alert-warning .alert-resp-button.button-primary:hover { + background: linear-gradient(135deg, #f57c00 0%, #ef6c00 100%); + border-color: #ef6c00; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(255, 152, 0, 0.3); +} + +.window-alert-error .alert-resp-button.button-primary { + background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%); + border-color: #d32f2f; +} + +.window-alert-error .alert-resp-button.button-primary:hover { + background: linear-gradient(135deg, #d32f2f 0%, #c62828 100%); + border-color: #c62828; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(244, 67, 54, 0.3); +} + +.window-alert-question .alert-resp-button.button-primary { + background: linear-gradient(135deg, #9c27b0 0%, #7b1fa2 100%); + border-color: #7b1fa2; +} + +.window-alert-question .alert-resp-button.button-primary:hover { + background: linear-gradient(135deg, #7b1fa2 0%, #6a1b9a 100%); + border-color: #6a1b9a; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(156, 39, 176, 0.3); +} + +/* Secondary button styling for alerts */ +.window-alert .alert-resp-button.button-secondary { + background: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(0, 0, 0, 0.2); + color: #666; +} + +.window-alert .alert-resp-button.button-secondary:hover { + background: rgba(255, 255, 255, 1); + border-color: rgba(0, 0, 0, 0.3); + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +/* Danger button styling for alerts */ +.window-alert .alert-resp-button.button-danger { + background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%); + border-color: #d32f2f; +} + +.window-alert .alert-resp-button.button-danger:hover { + background: linear-gradient(135deg, #d32f2f 0%, #c62828 100%); + border-color: #c62828; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(244, 67, 54, 0.3); +} + +/* Responsive button styling */ +@media (max-width: 480px) { + .alert-resp-button { + margin-top: 8px; + padding: 12px 16px; + font-size: 14px; + } +} + +/* Reduced motion support for buttons */ +@media (prefers-reduced-motion: reduce) { + .alert-resp-button { + transition: none; + } + + .alert-resp-button:hover { + transform: none; + } } .prompt-resp-button { diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index f855fa62e6..f9002284fb 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -681,9 +681,10 @@ window.show_save_account_notice_if_needed = function(message){ // Show the notice setTimeout(async () => { const alert_resp = await UIAlert({ + type: 'info', message: message ?? `Congrats on storing data!

Don't forget to save your session! You are in a temporary session. Save session to avoid accidentally losing your work.

`, - body_icon: window.icons['reminder.svg'], - buttons:[ + icon: 'reminder.svg', + buttons: [ { label: i18n('save_session'), value: 'save-session', @@ -1020,9 +1021,12 @@ window.copy_clipboard_items = async function(dest_path, dest_container_element){ item_with_same_name_already_exists = false; } } - else{ - if(err.message){ - UIAlert(err.message) + else { + if (err.message) { + UIAlert({ + type: 'error', + message: err.message + }) } item_with_same_name_already_exists = false; } @@ -1129,12 +1133,18 @@ window.copy_items = function(el_items, dest_path){ item_with_same_name_already_exists = false; } } - else{ - if(err.message){ - UIAlert(err.message) + else { + if (err.message) { + UIAlert({ + type: 'error', + message: err.message + }) } - else if(err){ - UIAlert(err) + else if (err) { + UIAlert({ + type: 'error', + message: err + }) } item_with_same_name_already_exists = false; } @@ -1206,8 +1216,11 @@ window.delete_item = async function(el_item, descendants_only = false){ // update all shortcuts to this item $(`.item[data-shortcut_to_path="${html_encode($(el_item).attr('data-path'))}" i]`).attr(`data-shortcut_to_path`, ''); }); - }catch(err){ - UIAlert(err.responseText); + } catch (err) { + UIAlert({ + type: 'error', + message: err.responseText + }); } } @@ -1418,7 +1431,10 @@ window.move_items = async function(el_items, dest_path, is_undo = false){ // moving an item into a trashed directory? deny. else if(dest_path.startsWith(window.trash_path)){ progwin?.close(); - UIAlert('Cannot move items into a deleted folder.'); + UIAlert({ + type: 'error', + message: 'Cannot move items into a deleted folder.' + }); return; } @@ -1706,7 +1722,7 @@ window.update_sites_cache = function(){ * @param {*} target_path */ -window.init_upload_using_dialog = function(el_target_container, target_path = null){ +window.init_upload_using_dialog = function (el_target_container, target_path = null) { $("#upload-file-dialog").unbind('onchange'); $("#upload-file-dialog").unbind('change'); $("#upload-file-dialog").unbind('onChange'); @@ -1736,8 +1752,11 @@ window.upload_items = async function(items, dest_path){ let upload_progress_window; let opid; - if(dest_path == window.trash_path){ - UIAlert('Uploading to trash is not allowed!'); + if (dest_path == window.trash_path) { + UIAlert({ + type: 'error', + message: 'Uploading to trash is not allowed!' + }); return; } @@ -1917,7 +1936,7 @@ window.getUsage = () => { console.error('There has been a problem with your fetch operation:', error); }); -} +} window.getAppUIDFromOrigin = async function(origin) { try { @@ -2223,8 +2242,11 @@ window.unzipItem = async function(itemPath) { terminateOp = fflate.unzip(file, async (err, unzipped) => { currentProgress += window.zippingProgressConfig.ZIPPING; progwin?.set_progress(currentProgress.toPrecision(2)); - if(err) { - UIAlert(e.message); + if (err) { + UIAlert({ + type: 'error', + message: err.message + }); // close progress window clearTimeout(progwin_timeout); setTimeout(() => { @@ -2242,7 +2264,10 @@ window.unzipItem = async function(itemPath) { currentProgress += perItemProgress; progwin?.set_progress(currentProgress.toPrecision(2)); } catch (e) { - UIAlert(e.message); + UIAlert({ + type: 'error', + message: e.message + }); } }); queuedFileWrites.length && puter.fs.upload( @@ -2375,7 +2400,7 @@ window.rename_file = async(options, new_name, old_name, old_path, el_item, el_it $(el_item_name_editor).val(html_encode($(el_item).attr('data-name'))); //show error - if(err.message){ + if (err.message) { UIAlert(err.message) } }, @@ -2395,8 +2420,11 @@ window.delete_item_with_path = async function(path){ descendantsOnly: false, recursive: true, }); - }catch(err){ - UIAlert(err.responseText); + } catch (err) { + UIAlert({ + type: 'error', + message: err.responseText + }); } } diff --git a/src/gui/src/helpers/open_item.js b/src/gui/src/helpers/open_item.js index efdf3686fd..abc6aacf0b 100644 --- a/src/gui/src/helpers/open_item.js +++ b/src/gui/src/helpers/open_item.js @@ -40,19 +40,28 @@ const open_item = async function(options){ // Is this a shortcut whose source is perma-deleted? //---------------------------------------------------------------- if(is_shortcut && shortcut_to_path === ''){ - UIAlert(`This shortcut can't be opened because its source has been deleted.`) + UIAlert({ + type: 'error', + message: `This shortcut can't be opened because its source has been deleted.` + }) } //---------------------------------------------------------------- // Is this a shortcut whose source is trashed? //---------------------------------------------------------------- else if(is_shortcut && shortcut_to_path.startsWith(window.trash_path + '/')){ - UIAlert(`This shortcut can't be opened because its source has been deleted.`) + UIAlert({ + type: 'error', + message: `This shortcut can't be opened because its source has been deleted.` + }) } //---------------------------------------------------------------- // Is this a trashed file? //---------------------------------------------------------------- else if(item_path.startsWith(window.trash_path + '/')){ - UIAlert(`This item can't be opened because it's in the trash. To use this item, first drag it out of the Trash.`) + UIAlert({ + type: 'error', + message: `This item can't be opened because it's in the trash. To use this item, first drag it out of the Trash.` + }) } //---------------------------------------------------------------- // Is this a file (no dir) on a SaveFileDialog? @@ -222,9 +231,10 @@ const open_item = async function(options){ window.unzipItem(item_path); return; } - const alert_resp = await UIAlert( - 'Found no suitable apps to open this file with. Would you like to download it instead?', - [ + const alert_resp = await UIAlert({ + type: 'question', + message: 'Found no suitable apps to open this file with. Would you like to download it instead?', + buttons: [ { label: i18n('download_file'), value: 'download_file', @@ -234,7 +244,8 @@ const open_item = async function(options){ { label: i18n('cancel') } - ]) + ] + }) if(alert_resp === 'download_file'){ window.trigger_download([item_path]); }