Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add jobs to queue in batches #1253

Merged
merged 26 commits into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d56ab78
feat: add jobs to queue in batches WIP
meteyou Jan 29, 2023
adbd8a5
feat(gcodefiles): add jobs to queue in batches
meteyou Feb 4, 2023
3bfcc27
Merge branch 'develop' into feat/add-to-queue-in-batches
meteyou Feb 10, 2023
3d1f7fa
refactor: add seperate button for "add patch to queue
meteyou Feb 11, 2023
676047c
fix: add jobs to queue with enter
meteyou Feb 11, 2023
1e45c59
feat: combine multiple same jobs in job queue
meteyou Feb 11, 2023
8cd2eb2
refactor: thumbnail vue-load-image slots in status panel jobqueue
meteyou Feb 11, 2023
9f27494
refactor: thumbnail vue-load-image slots in status panel jobqueue
meteyou Feb 11, 2023
3e15e26
feat: display count of jobqueue on status panel
meteyou Feb 11, 2023
5c3ece6
feat: display count of jobqueue on status panel
meteyou Feb 11, 2023
a669db4
refactor: thumbnail vue-load-image slots in gcode jobqueuepanel
meteyou Feb 11, 2023
0aa1e5e
refactor: change count to a array of ids
meteyou Feb 11, 2023
c6f1727
style: fix syntax
meteyou Feb 11, 2023
0665bbc
fix: addToQueue function
meteyou Feb 11, 2023
2b0d1db
fix: change color of addToQueue button in addPatchToQueue dialog
meteyou Feb 11, 2023
b48eb49
refactor: rework jobqueue entry and combine gcode and dashboard entry
meteyou Feb 11, 2023
f2add5c
feat: add option to change count of job queue
meteyou Feb 11, 2023
be206b5
fix: fix typo addBatch
meteyou Feb 11, 2023
9fdd386
refactor: change type of item in openChangeCountDialog function
meteyou Feb 11, 2023
9d1b99d
refactor: use current count as default for changeCountDialog
meteyou Feb 11, 2023
d43d0bc
refactor: input field in changeCountDialog
meteyou Feb 11, 2023
bcf4f63
refactor: remove unused imports
meteyou Feb 11, 2023
9a82203
refactor: use input type=number instead of js only number filter
meteyou Feb 11, 2023
391317a
refactor: change to input number with spin buttons in add to batch co…
meteyou Feb 11, 2023
a0cc044
feat: add addBatchToQueue to dashboard gcodefiles
meteyou Feb 11, 2023
17c4a8a
fix: isFirst in jobqueue data-table
meteyou Feb 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 105 additions & 2 deletions src/components/panels/GcodefilesPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down Expand Up @@ -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>

Expand All @@ -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,
Expand Down Expand Up @@ -552,6 +608,12 @@ interface dialogPrintFile {
item: FileStateGcodefile
}

interface dialogAddBatchToQueue {
show: boolean
count: number
item: FileStateGcodefile
}

interface dialogRenameObject {
show: boolean
newName: string
Expand All @@ -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
Expand Down Expand Up @@ -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: '',
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
135 changes: 10 additions & 125 deletions src/components/panels/JobqueuePanel.vue
Original file line number Diff line number Diff line change
@@ -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'"
Expand Down Expand Up @@ -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
Expand All @@ -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')
}
Expand All @@ -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()
}
Expand All @@ -235,7 +120,7 @@ export default class JobqueuePanel extends Mixins(BaseMixin) {
}
</script>

<style>
<style scoped>
.jobqueue-panel {
position: relative;
}
Expand Down
Loading