diff --git a/.prettierrc b/.prettierrc index 456bf2ce1..b0c885617 100644 --- a/.prettierrc +++ b/.prettierrc @@ -18,6 +18,14 @@ "options": { "tabWidth": 2 } + }, + { + "files": "src/locales/*.json", + "options": { + "plugins": ["prettier-plugin-sort-json"], + "jsonRecursiveSort": true, + "jsonSortOrder": "{ \"placeThisFirst\": null, \"/^[a-zA-Z0-9]/\": \"caseInsensitiveNumeric\" }" + } } ] } diff --git a/package-lock.json b/package-lock.json index 5032e8e7c..cc060d99e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@lezer/highlight": "^1.0.0", "@sindarius/gcodeviewer": "^3.7.11", "@uiw/codemirror-theme-vscode": "^4.19.11", - "axios": "^1.6.0", + "axios": "^1.7.4", "codemirror": "^6.0.1", "core-js": "^3.16.0", "detect-browser": "^5.3.0", @@ -75,9 +75,10 @@ "eslint-plugin-vue": "^9.0.0", "postcss": "^8.4.31", "postcss-nesting": "^12.0.1", - "prettier": "^3.0.0", + "prettier": "^3.3.3", + "prettier-plugin-sort-json": "^4.0.0", "sass": "~1.32", - "start-server-and-test": "^2.0.0", + "start-server-and-test": "^2.0.5", "typescript": "^4.5.5", "unplugin-vue-components": "^0.22.12", "vite": "^4.5.3", @@ -3177,9 +3178,9 @@ } }, "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0" @@ -4156,9 +4157,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -5244,9 +5245,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -7113,14 +7114,14 @@ "integrity": "sha512-4qjXl8JS138WyCZZoOYwXq/qVrHcE0UIpt2lMtGyq2wuBSPMNSzP1K2CEWSrwAMgjZ9jD7Btc0SxMkiLIhoHsg==" }, "node_modules/joi": { - "version": "17.10.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz", - "integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==", + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", "dev": true, "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } @@ -8052,9 +8053,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8066,6 +8067,18 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-plugin-sort-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-sort-json/-/prettier-plugin-sort-json-4.0.0.tgz", + "integrity": "sha512-zV5g+bWFD2zAqyQ8gCkwUTC49o9FxslaUdirwivt5GZHcf57hCocavykuyYqbExoEsuBOg8IU36OY7zmVEMOWA==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -8724,19 +8737,19 @@ } }, "node_modules/start-server-and-test": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.1.tgz", - "integrity": "sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.5.tgz", + "integrity": "sha512-2CV4pz69NJVJKQmJeSr+O+SPtOreu0yxvhPmSXclzmAKkPREuMabyMh+Txpzemjx0RDzXOcG2XkhiUuxjztSQw==", "dev": true, "dependencies": { "arg": "^5.0.2", "bluebird": "3.7.2", "check-more-types": "2.24.0", - "debug": "4.3.4", + "debug": "4.3.6", "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "7.0.1" + "wait-on": "7.2.0" }, "bin": { "server-test": "src/bin/start.js", @@ -10254,16 +10267,16 @@ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" }, "node_modules/wait-on": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", - "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", "dev": true, "dependencies": { - "axios": "^0.27.2", - "joi": "^17.7.0", + "axios": "^1.6.1", + "joi": "^17.11.0", "lodash": "^4.17.21", - "minimist": "^1.2.7", - "rxjs": "^7.8.0" + "minimist": "^1.2.8", + "rxjs": "^7.8.1" }, "bin": { "wait-on": "bin/wait-on" @@ -10272,16 +10285,6 @@ "node": ">=12.0.0" } }, - "node_modules/wait-on/node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } - }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index 2c22cbcb3..c97fef7c1 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@lezer/highlight": "^1.0.0", "@sindarius/gcodeviewer": "^3.7.11", "@uiw/codemirror-theme-vscode": "^4.19.11", - "axios": "^1.6.0", + "axios": "^1.7.4", "codemirror": "^6.0.1", "core-js": "^3.16.0", "detect-browser": "^5.3.0", @@ -90,9 +90,10 @@ "eslint-plugin-vue": "^9.0.0", "postcss": "^8.4.31", "postcss-nesting": "^12.0.1", - "prettier": "^3.0.0", + "prettier": "^3.3.3", + "prettier-plugin-sort-json": "^4.0.0", "sass": "~1.32", - "start-server-and-test": "^2.0.0", + "start-server-and-test": "^2.0.5", "typescript": "^4.5.5", "unplugin-vue-components": "^0.22.12", "vite": "^4.5.3", diff --git a/public/css/themes/vzbot.css b/public/css/themes/vzbot.css new file mode 100644 index 000000000..31df6bd4c --- /dev/null +++ b/public/css/themes/vzbot.css @@ -0,0 +1,3 @@ +div.v-navigation-drawer__image div.v-image__image { + background-position: bottom center !important; +} diff --git a/src/App.vue b/src/App.vue index 40b2bc9aa..06bf33c24 100644 --- a/src/App.vue +++ b/src/App.vue @@ -347,6 +347,26 @@ export default class App extends Mixins(BaseMixin, ThemeMixin) { this.drawFavicon(this.print_percent) } + @Watch('themeCss') + themeCssChanged(newVal: string | null): void { + // remove linked CSS file if it exists + const style = document.getElementById('theme-css') + if (style) style.remove() + + // if themeCss does not exist, stop here and load no CSS file + if (newVal === null) return + + // fetch the CSS file and append it to the head + fetch(newVal) + .then((response) => response.text()) + .then((css) => { + const newStyle = document.createElement('style') + newStyle.id = 'theme-css' + newStyle.innerHTML = css + document.head.appendChild(newStyle) + }) + } + @Watch('print_percent') print_percentChanged(newVal: number): void { this.drawFavicon(newVal) diff --git a/src/components/console/ConsoleTableEntry.vue b/src/components/console/ConsoleTableEntry.vue index 21c2af4d9..f8d14f631 100644 --- a/src/components/console/ConsoleTableEntry.vue +++ b/src/components/console/ConsoleTableEntry.vue @@ -1,7 +1,13 @@ {{ entryFormatTime }} - + + @@ -19,7 +25,7 @@ export default class ConsoleTableEntry extends Mixins(BaseMixin) { get entryStyle() { const classes = ['ma-0', 'flex-nowrap'] classes.push(this.$store.state.gui.console.entryStyle ?? 'default') - if (this.event.type === 'action') classes.push('text--disabled') + if (['action', 'debug'].includes(this.event.type)) classes.push('text--disabled') return classes } @@ -31,13 +37,17 @@ export default class ConsoleTableEntry extends Mixins(BaseMixin) { get messageClass() { const classes = ['console-message'] - if (this.event.type === 'action') classes.push('text--disabled') + if (['action', 'debug'].includes(this.event.type)) classes.push('text--disabled') else if (this.event.message.startsWith('!! ')) classes.push('error--text') else classes.push('text--primary') return classes } + get rawOutput() { + return this.$store.state.gui.console.rawOutput ?? false + } + commandClick(event: Event) { const eventTarget = event.target as Element if (eventTarget.localName === 'a' && eventTarget.className.indexOf('command') !== -1) { diff --git a/src/components/dialogs/CancelJobDialog.vue b/src/components/dialogs/CancelJobDialog.vue new file mode 100644 index 000000000..db9edc6b9 --- /dev/null +++ b/src/components/dialogs/CancelJobDialog.vue @@ -0,0 +1,50 @@ + + + + + + {{ mdiCloseThick }} + + + {{ $t('CancelJobDialog.AreYouSure') }} + + + {{ $t('CancelJobDialog.No') }} + {{ $t('CancelJobDialog.Yes') }} + + + + + + + + diff --git a/src/components/dialogs/TimelapseRenderingsettingsDialog.vue b/src/components/dialogs/TimelapseRenderingsettingsDialog.vue new file mode 100644 index 000000000..035b84561 --- /dev/null +++ b/src/components/dialogs/TimelapseRenderingsettingsDialog.vue @@ -0,0 +1,134 @@ + + + + + + {{ mdiCloseThick }} + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('Timelapse.Cancel') }} + {{ $t('Timelapse.StartRender') }} + + + + + diff --git a/src/components/gcodeviewer/Viewer.vue b/src/components/gcodeviewer/Viewer.vue index 6e195f752..a7257a165 100644 --- a/src/components/gcodeviewer/Viewer.vue +++ b/src/components/gcodeviewer/Viewer.vue @@ -209,7 +209,7 @@ - + {{ $t('GCodeViewer.Rendering') }} - {{ loadingPercent }}% @@ -222,7 +222,7 @@ - + {{ $t('GCodeViewer.Downloading') }} - {{ Math.round(downloadSnackbar.percent) }} % @ @@ -329,24 +329,24 @@ export default class Viewer extends Mixins(BaseMixin) { formatFilesize = formatFilesize - private isBusy = false - private loading = false - private loadingPercent = 0 + isBusy = false + loading = false + loadingPercent = 0 - private tracking = false - private loadedFile: string | null = null + tracking = false + loadedFile: string | null = null - private reloadRequired = false - private fileSize = 0 - private renderQuality = this.renderQualities[2] + reloadRequired = false + fileSize = 0 + renderQuality = this.renderQualities[2] - private scrubPosition = 0 - private scrubPlaying = false - private scrubSpeed = 1 - private scrubInterval: ReturnType | undefined = undefined - private scrubFileSize = 0 + scrubPosition = 0 + scrubPlaying = false + scrubSpeed = 1 + scrubInterval: ReturnType | undefined = undefined + scrubFileSize = 0 - private downloadSnackbar: downloadSnackbar = { + downloadSnackbar: downloadSnackbar = { status: false, filename: '', percent: 0, @@ -355,12 +355,12 @@ export default class Viewer extends Mixins(BaseMixin) { cancelTokenSource: {}, } - private excludeObject = { + excludeObject = { bool: false, name: '', } - private fileData: string = '' + fileData: string = '' @Prop({ type: String, default: '', required: false }) declare filename: string @Ref('fileInput') declare fileInput: HTMLInputElement @@ -705,42 +705,45 @@ export default class Viewer extends Mixins(BaseMixin) { @Watch('currentPosition') currentPositionChanged(newVal: number[]) { - if (viewer) { - const position = [ - { axes: 'X', position: newVal[0] }, - { axes: 'Y', position: newVal[1] }, - { axes: 'Z', position: newVal[2] }, - ] + if (!viewer || !this.tracking || this.scrubPlaying) return - viewer.updateToolPosition(position) - } + const position = [ + { axes: 'X', position: newVal[0] }, + { axes: 'Y', position: newVal[1] }, + { axes: 'Z', position: newVal[2] }, + ] + + viewer.updateToolPosition(position) } @Watch('filePosition') filePositionChanged(newVal: number) { - if (!viewer) return + if (!viewer || !this.tracking || this.scrubPlaying) return const offset = 350 if (newVal > 0 && this.printerIsPrinting && this.tracking && newVal > offset) { viewer.gcodeProcessor.updateFilePosition(newVal - offset) this.scrubPosition = newVal - offset - } else { - viewer.gcodeProcessor.updateFilePosition(viewer.fileSize) + return } + + viewer.gcodeProcessor.updateFilePosition(viewer.fileSize) } @Watch('tracking') async trackingChanged(newVal: boolean) { if (!viewer) return + if (newVal) { this.scrubPlaying = false //Force renderers reload. viewer.gcodeProcessor.updateFilePosition(0) viewer?.forceRender() - } else { - viewer.gcodeProcessor.setLiveTracking(false) - await this.reloadViewer() + return } + + viewer.gcodeProcessor.setLiveTracking(false) + await this.reloadViewer() } @Watch('printerIsPrinting') @@ -930,7 +933,7 @@ export default class Viewer extends Mixins(BaseMixin) { } } - private colorModes = [ + colorModes = [ { text: 'Extruder', value: 0 }, { text: 'Feed Rate', value: 1 }, { text: 'Feature', value: 2 }, diff --git a/src/components/mixins/theme.ts b/src/components/mixins/theme.ts index b3f612a8a..9cbfa0fb4 100644 --- a/src/components/mixins/theme.ts +++ b/src/components/mixins/theme.ts @@ -90,4 +90,10 @@ export default class ThemeMixin extends Vue { return `/img/themes/mainBackground-${this.themeName}.png` } + + get themeCss() { + if (!(this.theme.css ?? false)) return null + + return `/css/themes/${this.themeName}.css` + } } diff --git a/src/components/mixins/timelapse.ts b/src/components/mixins/timelapse.ts new file mode 100644 index 000000000..c1ad6be45 --- /dev/null +++ b/src/components/mixins/timelapse.ts @@ -0,0 +1,78 @@ +import Component from 'vue-class-component' +import Vue from 'vue' + +@Component +export default class TimelapseMixin extends Vue { + get variable_fps() { + return this.$store.state.server.timelapse?.settings?.variable_fps ?? false + } + + set variable_fps(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { variable_fps: newVal }) + } + + get variable_fps_min() { + return this.$store.state.server.timelapse?.settings?.variable_fps_min ?? 5 + } + + set variable_fps_min(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { variable_fps_min: newVal }) + } + + get variable_fps_max() { + return this.$store.state.server.timelapse?.settings?.variable_fps_max ?? 60 + } + + set variable_fps_max(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { variable_fps_max: newVal }) + } + + get targetlength() { + return this.$store.state.server.timelapse?.settings?.targetlength ?? 10 + } + + set targetlength(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { targetlength: newVal }) + } + + get output_framerate() { + return this.$store.state.server.timelapse?.settings?.output_framerate ?? 30 + } + + set output_framerate(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { output_framerate: newVal }) + } + + get duplicatelastframe() { + return this.$store.state.server.timelapse?.settings?.duplicatelastframe ?? 0 + } + + set duplicatelastframe(newVal) { + this.$store.dispatch('server/timelapse/saveSetting', { duplicatelastframe: newVal }) + } + + get framesCount() { + return this.$store.state.server.timelapse?.lastFrame?.count ?? 0 + } + + get estimatedVideoLength() { + let seconds = Math.round((this.framesCount + this.duplicatelastframe) / this.output_framerate) + + if (this.variable_fps) { + seconds = Math.round((this.framesCount + this.duplicatelastframe) / this.variableTargetFps) + if (seconds < this.targetlength) seconds = this.targetlength + } + + return seconds > 60 + ? Math.floor(seconds / 60) + 'm ' + (seconds - Math.floor(seconds / 60) * 60) + 's' + : seconds + 's' + } + + get variableTargetFps() { + let targetFps = Math.floor(this.framesCount / this.targetlength) + targetFps = Math.max(targetFps, this.variable_fps_min) + targetFps = Math.min(targetFps, this.variable_fps_max) + + return targetFps + } +} diff --git a/src/components/panels/Extruder/ExtruderControlPanelControl.vue b/src/components/panels/Extruder/ExtruderControlPanelControl.vue index fdb7a10a8..b430f68ab 100644 --- a/src/components/panels/Extruder/ExtruderControlPanelControl.vue +++ b/src/components/panels/Extruder/ExtruderControlPanelControl.vue @@ -93,7 +93,7 @@ diff --git a/src/components/panels/Machine/UpdatePanel/Entry.vue b/src/components/panels/Machine/UpdatePanel/Entry.vue index a13f7c3e8..f837eb740 100644 --- a/src/components/panels/Machine/UpdatePanel/Entry.vue +++ b/src/components/panels/Machine/UpdatePanel/Entry.vue @@ -2,7 +2,7 @@ - {{ repo.name }} + {{ name }} @@ -159,6 +159,11 @@ export default class UpdatePanelEntry extends Mixins(BaseMixin) { @Prop({ required: true }) readonly repo!: ServerUpdateManagerStateGitRepo get name() { + const info_tags = this.repo.info_tags ?? [] + const description = info_tags.find((tag) => tag.startsWith('desc=')) + + if (description && description.trim() !== 'desc=') return description.replace('desc=', '').trim() + return this.repo.name ?? 'UNKNOWN' } diff --git a/src/components/panels/MiniconsolePanel.vue b/src/components/panels/MiniconsolePanel.vue index 1c5d0daf3..8a5168dc6 100644 --- a/src/components/panels/MiniconsolePanel.vue +++ b/src/components/panels/MiniconsolePanel.vue @@ -50,6 +50,13 @@ :label="filter.name" @change="toggleFilter(filter)" /> + + + @@ -204,6 +211,14 @@ export default class MiniconsolePanel extends Mixins(BaseMixin) { this.$store.dispatch('gui/saveSetting', { name: 'console.autoscroll', value: newVal }) } + get rawOutput(): boolean { + return this.$store.state.gui.console.rawOutput ?? false + } + + set rawOutput(newVal) { + this.$store.dispatch('gui/saveSetting', { name: 'console.rawOutput', value: newVal }) + } + commandClick(msg: string): void { this.gcode = msg diff --git a/src/components/panels/Status/ExcludeObjectDialogMap.vue b/src/components/panels/Status/ExcludeObjectDialogMap.vue index 2a5a18dcb..b004817f4 100644 --- a/src/components/panels/Status/ExcludeObjectDialogMap.vue +++ b/src/components/panels/Status/ExcludeObjectDialogMap.vue @@ -62,8 +62,8 @@ hoverName === object.name ? primaryColor : excluded_objects.includes(object.name) - ? '#6668' - : '#bbb' + ? '#6668' + : '#bbb' " @mouseover="showObjectTooltip(object.name)" @mouseout="hideObjectTooltip" diff --git a/src/components/panels/StatusPanel.vue b/src/components/panels/StatusPanel.vue index ba405f501..d0a3833bb 100644 --- a/src/components/panels/StatusPanel.vue +++ b/src/components/panels/StatusPanel.vue @@ -110,6 +110,10 @@ + @@ -141,9 +145,11 @@ import { mdiDotsVertical, } from '@mdi/js' import { PrinterStateMacro } from '@/store/printer/types' +import CancelJobDialog from '@/components/dialogs/CancelJobDialog.vue' @Component({ components: { + CancelJobDialog, KlippyStatePanel, MinSettingsPanel, Panel, @@ -166,6 +172,7 @@ export default class StatusPanel extends Mixins(BaseMixin) { bigThumbnail: any } + showCancelJobDialog = false boolShowObjects = false boolShowPauseAtLayer = false @@ -392,6 +399,17 @@ export default class StatusPanel extends Mixins(BaseMixin) { } btnCancelJob() { + const confirmOnCancelJob = this.$store.state.gui.uiSettings.confirmOnCancelJob + if (confirmOnCancelJob) { + this.showCancelJobDialog = true + return + } + + this.cancelJob() + } + + cancelJob() { + this.showCancelJobDialog = false this.$socket.emit('printer.print.cancel', {}, { loading: 'statusPrintCancel' }) } diff --git a/src/components/panels/Timelapse/TimelapseStatusPanel.vue b/src/components/panels/Timelapse/TimelapseStatusPanel.vue index 2129fc85c..29a3ca7d3 100644 --- a/src/components/panels/Timelapse/TimelapseStatusPanel.vue +++ b/src/components/panels/Timelapse/TimelapseStatusPanel.vue @@ -1,223 +1,100 @@ - - - - - - - - {{ mdiInformation }} - {{ $t('Timelapse.Status') }} - - - - - - + + + + + + + + + + + {{ mdiFile }} + + + + + + + + {{ framesCount }} + + + + {{ estimatedVideoLength }} + + + - - - - - - - - {{ mdiFile }} - - + + + {{ $t('Timelapse.Render') }} + + + {{ $t('Timelapse.SaveFrames') }} + - - - - - - - {{ framesCount }} - - - - {{ estimatedVideoLength }} - - - - - - - - - - - - - - - - - - - - {{ $t('Timelapse.Render') }} - - - {{ $t('Timelapse.SaveFrames') }} - - - - - - - - - {{ $t('Timelapse.NoActiveTimelapse') }} - + - - - - - - {{ mdiCloseThick }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{ $t('Timelapse.Cancel') }} - {{ $t('Timelapse.StartRender') }} - - - - + + + {{ $t('Timelapse.NoActiveTimelapse') }} + + + + + + + + + + + + + + +
{{ $t('Timelapse.NoActiveTimelapse') }}