diff --git a/src/components/settings/Presets/PresetsForm.vue b/src/components/settings/Presets/PresetsForm.vue
index d13c71eeb8..8db2b5177d 100644
--- a/src/components/settings/Presets/PresetsForm.vue
+++ b/src/components/settings/Presets/PresetsForm.vue
@@ -139,10 +139,8 @@ export default class PresetsForm extends Mixins(BaseMixin) {
}
existsPresetName(name: string) {
- return (
- this.presets.findIndex(
- (preset: GuiPresetsStatePreset) => preset.name === name && preset.id !== this.preset.id
- ) !== -1
+ return this.presets.some(
+ (preset: GuiPresetsStatePreset) => preset.name === name && preset.id !== this.preset.id
)
}
@@ -156,9 +154,9 @@ export default class PresetsForm extends Mixins(BaseMixin) {
savePreset() {
let setValues = 0
- for (const key of Object.keys(this.preset.values)) {
+ Object.keys(this.preset.values).forEach((key: string) => {
if (this.preset.values[key].bool) setValues++
- }
+ })
if (this.preset.gcode.length) setValues++
// stop here, when no values are set
@@ -167,15 +165,17 @@ export default class PresetsForm extends Mixins(BaseMixin) {
return
}
+ const values = structuredClone(this.preset)
+
// create new preset, if id === null
if (this.preset.id === null) {
- this.$store.dispatch('gui/presets/store', { values: this.preset })
+ this.$store.dispatch('gui/presets/store', { values })
this.closeForm()
return
}
// update existing preset
- this.$store.dispatch('gui/presets/update', { id: this.preset.id, values: this.preset })
+ this.$store.dispatch('gui/presets/update', { id: this.preset.id, values })
this.closeForm()
}
}
diff --git a/src/components/settings/SettingsPresetsTab.vue b/src/components/settings/SettingsPresetsTab.vue
index 536f0359ad..28beb142a7 100644
--- a/src/components/settings/SettingsPresetsTab.vue
+++ b/src/components/settings/SettingsPresetsTab.vue
@@ -62,7 +62,7 @@ export default class SettingsPresetsTab extends Mixins(BaseMixin) {
}
edit(preset: GuiPresetsStatePreset) {
- this.formPreset = { ...preset }
+ this.formPreset = structuredClone(preset)
this.boolForm = true
}
}
diff --git a/src/components/webcams/streamers/Hlsstreamer.vue b/src/components/webcams/streamers/Hlsstreamer.vue
index 63b5184222..962293c0d9 100644
--- a/src/components/webcams/streamers/Hlsstreamer.vue
+++ b/src/components/webcams/streamers/Hlsstreamer.vue
@@ -1,18 +1,11 @@
-
+
diff --git a/src/components/webcams/streamers/JMuxerStream.vue b/src/components/webcams/streamers/JMuxerStream.vue
index b408935a0a..a66fa814b4 100644
--- a/src/components/webcams/streamers/JMuxerStream.vue
+++ b/src/components/webcams/streamers/JMuxerStream.vue
@@ -20,6 +20,7 @@ import WebcamMixin from '@/components/mixins/webcam'
@Component
export default class JMuxerStreamer extends Mixins(BaseMixin, WebcamMixin) {
jmuxer: JMuxer | null = null
+ ws: WebSocket | null = null
status: string = 'connecting'
aspectRatio: number | null = null
@@ -52,7 +53,7 @@ export default class JMuxerStreamer extends Mixins(BaseMixin, WebcamMixin) {
play() {
this.status = 'connecting'
- this.jmuxer?.destroy()
+ this.stop()
// Only websocket streams supported
if (!this.url.startsWith('ws://') && !this.url.startsWith('wss://')) {
@@ -80,21 +81,37 @@ export default class JMuxerStreamer extends Mixins(BaseMixin, WebcamMixin) {
})
const ws = new WebSocket(this.url)
+ this.ws = ws
ws.binaryType = 'arraybuffer'
+
+ // guard every handler against `ws` having been replaced by a later play(),
+ // so a socket still closing down can never feed the current jmuxer instance
ws.addEventListener('message', (event) => {
+ if (this.ws !== ws) return
+
this.jmuxer?.feed({
video: new Uint8Array(event.data),
})
})
ws.addEventListener('error', (event) => {
+ if (this.ws !== ws) return
+
this.status = 'error'
console.log('jmuxer ws error:', event)
})
}
- beforeUnmount() {
+ stop() {
+ this.ws?.close()
+ this.ws = null
+
this.jmuxer?.destroy()
+ this.jmuxer = null
+ }
+
+ beforeDestroy() {
+ this.stop()
}
@Watch('camSettings', { deep: true })
diff --git a/src/locales/en.json b/src/locales/en.json
index a46e38bcff..538ceb463b 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -949,12 +949,6 @@
},
"Unknown": "Unknown"
},
- "PowerControlPanel": {
- "Error": "Error",
- "Off": "Off",
- "On": "On",
- "PowerControl": "Power Control"
- },
"SpoolmanPanel": {
"ActiveSpool": "Active Spool",
"ChangeSpool": "Change Spool",
@@ -1056,8 +1050,6 @@
"State": "State",
"Target": "Target",
"TemperaturesInChart": "Temperature [°C]",
- "TempTooHigh": "Temperature too high for {name}! (max: {max})",
- "TempTooLow": "Temperature too low for {name}! (min: {min})",
"TurnHeaterOff": "Turn Heater Off"
},
"ToolheadControlPanel": {
@@ -1600,6 +1592,7 @@
"Create": "Create",
"CreateNewDirectory": "create directory",
"CurrentPath": "Current Path",
+ "Delete": "Delete",
"DeleteDirectory": "Delete Directory",
"DeleteDirectoryQuestion": "Do you really want to delete the \"{name}\" directory with all its contents?",
"DeleteSelectedQuestion": "Do you really want to delete {count} selected files?",