flamenco/web/app/src/views/JobsView.vue
Sybren A. Stüvel e4e24fabf2 Webapp: update task details when a task update is received
Fix an issue where the task details panel was not updated when the Manager
sends a task update.
2025-09-04 17:52:36 +02:00

196 lines
5.5 KiB
Vue

<template>
<div class="col col-1">
<jobs-table ref="jobsTable" :activeJobID="jobID" />
</div>
<div class="col col-2 job-details-column" id="col-job-details">
<get-the-addon v-if="jobs.isJobless" />
<template v-else>
<job-details
ref="jobDetails"
:jobData="jobs.activeJob"
@reshuffled="_recalcTasksTableHeight" />
<tasks-table v-if="hasJobData" ref="tasksTable" :jobID="jobID" :taskID="taskID" />
</template>
</div>
<div class="col col-3">
<task-details
v-if="hasJobData"
:taskData="tasks.activeTask"
@showTaskLogTail="showTaskLogTail" />
</div>
<footer class="app-footer" v-if="!showFooterPopup" @click="showFooterPopup = true">
<notification-bar />
<div class="app-footer-expand">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round">
<line x1="12" y1="19" x2="12" y2="5"></line>
<polyline points="5 12 12 5 19 12"></polyline>
</svg>
</div>
</footer>
<footer-popup v-if="showFooterPopup" ref="footerPopup" @clickClose="showFooterPopup = false" />
<update-listener
ref="updateListener"
mainSubscription="allJobs"
:subscribedJobID="jobID"
:subscribedTaskID="taskID"
@jobUpdate="onSioJobUpdate"
@taskUpdate="onSioTaskUpdate"
@taskLogUpdate="onSioTaskLogUpdate"
@lastRenderedUpdate="onSioLastRenderedUpdate"
@message="onChatMessage"
@sioReconnected="onSIOReconnected"
@sioDisconnected="onSIODisconnected" />
</template>
<script>
import { useJobs } from '@/stores/jobs';
import { useTasks } from '@/stores/tasks';
import { useNotifs } from '@/stores/notifications';
import { useTaskLog } from '@/stores/tasklog';
import FooterPopup from '@/components/footer/FooterPopup.vue';
import GetTheAddon from '@/components/GetTheAddon.vue';
import JobDetails from '@/components/jobs/JobDetails.vue';
import JobsTable from '@/components/jobs/JobsTable.vue';
import NotificationBar from '@/components/footer/NotificationBar.vue';
import TaskDetails from '@/components/jobs/TaskDetails.vue';
import TasksTable from '@/components/jobs/TasksTable.vue';
import UpdateListener from '@/components/UpdateListener.vue';
export default {
name: 'JobsView',
props: ['jobID', 'taskID'], // provided by Vue Router.
components: {
FooterPopup,
GetTheAddon,
JobDetails,
JobsTable,
NotificationBar,
TaskDetails,
TasksTable,
UpdateListener,
},
data: () => ({
messages: [],
jobs: useJobs(),
tasks: useTasks(),
notifs: useNotifs(),
taskLog: useTaskLog(),
showFooterPopup: !!localStorage.getItem('footer-popover-visible'),
}),
computed: {
hasJobData() {
return !objectEmpty(this.jobs.activeJob);
},
},
mounted() {
window.jobsView = this;
window.footerPopup = this.$refs.footerPopup;
// Useful for debugging:
// this.jobs.$subscribe((mutation, state) => {
// console.log("Pinia mutation:", mutation)
// console.log("Pinia state :", state)
// })
window.addEventListener('resize', this._recalcTasksTableHeight);
},
unmounted() {
window.removeEventListener('resize', this._recalcTasksTableHeight);
},
watch: {
showFooterPopup(shown) {
if (shown) localStorage.setItem('footer-popover-visible', 'true');
else localStorage.removeItem('footer-popover-visible');
this._recalcTasksTableHeight();
},
},
methods: {
showTaskLogTail() {
this.showFooterPopup = true;
this.$nextTick(() => {
this.$refs.footerPopup.showTaskLogTail();
});
},
// SocketIO data event handlers:
onSioJobUpdate(jobUpdate) {
this.notifs.addJobUpdate(jobUpdate);
this.jobs.setIsJobless(false);
if (this.$refs.jobsTable) {
this.$refs.jobsTable.processJobUpdate(jobUpdate);
}
if (this.jobID != jobUpdate.id || jobUpdate.was_deleted) {
return;
}
if (jobUpdate.refresh_tasks) {
if (this.$refs.tasksTable) this.$refs.tasksTable.fetchTasks();
}
},
/**
* Event handler for SocketIO task updates.
* @param {API.EventTaskUpdate} taskUpdate
*/
onSioTaskUpdate(taskUpdate) {
if (this.$refs.tasksTable) this.$refs.tasksTable.processTaskUpdate(taskUpdate);
this.tasks.updateActiveTask(taskUpdate);
this.notifs.addTaskUpdate(taskUpdate);
},
/**
* Event handler for SocketIO task log updates.
* @param {API.EventTaskLogUpdate} taskLogUpdate
*/
onSioTaskLogUpdate(taskLogUpdate) {
this.taskLog.addTaskLogUpdate(taskLogUpdate);
},
/**
* Event handler for SocketIO "last-rendered" updates.
* @param {API.EventLastRenderedUpdate} lastRenderedUpdate
*/
onSioLastRenderedUpdate(lastRenderedUpdate) {
this.$refs.jobDetails.refreshLastRenderedImage(lastRenderedUpdate);
},
onChatMessage(message) {
console.log('chat message received:', message);
this.messages.push(`${message.text}`);
},
// SocketIO connection event handlers:
onSIOReconnected() {
this.$refs.jobsTable.onReconnected();
if (this.$refs.tasksTable) this.$refs.tasksTable.onReconnected();
},
onSIODisconnected(reason) {},
_recalcTasksTableHeight() {
if (!this.$refs.tasksTable) return;
// Any recalculation should be done after the DOM has updated.
this.$nextTick(this.$refs.tasksTable.recalcTableHeight);
},
},
};
</script>
<style scoped>
.isFetching {
opacity: 50%;
}
</style>