123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <script setup lang="ts">
- import { defineAsyncComponent, ref, onMounted } from "vue";
- import { storeToRefs } from "pinia";
- import { useWebsocketsStore } from "@/stores/websockets";
- import { useLongJobsStore } from "@/stores/longJobs";
- import { useUserAuthStore } from "@/stores/userAuth";
- const FloatingBox = defineAsyncComponent(
- () => import("@/components/FloatingBox.vue")
- );
- const body = ref(document.body);
- const userAuthStore = useUserAuthStore();
- const { loggedIn } = storeToRefs(userAuthStore);
- const { socket } = useWebsocketsStore();
- const longJobsStore = useLongJobsStore();
- const { activeJobs } = storeToRefs(longJobsStore);
- const { setJob, setJobs, removeJob } = longJobsStore;
- const remove = job => {
- if (job.status === "success" || job.status === "error") {
- socket.dispatch("users.removeLongJob", job.id, res => {
- if (res.status === "success") {
- removeJob(job.id);
- } else console.log(res.message);
- });
- }
- };
- onMounted(() => {
- socket.onConnect(() => {
- if (loggedIn.value) {
- socket.dispatch("users.getLongJobs", {
- cb: res => {
- if (res.status === "success") {
- setJobs(res.data.longJobs);
- } else console.log(res.message);
- },
- onProgress: res => {
- setJob(res);
- }
- });
- }
- });
- socket.on("keep.event:longJob.removed", ({ data }) => {
- removeJob(data.jobId);
- });
- socket.on("keep.event:longJob.added", ({ data }) => {
- if (!activeJobs.value.find(activeJob => activeJob.id === data.jobId))
- socket.dispatch("users.getLongJob", data.jobId, {
- cb: res => {
- if (res.status === "success") {
- setJob(res.data.longJob);
- } else console.log(res.message);
- },
- onProgress: res => {
- setJob(res);
- }
- });
- });
- });
- </script>
- <template>
- <floating-box
- v-if="activeJobs.length > 0"
- title="Jobs"
- id="longJobs"
- ref="longJobs"
- :persist="true"
- initial="align-bottom"
- :min-width="200"
- :max-width="400"
- :min-height="200"
- >
- <template #body>
- <div class="active-jobs">
- <div
- v-for="job in activeJobs"
- :key="`activeJob-${job.id}`"
- class="active-job"
- >
- <i
- v-if="
- job.status === 'started' || job.status === 'update'
- "
- class="material-icons"
- content="In Progress"
- v-tippy="{ theme: 'info', placement: 'right' }"
- >
- pending
- </i>
- <i
- v-else-if="job.status === 'success'"
- class="material-icons success"
- content="Complete"
- v-tippy="{ theme: 'info', placement: 'right' }"
- >
- check_circle
- </i>
- <i
- v-else
- class="material-icons error"
- content="Failed"
- v-tippy="{ theme: 'info', placement: 'right' }"
- >
- error
- </i>
- <div class="name" :title="job.name">{{ job.name }}</div>
- <div class="actions">
- <i
- class="material-icons clear"
- :class="{
- disabled: !(
- job.status === 'success' ||
- job.status === 'error'
- )
- }"
- content="Clear"
- v-tippy="{ placement: 'left' }"
- @click="remove(job)"
- >
- remove_circle
- </i>
- <tippy
- :touch="true"
- :interactive="true"
- placement="left"
- ref="longJobMessage"
- :append-to="body"
- >
- <i class="material-icons message">chat</i>
- <template #content>
- <div class="long-job-message">
- <strong>Latest Update:</strong>
- <span :title="job.message">{{
- job.message
- }}</span>
- </div>
- </template>
- </tippy>
- </div>
- </div>
- </div>
- </template>
- </floating-box>
- </template>
- <style lang="less" scoped>
- .night-mode {
- #longJobs {
- .active-jobs {
- .active-job {
- background-color: var(--dark-grey);
- border: 0;
- }
- }
- }
- .long-job-message {
- color: var(--black);
- }
- }
- #longJobs {
- z-index: 5000 !important;
- .active-jobs {
- .active-job {
- display: flex;
- padding: 5px;
- margin: 5px 0;
- border: 1px solid var(--light-grey-3);
- border-radius: @border-radius;
- &:first-child {
- margin-top: 0;
- }
- &:last-child {
- margin-bottom: 0;
- }
- .name {
- line-height: 24px;
- font-weight: 600;
- text-transform: capitalize;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- margin-right: auto;
- }
- .material-icons {
- font-size: 20px;
- color: var(--primary-color);
- margin: auto 5px auto 0;
- cursor: pointer;
- &.success {
- color: var(--green);
- }
- &.error,
- &.clear {
- color: var(--red);
- }
- &.disabled {
- color: var(--light-grey-3);
- cursor: not-allowed;
- }
- }
- .actions {
- display: flex;
- .material-icons {
- margin: auto 0 auto 5px;
- }
- & > span {
- display: flex;
- padding: 0;
- }
- }
- }
- }
- }
- .long-job-message {
- display: flex;
- flex-direction: column;
- strong {
- font-size: 12px;
- }
- span {
- display: -webkit-inline-box;
- text-overflow: ellipsis;
- white-space: normal;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 3;
- overflow: hidden;
- max-width: 200px;
- font-size: 12px;
- }
- }
- </style>
|