Browse Source

feat: links to argument forms (#551)

Co-authored-by: James Read <contact@jread.com>
Noah Perks Sloan 1 year ago
parent
commit
ec1f974f67
3 changed files with 91 additions and 4 deletions
  1. 13 0
      webui.dev/js/ActionButton.js
  2. 39 1
      webui.dev/js/ArgumentForm.js
  3. 39 3
      webui.dev/js/marshaller.js

+ 13 - 0
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')

+ 39 - 1
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)

+ 39 - 3
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) {