ActionButton.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import './ArgumentForm.js'
  2. import './ExecutionButton.js'
  3. class ActionButton extends window.HTMLElement {
  4. constructFromJson (json) {
  5. this.updateIterationTimestamp = 0
  6. this.constructDomFromTemplate()
  7. // Class attributes
  8. this.temporaryStatusMessage = null
  9. this.isWaiting = false
  10. this.actionCallUrl = window.restBaseUrl + 'StartAction'
  11. this.updateFromJson(json)
  12. // DOM Attributes
  13. this.setAttribute('role', 'none')
  14. this.btn.title = json.title
  15. this.btn.onclick = () => {
  16. if (json.arguments.length > 0) {
  17. for (const oldArgumentForm of document.querySelectorAll('argument-form')) {
  18. oldArgumentForm.remove()
  19. }
  20. const frm = document.createElement('argument-form')
  21. frm.setup(json, (args) => {
  22. this.startAction(args)
  23. })
  24. document.body.appendChild(frm)
  25. frm.querySelector('dialog').showModal()
  26. } else {
  27. this.startAction()
  28. }
  29. }
  30. this.updateFromJson(json)
  31. this.domTitle.innerText = this.btn.title
  32. this.domIcon.innerHTML = this.unicodeIcon
  33. this.setAttribute('id', 'actionButton_' + json.id)
  34. }
  35. updateFromJson (json) {
  36. // Fields that should not be updated
  37. //
  38. // title - as the callback URL relies on it
  39. // actionCallbackUrl - as it's based on the title
  40. // temporaryStatusMessage - as the button might be "waiting" on execution to finish while it's being updated.
  41. if (json.icon === '') {
  42. this.unicodeIcon = '&#x1f4a9'
  43. } else {
  44. this.unicodeIcon = unescape(json.icon)
  45. }
  46. }
  47. getUniqueId () {
  48. if (window.isSecureContext) {
  49. return window.crypto.randomUUID()
  50. } else {
  51. return Date.now().toString()
  52. }
  53. }
  54. startAction (actionArgs) {
  55. // this.btn.disabled = true
  56. // this.isWaiting = true
  57. // this.updateDom()
  58. this.btn.classList = [] // Removes old animation classes
  59. if (actionArgs === undefined) {
  60. actionArgs = []
  61. }
  62. // UUIDs are create client side, so that we can setup a "execution-button"
  63. // to track the execution before we send the request to the server.
  64. const startActionArgs = {
  65. actionName: this.btn.title,
  66. arguments: actionArgs,
  67. uuid: this.getUniqueId()
  68. }
  69. const btnExecution = document.createElement('execution-button')
  70. btnExecution.constructFromJson(startActionArgs.uuid)
  71. this.querySelector('.executions').appendChild(btnExecution)
  72. this.querySelector('summary').innerText = (this.querySelector('.executions').children.length - 1) + ' executions.'
  73. window.fetch(this.actionCallUrl, {
  74. method: 'POST',
  75. headers: {
  76. 'Content-Type': 'application/json'
  77. },
  78. body: JSON.stringify(startActionArgs)
  79. }).then((res) => {
  80. if (res.ok) {
  81. return res.json()
  82. } else {
  83. throw new Error(res.statusText)
  84. }
  85. }
  86. ).then((json) => {
  87. // The button used to wait for the action to finish, but now it is fire & forget
  88. }).catch(err => {
  89. this.onActionError(err)
  90. })
  91. }
  92. constructDomFromTemplate () {
  93. const tpl = document.getElementById('tplActionButton')
  94. const content = tpl.content.cloneNode(true)
  95. /*
  96. * FIXME: Should probably be using a shadowdom here, but seem to
  97. * get an error when combined with custom elements.
  98. */
  99. this.appendChild(content)
  100. this.btn = this.querySelector('button')
  101. this.domTitle = this.btn.querySelector('.title')
  102. this.domIcon = this.btn.querySelector('.icon')
  103. }
  104. }
  105. window.customElements.define('action-button', ActionButton)