diff --git a/webui.dev/js/ActionButton.js b/webui.dev/js/ActionButton.js index 359749e..c944bce 100644 --- a/webui.dev/js/ActionButton.js +++ b/webui.dev/js/ActionButton.js @@ -45,6 +45,8 @@ class ActionButton extends ExecutionFeedbackButton { oldArgumentForm.remove() } + this.updateUrlWithAction() + const frm = document.createElement('argument-form') frm.setup(json, (args) => { this.startAction(args) @@ -132,6 +134,17 @@ class ActionButton extends ExecutionFeedbackButton { }) } + updateUrlWithAction () { + // Get the current URL and create a new URL object + const url = new URL(window.location.href) + + // Set the action parameter + url.searchParams.set('action', this.btn.title) + + // Update the URL without reloading the page + window.history.replaceState({}, '', url.toString()) + } + onActionStarted (executionTrackingId) { if (this.popupOnStart === 'execution-button') { const btnExecution = document.createElement('execution-button') diff --git a/webui.dev/js/ArgumentForm.js b/webui.dev/js/ArgumentForm.js index 630edaf..21d74f4 100644 --- a/webui.dev/js/ArgumentForm.js +++ b/webui.dev/js/ArgumentForm.js @@ -1,5 +1,9 @@ class ArgumentForm extends window.HTMLElement { + getQueryParams () { + return new URLSearchParams(window.location.search.substring(1)) + } + setup (json, callback) { this.setAttribute('class', 'action-arguments') @@ -23,6 +27,7 @@ class ArgumentForm extends window.HTMLElement { } this.domBtnCancel.onclick = () => { + this.clearBookmark() this.remove() } } @@ -189,7 +194,19 @@ class ArgumentForm extends window.HTMLElement { } domEl.name = arg.name - domEl.value = arg.defaultValue + + // Use query parameter value if available + const params = this.getQueryParams() + const paramValue = params.get(arg.name) + + if (paramValue !== null) { + domEl.value = paramValue + } else { + domEl.value = arg.defaultValue + } + + // update the URL when a parameter is changed + domEl.addEventListener('change', this.updateUrlWithArg) if (typeof arg.suggestions === 'object' && Object.keys(arg.suggestions).length > 0) { domEl.setAttribute('list', arg.name + '-choices') @@ -200,6 +217,20 @@ class ArgumentForm extends window.HTMLElement { return domEl } + updateUrlWithArg (ev) { + if (!ev.target.name) { + return + } + // Get the current URL and create a new URL object + const url = new URL(window.location.href) + + // copy the parameter value + url.searchParams.set(ev.target.name, ev.target.value) + + // Update the URL without reloading the page + window.history.replaceState({}, '', url.toString()) + } + createDomDescription (arg) { const domArgumentDescription = document.createElement('span') domArgumentDescription.classList.add('argument-description') @@ -216,6 +247,13 @@ class ArgumentForm extends window.HTMLElement { return domEl } + + clearBookmark () { + // remove the action from the URL + window.history.replaceState({ + path: window.location.pathname + }, '', window.location.pathname) + } } window.customElements.define('argument-form', ArgumentForm) diff --git a/webui.dev/js/marshaller.js b/webui.dev/js/marshaller.js index 9ebd112..eaafb95 100644 --- a/webui.dev/js/marshaller.js +++ b/webui.dev/js/marshaller.js @@ -2,6 +2,33 @@ import './ActionButton.js' // To define action-button import { ExecutionDialog } from './ExecutionDialog.js' import { ActionStatusDisplay } from './ActionStatusDisplay.js' +function getQueryParams () { + return new URLSearchParams(window.location.search.substring(1)) +} + +function checkAndTriggerActionFromQueryParam () { + const params = getQueryParams() + + const action = params.get('action') + if (action && window.actionButtons) { + // Look for an action button with matching title + const actionButton = window.actionButtons[action] + + if (actionButton) { + // Only trigger actions that have arguments + const jsonButton = window.actionButtonsJson[action] + if (jsonButton && jsonButton.arguments && jsonButton.arguments.length > 0) { + // Trigger the action button click + setTimeout(() => { + actionButton.btn.click() + }, 500) // Small delay to ensure UI is fully loaded + return true + } + } + } + return false +} + function createElement (tag, attributes) { const el = document.createElement(tag) @@ -106,6 +133,7 @@ function marshalActionsJsonToHtml (json) { const currentIterationTimestamp = Date.now() window.actionButtons = {} + window.actionButtonsJson = {} // Store the JSON representation for (const jsonButton of json.actions) { let htmlButton = window.actionButtons[jsonButton.id] @@ -115,6 +143,7 @@ function marshalActionsJsonToHtml (json) { htmlButton.constructFromJson(jsonButton) window.actionButtons[jsonButton.title] = htmlButton + window.actionButtonsJson[jsonButton.title] = jsonButton // Store the JSON representation } htmlButton.updateFromJson(jsonButton) @@ -169,7 +198,7 @@ function onExecutionFinished (evt) { } break - case 'execution-dialog-output-html': + case 'execution-dialog-output-html': case 'execution-dialog-stdout-only': case 'execution-dialog': // We don't need to fetch the logEntry for the dialog because we already @@ -246,7 +275,10 @@ function showSection (pathName) { } } - pushNewNavigationPath(pathName) + // Check for action parameter in query string + if (!checkAndTriggerActionFromQueryParam()) { + pushNewNavigationPath(pathName) + } setSectionNavigationVisible(false) @@ -254,9 +286,13 @@ function showSection (pathName) { } function pushNewNavigationPath (pathName) { + // Get the current query string + const queryString = window.location.search + + // Push the new state with the path and preserve the query string window.history.pushState({ path: pathName - }, null, pathName) + }, null, pathName + queryString) } function setSectionNavigationVisible (visible) {