-
Notifications
You must be signed in to change notification settings - Fork 157
feat: Enhanced alert system with multiple types and flexible configuration #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -160,14 +160,24 @@ const ipc_listener = async (event, handled) => { | |
| // ALERT | ||
| //-------------------------------------------------------- | ||
| else if(event.data.msg === 'ALERT' && event.data.message !== undefined){ | ||
| if (event.data.message === undefined || event.data.message === null) { | ||
| console.error('Alert message is undefined or null', event.data); | ||
| event.data.message = 'Alert'; // Provide a default message | ||
| } | ||
| // Normalize message format - handle both string and object | ||
| const msgData = typeof event.data.message === 'string' | ||
| ? { message: event.data.message } | ||
| : event.data.message; | ||
|
Comment on lines
+168
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is discarding some information. If Now, if |
||
|
|
||
| const alert_resp = await UIAlert({ | ||
| message: event.data.message, | ||
| buttons: event.data.buttons, | ||
| type: event.data.options?.type, | ||
| window_options: { | ||
| parent_uuid: event.data.appInstanceID, | ||
| disable_parent_window: true, | ||
| } | ||
| message: msgData.message, | ||
| buttons: msgData.buttons, | ||
| type: msgData.type, | ||
| customUI: msgData.customUI, | ||
| window_options: { | ||
| parent_uuid: event.data.appInstanceID, | ||
| disable_parent_window: true, | ||
| } | ||
| }) | ||
|
|
||
| target_iframe.contentWindow.postMessage({ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,33 +34,89 @@ function UIAlert(options){ | |
| } | ||
|
|
||
| return new Promise(async (resolve) => { | ||
| // provide an 'OK' button if no buttons are provided | ||
| // Provide type-specific default buttons if no buttons are provided | ||
| if(!options.buttons || options.buttons.length === 0){ | ||
| options.buttons = [ | ||
| {label: i18n('ok'), value: true, type: 'primary'} | ||
| ] | ||
| switch (options.type) { | ||
| case 'question': | ||
| options.buttons = [ | ||
| { label: i18n('yes'), value: 'yes', type: 'primary' }, | ||
| { label: i18n('no'), value: 'no', type: 'default' } | ||
| ]; | ||
| break; | ||
| case 'warning': | ||
| options.buttons = [ | ||
| { label: i18n('ok'), value: true, type: 'primary' }, | ||
| { label: i18n('cancel'), value: false, type: 'default' } | ||
| ]; | ||
| break; | ||
| case 'error': | ||
| case 'info': | ||
| case 'success': | ||
| default: | ||
| options.buttons = [ | ||
| { label: i18n('ok'), value: true, type: 'primary' } | ||
| ]; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // Convert string array to button objects | ||
| if (options.buttons && options.buttons.length > 0 && | ||
| typeof options.buttons[0] === 'string') { | ||
| options.buttons = options.buttons.map((label, index) => ({ | ||
| label: label, | ||
| value: label, | ||
| type: index === 0 ? 'primary' : 'default' | ||
| })); | ||
|
Comment on lines
+64
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is inconsistent because it is assuming that all elements in the array are of type Is there a case where |
||
| } | ||
|
|
||
| // 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']; | ||
| // Icon mapping for all alert types | ||
| const iconMap = { | ||
| 'warning': window.icons['warning-sign.svg'], | ||
| 'success': window.icons['c-check.svg'], | ||
| 'error': window.icons['danger.svg'], | ||
| 'info': window.icons['reminder.svg'], | ||
| 'question': window.icons['reminder.svg'], | ||
| }; | ||
|
|
||
| let santized_message = html_encode(options.message); | ||
| // Set body icon based on type, or use custom override | ||
| options.body_icon = options.body_icon ?? | ||
| (options.type ? iconMap[options.type] : iconMap['warning']); | ||
| let message = options.message; | ||
| if (typeof message !== 'string') { | ||
| message = message != null ? String(message) : ''; | ||
| } | ||
|
|
||
| let sanitized_message = html_encode(message); | ||
|
|
||
| // replace sanitized <strong> with <strong> | ||
| santized_message = santized_message.replace(/<strong>/g, '<strong>'); | ||
| santized_message = santized_message.replace(/<\/strong>/g, '</strong>'); | ||
| sanitized_message = sanitized_message.replace(/<strong>/g, '<strong>'); | ||
| sanitized_message = sanitized_message.replace(/<\/strong>/g, '</strong>'); | ||
|
|
||
| // replace sanitized <p> with <p> | ||
| santized_message = santized_message.replace(/<p>/g, '<p>'); | ||
| santized_message = santized_message.replace(/<\/p>/g, '</p>'); | ||
| sanitized_message = sanitized_message.replace(/<p>/g, '<p>'); | ||
| sanitized_message = sanitized_message.replace(/<\/p>/g, '</p>'); | ||
|
|
||
| let h = ''; | ||
| // icon | ||
| h += `<img class="window-alert-icon" src="${html_encode(options.body_icon)}">`; | ||
| // message | ||
| h += `<div class="window-alert-message">${santized_message}</div>`; | ||
| h += `<div class="window-alert-message">${sanitized_message}</div>`; | ||
|
|
||
| // Custom UI content (if provided) | ||
| if (options.customUI) { | ||
| let sanitized_custom = html_encode(options.customUI); | ||
| // Allow safe tags | ||
| sanitized_custom = sanitized_custom.replace(/<strong>/g, '<strong>'); | ||
| sanitized_custom = sanitized_custom.replace(/<\/strong>/g, '</strong>'); | ||
| sanitized_custom = sanitized_custom.replace(/<p>/g, '<p>'); | ||
| sanitized_custom = sanitized_custom.replace(/<\/p>/g, '</p>'); | ||
| sanitized_custom = sanitized_custom.replace(/<br>/g, '<br>'); | ||
| sanitized_custom = sanitized_custom.replace(/<br\/>/g, '<br/>'); | ||
|
|
||
| h += `<div class="window-alert-custom" style="margin-top: 15px;">${sanitized_custom}</div>`; | ||
| } | ||
|
|
||
| // buttons | ||
| if(options.buttons && options.buttons.length > 0){ | ||
| h += `<div style="overflow:hidden; margin-top:20px;">`; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we can remove this log as doesn't bring much value here.