ActionButton.js 3.4 KB

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