feat: add jobs to queue in batches (#1253)
fixes https://github.com/mainsail-crew/mainsail/issues/920
This commit is contained in:
parent
c904b7ba71
commit
b3ce868dec
@ -324,6 +324,13 @@
|
||||
<v-icon class="mr-1">{{ mdiPlaylistPlus }}</v-icon>
|
||||
{{ $t('Files.AddToQueue') }}
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-if="!contextMenu.item.isDirectory && moonrakerComponents.includes('job_queue')"
|
||||
:disabled="!isGcodeFile(contextMenu.item)"
|
||||
@click="openAddBatchToQueueDialog(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiPlaylistPlus }}</v-icon>
|
||||
{{ $t('Files.AddBatchToQueue') }}
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-if="contextMenu.item.preheat_gcode !== null"
|
||||
:disabled="['error', 'printing', 'paused'].includes(printer_state)"
|
||||
@ -496,6 +503,53 @@
|
||||
</v-card-actions>
|
||||
</panel>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="dialogAddBatchToQueue.show" max-width="400">
|
||||
<panel
|
||||
:title="$t('Files.AddToQueue').toString()"
|
||||
card-class="gcode-files-add-to-queue-dialog"
|
||||
:icon="mdiPlaylistPlus"
|
||||
:margin-bottom="false">
|
||||
<template #buttons>
|
||||
<v-btn icon tile @click="dialogAddBatchToQueue.show = false">
|
||||
<v-icon>{{ mdiCloseThick }}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
ref="inputFieldAddToQueueCount"
|
||||
v-model="dialogAddBatchToQueue.count"
|
||||
:label="$t('Files.Count')"
|
||||
required
|
||||
hide-spin-buttons
|
||||
type="number"
|
||||
:rules="countInputRules"
|
||||
@keyup.enter="addBatchToQueueAction">
|
||||
<template #append-outer>
|
||||
<div class="_spin_button_group">
|
||||
<v-btn class="mt-n3" icon plain small @click="dialogAddBatchToQueue.count++">
|
||||
<v-icon>{{ mdiChevronUp }}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="dialogAddBatchToQueue.count <= 1"
|
||||
class="mb-n3"
|
||||
icon
|
||||
plain
|
||||
small
|
||||
@click="dialogAddBatchToQueue.count--">
|
||||
<v-icon>{{ mdiChevronDown }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="" text @click="dialogAddBatchToQueue.show = false">{{ $t('Files.Cancel') }}</v-btn>
|
||||
<v-btn color="primary" text @click="addBatchToQueueAction">{{ $t('Files.AddToQueue') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</panel>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -509,6 +563,8 @@ import Panel from '@/components/ui/Panel.vue'
|
||||
import SettingsRow from '@/components/settings/SettingsRow.vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import {
|
||||
mdiChevronDown,
|
||||
mdiChevronUp,
|
||||
mdiDragVertical,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiCheckboxMarked,
|
||||
@ -552,6 +608,12 @@ interface dialogPrintFile {
|
||||
item: FileStateGcodefile
|
||||
}
|
||||
|
||||
interface dialogAddBatchToQueue {
|
||||
show: boolean
|
||||
count: number
|
||||
item: FileStateGcodefile
|
||||
}
|
||||
|
||||
interface dialogRenameObject {
|
||||
show: boolean
|
||||
newName: string
|
||||
@ -572,6 +634,8 @@ interface tableColumnSetting {
|
||||
components: { StartPrintDialog, Panel, SettingsRow, draggable },
|
||||
})
|
||||
export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) {
|
||||
mdiChevronDown = mdiChevronDown
|
||||
mdiChevronUp = mdiChevronUp
|
||||
mdiFile = mdiFile
|
||||
mdiFileDocumentMultipleOutline = mdiFileDocumentMultipleOutline
|
||||
mdiMagnify = mdiMagnify
|
||||
@ -646,6 +710,12 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) {
|
||||
item: { ...this.contextMenu.item },
|
||||
}
|
||||
|
||||
private dialogAddBatchToQueue: dialogAddBatchToQueue = {
|
||||
show: false,
|
||||
count: 1,
|
||||
item: { ...this.contextMenu.item },
|
||||
}
|
||||
|
||||
private dialogRenameFile: dialogRenameObject = {
|
||||
show: false,
|
||||
newName: '',
|
||||
@ -671,6 +741,10 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) {
|
||||
(value: string) => !!value || this.$t('Files.InvalidNameEmpty'),
|
||||
(value: string) => !this.existsFilename(value) || this.$t('Files.InvalidNameAlreadyExists'),
|
||||
]
|
||||
private countInputRules = [
|
||||
(value: string) => !!value || this.$t('JobQueue.InvalidCountEmpty'),
|
||||
(value: string) => parseInt(value) > 0 || this.$t('JobQueue.InvalidCountGreaterZero'),
|
||||
]
|
||||
|
||||
existsFilename(name: string) {
|
||||
return this.files.findIndex((file: FileStateFile) => file.filename === name) >= 0
|
||||
@ -1097,11 +1171,31 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) {
|
||||
this.currentPath = this.currentPath.slice(0, this.currentPath.lastIndexOf('/'))
|
||||
}
|
||||
|
||||
addToQueue(item: FileStateGcodefile | FileStateFile) {
|
||||
async addToQueue(item: FileStateGcodefile) {
|
||||
let filename = [this.currentPath, item.filename].join('/')
|
||||
if (filename.startsWith('/')) filename = filename.slice(1)
|
||||
|
||||
this.$store.dispatch('server/jobQueue/addToQueue', [filename])
|
||||
await this.$store.dispatch('server/jobQueue/addToQueue', [filename])
|
||||
}
|
||||
|
||||
openAddBatchToQueueDialog(item: FileStateGcodefile) {
|
||||
this.dialogAddBatchToQueue.show = true
|
||||
this.dialogAddBatchToQueue.count = 1
|
||||
this.dialogAddBatchToQueue.item = item
|
||||
}
|
||||
|
||||
async addBatchToQueueAction() {
|
||||
let filename = [this.currentPath, this.dialogAddBatchToQueue.item.filename].join('/')
|
||||
if (filename.startsWith('/')) filename = filename.slice(1)
|
||||
|
||||
const array: string[] = []
|
||||
for (let i = 0; i < this.dialogAddBatchToQueue.count; i++) {
|
||||
array.push(filename)
|
||||
}
|
||||
|
||||
await this.$store.dispatch('server/jobQueue/addToQueue', array)
|
||||
|
||||
this.dialogAddBatchToQueue.show = false
|
||||
}
|
||||
|
||||
changeMetadataVisible(name: string, value: boolean) {
|
||||
@ -1336,6 +1430,15 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
._spin_button_group {
|
||||
width: 24px;
|
||||
margin-top: -6px;
|
||||
margin-left: -6px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/*noinspection CssUnusedSymbol*/
|
||||
.files-table .v-data-table-header__icon {
|
||||
|
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<panel ref="jobqueuePanel" :icon="mdiTrayFull" :title="$t('JobQueue.JobQueue')" card-class="jobqueue-panel">
|
||||
<panel
|
||||
ref="jobqueuePanel"
|
||||
:icon="mdiTrayFull"
|
||||
:title="$t('JobQueue.JobQueue').toString()"
|
||||
card-class="jobqueue-panel">
|
||||
<template #buttons>
|
||||
<v-btn
|
||||
v-if="queueState === 'paused'"
|
||||
@ -48,98 +52,29 @@
|
||||
</template>
|
||||
|
||||
<template #item="{ item }">
|
||||
<tr
|
||||
:key="item.job_id"
|
||||
v-longpress:600="(e) => showContextMenu(e, item)"
|
||||
class="file-list-cursor user-select-none"
|
||||
@contextmenu="showContextMenu($event, item)">
|
||||
<td class="pr-0 text-center" style="width: 32px">
|
||||
<template v-if="getSmallThumbnail(item) && getBigThumbnail(item)">
|
||||
<v-tooltip
|
||||
v-if="!item.isDirectory && getSmallThumbnail(item) && getBigThumbnail(item)"
|
||||
top
|
||||
content-class="tooltip__content-opacity1">
|
||||
<template #activator="{ on, attrs }">
|
||||
<vue-load-image>
|
||||
<img
|
||||
slot="image"
|
||||
:src="getSmallThumbnail(item)"
|
||||
width="32"
|
||||
height="32"
|
||||
v-bind="attrs"
|
||||
v-on="on" />
|
||||
<v-progress-circular
|
||||
slot="preloader"
|
||||
indeterminate
|
||||
color="primary"></v-progress-circular>
|
||||
<v-icon slot="error">{{ mdiFile }}</v-icon>
|
||||
</vue-load-image>
|
||||
</template>
|
||||
<span><img :src="getBigThumbnail(item)" width="250" /></span>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
<template v-else-if="getSmallThumbnail(item)">
|
||||
<vue-load-image>
|
||||
<img slot="image" :src="getSmallThumbnail(item)" width="32" height="32" />
|
||||
<v-progress-circular
|
||||
slot="preloader"
|
||||
indeterminate
|
||||
color="primary"></v-progress-circular>
|
||||
<v-icon slot="error">{{ mdiFile }}</v-icon>
|
||||
</vue-load-image>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-icon>{{ mdiFile }}</v-icon>
|
||||
</template>
|
||||
</td>
|
||||
<td class=" ">
|
||||
<div class="d-block text-truncate" :style="styleContentTdWidth">{{ item.filename }}</div>
|
||||
<small v-if="existMetadata(item)">{{ getDescription(item) }}</small>
|
||||
</td>
|
||||
</tr>
|
||||
<jobqueue-entry :key="item.job_id" :item="item" :content-td-width="contentTdWidth" />
|
||||
</template>
|
||||
</v-data-table>
|
||||
<resize-observer @notify="handleResize" />
|
||||
</panel>
|
||||
<v-menu v-model="contextMenu.shown" :position-x="contextMenu.x" :position-y="contextMenu.y" absolute offset-y>
|
||||
<v-list>
|
||||
<v-list-item @click="deleteJob(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiPlaylistRemove }}</v-icon>
|
||||
{{ $t('JobQueue.RemoveFromQueue') }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Mixins } from 'vue-property-decorator'
|
||||
import BaseMixin from '@/components/mixins/base'
|
||||
import { ServerHistoryStateJob } from '@/store/server/history/types'
|
||||
import { formatFilesize, formatPrintTime } from '@/plugins/helpers'
|
||||
import Panel from '@/components/ui/Panel.vue'
|
||||
import { ServerJobQueueStateJob } from '@/store/server/jobQueue/types'
|
||||
import { mdiPlay, mdiPause, mdiFile, mdiPlaylistRemove, mdiTrayFull } from '@mdi/js'
|
||||
import { mdiPlay, mdiPause, mdiTrayFull } from '@mdi/js'
|
||||
import JobqueueEntry from '@/components/panels/Status/JobqueueEntry.vue'
|
||||
@Component({
|
||||
components: { Panel },
|
||||
components: { JobqueueEntry, Panel },
|
||||
})
|
||||
export default class JobqueuePanel extends Mixins(BaseMixin) {
|
||||
mdiPlay = mdiPlay
|
||||
mdiPause = mdiPause
|
||||
mdiFile = mdiFile
|
||||
mdiPlaylistRemove = mdiPlaylistRemove
|
||||
mdiTrayFull = mdiTrayFull
|
||||
|
||||
formatFilesize = formatFilesize
|
||||
|
||||
private contentTdWidth = 100
|
||||
private contextMenu = {
|
||||
shown: false,
|
||||
touchTimer: undefined,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: {},
|
||||
}
|
||||
|
||||
declare $refs: {
|
||||
jobqueuePanel: any
|
||||
@ -161,27 +96,6 @@ export default class JobqueuePanel extends Mixins(BaseMixin) {
|
||||
this.$store.dispatch('gui/saveSetting', { name: 'view.jobqueue.countPerPage', value: newVal })
|
||||
}
|
||||
|
||||
get styleContentTdWidth() {
|
||||
return `width: ${this.contentTdWidth}px;`
|
||||
}
|
||||
|
||||
showContextMenu(e: any, item: ServerHistoryStateJob) {
|
||||
if (!this.contextMenu.shown) {
|
||||
e?.preventDefault()
|
||||
this.contextMenu.shown = true
|
||||
this.contextMenu.x = e?.clientX || e?.pageX || window.screenX / 2
|
||||
this.contextMenu.y = e?.clientY || e?.pageY || window.screenY / 2
|
||||
this.contextMenu.item = item
|
||||
this.$nextTick(() => {
|
||||
this.contextMenu.shown = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deleteJob(item: ServerJobQueueStateJob) {
|
||||
this.$store.dispatch('server/jobQueue/deleteFromQueue', [item.job_id])
|
||||
}
|
||||
|
||||
startJobqueue() {
|
||||
this.$store.dispatch('server/jobQueue/start')
|
||||
}
|
||||
@ -190,35 +104,6 @@ export default class JobqueuePanel extends Mixins(BaseMixin) {
|
||||
this.$store.dispatch('server/jobQueue/pause')
|
||||
}
|
||||
|
||||
getSmallThumbnail(item: ServerJobQueueStateJob) {
|
||||
return this.$store.getters['server/jobQueue/getSmallThumbnail'](item)
|
||||
}
|
||||
|
||||
getBigThumbnail(item: ServerJobQueueStateJob) {
|
||||
return this.$store.getters['server/jobQueue/getBigThumbnail'](item)
|
||||
}
|
||||
|
||||
getDescription(item: ServerJobQueueStateJob) {
|
||||
let output = ''
|
||||
|
||||
output += this.$t('Files.Filament') + ': '
|
||||
if (item.metadata?.filament_total || item.metadata.filament_weight_total) {
|
||||
if (item.metadata?.filament_total) output += item.metadata.filament_total.toFixed() + ' mm'
|
||||
if (item.metadata?.filament_total && item.metadata.filament_weight_total) output += ' / '
|
||||
if (item.metadata?.filament_weight_total) output += item.metadata.filament_weight_total.toFixed(2) + ' g'
|
||||
} else output += '--'
|
||||
|
||||
output += ', ' + this.$t('Files.PrintTime') + ': '
|
||||
if (item.metadata?.estimated_time) output += formatPrintTime(item.metadata.estimated_time)
|
||||
else output += '--'
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
existMetadata(item: ServerJobQueueStateJob) {
|
||||
return item?.metadata?.metadataPulled
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.calcContentTdWidth()
|
||||
}
|
||||
@ -235,7 +120,7 @@ export default class JobqueuePanel extends Mixins(BaseMixin) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.jobqueue-panel {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -83,6 +83,12 @@
|
||||
<v-icon class="mr-1">{{ mdiPlaylistPlus }}</v-icon>
|
||||
{{ $t('Files.AddToQueue') }}
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-if="moonrakerComponents.includes('job_queue')"
|
||||
@click="openAddBatchToQueueDialog(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiPlaylistPlus }}</v-icon>
|
||||
{{ $t('Files.AddBatchToQueue') }}
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-if="contextMenu.item.preheat_gcode !== null"
|
||||
:disabled="['error', 'printing', 'paused'].includes(printer_state)"
|
||||
@ -137,6 +143,53 @@
|
||||
</v-card-actions>
|
||||
</panel>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="dialogAddBatchToQueue.show" max-width="400">
|
||||
<panel
|
||||
:title="$t('Files.AddToQueue').toString()"
|
||||
card-class="gcode-files-add-to-queue-dialog"
|
||||
:icon="mdiPlaylistPlus"
|
||||
:margin-bottom="false">
|
||||
<template #buttons>
|
||||
<v-btn icon tile @click="dialogAddBatchToQueue.show = false">
|
||||
<v-icon>{{ mdiCloseThick }}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
ref="inputFieldAddToQueueCount"
|
||||
v-model="dialogAddBatchToQueue.count"
|
||||
:label="$t('Files.Count')"
|
||||
required
|
||||
hide-spin-buttons
|
||||
type="number"
|
||||
:rules="countInputRules"
|
||||
@keyup.enter="addBatchToQueueAction">
|
||||
<template #append-outer>
|
||||
<div class="_spin_button_group">
|
||||
<v-btn class="mt-n3" icon plain small @click="dialogAddBatchToQueue.count++">
|
||||
<v-icon>{{ mdiChevronUp }}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="dialogAddBatchToQueue.count <= 1"
|
||||
class="mb-n3"
|
||||
icon
|
||||
plain
|
||||
small
|
||||
@click="dialogAddBatchToQueue.count--">
|
||||
<v-icon>{{ mdiChevronDown }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="" text @click="dialogAddBatchToQueue.show = false">{{ $t('Files.Cancel') }}</v-btn>
|
||||
<v-btn color="primary" text @click="addBatchToQueueAction">{{ $t('Files.AddToQueue') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</panel>
|
||||
</v-dialog>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
@ -148,6 +201,8 @@ import ControlMixin from '@/components/mixins/control'
|
||||
import { FileStateGcodefile } from '@/store/files/types'
|
||||
import StartPrintDialog from '@/components/dialogs/StartPrintDialog.vue'
|
||||
import {
|
||||
mdiChevronDown,
|
||||
mdiChevronUp,
|
||||
mdiFile,
|
||||
mdiPlay,
|
||||
mdiPlaylistPlus,
|
||||
@ -166,12 +221,20 @@ interface dialogRenameObject {
|
||||
item: FileStateGcodefile
|
||||
}
|
||||
|
||||
interface dialogAddBatchToQueue {
|
||||
show: boolean
|
||||
count: number
|
||||
item: FileStateGcodefile
|
||||
}
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
StartPrintDialog,
|
||||
},
|
||||
})
|
||||
export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixin) {
|
||||
mdiChevronDown = mdiChevronDown
|
||||
mdiChevronUp = mdiChevronUp
|
||||
mdiFile = mdiFile
|
||||
mdiPlay = mdiPlay
|
||||
mdiPlaylistPlus = mdiPlaylistPlus
|
||||
@ -199,6 +262,7 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
|
||||
last_status: null,
|
||||
last_start_time: null,
|
||||
last_total_duration: null,
|
||||
preheat_gcode: null,
|
||||
}
|
||||
private currentPath = ''
|
||||
private contentTdWidth = 100
|
||||
@ -222,6 +286,17 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
|
||||
item: { ...this.dialogFile },
|
||||
}
|
||||
|
||||
private dialogAddBatchToQueue: dialogAddBatchToQueue = {
|
||||
show: false,
|
||||
count: 1,
|
||||
item: { ...this.contextMenu.item },
|
||||
}
|
||||
|
||||
private countInputRules = [
|
||||
(value: string) => !!value || this.$t('JobQueue.InvalidCountEmpty'),
|
||||
(value: string) => parseInt(value) > 0 || this.$t('JobQueue.InvalidCountGreaterZero'),
|
||||
]
|
||||
|
||||
get gcodeFiles() {
|
||||
let gcodes = this.$store.getters['files/getAllGcodes'] ?? []
|
||||
gcodes = gcodes
|
||||
@ -343,6 +418,26 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
|
||||
this.$store.dispatch('server/jobQueue/addToQueue', [item.filename])
|
||||
}
|
||||
|
||||
openAddBatchToQueueDialog(item: FileStateGcodefile) {
|
||||
this.dialogAddBatchToQueue.show = true
|
||||
this.dialogAddBatchToQueue.count = 1
|
||||
this.dialogAddBatchToQueue.item = item
|
||||
}
|
||||
|
||||
async addBatchToQueueAction() {
|
||||
let filename = [this.currentPath, this.dialogAddBatchToQueue.item.filename].join('/')
|
||||
if (filename.startsWith('/')) filename = filename.slice(1)
|
||||
|
||||
const array: string[] = []
|
||||
for (let i = 0; i < this.dialogAddBatchToQueue.count; i++) {
|
||||
array.push(filename)
|
||||
}
|
||||
|
||||
await this.$store.dispatch('server/jobQueue/addToQueue', array)
|
||||
|
||||
this.dialogAddBatchToQueue.show = false
|
||||
}
|
||||
|
||||
view3D(item: FileStateGcodefile) {
|
||||
this.$router.push({ path: '/viewer', query: { filename: 'gcodes/' + item.filename } })
|
||||
}
|
||||
@ -419,8 +514,15 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style scoped>
|
||||
.filesGcodeCard {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
._spin_button_group {
|
||||
width: 24px;
|
||||
margin-top: -6px;
|
||||
margin-left: -6px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
</style>
|
||||
|
@ -5,77 +5,27 @@
|
||||
hide-default-footer
|
||||
class="dashboard-jobqueue-table"
|
||||
sort-by="time_added"
|
||||
mobile-breakpoint="0"
|
||||
@current-items="setFirst">
|
||||
mobile-breakpoint="0">
|
||||
<template #no-data>
|
||||
<div class="text-center">{{ $t('Panels.StatusPanel.EmptyJobqueue') }}</div>
|
||||
</template>
|
||||
|
||||
<template #item="{ item }">
|
||||
<tr
|
||||
<template #item="{ item, index }">
|
||||
<jobqueue-entry
|
||||
:key="item.job_id"
|
||||
v-longpress:600="(e) => showContextMenu(e, item)"
|
||||
class="cursor-pointer"
|
||||
@contextmenu="showContextMenu($event, item)">
|
||||
<td class="pr-0 text-center" style="width: 32px">
|
||||
<template v-if="getSmallThumbnail(item) && getBigThumbnail(item)">
|
||||
<v-tooltip
|
||||
v-if="!item.isDirectory && getSmallThumbnail(item) && getBigThumbnail(item)"
|
||||
top
|
||||
content-class="tooltip__content-opacity1">
|
||||
<template #activator="{ on, attrs }">
|
||||
<vue-load-image>
|
||||
<img
|
||||
slot="image"
|
||||
:src="getSmallThumbnail(item)"
|
||||
width="32"
|
||||
height="32"
|
||||
v-bind="attrs"
|
||||
v-on="on" />
|
||||
<v-progress-circular
|
||||
slot="preloader"
|
||||
indeterminate
|
||||
color="primary"></v-progress-circular>
|
||||
<v-icon slot="error">{{ mdiFile }}</v-icon>
|
||||
</vue-load-image>
|
||||
:item="item"
|
||||
:isFirst="index === 0"
|
||||
:content-td-width="contentTdWidth" />
|
||||
</template>
|
||||
<span><img :src="getBigThumbnail(item)" width="250" /></span>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
<template v-else-if="getSmallThumbnail(item)">
|
||||
<vue-load-image>
|
||||
<img slot="image" :src="getSmallThumbnail(item)" width="32" height="32" />
|
||||
<v-progress-circular
|
||||
slot="preloader"
|
||||
indeterminate
|
||||
color="primary"></v-progress-circular>
|
||||
<v-icon slot="error">{{ mdiFile }}</v-icon>
|
||||
</vue-load-image>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-icon>{{ mdiFile }}</v-icon>
|
||||
</template>
|
||||
</td>
|
||||
<td class="pr-2">
|
||||
<template v-if="item.isFirst && !printerIsPrinting">
|
||||
<v-btn icon color="success" class="float-right minwidth-0 mt-1" @click="startJobqueue">
|
||||
<v-icon>{{ mdiPlay }}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<div class="d-block text-truncate" :style="styleContentTdWidth">{{ item.filename }}</div>
|
||||
<small v-if="existMetadata(item)">{{ getDescription(item) }}</small>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template v-if="jobs.length > jobsTable.length" #body.append>
|
||||
<template v-if="jobsRest.length" #body.append>
|
||||
<tr>
|
||||
<td class="pr-0 text-center" style="width: 32px">
|
||||
<v-icon>{{ mdiFileMultiple }}</v-icon>
|
||||
</td>
|
||||
<td class="pr-2">
|
||||
{{
|
||||
$tc('Panels.StatusPanel.JobqueueMoreFiles', jobs.length - jobsTable.length, {
|
||||
count: jobs.length - jobsTable.length,
|
||||
$tc('Panels.StatusPanel.JobqueueMoreFiles', restJobsLength, {
|
||||
count: restJobsLength,
|
||||
})
|
||||
}}
|
||||
<br />
|
||||
@ -85,14 +35,6 @@
|
||||
</template>
|
||||
</v-data-table>
|
||||
<resize-observer @notify="handleResize" />
|
||||
<v-menu v-model="contextMenu.shown" :position-x="contextMenu.x" :position-y="contextMenu.y" absolute offset-y>
|
||||
<v-list>
|
||||
<v-list-item @click="removeFromJobqueue(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiPlaylistRemove }}</v-icon>
|
||||
{{ $t('JobQueue.RemoveFromQueue') }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
@ -101,24 +43,15 @@ import Component from 'vue-class-component'
|
||||
import { Mixins } from 'vue-property-decorator'
|
||||
import BaseMixin from '@/components/mixins/base'
|
||||
import { ServerJobQueueStateJob } from '@/store/server/jobQueue/types'
|
||||
import { mdiFile, mdiPlay, mdiFileMultiple, mdiPlaylistRemove } from '@mdi/js'
|
||||
import { mdiFileMultiple } from '@mdi/js'
|
||||
import JobqueueEntry from '@/components/panels/Status/JobqueueEntry.vue'
|
||||
@Component({
|
||||
components: {},
|
||||
components: { JobqueueEntry },
|
||||
})
|
||||
export default class StatusPanelJobqueue extends Mixins(BaseMixin) {
|
||||
mdiFile = mdiFile
|
||||
mdiPlay = mdiPlay
|
||||
mdiFileMultiple = mdiFileMultiple
|
||||
mdiPlaylistRemove = mdiPlaylistRemove
|
||||
|
||||
private contentTdWidth = 100
|
||||
private contextMenu = {
|
||||
shown: false,
|
||||
touchTimer: undefined,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: {},
|
||||
}
|
||||
|
||||
declare $refs: {
|
||||
filesJobqueue: any
|
||||
@ -136,15 +69,27 @@ export default class StatusPanelJobqueue extends Mixins(BaseMixin) {
|
||||
return this.jobs.slice(5)
|
||||
}
|
||||
|
||||
get restJobsLength() {
|
||||
let count = 0
|
||||
|
||||
this.jobsRest.forEach((item: ServerJobQueueStateJob) => {
|
||||
count += (item.combinedIds?.length ?? 0) + 1
|
||||
})
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
get descriptionRestJobs() {
|
||||
let filamentLength = 0
|
||||
let filamentWeight = 0
|
||||
let printTime = 0
|
||||
|
||||
this.jobsRest.forEach((item: ServerJobQueueStateJob) => {
|
||||
if (item.metadata?.filament_total) filamentLength += item.metadata?.filament_total
|
||||
if (item.metadata?.filament_weight_total) filamentWeight += item.metadata?.filament_weight_total
|
||||
if (item.metadata?.estimated_time) printTime = item.metadata.estimated_time
|
||||
const count = (item.combinedIds?.length ?? 0) + 1
|
||||
|
||||
if (item.metadata?.filament_total) filamentLength += item.metadata?.filament_total * count
|
||||
if (item.metadata?.filament_weight_total) filamentWeight += item.metadata?.filament_weight_total * count
|
||||
if (item.metadata?.estimated_time) printTime = item.metadata.estimated_time * count
|
||||
})
|
||||
|
||||
let output = ''
|
||||
@ -163,49 +108,6 @@ export default class StatusPanelJobqueue extends Mixins(BaseMixin) {
|
||||
return output
|
||||
}
|
||||
|
||||
get styleContentTdWidth() {
|
||||
return `width: ${this.contentTdWidth}px;`
|
||||
}
|
||||
|
||||
getSmallThumbnail(item: ServerJobQueueStateJob) {
|
||||
return this.$store.getters['server/jobQueue/getSmallThumbnail'](item)
|
||||
}
|
||||
|
||||
getBigThumbnail(item: ServerJobQueueStateJob) {
|
||||
return this.$store.getters['server/jobQueue/getBigThumbnail'](item)
|
||||
}
|
||||
|
||||
getDescription(item: ServerJobQueueStateJob) {
|
||||
let output = ''
|
||||
|
||||
output += this.$t('Panels.StatusPanel.Filament') + ': '
|
||||
if (item.metadata?.filament_total || item.metadata.filament_weight_total) {
|
||||
if (item.metadata?.filament_total) output += item.metadata.filament_total.toFixed() + ' mm'
|
||||
if (item.metadata?.filament_total && item.metadata.filament_weight_total) output += ' / '
|
||||
if (item.metadata?.filament_weight_total) output += item.metadata.filament_weight_total.toFixed(2) + ' g'
|
||||
} else output += '--'
|
||||
|
||||
output += ', ' + this.$t('Panels.StatusPanel.PrintTime') + ': '
|
||||
if (item.metadata?.estimated_time) output += this.formatPrintTime(item.metadata.estimated_time)
|
||||
else output += '--'
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
existMetadata(item: ServerJobQueueStateJob) {
|
||||
return item?.metadata?.metadataPulled
|
||||
}
|
||||
|
||||
setFirst(currItems: ServerJobQueueStateJob[]) {
|
||||
// first check that actually exists values
|
||||
if (currItems.length) {
|
||||
// toggle all to false
|
||||
currItems.forEach((x: ServerJobQueueStateJob) => (x.isFirst = false))
|
||||
// just set first to true
|
||||
currItems[0].isFirst = true
|
||||
}
|
||||
}
|
||||
|
||||
formatPrintTime(totalSeconds: number) {
|
||||
if (totalSeconds) {
|
||||
let output = ''
|
||||
@ -232,27 +134,10 @@ export default class StatusPanelJobqueue extends Mixins(BaseMixin) {
|
||||
return '--'
|
||||
}
|
||||
|
||||
showContextMenu(e: any, item: ServerJobQueueStateJob) {
|
||||
if (!this.contextMenu.shown) {
|
||||
e?.preventDefault()
|
||||
this.contextMenu.shown = true
|
||||
this.contextMenu.x = e?.clientX || e?.pageX || window.screenX / 2
|
||||
this.contextMenu.y = e?.clientY || e?.pageY || window.screenY / 2
|
||||
this.contextMenu.item = item
|
||||
this.$nextTick(() => {
|
||||
this.contextMenu.shown = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
startJobqueue() {
|
||||
this.$store.dispatch('server/jobQueue/start')
|
||||
}
|
||||
|
||||
removeFromJobqueue(item: ServerJobQueueStateJob) {
|
||||
this.$store.dispatch('server/jobQueue/deleteFromQueue', [item.job_id])
|
||||
}
|
||||
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.calcContentTdWidth()
|
||||
|
271
src/components/panels/Status/JobqueueEntry.vue
Normal file
271
src/components/panels/Status/JobqueueEntry.vue
Normal file
@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<tr
|
||||
v-longpress:600="(e) => showContextMenu(e, item)"
|
||||
class="cursor-pointer"
|
||||
@contextmenu="showContextMenu($event, item)">
|
||||
<td class="pr-0 text-center" style="width: 32px">
|
||||
<template v-if="smallThumbnail && bigThumbnail">
|
||||
<v-tooltip v-if="smallThumbnail && bigThumbnail" top content-class="tooltip__content-opacity1">
|
||||
<template #activator="{ on, attrs }">
|
||||
<vue-load-image>
|
||||
<img slot="image" :src="smallThumbnail" width="32" height="32" v-bind="attrs" v-on="on" />
|
||||
<div slot="preloader">
|
||||
<v-progress-circular indeterminate color="primary" />
|
||||
</div>
|
||||
<div slot="error">
|
||||
<v-icon>{{ mdiFile }}</v-icon>
|
||||
</div>
|
||||
</vue-load-image>
|
||||
</template>
|
||||
<span><img :src="bigThumbnail" width="250" /></span>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
<template v-else-if="smallThumbnail">
|
||||
<vue-load-image>
|
||||
<img slot="image" :src="smallThumbnail" width="32" height="32" />
|
||||
<div slot="preloader">
|
||||
<v-progress-circular indeterminate color="primary" />
|
||||
</div>
|
||||
<div slot="error">
|
||||
<v-icon>{{ mdiFile }}</v-icon>
|
||||
</div>
|
||||
</vue-load-image>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-icon>{{ mdiFile }}</v-icon>
|
||||
</template>
|
||||
</td>
|
||||
<td class="pr-2">
|
||||
<template v-if="isFirst && !printerIsPrinting">
|
||||
<v-btn icon color="success" class="float-right minwidth-0 mt-1" @click="startJobqueue">
|
||||
<v-icon>{{ mdiPlay }}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<div class="d-block text-truncate" :style="styleContentTdWidth">
|
||||
<strong v-if="item.combinedIds.length">{{ item.combinedIds.length + 1 }}x</strong>
|
||||
{{ item.filename }}
|
||||
</div>
|
||||
<small v-if="item?.metadata?.metadataPulled">{{ description }}</small>
|
||||
</td>
|
||||
<v-menu v-model="contextMenu.shown" :position-x="contextMenu.x" :position-y="contextMenu.y" absolute offset-y>
|
||||
<v-list>
|
||||
<v-list-item @click="openChangeCountDialog(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiCounter }}</v-icon>
|
||||
{{ $t('JobQueue.ChangeCount') }}
|
||||
</v-list-item>
|
||||
<v-list-item @click="removeFromJobqueue(contextMenu.item)">
|
||||
<v-icon class="mr-1">{{ mdiPlaylistRemove }}</v-icon>
|
||||
{{ $t('JobQueue.RemoveFromQueue') }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-dialog v-model="dialogChangeCount.show" max-width="400">
|
||||
<panel
|
||||
:title="$t('JobQueue.ChangeCount').toString()"
|
||||
:icon="mdiCounter"
|
||||
card-class="jobqueue-change-count-dialog"
|
||||
:margin-bottom="false">
|
||||
<template #buttons>
|
||||
<v-btn icon tile @click="dialogChangeCount.show = false">
|
||||
<v-icon>{{ mdiCloseThick }}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
ref="inputFieldAddToQueueCount"
|
||||
v-model="dialogChangeCount.count"
|
||||
:label="$t('JobQueue.Count')"
|
||||
required
|
||||
:rules="countInputRules"
|
||||
hide-spin-buttons
|
||||
type="number"
|
||||
@keyup.enter="changeCountAction">
|
||||
<template #append-outer>
|
||||
<div class="_spin_button_group">
|
||||
<v-btn class="mt-n3" icon plain small @click="dialogChangeCount.count++">
|
||||
<v-icon>{{ mdiChevronUp }}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="dialogChangeCount.count <= 1"
|
||||
class="mb-n3"
|
||||
icon
|
||||
plain
|
||||
small
|
||||
@click="dialogChangeCount.count--">
|
||||
<v-icon>{{ mdiChevronDown }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn color="" text @click="dialogChangeCount.show = false">{{ $t('JobQueue.Cancel') }}</v-btn>
|
||||
<v-btn color="primary" text @click="changeCountAction">{{ $t('JobQueue.ChangeCount') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</panel>
|
||||
</v-dialog>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Component from 'vue-class-component'
|
||||
import { Mixins, Prop } from 'vue-property-decorator'
|
||||
import BaseMixin from '@/components/mixins/base'
|
||||
import { ServerJobQueueStateJob } from '@/store/server/jobQueue/types'
|
||||
import { mdiChevronDown, mdiChevronUp, mdiCloseThick, mdiCounter, mdiFile, mdiPlay, mdiPlaylistRemove } from '@mdi/js'
|
||||
import NumberInput from '@/components/inputs/NumberInput.vue'
|
||||
@Component({
|
||||
components: { NumberInput },
|
||||
})
|
||||
export default class StatusPanelJobqueueEntry extends Mixins(BaseMixin) {
|
||||
mdiChevronDown = mdiChevronDown
|
||||
mdiChevronUp = mdiChevronUp
|
||||
mdiCloseThick = mdiCloseThick
|
||||
mdiCounter = mdiCounter
|
||||
mdiFile = mdiFile
|
||||
mdiPlay = mdiPlay
|
||||
mdiPlaylistRemove = mdiPlaylistRemove
|
||||
|
||||
@Prop({ type: Object, required: true }) declare item: ServerJobQueueStateJob
|
||||
@Prop({ type: Number, required: true }) declare contentTdWidth: number
|
||||
@Prop({ type: Boolean, default: false }) declare isFirst: boolean
|
||||
private contextMenu: {
|
||||
shown: boolean
|
||||
x: number
|
||||
y: number
|
||||
item: ServerJobQueueStateJob | any
|
||||
} = {
|
||||
shown: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: {},
|
||||
}
|
||||
|
||||
private dialogChangeCount: {
|
||||
show: boolean
|
||||
count: number
|
||||
item: ServerJobQueueStateJob | any
|
||||
} = {
|
||||
show: false,
|
||||
count: 1,
|
||||
item: {},
|
||||
}
|
||||
|
||||
private countInputRules = [
|
||||
(value: string) => !!value || this.$t('JobQueue.InvalidCountEmpty'),
|
||||
(value: string) => parseInt(value) > 0 || this.$t('JobQueue.InvalidCountGreaterZero'),
|
||||
]
|
||||
|
||||
declare $refs: {
|
||||
filesJobqueue: any
|
||||
}
|
||||
|
||||
get styleContentTdWidth() {
|
||||
return `width: ${this.contentTdWidth}px;`
|
||||
}
|
||||
|
||||
get smallThumbnail() {
|
||||
return this.$store.getters['server/jobQueue/getSmallThumbnail'](this.item)
|
||||
}
|
||||
|
||||
get bigThumbnail() {
|
||||
return this.$store.getters['server/jobQueue/getBigThumbnail'](this.item)
|
||||
}
|
||||
|
||||
get description() {
|
||||
let output = ''
|
||||
|
||||
output += this.$t('Panels.StatusPanel.Filament') + ': '
|
||||
if (this.item.metadata?.filament_total || this.item.metadata.filament_weight_total) {
|
||||
if (this.item.metadata?.filament_total) output += this.item.metadata.filament_total.toFixed() + ' mm'
|
||||
if (this.item.metadata?.filament_total && this.item.metadata.filament_weight_total) output += ' / '
|
||||
if (this.item.metadata?.filament_weight_total)
|
||||
output += this.item.metadata.filament_weight_total.toFixed(2) + ' g'
|
||||
} else output += '--'
|
||||
|
||||
output += ', ' + this.$t('Panels.StatusPanel.PrintTime') + ': '
|
||||
if (this.item.metadata?.estimated_time) output += this.formatPrintTime(this.item.metadata.estimated_time)
|
||||
else output += '--'
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
formatPrintTime(totalSeconds: number) {
|
||||
if (totalSeconds) {
|
||||
let output = ''
|
||||
|
||||
const days = Math.floor(totalSeconds / (3600 * 24))
|
||||
if (days) {
|
||||
totalSeconds %= 3600 * 24
|
||||
output += days + 'd'
|
||||
}
|
||||
|
||||
const hours = Math.floor(totalSeconds / 3600)
|
||||
totalSeconds %= 3600
|
||||
if (hours) output += ' ' + hours + 'h'
|
||||
|
||||
const minutes = Math.floor(totalSeconds / 60)
|
||||
if (minutes) output += ' ' + minutes + 'm'
|
||||
|
||||
const seconds = totalSeconds % 60
|
||||
if (seconds) output += ' ' + seconds.toFixed(0) + 's'
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
return '--'
|
||||
}
|
||||
|
||||
showContextMenu(e: any, item: ServerJobQueueStateJob) {
|
||||
if (!this.contextMenu.shown) {
|
||||
e?.preventDefault()
|
||||
this.contextMenu.shown = true
|
||||
this.contextMenu.x = e?.clientX || e?.pageX || window.screenX / 2
|
||||
this.contextMenu.y = e?.clientY || e?.pageY || window.screenY / 2
|
||||
this.contextMenu.item = item
|
||||
this.$nextTick(() => {
|
||||
this.contextMenu.shown = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
startJobqueue() {
|
||||
this.$store.dispatch('server/jobQueue/start')
|
||||
}
|
||||
|
||||
removeFromJobqueue(item: ServerJobQueueStateJob) {
|
||||
const ids = [...(item.combinedIds ?? [])]
|
||||
ids.push(item.job_id)
|
||||
|
||||
this.$store.dispatch('server/jobQueue/deleteFromQueue', ids)
|
||||
}
|
||||
|
||||
openChangeCountDialog(item: ServerJobQueueStateJob) {
|
||||
this.dialogChangeCount.show = true
|
||||
this.dialogChangeCount.count = (item.combinedIds?.length ?? 0) + 1
|
||||
this.dialogChangeCount.item = item
|
||||
}
|
||||
|
||||
changeCountAction() {
|
||||
this.$store.dispatch('server/jobQueue/changeCount', {
|
||||
job_id: this.dialogChangeCount.item.job_id,
|
||||
count: this.dialogChangeCount.count,
|
||||
})
|
||||
this.dialogChangeCount.show = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.filesJobqueue {
|
||||
position: relative;
|
||||
}
|
||||
._spin_button_group {
|
||||
width: 24px;
|
||||
margin-top: -6px;
|
||||
margin-left: -6px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
</style>
|
@ -133,7 +133,7 @@ export default class StatusPanel extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
get jobsCount() {
|
||||
return this.jobs?.length ?? 0
|
||||
return this.$store.getters['server/jobQueue/getJobsCount'] ?? 0
|
||||
}
|
||||
|
||||
get current_filename() {
|
||||
|
@ -164,11 +164,13 @@
|
||||
"Yes": "Yes"
|
||||
},
|
||||
"Files": {
|
||||
"AddBatchToQueue": "Add batch to Queue",
|
||||
"AddToQueue": "Add to Queue",
|
||||
"AllFiles": "All",
|
||||
"BedTemp": "Bed Temp.",
|
||||
"Cancel": "Cancel",
|
||||
"ChamberTemp": "Chamber Temp.",
|
||||
"Count": "Count",
|
||||
"Create": "Create",
|
||||
"CreateNewDirectory": "Create new Directory",
|
||||
"CurrentPath": "Current path",
|
||||
@ -369,7 +371,12 @@
|
||||
},
|
||||
"JobQueue": {
|
||||
"AllJobs": "All Jobs",
|
||||
"ChangeCount": "Change count",
|
||||
"Cancel": "Cancel",
|
||||
"Count": "Count",
|
||||
"Empty": "Empty",
|
||||
"InvalidCountEmpty": "Input must not be empty!",
|
||||
"InvalidCountGreaterZero": "Input must be greater than 0!",
|
||||
"JobQueue": "Job Queue",
|
||||
"Jobs": "Jobs",
|
||||
"Pause": "Pause",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import { ActionTree } from 'vuex'
|
||||
import { RootState } from '@/store/types'
|
||||
import { ServerJobQueueState } from '@/store/server/jobQueue/types'
|
||||
import { ServerJobQueueState, ServerJobQueueStateJob } from '@/store/server/jobQueue/types'
|
||||
|
||||
export const actions: ActionTree<ServerJobQueueState, RootState> = {
|
||||
reset({ commit }) {
|
||||
@ -28,6 +28,31 @@ export const actions: ActionTree<ServerJobQueueState, RootState> = {
|
||||
Vue.$socket.emit('server.job_queue.post_job', { filenames: filenames })
|
||||
},
|
||||
|
||||
changeCount({ getters }, payload: { job_id: string; count: number }) {
|
||||
const filenames: string[] = []
|
||||
const jobs = getters['getJobs']
|
||||
|
||||
jobs.forEach((job: ServerJobQueueStateJob) => {
|
||||
if (job.job_id === payload.job_id) {
|
||||
for (let i = 0; i < payload.count; i++) {
|
||||
filenames.push(job.filename)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const count = (job.combinedIds?.length ?? 0) + 1
|
||||
for (let i = 0; i < count; i++) {
|
||||
filenames.push(job.filename)
|
||||
}
|
||||
})
|
||||
|
||||
Vue.$socket.emit('server.job_queue.post_job', {
|
||||
filenames,
|
||||
reset: true,
|
||||
})
|
||||
},
|
||||
|
||||
deleteFromQueue(_, job_ids: string[]) {
|
||||
Vue.$socket.emit('server.job_queue.delete_job', { job_ids })
|
||||
},
|
||||
|
@ -10,10 +10,17 @@ export const getters: GetterTree<ServerJobQueueState, any> = {
|
||||
|
||||
state.queued_jobs.forEach((queuedJob) => {
|
||||
const job = { ...queuedJob }
|
||||
|
||||
if (jobs.length && jobs[jobs.length - 1].filename === job.filename) {
|
||||
jobs[jobs.length - 1].combinedIds?.push(job.job_id)
|
||||
return
|
||||
}
|
||||
|
||||
const file = rootGetters['files/getFile']('gcodes/' + job.filename)
|
||||
if (!file?.metadataPulled)
|
||||
Vue.$socket.emit('server.files.metadata', { filename: job.filename }, { action: 'files/getMetadata' })
|
||||
job['metadata'] = file
|
||||
job.metadata = file
|
||||
job.combinedIds = []
|
||||
|
||||
jobs.push(job)
|
||||
})
|
||||
@ -21,6 +28,10 @@ export const getters: GetterTree<ServerJobQueueState, any> = {
|
||||
return jobs
|
||||
},
|
||||
|
||||
getJobsCount: (state) => {
|
||||
return state.queued_jobs.length
|
||||
},
|
||||
|
||||
getSmallThumbnail: (state, getters, rootState, rootGetters) => (item: ServerJobQueueStateJob) => {
|
||||
if (item?.metadata?.thumbnails?.length) {
|
||||
const thumbnail = item?.metadata?.thumbnails.find(
|
||||
|
@ -10,4 +10,5 @@ export interface ServerJobQueueStateJob {
|
||||
time_in_queue: number
|
||||
metadata?: any
|
||||
isFirst?: boolean
|
||||
combinedIds?: string[]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user