+ {{ $t('ConnectionDialog.CannotConnectTo', { host: formatHostname }) }}
+
+
+ {{ $t('ConnectionDialog.ErrorMessage', { message: connectionFailedMessage }) }}
+
+
{{ $t('ConnectionDialog.TryAgain') }}
-
+
-
+
@@ -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 @@
+
+
+
+
+
+ {{ 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/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/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/MachineSettings/MachineSettingsPanel.vue b/src/components/panels/MachineSettings/MachineSettingsPanel.vue
deleted file mode 100644
index 8b2bdb823..000000000
--- a/src/components/panels/MachineSettings/MachineSettingsPanel.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/components/panels/MachineSettings/MotionSettings.vue b/src/components/panels/MachineSettings/MotionSettings.vue
deleted file mode 100644
index 315290a08..000000000
--- a/src/components/panels/MachineSettings/MotionSettings.vue
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/panels/MachineSettingsPanel.vue b/src/components/panels/MachineSettingsPanel.vue
new file mode 100644
index 000000000..73319a34a
--- /dev/null
+++ b/src/components/panels/MachineSettingsPanel.vue
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -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 @@
-
-
-
-
-