ActionButton.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { marshalLogsJsonToHtml } from './marshaller.js';
  2. import "./ArgumentForm.js"
  3. class ActionButton extends window.HTMLButtonElement {
  4. constructFromJson (json) {
  5. this.updateIterationTimestamp = 0
  6. this.title = json.title
  7. this.temporaryStatusMessage = null
  8. this.isWaiting = false
  9. this.actionCallUrl = window.restBaseUrl + 'StartAction?actionName=' + this.title
  10. this.updateFromJson(json)
  11. this.onclick = () => {
  12. if (json.arguments.length > 0) {
  13. let frm = document.createElement('form', { is: 'argument-form' })
  14. window.frm = frm
  15. console.log(frm)
  16. frm.setup(json, this.startAction)
  17. document.body.appendChild(frm)
  18. } else {
  19. this.startAction()
  20. }
  21. }
  22. this.constructTemplate()
  23. this.updateHtml()
  24. this.setAttribute('id', 'actionButton_' + json.id)
  25. }
  26. updateFromJson (json) {
  27. // Fields that should not be updated
  28. //
  29. // title - as the callback URL relies on it
  30. // actionCallbackUrl - as it's based on the title
  31. // temporaryStatusMessage - as the button might be "waiting" on execution to finish while it's being updated.
  32. if (json.icon === '') {
  33. this.unicodeIcon = '&#x1f4a9'
  34. } else {
  35. this.unicodeIcon = unescape(json.icon)
  36. }
  37. }
  38. startAction () {
  39. this.disabled = true
  40. this.isWaiting = true
  41. this.updateHtml()
  42. this.classList = [] // Removes old animation classes
  43. window.fetch(this.actionCallUrl).then(res => res.json()
  44. ).then((json) => {
  45. marshalLogsJsonToHtml({ logs: [json.logEntry] })
  46. if (json.logEntry.timedOut) {
  47. this.onActionResult('actionTimeout', 'Timed out')
  48. } else if (json.logEntry.exitCode !== 0) {
  49. this.onActionResult('actionNonZeroExit', 'Exit code ' + json.logEntry.exitCode)
  50. } else {
  51. this.onActionResult('actionSuccess', 'Success!')
  52. }
  53. }).catch(err => {
  54. this.onActionError(err)
  55. })
  56. }
  57. onActionResult (cssClass, temporaryStatusMessage) {
  58. this.temporaryStatusMessage = '[ ' + temporaryStatusMessage + ' ]'
  59. this.updateHtml()
  60. this.classList.add(cssClass)
  61. setTimeout(() => {
  62. this.classList.remove(cssClass)
  63. }, 1000)
  64. }
  65. onActionError (err) {
  66. console.log('callback error', err)
  67. this.disabled = false
  68. this.isWaiting = false
  69. this.updateHtml()
  70. this.classList.add('actionFailed')
  71. setTimeout(() => {
  72. this.classList.remove('actionFailed')
  73. }, 1000)
  74. }
  75. constructTemplate () {
  76. const tpl = document.getElementById('tplActionButton')
  77. const content = tpl.content.cloneNode(true)
  78. /*
  79. * FIXME: Should probably be using a shadowdom here, but seem to
  80. * get an error when combined with custom elements.
  81. */
  82. this.appendChild(content)
  83. this.domTitle = this.querySelector('.title')
  84. this.domIcon = this.querySelector('.icon')
  85. }
  86. updateHtml () {
  87. if (this.temporaryStatusMessage != null) {
  88. this.domTitle.innerText = this.temporaryStatusMessage
  89. this.domTitle.classList.add('temporaryStatusMessage')
  90. this.isWaiting = false
  91. this.disabled = false
  92. setTimeout(() => {
  93. this.temporaryStatusMessage = null
  94. this.domTitle.classList.remove('temporaryStatusMessage')
  95. this.updateHtml()
  96. }, 2000)
  97. } else if (this.isWaiting) {
  98. this.domTitle.innerText = 'Waiting...'
  99. } else {
  100. this.domTitle.innerText = this.title
  101. }
  102. this.domIcon.innerHTML = this.unicodeIcon
  103. }
  104. }
  105. window.customElements.define('action-button', ActionButton, { extends: 'button' })