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 255490f1d..cc060d99e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,8 @@ "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.5", "typescript": "^4.5.5", @@ -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", diff --git a/package.json b/package.json index 65de31342..c97fef7c1 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,8 @@ "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.5", "typescript": "^4.5.5", diff --git a/src/components/TheConnectingDialog.vue b/src/components/TheConnectingDialog.vue index d32bdd7c9..68bff8c66 100644 --- a/src/components/TheConnectingDialog.vue +++ b/src/components/TheConnectingDialog.vue @@ -1,35 +1,30 @@ - - @@ -52,10 +47,6 @@ export default class TheConnectingDialog extends Mixins(BaseMixin, ThemeMixin) { counter = 0 - get protocol() { - return this.$store.state.socket.protocol - } - get hostname() { return this.$store.state.socket.hostname } @@ -94,6 +85,10 @@ export default class TheConnectingDialog extends Mixins(BaseMixin, ThemeMixin) { return this.formatHostname } + get connectionFailedMessage() { + return this.$store.state.socket.connectionFailedMessage ?? null + } + reconnect() { this.counter++ this.$store.dispatch('socket/setData', { connectingFailed: false }) diff --git a/src/components/TheEditor.vue b/src/components/TheEditor.vue index e740c7db8..215ed1ccd 100644 --- a/src/components/TheEditor.vue +++ b/src/components/TheEditor.vue @@ -31,6 +31,10 @@ {{ mdiHelp }} {{ $t('Editor.ConfigReference') }} + + {{ mdiFormatListCheckbox }} + {{ $t('Editor.FileStructure') }} + {{ mdiCloseThick }} - + + :file-extension="fileExtension" + class="codemirror" + @lineChange="lineChanges" /> +
+ + + + +
- +
{{ snackbarHeadline }}
@@ -123,7 +160,7 @@ + + 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 @@ + + diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 9c54459ec..232e675e5 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -1,13 +1,13 @@ 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 @@ @@ -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 @@ - - @@ -261,4 +355,8 @@ export default class Mjpegstreamer extends Mixins(BaseMixin, WebcamMixin) { html.theme--light .webcamFpsOutput { background: rgba(255, 255, 255, 0.7); } + +._webcam_mjpegstreamer_output { + aspect-ratio: calc(3 / 2); +} diff --git a/src/components/webcams/streamers/MjpegstreamerAdaptive.vue b/src/components/webcams/streamers/MjpegstreamerAdaptive.vue index 39f04cc30..cac1ee5f8 100644 --- a/src/components/webcams/streamers/MjpegstreamerAdaptive.vue +++ b/src/components/webcams/streamers/MjpegstreamerAdaptive.vue @@ -1,55 +1,58 @@