From acde4e7d482ac52d27ebdaf887638f0de2359f78 Mon Sep 17 00:00:00 2001 From: Flawid DSouza Date: Fri, 8 Mar 2024 23:20:12 +0530 Subject: [PATCH] feat(ui): Replace all browser native confirm('Are you sure?') calls with in ui confirm dialog to avoid cross platform design changes + fixes #96 --- packages/ui/src/components/RequestPanel.vue | 2 +- packages/ui/src/components/ResponsePanel.vue | 4 +- packages/ui/src/components/Sidebar.vue | 5 +- packages/ui/src/components/SocketPanel.vue | 8 +- packages/ui/src/components/Workspaces.vue | 4 +- .../modals/BackupAndRestoreModal.vue | 2 +- .../components/modals/EnvironmentModal.vue | 6 +- .../components/modals/PluginManagerModal.vue | 4 +- .../web-components/alert-confirm-prompt.js | 237 ++++++++++-------- 9 files changed, 147 insertions(+), 125 deletions(-) diff --git a/packages/ui/src/components/RequestPanel.vue b/packages/ui/src/components/RequestPanel.vue index d736b2d3..b0ddc2e4 100644 --- a/packages/ui/src/components/RequestPanel.vue +++ b/packages/ui/src/components/RequestPanel.vue @@ -584,7 +584,7 @@ export default { e.stopPropagation() const content = e.clipboardData.getData('text/plain').trim() if (content.startsWith('curl')) { - if(!confirm(`We've detected that you've pasted a curl command. Do you want to import the curl command into the current request?`)) { + if(!await window.createConfirm(`We've detected that you've pasted a curl command. Do you want to import the curl command into the current request?`)) { return } const result = await convertCurlCommandToRestfoxCollection(content, this.activeWorkspace._id) diff --git a/packages/ui/src/components/ResponsePanel.vue b/packages/ui/src/components/ResponsePanel.vue index 2dc840f4..ec1b7f35 100644 --- a/packages/ui/src/components/ResponsePanel.vue +++ b/packages/ui/src/components/ResponsePanel.vue @@ -372,8 +372,8 @@ export default { a.click() URL.revokeObjectURL(url) }, - restoreCurrentResponseRequest() { - if(!confirm('Are you sure? Restoring a request will reset your existing request and make it the same as the saved response\'s request.')) { + async restoreCurrentResponseRequest() { + if(!await window.createConfirm('Are you sure? Restoring a request will reset your existing request and make it the same as the saved response\'s request.')) { return } diff --git a/packages/ui/src/components/Sidebar.vue b/packages/ui/src/components/Sidebar.vue index 48c482c6..ddf542f2 100644 --- a/packages/ui/src/components/Sidebar.vue +++ b/packages/ui/src/components/Sidebar.vue @@ -288,8 +288,9 @@ export default { methods: { async handleClick(clickedSidebarItem) { if(clickedSidebarItem === 'Delete') { - if(confirm('Are you sure?')) { - this.$store.dispatch('deleteCollectionItem', this.activeSidebarItemForContextMenu) + const collectionItemToDelete = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu)) + if(await window.createConfirm('Are you sure?')) { + this.$store.dispatch('deleteCollectionItem', collectionItemToDelete) } } diff --git a/packages/ui/src/components/SocketPanel.vue b/packages/ui/src/components/SocketPanel.vue index 3281a3b5..7f7f7293 100644 --- a/packages/ui/src/components/SocketPanel.vue +++ b/packages/ui/src/components/SocketPanel.vue @@ -292,8 +292,8 @@ function addClient() { }) } -function removeClient(client: Client) { - if (!confirm('Are you sure you want to remove this client?')) { +async function removeClient(client: Client) { + if (!await (window as any).createConfirm('Are you sure you want to remove this client?')) { return } sockets[activeTab.value._id + '-' + client.id]?.close() @@ -616,13 +616,13 @@ function changePayloadTab(client: Client, tab: ClientPayload) { client.event = tab.event } -function closePayloadTab(client: Client, event: { tabToClose: ClientPayload, tabToOpen: ClientPayload }) { +async function closePayloadTab(client: Client, event: { tabToClose: ClientPayload, tabToOpen: ClientPayload }) { if(client.payloads.length === 1) { alert('Cannot delete payload as there\'s only one payload left') return } - if(!confirm(`Are you sure you want to remove "${event.tabToClose.name}?"`)) { + if(!await (window as any).createConfirm(`Are you sure you want to remove "${event.tabToClose.name}?"`)) { return } diff --git a/packages/ui/src/components/Workspaces.vue b/packages/ui/src/components/Workspaces.vue index f504f807..eeb7a093 100644 --- a/packages/ui/src/components/Workspaces.vue +++ b/packages/ui/src/components/Workspaces.vue @@ -75,7 +75,7 @@ export default { this.contextMenuWorkspace = workspace this.showContextMenu = true }, - handleContextMenuClick(clickedContextMenuItem) { + async handleContextMenuClick(clickedContextMenuItem) { if(clickedContextMenuItem === 'Duplicate') { this.workspaceToDuplicate = JSON.parse(JSON.stringify(this.contextMenuWorkspace)) this.showDuplicateWorkspaceModal = true @@ -86,7 +86,7 @@ export default { } if(clickedContextMenuItem === 'Delete') { - if(confirm('Are you sure?')) { + if(await window.createConfirm('Are you sure?')) { this.$store.dispatch('deleteWorkspace', this.contextMenuWorkspace._id) } } diff --git a/packages/ui/src/components/modals/BackupAndRestoreModal.vue b/packages/ui/src/components/modals/BackupAndRestoreModal.vue index 4bcaaae5..093e7e49 100644 --- a/packages/ui/src/components/modals/BackupAndRestoreModal.vue +++ b/packages/ui/src/components/modals/BackupAndRestoreModal.vue @@ -57,7 +57,7 @@ export default { downloadBlob(`Restfox_Backup_${todayISODate()}.json`, blob) }, async restoreBackup() { - if(!confirm('Are you sure?')) { + if(!await window.createConfirm('Are you sure?')) { return } diff --git a/packages/ui/src/components/modals/EnvironmentModal.vue b/packages/ui/src/components/modals/EnvironmentModal.vue index e67a13d5..b1c096db 100644 --- a/packages/ui/src/components/modals/EnvironmentModal.vue +++ b/packages/ui/src/components/modals/EnvironmentModal.vue @@ -192,7 +192,7 @@ export default { alert(`Given environment name already exists: ${newEnvironmentName}`) return } else { - if(!confirm(`Given environment name already exists: ${newEnvironmentName}\nDo you want to merge with the existing one?`)) { + if(!await window.createConfirm(`Given environment name already exists: ${newEnvironmentName}\nDo you want to merge with the existing one?`)) { return } @@ -372,14 +372,14 @@ export default { this.hideEnvironmentContextMenu() }, - deleteEnvironment() { + async deleteEnvironment() { if(this.environments.length === 1) { alert('Cannot delete environment as there\'s only one environment left') this.hideEnvironmentContextMenu() return } - if(!confirm('Are you sure you want to delete this environment?')) { + if(!await window.createConfirm('Are you sure you want to delete this environment?')) { this.hideEnvironmentContextMenu() return } diff --git a/packages/ui/src/components/modals/PluginManagerModal.vue b/packages/ui/src/components/modals/PluginManagerModal.vue index 87b01c76..7ef013d2 100644 --- a/packages/ui/src/components/modals/PluginManagerModal.vue +++ b/packages/ui/src/components/modals/PluginManagerModal.vue @@ -192,8 +192,8 @@ export default { updatePluginStatus(pluginId, enabled) { this.$store.commit('updatePluginStatus', { _id: pluginId, enabled: enabled === '1' ? true : false }) }, - deletePlugin(pluginId) { - if(confirm('Are you sure?')) { + async deletePlugin(pluginId) { + if(await window.createConfirm('Are you sure?')) { this.$store.commit('deletePlugin', pluginId) } }, diff --git a/packages/ui/src/web-components/alert-confirm-prompt.js b/packages/ui/src/web-components/alert-confirm-prompt.js index 36efe1c3..b964a581 100644 --- a/packages/ui/src/web-components/alert-confirm-prompt.js +++ b/packages/ui/src/web-components/alert-confirm-prompt.js @@ -5,37 +5,48 @@ class AlertConfirmPrompt extends HTMLElement { this.attachShadow({ mode: 'open' }) } - createPrompt = (title, defaultValue = '', selectList = []) => { + createDialog = (type, title, defaultValue = '', selectList = []) => { const div = document.createElement('div') - div.innerHTML = ` -
-
-
${title}
-
- - - ${selectList.map(item => ``)} - -
-
- - -
+ let inputHtml = '' + if (type === 'prompt') { + inputHtml = ` +
+ + + ${selectList.map(item => ``).join('')} + +
+ ` + } + + if (type === 'confirm') { + inputHtml = '
' + } + + div.innerHTML = ` +
+
+
${title}
+ ${inputHtml} +
+ +
+
` this.shadowRoot.querySelector('#root').appendChild(div) - this.shadowRoot.getElementById('p-input').focus() - this.shadowRoot.getElementById('p-input').select() + if (type === 'prompt') { + this.shadowRoot.getElementById('dialog-input').focus() + this.shadowRoot.getElementById('dialog-input').select() + } else { + this.shadowRoot.getElementById('dialog-confirm').focus() + } return new Promise((resolve) => { - const focusableEls = div.querySelectorAll('button:not(:disabled), input[type="text"]:not(:disabled)') - const firstFocusableEl = focusableEls[0] - const lastFocusableEl = focusableEls[focusableEls.length - 1] - const closeModal = () => { document.removeEventListener('click', eventHandler) document.removeEventListener('keyup', eventHandler) @@ -44,58 +55,64 @@ class AlertConfirmPrompt extends HTMLElement { } const confirm = () => { - resolve(this.shadowRoot.getElementById('p-input').value) + if (type === 'prompt') { + resolve(this.shadowRoot.getElementById('dialog-input').value) + } else { + resolve(true) + } closeModal() } const cancel = () => { - resolve(null) + resolve(type === 'prompt' ? null : false) closeModal() } const eventHandler = e => { - if(e.type === 'keyup') { - if(e.key === 'Enter') { + if (e.type === 'keyup') { + if (e.key === 'Enter') { confirm() } - if(e.key === 'Escape') { + if (e.key === 'Escape') { cancel() } return } - // trap focus inside dialog - if(e.type === 'keydown') { - const isTabPressed = e.key === 'Tab' + // Trap focus inside dialog + if (e.type === 'keydown') { + const focusableEls = div.querySelectorAll('button:not(:disabled), input[type="text"]:not(:disabled)') + const firstFocusableEl = focusableEls[0] + const lastFocusableEl = focusableEls[focusableEls.length - 1] - if(!isTabPressed) { + const isTabPressed = e.key === 'Tab' + if (!isTabPressed) { return } - if(e.shiftKey) { - if(this.shadowRoot.activeElement === firstFocusableEl) { + if (e.shiftKey) { + if (this.shadowRoot.activeElement === firstFocusableEl) { lastFocusableEl.focus() e.preventDefault() } } else { - if(this.shadowRoot.activeElement === lastFocusableEl) { + if (this.shadowRoot.activeElement === lastFocusableEl) { firstFocusableEl.focus() e.preventDefault() } } - return } const target = e.composedPath()[0] - if(target.id === 'p-confirm') { + if (target.id === 'dialog-confirm') { confirm() } - if(target.id === 'p-cancel') { + if (target.id === 'dialog-cancel') { cancel() } } @@ -106,84 +123,88 @@ class AlertConfirmPrompt extends HTMLElement { }) } + createPrompt = (title, defaultValue = '', selectList = []) => { + return this.createDialog('prompt', title, defaultValue, selectList) + } + + createConfirm = (title) => { + return this.createDialog('confirm', title) + } connectedCallback() { this.shadowRoot.innerHTML = /* html */ ` -
- +
+ ` window.createPrompt = this.createPrompt + window.createConfirm = this.createConfirm } }