LongJobs.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <template>
  2. <floating-box
  3. v-if="activeJobs.length > 0"
  4. title="Jobs"
  5. id="longJobs"
  6. ref="longJobs"
  7. :persist="true"
  8. initial="align-bottom"
  9. :min-width="200"
  10. :max-width="400"
  11. :min-height="200"
  12. >
  13. <template #body>
  14. <div class="active-jobs">
  15. <div
  16. v-for="job in activeJobs"
  17. :key="`activeJob-${job.id}`"
  18. class="active-job"
  19. >
  20. <i
  21. v-if="
  22. job.status === 'started' || job.status === 'update'
  23. "
  24. class="material-icons"
  25. content="In Progress"
  26. v-tippy="{ theme: 'info', placement: 'right' }"
  27. >
  28. pending
  29. </i>
  30. <i
  31. v-else-if="job.status === 'success'"
  32. class="material-icons success"
  33. content="Complete"
  34. v-tippy="{ theme: 'info', placement: 'right' }"
  35. >
  36. check_circle
  37. </i>
  38. <i
  39. v-else
  40. class="material-icons error"
  41. content="Failed"
  42. v-tippy="{ theme: 'info', placement: 'right' }"
  43. >
  44. error
  45. </i>
  46. <div class="name" :title="job.name">{{ job.name }}</div>
  47. <div class="actions">
  48. <i
  49. class="material-icons clear"
  50. :class="{
  51. disabled: !(
  52. job.status === 'success' ||
  53. job.status === 'error'
  54. )
  55. }"
  56. content="Clear"
  57. v-tippy="{ placement: 'left' }"
  58. @click="remove(job)"
  59. >
  60. remove_circle
  61. </i>
  62. <tippy
  63. :touch="true"
  64. :interactive="true"
  65. placement="left"
  66. ref="longJobMessage"
  67. :append-to="body"
  68. >
  69. <i class="material-icons">chat</i>
  70. <template #content>
  71. <div class="long-job-message">
  72. <strong>Latest Update:</strong>
  73. <span :title="job.message">{{
  74. job.message
  75. }}</span>
  76. </div>
  77. </template>
  78. </tippy>
  79. </div>
  80. </div>
  81. </div>
  82. </template>
  83. </floating-box>
  84. </template>
  85. <script>
  86. import { mapState, mapActions, mapGetters } from "vuex";
  87. import FloatingBox from "@/components/FloatingBox.vue";
  88. export default {
  89. components: {
  90. FloatingBox
  91. },
  92. data() {
  93. return {
  94. minimise: true,
  95. body: document.body
  96. };
  97. },
  98. computed: {
  99. ...mapState("longJobs", {
  100. activeJobs: state => state.activeJobs
  101. }),
  102. ...mapGetters({
  103. socket: "websockets/getSocket"
  104. })
  105. },
  106. mounted() {
  107. this.socket.dispatch("users.getLongJobs", {
  108. cb: res => {
  109. if (res.status === "success") {
  110. this.setJobs(res.data.longJobs);
  111. } else console.log(res.message);
  112. },
  113. onProgress: res => {
  114. this.setJob(res);
  115. }
  116. });
  117. },
  118. methods: {
  119. remove(job) {
  120. if (job.status === "success" || job.status === "error") {
  121. this.socket.dispatch("users.removeLongJob", job.id, res => {
  122. if (res.status === "success") {
  123. this.removeJob(job.id);
  124. } else console.log(res.message);
  125. });
  126. }
  127. },
  128. ...mapActions("longJobs", ["setJob", "setJobs", "removeJob"])
  129. }
  130. };
  131. </script>
  132. <style lang="less" scoped>
  133. .night-mode {
  134. #longJobs {
  135. .active-jobs {
  136. .active-job {
  137. background-color: var(--dark-grey);
  138. border: 0;
  139. }
  140. }
  141. }
  142. .long-job-message {
  143. color: var(--black);
  144. }
  145. }
  146. #longJobs {
  147. z-index: 5000 !important;
  148. .active-jobs {
  149. .active-job {
  150. display: flex;
  151. padding: 5px;
  152. margin: 5px 0;
  153. border: 1px solid var(--light-grey-3);
  154. border-radius: @border-radius;
  155. &:first-child {
  156. margin-top: 0;
  157. }
  158. &:last-child {
  159. margin-bottom: 0;
  160. }
  161. .name {
  162. line-height: 24px;
  163. font-weight: 600;
  164. text-transform: capitalize;
  165. text-overflow: ellipsis;
  166. white-space: nowrap;
  167. overflow: hidden;
  168. margin-right: auto;
  169. }
  170. .material-icons {
  171. font-size: 20px;
  172. color: var(--primary-color);
  173. margin: auto 5px auto 0;
  174. cursor: pointer;
  175. &.success {
  176. color: var(--green);
  177. }
  178. &.error,
  179. &.clear {
  180. color: var(--red);
  181. }
  182. &.disabled {
  183. color: var(--light-grey-3);
  184. cursor: not-allowed;
  185. }
  186. }
  187. .actions {
  188. display: flex;
  189. .material-icons {
  190. margin: auto 0 auto 5px;
  191. }
  192. & > span {
  193. display: flex;
  194. padding: 0;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. .long-job-message {
  201. display: flex;
  202. flex-direction: column;
  203. strong {
  204. font-size: 12px;
  205. }
  206. span {
  207. display: -webkit-inline-box;
  208. text-overflow: ellipsis;
  209. white-space: normal;
  210. -webkit-box-orient: vertical;
  211. -webkit-line-clamp: 3;
  212. overflow: hidden;
  213. max-width: 200px;
  214. font-size: 12px;
  215. }
  216. }
  217. </style>