ExecutionDialog.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // This ExecutionDialog is NOT a custom HTML element, but rather just picks up
  2. // the <dialog /> element out of index.html and just re-uses that - as only
  3. // one dialog can be shown at a time.
  4. export class ExecutionDialog {
  5. constructor () {
  6. this.dlg = document.querySelector('dialog#execution-results-popup')
  7. this.domIcon = document.getElementById('execution-dialog-icon')
  8. this.domTitle = document.getElementById('execution-dialog-title')
  9. this.domOutput = document.getElementById('execution-dialog-xterm')
  10. this.domOutputDetails = document.getElementById('execution-dialog-output-details')
  11. this.domOutputToggleBig = document.getElementById('execution-dialog-toggle-size')
  12. this.domOutputToggleBig.onclick = () => {
  13. this.toggleSize()
  14. }
  15. this.domBtnKill = document.getElementById('execution-dialog-kill-action')
  16. this.domDatetimeStarted = document.getElementById('execution-dialog-datetime-started')
  17. this.domDatetimeFinished = document.getElementById('execution-dialog-datetime-finished')
  18. this.domExitCode = document.getElementById('execution-dialog-exit-code')
  19. this.domStatus = document.getElementById('execution-dialog-status')
  20. this.domExecutionBasics = document.getElementById('execution-dialog-basics')
  21. this.domExecutionDetails = document.getElementById('execution-dialog-details')
  22. this.domExecutionOutput = document.getElementById('execution-dialog-output')
  23. window.terminal.open(this.domOutput)
  24. }
  25. showOutput () {
  26. this.domOutput.hidden = false
  27. this.domOutputDetails.open = true
  28. this.domExecutionOutput.hidden = false
  29. }
  30. toggleSize () {
  31. if (this.dlg.classList.contains('big')) {
  32. this.dlg.classList.remove('big')
  33. this.domOutputDetails.open = false
  34. } else {
  35. this.dlg.classList.add('big')
  36. this.domOutputDetails.open = true
  37. }
  38. }
  39. reset () {
  40. this.executionSeconds = 0
  41. this.executionTrackingId = 'notset'
  42. this.dlg.classList.remove('big')
  43. this.domOutputToggleBig.hidden = false
  44. this.domIcon.innerText = ''
  45. this.domTitle.innerText = 'Waiting for result... '
  46. this.domExitCode.innerText = '?'
  47. this.domStatus.className = ''
  48. this.domDatetimeStarted.innerText = ''
  49. this.domDatetimeFinished.innerText = ''
  50. // window.terminal.close()
  51. this.domBtnKill.disabled = true
  52. this.domBtnKill.onclick = () => {}
  53. this.hideDetailsOnResult = false
  54. this.domExecutionBasics.hidden = false
  55. this.domExecutionDetails.hidden = true
  56. this.domOutputDetails.open = false
  57. window.terminal.reset()
  58. window.terminal.fit.fit()
  59. this.domExecutionOutput.hidden = true
  60. }
  61. show (actionButton) {
  62. if (typeof actionButton !== 'undefined' && actionButton != null) {
  63. this.domIcon.innerText = actionButton.domIcon.innerText
  64. }
  65. this.domBtnKill.disabled = false
  66. this.domBtnKill.onclick = () => {
  67. this.killAction()
  68. }
  69. clearInterval(window.executionDialogTicker)
  70. this.executionSeconds = 0
  71. this.executionTick()
  72. window.executionDialogTicker = setInterval(() => {
  73. this.executionTick()
  74. }, 1000)
  75. if (this.dlg.open) {
  76. this.dlg.close()
  77. }
  78. this.dlg.showModal()
  79. }
  80. killAction () {
  81. const killActionArgs = {
  82. executionTrackingId: this.executionTrackingId
  83. }
  84. window.fetch(window.restBaseUrl + 'KillAction', {
  85. cors: 'cors',
  86. method: 'POST',
  87. headers: {
  88. 'Content-Type': 'application/json'
  89. },
  90. body: JSON.stringify(killActionArgs)
  91. }).then((res) => {
  92. return res.json() // This isn't used by anything. UI is updated by OnExecutionFinished like normal.
  93. }).catch(err => {
  94. throw err
  95. })
  96. }
  97. executionTick () {
  98. this.executionSeconds++
  99. this.domDatetimeStarted.innerText = this.executionSeconds + ' seconds ago'
  100. }
  101. hideEverythingApartFromOutput () {
  102. this.hideDetailsOnResult = true
  103. this.domExecutionBasics.hidden = true
  104. }
  105. fetchExecutionResult (executionTrackingId) {
  106. this.executionTrackingId = executionTrackingId
  107. const executionStatusArgs = {
  108. executionTrackingId: this.executionTrackingId
  109. }
  110. window.fetch(window.restBaseUrl + 'ExecutionStatus', {
  111. cors: 'cors',
  112. method: 'POST',
  113. headers: {
  114. 'Content-Type': 'application/json'
  115. },
  116. body: JSON.stringify(executionStatusArgs)
  117. }).then((res) => {
  118. if (res.ok) {
  119. return res.json()
  120. } else {
  121. throw new Error(res.statusText)
  122. }
  123. }
  124. ).then((json) => {
  125. this.renderExecutionResult(json)
  126. }).catch(err => {
  127. this.renderError(err)
  128. })
  129. }
  130. renderExecutionResult (res) {
  131. this.res = res
  132. clearInterval(window.executionDialogTicker)
  133. this.domExecutionOutput.hidden = false
  134. if (!this.hideDetailsOnResult) {
  135. this.domExecutionDetails.hidden = false
  136. } else {
  137. this.domOutputDetails.open = true
  138. }
  139. this.executionTrackingId = res.logEntry.executionTrackingId
  140. this.domBtnKill.disabled = res.logEntry.executionFinished
  141. if (res.logEntry.executionFinished) {
  142. this.domStatus.innerText = 'Completed'
  143. this.domStatus.classList.add('action-success')
  144. this.domDatetimeFinished.innerText = res.logEntry.datetimeFinished
  145. if (res.logEntry.timedOut) {
  146. this.domExitCode.innerText = 'Timed out'
  147. this.domStatus.classList.add('action-timeout')
  148. } else if (res.logEntry.blocked) {
  149. this.domStatus.innerText = 'Blocked'
  150. this.domStatus.classList.add('action-blocked')
  151. } else if (res.logEntry.exitCode !== 0) {
  152. this.domStatus.innerText = 'Non-Zero Exit'
  153. this.domStatus.classList.add('action-nonzero-exit')
  154. } else {
  155. this.domExitCode.innerText = res.logEntry.exitCode
  156. }
  157. } else {
  158. this.domDatetimeFinished.innerText = 'Still running...'
  159. this.domExitCode.innerText = 'Still running...'
  160. this.domStatus.innerText = 'Still running...'
  161. }
  162. this.domIcon.innerHTML = res.logEntry.actionIcon
  163. this.domTitle.innerText = res.logEntry.actionTitle
  164. this.domDatetimeStarted.innerText = res.logEntry.datetimeStarted
  165. window.terminal.reset()
  166. window.terminal.write(res.logEntry.output, () => {
  167. window.terminal.fit.fit()
  168. })
  169. }
  170. renderError (err) {
  171. this.dlg.querySelector('pre').innerText = JSON.stringify(err)
  172. }
  173. }