Browse Source

feat: UIAlert with dynamic icon types and default button configurations (#1175)

* UIAlert with dynamic icon types and default button configurations

* Update src/gui/src/UI/UIAlert.js

Co-authored-by: Eric Dubé <eric.alex.dube@gmail.com>

* Update src/gui/src/UI/UIAlert.js

Co-authored-by: Eric Dubé <eric.alex.dube@gmail.com>

* fix: improve error handling in UIAlert component and reseting package-lock

* fix: update UIAlert to use 'type' for alert type selection

* fix: update UIAlert to use 'type' for button configuration

---------

Co-authored-by: Eric Dubé <eric.alex.dube@gmail.com>
Aman Purohit 2 tháng trước cách đây
mục cha
commit
a278a6140b

+ 55 - 14
src/gui/src/UI/UIAlert.js

@@ -19,31 +19,72 @@
 
 
 import UIWindow from './UIWindow.js'
 import UIWindow from './UIWindow.js'
 
 
-function UIAlert(options){
+function UIAlert(options) {
     // set sensible defaults
     // set sensible defaults
-    if(arguments.length > 0){
+    if (arguments.length > 0) {
         // if first argument is a string, then assume it is the message
         // if first argument is a string, then assume it is the message
-        if(window.isString(arguments[0])){
+        if (window.isString(arguments[0])) {
             options = {};
             options = {};
             options.message = arguments[0];
             options.message = arguments[0];
         }
         }
         // if second argument is an array, then assume it is the buttons
         // 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];
             options.buttons = arguments[1];
         }
         }
     }
     }
 
 
     return new Promise(async (resolve) => {
     return new Promise(async (resolve) => {
         // provide an 'OK' button if no buttons are provided
         // 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 = [
             options.buttons = [
-                {label: i18n('ok'), value: true, type: 'primary'}
+                { label: i18n('ok'), value: true, type: 'primary' }
             ]
             ]
         }
         }
+        // Define alert types
+        const alertTypes = {
+            error: { icon: "danger.svg", title: "Error!", color: "#D32F2F" },
+            warning: { icon: "warning-sign.svg", title: "Warning!", color: "#FFA000" },
+            info: { icon: "reminder.svg", title: "Info", color: "#1976D2" },
+            success: { icon: "c-check.svg", title: "Success!", color: "#388E3C" },
+            confirm: { icon: "question.svg", title: "Are you sure?", color: "#555555" }
+        };
 
 
-        // set body icon
-        options.body_icon = options.body_icon ?? window.icons['warning-sign.svg'];
-        if(options.type === 'success')
+        // Set default values
+        const alertType = alertTypes[options.type] || alertTypes.warning;
+        options.message = options.title || alertType.title;
+        options.body_icon = options.body_icon ?? window.icons[alertType.icon];
+        options.color = options.color ?? alertType.color;
+
+        // Define buttons if not provided
+        if (!options.buttons || options.buttons.length === 0) {
+            switch (options.type) {
+                case "confirm":
+                    options.buttons = [
+                        { label: "Yes", value: true, type: "primary" },
+                        { label: "No", value: false, type: "secondary" }
+                    ];
+                    break;
+                case "error":
+                    options.buttons = [
+                        { label: "Retry", value: "retry", type: "danger" },
+                        { label: "Cancel", value: "cancel", type: "secondary" }
+                    ];
+                    break;
+                default:
+                    options.buttons = [{ label: i18n('ok'), value: true, type: "primary" }];
+                    break;
+            }
+        }
+        // callback support with correct resolve handling
+        options.buttons.forEach(button => {
+            button.onClick = () => {
+                if (options.callback) {
+                    options.callback(button.value);
+                }
+                puter.ui.closeDialog();
+            };
+        });
+        if (options.type === 'success')
             options.body_icon = window.icons['c-check.svg'];
             options.body_icon = window.icons['c-check.svg'];
 
 
         let santized_message = html_encode(options.message);
         let santized_message = html_encode(options.message);
@@ -62,9 +103,9 @@ function UIAlert(options){
         // message
         // message
         h += `<div class="window-alert-message">${santized_message}</div>`;
         h += `<div class="window-alert-message">${santized_message}</div>`;
         // buttons
         // buttons
-        if(options.buttons && options.buttons.length > 0){
+        if (options.buttons && options.buttons.length > 0) {
             h += `<div style="overflow:hidden; margin-top:20px;">`;
             h += `<div style="overflow:hidden; margin-top:20px;">`;
-            for(let y=0; y<options.buttons.length; y++){
+            for (let y = 0; y < options.buttons.length; y++) {
                 h += `<button class="button button-block button-${html_encode(options.buttons[y].type)} alert-resp-button" 
                 h += `<button class="button button-block button-${html_encode(options.buttons[y].type)} alert-resp-button" 
                                 data-label="${html_encode(options.buttons[y].label)}"
                                 data-label="${html_encode(options.buttons[y].label)}"
                                 data-value="${html_encode(options.buttons[y].value ?? options.buttons[y].label)}"
                                 data-value="${html_encode(options.buttons[y].value ?? options.buttons[y].label)}"
@@ -96,7 +137,7 @@ function UIAlert(options){
             width: 350,
             width: 350,
             parent_uuid: options.parent_uuid,
             parent_uuid: options.parent_uuid,
             ...options.window_options,
             ...options.window_options,
-            window_css:{
+            window_css: {
                 height: 'initial',
                 height: 'initial',
             },
             },
             body_css: {
             body_css: {
@@ -112,8 +153,8 @@ function UIAlert(options){
         // --------------------------------------------------------
         // --------------------------------------------------------
         // Button pressed
         // 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();
             event.stopPropagation();
             resolve($(this).attr('data-value'));
             resolve($(this).attr('data-value'));
             $(el_window).close();
             $(el_window).close();

+ 7 - 0
src/gui/src/icons/question.svg

@@ -0,0 +1,7 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
+<svg width="256px" height="256px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#0f94e6">
+
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
+
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#30698d" stroke-width="0.096"/>
+
<g id="SVGRepo_iconCarrier"> <path opacity="0.15" d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" fill="#30698d"/> <path d="M12 17V16.9929M12 14.8571C12 11.6429 15 12.3571 15 9.85714C15 8.27919 13.6568 7 12 7C10.6567 7 9.51961 7.84083 9.13733 9M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="#30698d" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </g>
+
</svg>