diff --git a/.docker/nginx.conf b/.docker/nginx.conf
index 3465fa1e7..83746d3bb 100644
--- a/.docker/nginx.conf
+++ b/.docker/nginx.conf
@@ -1,6 +1,7 @@
server {
listen 80;
-
+ listen [::]:80;
+
location / {
root /usr/share/nginx/html;
index index.html index.htm;
@@ -8,4 +9,4 @@ server {
}
include /etc/nginx/extra-conf.d/*.conf;
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index cc060d99e..71b025c57 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -81,7 +81,7 @@
"start-server-and-test": "^2.0.5",
"typescript": "^4.5.5",
"unplugin-vue-components": "^0.22.12",
- "vite": "^4.5.3",
+ "vite": "^4.5.5",
"vite-plugin-checker": "^0.6.0",
"vite-plugin-package-version": "^1.0.2",
"vite-plugin-pwa": "^0.16.4",
@@ -8421,9 +8421,9 @@
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/rollup": {
- "version": "3.29.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
- "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "version": "3.29.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
+ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -9600,9 +9600,9 @@
}
},
"node_modules/vite": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
- "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
+ "version": "4.5.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz",
+ "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==",
"dev": true,
"dependencies": {
"esbuild": "^0.18.10",
@@ -9870,9 +9870,9 @@
}
},
"node_modules/vite-plugin-vue2/node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "version": "2.79.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -10580,9 +10580,9 @@
}
},
"node_modules/workbox-build/node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "version": "2.79.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
diff --git a/package.json b/package.json
index c97fef7c1..1a97707ef 100644
--- a/package.json
+++ b/package.json
@@ -96,7 +96,7 @@
"start-server-and-test": "^2.0.5",
"typescript": "^4.5.5",
"unplugin-vue-components": "^0.22.12",
- "vite": "^4.5.3",
+ "vite": "^4.5.5",
"vite-plugin-checker": "^0.6.0",
"vite-plugin-package-version": "^1.0.2",
"vite-plugin-pwa": "^0.16.4",
diff --git a/src/components/TheConnectingDialog.vue b/src/components/TheConnectingDialog.vue
index 68bff8c66..0ee067331 100644
--- a/src/components/TheConnectingDialog.vue
+++ b/src/components/TheConnectingDialog.vue
@@ -18,6 +18,10 @@
+
+ {{ mdiHelp }}
+ {{ $t('ConnectionDialog.Help') }}
+
{{ $t('ConnectionDialog.TryAgain') }}
@@ -35,7 +39,7 @@ import BaseMixin from '@/components/mixins/base'
import ThemeMixin from '@/components/mixins/theme'
import ConnectionStatus from '@/components/ui/ConnectionStatus.vue'
-import { mdiConnection } from '@mdi/js'
+import { mdiConnection, mdiHelp } from '@mdi/js'
@Component({
components: {
@@ -44,6 +48,7 @@ import { mdiConnection } from '@mdi/js'
})
export default class TheConnectingDialog extends Mixins(BaseMixin, ThemeMixin) {
mdiConnection = mdiConnection
+ mdiHelp = mdiHelp
counter = 0
@@ -89,6 +94,12 @@ export default class TheConnectingDialog extends Mixins(BaseMixin, ThemeMixin) {
return this.$store.state.socket.connectionFailedMessage ?? null
}
+ get helpButtonUrl() {
+ if (!this.$store.state.socket.connectionFailedMessage) return null
+
+ return `https://docs.mainsail.xyz/faq/mainsail_errors/connection-${this.connectionFailedMessage?.toLowerCase()}`
+ }
+
reconnect() {
this.counter++
this.$store.dispatch('socket/setData', { connectingFailed: false })
diff --git a/src/components/TheEditor.vue b/src/components/TheEditor.vue
index 215ed1ccd..f122c2ca0 100644
--- a/src/components/TheEditor.vue
+++ b/src/components/TheEditor.vue
@@ -60,6 +60,7 @@
:name="filename"
:file-extension="fileExtension"
class="codemirror"
+ :class="{ withSidebar: fileStructureSidebar }"
@lineChange="lineChanges" />
diff --git a/src/components/inputs/ConsoleTextarea.vue b/src/components/inputs/ConsoleTextarea.vue
new file mode 100644
index 000000000..604772121
--- /dev/null
+++ b/src/components/inputs/ConsoleTextarea.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
diff --git a/src/components/mixins/console.ts b/src/components/mixins/console.ts
new file mode 100644
index 000000000..e337bb658
--- /dev/null
+++ b/src/components/mixins/console.ts
@@ -0,0 +1,69 @@
+import Vue from 'vue'
+import Component from 'vue-class-component'
+import { GuiConsoleStateFilter } from '@/store/gui/console/types'
+
+@Component
+export default class ConsoleMixin extends Vue {
+ get helplist() {
+ const commands: { [key: string]: { help?: string } } = this.$store.state.printer.gcode?.commands ?? {}
+ const helplist: { command: string; help: string }[] = []
+
+ for (const [key, values] of Object.entries(commands)) {
+ helplist.push({ command: key, help: values.help ?? '' })
+ }
+
+ return helplist
+ }
+
+ get consoleDirection() {
+ return this.$store.state.gui.console.direction ?? 'table'
+ }
+
+ get hideWaitTemperatures(): boolean {
+ return this.$store.state.gui.console.hideWaitTemperatures
+ }
+
+ set hideWaitTemperatures(newVal) {
+ this.$store.dispatch('gui/saveSetting', { name: 'console.hideWaitTemperatures', value: newVal })
+ }
+
+ get hideTlCommands(): boolean {
+ return this.$store.state.gui.console.hideTlCommands
+ }
+
+ set hideTlCommands(newVal) {
+ this.$store.dispatch('gui/saveSetting', { name: 'console.hideTlCommands', value: newVal })
+ }
+
+ get customFilters() {
+ return this.$store.state.gui.console.consolefilters ?? {}
+ }
+
+ get autoscroll(): boolean {
+ return this.$store.state.gui.console.autoscroll ?? true
+ }
+
+ set autoscroll(newVal) {
+ 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 })
+ }
+
+ get lastCommands(): string[] {
+ return this.$store.state.gui.gcodehistory.entries ?? []
+ }
+
+ toggleFilter(id: string | number, filter: GuiConsoleStateFilter): void {
+ this.$store.dispatch('gui/console/filterUpdate', { id, values: filter })
+ }
+
+ clearConsole() {
+ this.$store.dispatch('gui/console/clear')
+ }
+}
diff --git a/src/components/mixins/control.ts b/src/components/mixins/control.ts
index 0e669f1a4..e8a2b2df7 100644
--- a/src/components/mixins/control.ts
+++ b/src/components/mixins/control.ts
@@ -64,6 +64,19 @@ export default class ControlMixin extends Vue {
return this.$store.getters['gui/getDefaultControlActionButton']
}
+ get actionButton(): string {
+ const button = this.$store.state.gui.control.actionButton ?? this.defaultActionButton
+
+ if (
+ (button === 'qgl' && !this.$store.getters['printer/existsQGL']) ||
+ (button === 'ztilt' && !this.$store.getters['printer/existsZTilt'])
+ ) {
+ return this.defaultActionButton
+ }
+
+ return button
+ }
+
/**
* Axes home states
*/
@@ -135,9 +148,11 @@ export default class ControlMixin extends Vue {
}
doSendMove(gcode: string, feedrate: number) {
- gcode = 'G91' + '\n' + 'G1 ' + gcode + ' F' + feedrate * 60
-
- if (this.absolute_coordinates) gcode += '\nG90'
+ gcode =
+ `SAVE_GCODE_STATE NAME=_ui_movement\n` +
+ `G91\n` +
+ `G1 ${gcode} F${feedrate * 60}\n` +
+ `RESTORE_GCODE_STATE NAME=_ui_movement`
this.doSend(gcode)
}
diff --git a/src/components/mixins/historyStats.ts b/src/components/mixins/historyStats.ts
new file mode 100644
index 000000000..e761a993e
--- /dev/null
+++ b/src/components/mixins/historyStats.ts
@@ -0,0 +1,124 @@
+import Vue from 'vue'
+import Component from 'vue-class-component'
+import {
+ HistoryStatsValueNames,
+ ServerHistoryStateAllPrintStatusEntry,
+ ServerHistoryStateJob,
+} from '@/store/server/history/types'
+import i18n from '@/plugins/i18n'
+
+@Component
+export default class HistoryStatsMixin extends Vue {
+ valueName!: HistoryStatsValueNames
+
+ get allPrintStatusChartData() {
+ return this.getChartData(this.$store.state.server.history.jobs ?? [])
+ }
+
+ get selectedPrintStatusChartData() {
+ return this.getChartData(this.$store.getters['server/history/getSelectedJobs'])
+ }
+
+ private getStatusColor(status: string) {
+ const colorMap: Record = {
+ completed: '#BDBDBD',
+ in_progress: '#EEEEEE',
+ cancelled: '#616161',
+ default: '#424242',
+ }
+
+ return colorMap[status] ?? colorMap.default
+ }
+
+ private getLocalizedStatusName(status: string) {
+ return i18n.te(`History.StatusValues.${status}`, 'en')
+ ? i18n.t(`History.StatusValues.${status}`).toString()
+ : status
+ }
+
+ private getChartData(jobs: ServerHistoryStateJob[]) {
+ const output: ServerHistoryStateAllPrintStatusEntry[] = []
+ const hidePrintStatus = this.$store.state.gui.view.history.hidePrintStatus ?? []
+
+ jobs.forEach((current: ServerHistoryStateJob) => {
+ const index = output.findIndex((element) => element.name === current.status)
+ if (index !== -1) {
+ output[index].value += 1
+ output[index].valueFilament += current.filament_used
+ output[index].valueTime += current.print_duration
+ return
+ }
+
+ output.push({
+ name: current.status,
+ displayName: this.getLocalizedStatusName(current.status),
+ value: 1,
+ valueFilament: current.filament_used,
+ valueTime: current.print_duration,
+ itemStyle: {
+ opacity: 0.9,
+ color: this.getStatusColor(current.status),
+ borderColor: '#1E1E1E',
+ borderWidth: 2,
+ borderRadius: 3,
+ },
+ showInTable: !hidePrintStatus.includes(current.status),
+ })
+ })
+
+ return output
+ }
+
+ private groupSmallEntries(
+ entries: ServerHistoryStateAllPrintStatusEntry[],
+ threshold: number
+ ): ServerHistoryStateAllPrintStatusEntry[] {
+ const totalCount = entries.reduce((acc, cur) => acc + cur.value, 0)
+ const otherLimit = totalCount * threshold
+ const others = entries.filter((entry) => entry.value < otherLimit)
+
+ if (others.length < 2) return entries
+
+ const value = others.reduce((acc, cur) => acc + cur.value, 0)
+ const remaining = entries.filter((entry) => entry.value >= otherLimit)
+ const displayName = i18n.t(`History.StatusValues.Others`).toString() + ` (${others.length})`
+
+ remaining.push({
+ name: displayName,
+ displayName,
+ value,
+ valueFilament: 0,
+ valueTime: 0,
+ itemStyle: {
+ opacity: 0.9,
+ color: '#616161',
+ borderColor: '#1E1E1E',
+ borderWidth: 2,
+ borderRadius: 3,
+ },
+ showInTable: true,
+ })
+
+ return remaining
+ }
+
+ get printStatusArray() {
+ const countSelected = this.$store.getters['server/history/getSelectedJobs'].length
+ const orgArray = countSelected ? this.selectedPrintStatusChartData : this.allPrintStatusChartData
+
+ return orgArray.map((status) => ({
+ ...status,
+ name: status.displayName,
+ value:
+ this.valueName === 'filament'
+ ? status.valueFilament
+ : this.valueName === 'time'
+ ? status.valueTime
+ : status.value,
+ }))
+ }
+
+ get groupedPrintStatusArray() {
+ return this.groupSmallEntries(this.printStatusArray, 0.05)
+ }
+}
diff --git a/src/components/mixins/zoffset.ts b/src/components/mixins/zoffset.ts
index 9785f34ca..9ea91a429 100644
--- a/src/components/mixins/zoffset.ts
+++ b/src/components/mixins/zoffset.ts
@@ -1,6 +1,5 @@
import Vue from 'vue'
import Component from 'vue-class-component'
-import { CommandHelp } from '@/store/printer/types'
@Component
export default class ZoffsetMixin extends Vue {
@@ -11,8 +10,9 @@ export default class ZoffsetMixin extends Vue {
get z_gcode_offset() {
return this.homing_origin.length > 1 ? Math.round(this.homing_origin[2] * 1000) / 1000 : 0
}
- get helplist() {
- return this.$store.state.printer.helplist ?? []
+
+ get commands() {
+ return this.$store.state.printer.gcode?.commands ?? {}
}
get settings() {
@@ -44,11 +44,11 @@ export default class ZoffsetMixin extends Vue {
}
get existZOffsetApplyProbe() {
- return this.helplist.findIndex((gcode: CommandHelp) => gcode.commandLow === 'z_offset_apply_probe') !== -1
+ return 'Z_OFFSET_APPLY_PROBE' in this.commands
}
get existZOffsetApplyEndstop() {
- return this.helplist.findIndex((gcode: CommandHelp) => gcode.commandLow === 'z_offset_apply_endstop') !== -1
+ return 'Z_OFFSET_APPLY_ENDSTOP' in this.commands
}
get showSaveButton() {
diff --git a/src/components/panels/Extruder/EstimatedExtrusionOutput.vue b/src/components/panels/Extruder/EstimatedExtrusionOutput.vue
index 2ce18edae..bce476324 100644
--- a/src/components/panels/Extruder/EstimatedExtrusionOutput.vue
+++ b/src/components/panels/Extruder/EstimatedExtrusionOutput.vue
@@ -16,10 +16,10 @@
- {{ $t('Panels.ToolheadControlPanel.SpeedFactor') }}: {{ speed_factor * 100 }} %
+ {{ $t('Panels.ToolheadControlPanel.SpeedFactor') }}: {{ speedFactorOutput }} %
- {{ $t('Panels.ExtruderControlPanel.ExtrusionFactor') }}: {{ extrudeFactor * 100 }} %
+ {{ $t('Panels.ExtruderControlPanel.ExtrusionFactor') }}: {{ extrudeFactorOutput }} %
@@ -64,5 +64,13 @@ export default class PressureAdvanceSettings extends Mixins(BaseMixin, ExtruderM
get showTooltip() {
return this.speed_factor !== 1 || this.extrudeFactor !== 1
}
+
+ get speedFactorOutput() {
+ return (this.speed_factor * 100).toFixed(0)
+ }
+
+ get extrudeFactorOutput() {
+ return (this.extrudeFactor * 100).toFixed(0)
+ }
}
diff --git a/src/components/panels/Extruder/ExtruderControlPanelTools.vue b/src/components/panels/Extruder/ExtruderControlPanelTools.vue
index 5cce8979d..1ae8b6bc0 100644
--- a/src/components/panels/Extruder/ExtruderControlPanelTools.vue
+++ b/src/components/panels/Extruder/ExtruderControlPanelTools.vue
@@ -21,7 +21,8 @@ export default class ExtruderControlPanel extends Mixins(BaseMixin, ControlMixin
mdiPrinter3dNozzle = mdiPrinter3dNozzle
get rows() {
- const cols = 6
+ const len = this.toolchangeMacros.length
+ const cols = Math.ceil(len / Math.ceil(len / 6))
let rows = []
for (let i = 0; i < this.toolchangeMacros.length; i += cols) {
diff --git a/src/components/panels/History/HistoryListEntryJob.vue b/src/components/panels/History/HistoryListEntryJob.vue
index aa8da85d9..d6444cfc4 100644
--- a/src/components/panels/History/HistoryListEntryJob.vue
+++ b/src/components/panels/History/HistoryListEntryJob.vue
@@ -134,6 +134,7 @@ import { Component, Mixins, Prop } from 'vue-property-decorator'
import HistoryListPanelDetailsDialog from '@/components/dialogs/HistoryListPanelDetailsDialog.vue'
import Panel from '@/components/ui/Panel.vue'
import BaseMixin from '@/components/mixins/base'
+import { FileStateFileThumbnail } from '@/store/files/types'
import { ServerHistoryStateJob } from '@/store/server/history/types'
import { thumbnailBigMin, thumbnailSmallMax, thumbnailSmallMin } from '@/store/variables'
import {
@@ -187,40 +188,22 @@ export default class HistoryListPanel extends Mixins(BaseMixin) {
if ((this.item.metadata?.thumbnails?.length ?? 0) < 1) return false
const thumbnail = this.item.metadata?.thumbnails?.find(
- (thumb: any) =>
+ (thumb) =>
thumb.width >= thumbnailSmallMin &&
thumb.width <= thumbnailSmallMax &&
thumb.height >= thumbnailSmallMin &&
thumb.height <= thumbnailSmallMax
)
- let relative_url = ''
- if (this.item.filename.lastIndexOf('/') !== -1) {
- relative_url = this.item.filename.substring(0, this.item.filename.lastIndexOf('/'))
- }
-
- if ((thumbnail?.relative_path ?? null) === null) return false
-
- return `${this.apiUrl}/server/files/gcodes/${encodeURI(relative_url + thumbnail?.relative_path)}?timestamp=${
- this.item.metadata.modified
- }`
+ return thumbnail ? this.createThumbnailUrl(thumbnail) : false
}
get bigThumbnail() {
if ((this.item.metadata?.thumbnails?.length ?? 0) < 1) return false
- const thumbnail = this.item.metadata?.thumbnails?.find((thumb: any) => thumb.width >= thumbnailBigMin)
-
- let relative_url = ''
- if (this.item.filename.lastIndexOf('/') !== -1) {
- relative_url = this.item.filename.substring(0, this.item.filename.lastIndexOf('/') + 1)
- }
-
- if ((thumbnail?.relative_path ?? null) === null) return false
+ const thumbnail = this.item.metadata?.thumbnails?.find((thumb) => thumb.width >= thumbnailBigMin)
- return `${this.apiUrl}/server/files/gcodes/${encodeURI(relative_url + thumbnail?.relative_path)}?timestamp=${
- this.item.metadata.modified
- }`
+ return thumbnail ? this.createThumbnailUrl(thumbnail) : false
}
get statusIcon() {
@@ -331,5 +314,16 @@ export default class HistoryListPanel extends Mixins(BaseMixin) {
return value
}
}
+
+ createThumbnailUrl(thumbnail: FileStateFileThumbnail) {
+ let relative_url = ''
+ if (this.item.filename.lastIndexOf('/') !== -1) {
+ relative_url = this.item.filename.substring(0, this.item.filename.lastIndexOf('/') + 1)
+ }
+
+ return `${this.apiUrl}/server/files/gcodes/${encodeURI(relative_url + thumbnail.relative_path)}?timestamp=${
+ this.item.metadata.modified
+ }`
+ }
}
diff --git a/src/components/panels/HistoryListPanel.vue b/src/components/panels/HistoryListPanel.vue
index 85b2b404f..eca41eb34 100644
--- a/src/components/panels/HistoryListPanel.vue
+++ b/src/components/panels/HistoryListPanel.vue
@@ -14,15 +14,19 @@
dense />
-
-
- {{ mdiDelete }}
-
-
+
+
+
+ {{ mdiDelete }}
+
+
+ {{ $t('History.Delete') }}
+
-
- {{ mdiCog }}
-
+
+
+
+ {{ mdiCog }}
+
+
+ {{ $t('History.Settings') }}
+
@@ -80,11 +89,8 @@
@change="showPrintJobs = !showPrintJobs" />
-
-
+
+
-
-
+
+
{{ $t('History.Chart') }}
@@ -41,6 +41,13 @@
{{ $t('History.LoadCompleteHistory') }}
+
+
+
+ {{ option.text }}
+
+
+
@@ -64,10 +71,16 @@ import Panel from '@/components/ui/Panel.vue'
import HistoryFilamentUsage from '@/components/charts/HistoryFilamentUsage.vue'
import HistoryPrinttimeAvg from '@/components/charts/HistoryPrinttimeAvg.vue'
import HistoryAllPrintStatusChart from '@/components/charts/HistoryAllPrintStatusChart.vue'
-import { ServerHistoryStateJob, ServerHistoryStateJobAuxiliaryTotal } from '@/store/server/history/types'
+import {
+ HistoryStatsValueNames,
+ ServerHistoryStateJob,
+ ServerHistoryStateJobAuxiliaryTotal,
+} from '@/store/server/history/types'
import { mdiChartAreaspline, mdiDatabaseArrowDownOutline } from '@mdi/js'
import { formatPrintTime } from '@/plugins/helpers'
import HistoryMixin from '@/components/mixins/history'
+import { TranslateResult } from 'vue-i18n'
+
@Component({
components: { Panel, HistoryFilamentUsage, HistoryPrinttimeAvg, HistoryAllPrintStatusChart },
})
@@ -76,6 +89,16 @@ export default class HistoryStatisticsPanel extends Mixins(BaseMixin, HistoryMix
mdiDatabaseArrowDownOutline = mdiDatabaseArrowDownOutline
formatPrintTime = formatPrintTime
+ toggleValue = 'jobs'
+
+ get toggleValueOptions(): { text: TranslateResult; value: HistoryStatsValueNames }[] {
+ return [
+ { text: this.$t('History.Jobs'), value: 'jobs' },
+ { text: this.$t('History.Filament'), value: 'filament' },
+ { text: this.$t('History.Time'), value: 'time' },
+ ]
+ }
+
get selectedJobs() {
return this.$store.getters['server/history/getSelectedJobs']
}
diff --git a/src/components/panels/Machine/ConfigFilesPanel.vue b/src/components/panels/Machine/ConfigFilesPanel.vue
index a02bd2649..db3c9153c 100644
--- a/src/components/panels/Machine/ConfigFilesPanel.vue
+++ b/src/components/panels/Machine/ConfigFilesPanel.vue
@@ -260,9 +260,9 @@
-
+
diff --git a/src/components/panels/Machine/SystemPanel.vue b/src/components/panels/Machine/SystemPanel.vue
index ecc91dd72..329fb1790 100644
--- a/src/components/panels/Machine/SystemPanel.vue
+++ b/src/components/panels/Machine/SystemPanel.vue
@@ -1,25 +1,27 @@
-
-
-
+
+
+
+ {{ mdiUsb }}
+ {{ $t('Editor.DeviceDialog') }}
+
+
-
-
+
+
-
-
+
+
+
@@ -28,7 +30,7 @@ import { Component, Mixins } from 'vue-property-decorator'
import BaseMixin from '../../mixins/base'
import Panel from '@/components/ui/Panel.vue'
import { caseInsensitiveSort } from '@/plugins/helpers'
-import { mdiCloseThick, mdiMemory } from '@mdi/js'
+import { mdiCloseThick, mdiMemory, mdiUsb } from '@mdi/js'
import SystemPanelHost from '@/components/panels/Machine/SystemPanelHost.vue'
import SystemPanelMcu from '@/components/panels/Machine/SystemPanelMcu.vue'
@Component({
@@ -37,6 +39,9 @@ import SystemPanelMcu from '@/components/panels/Machine/SystemPanelMcu.vue'
export default class SystemPanel extends Mixins(BaseMixin) {
mdiCloseThick = mdiCloseThick
mdiMemory = mdiMemory
+ mdiUsb = mdiUsb
+
+ dialogDevices = false
get mcus() {
const mcus = this.$store.getters['printer/getMcus'] ?? []
@@ -49,3 +54,9 @@ export default class SystemPanel extends Mixins(BaseMixin) {
}
}
+
+
diff --git a/src/components/panels/Machine/UpdatePanel/GitCommitsList.vue b/src/components/panels/Machine/UpdatePanel/GitCommitsList.vue
index cc11e51d5..b0e6f554d 100644
--- a/src/components/panels/Machine/UpdatePanel/GitCommitsList.vue
+++ b/src/components/panels/Machine/UpdatePanel/GitCommitsList.vue
@@ -103,7 +103,7 @@ export default class GitCommitsList extends Mixins(BaseMixin) {
}
get linkToGithub() {
- return `https://github.com/${this.repo?.owner}/${this.repo?.name}/commits/${this.repo?.branch}/?after=${this.lastCommit?.sha}+0`
+ return `https://github.com/${this.repo?.owner}/${this.repo?.repo_name}/commits/${this.repo?.branch}/?after=${this.lastCommit?.sha}+0`
}
get overlayScrollbarsStyle() {
diff --git a/src/components/panels/MiniconsolePanel.vue b/src/components/panels/MiniconsolePanel.vue
index 8a5168dc6..93178fad7 100644
--- a/src/components/panels/MiniconsolePanel.vue
+++ b/src/components/panels/MiniconsolePanel.vue
@@ -10,7 +10,7 @@
{{ mdiTrashCan }}
-
+
+ @change="toggleFilter(index, filter)" />
-
+
@@ -107,14 +86,14 @@
@@ -359,8 +169,4 @@ export default class MiniconsolePanel extends Mixins(BaseMixin) {
html.theme--light .consoleTable {
border-top: 1px solid rgba(0, 0, 0, 0.12);
}
-
-.gcode-command-field {
- font-family: 'Roboto Mono', monospace;
-}
diff --git a/src/components/panels/Status/Gcodefiles.vue b/src/components/panels/Status/Gcodefiles.vue
index d2a38e6fa..493a2d6f7 100644
--- a/src/components/panels/Status/Gcodefiles.vue
+++ b/src/components/panels/Status/Gcodefiles.vue
@@ -5,178 +5,16 @@
hide-default-footer
class="dashboard-gcodes-table"
sort-by="time_added"
- mobile-breakpoint="0"
- @current-items="setFirst">
+ mobile-breakpoint="0">
{{ $t('Panels.StatusPanel.EmptyGcodes') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ mdiFile }}
-
-
-
-
-
-
-
- {{ mdiFile }}
-
- |
-
- {{ item.filename }}
-
- {{ getDescription(item) }}
-
- |
-
-
-
-
-
- {{ getStatusIcon(item.last_status) }}
-
-
-
- {{ item.last_status.replace(/_/g, ' ') }}
-
- |
-
+
-
-
-
-
- {{ mdiPlay }}
- {{ $t('Files.PrintStart') }}
-
-
- {{ mdiPlaylistPlus }}
- {{ $t('Files.AddToQueue') }}
-
-
- {{ mdiPlaylistPlus }}
- {{ $t('Files.AddBatchToQueue') }}
-
-
- {{ mdiFire }}
- {{ $t('Files.Preheat') }}
-
-
- {{ mdiVideo3d }}
- {{ $t('Files.View3D') }}
-
-
- {{ mdiCloudDownload }}
- {{ $t('Files.Download') }}
-
-
- {{ mdiFileDocumentEditOutline }}
- {{ $t('Files.EditFile') }}
-
-
- {{ mdiRenameBox }}
- {{ $t('Files.Rename') }}
-
-
- {{ mdiDelete }}
- {{ $t('Files.Delete') }}
-
-
-
-
-
-
-
- {{ mdiCloseThick }}
-
-
-
-
-
-
-
- {{ $t('Files.Cancel') }}
- {{ $t('Files.Rename') }}
-
-
-
-
-
-
-
-
-
- {{ mdiCloseThick }}
-
-
-
-
- {{ $t('Files.DeleteSingleFileQuestion', { name: filename }) }}
-
-
-
-
-
- {{ $t('Files.Cancel') }}
-
-
- {{ $t('Files.Delete') }}
-
-
-
-
-
-
@@ -186,107 +24,51 @@ import { Mixins } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import ControlMixin from '@/components/mixins/control'
import { FileStateGcodefile } from '@/store/files/types'
-import StartPrintDialog from '@/components/dialogs/StartPrintDialog.vue'
-import {
- mdiFile,
- mdiPlay,
- mdiPlaylistPlus,
- mdiFire,
- mdiVideo3d,
- mdiCloudDownload,
- mdiFileDocumentEditOutline,
- mdiRenameBox,
- mdiDelete,
- mdiCloseThick,
-} from '@mdi/js'
import Panel from '@/components/ui/Panel.vue'
-import { defaultBigThumbnailBackground } from '@/store/variables'
-import AddBatchToQueueDialog from '@/components/dialogs/AddBatchToQueueDialog.vue'
-
-interface dialogRenameObject {
- show: boolean
- newName: string
- item: FileStateGcodefile
-}
+import StatusPanelGcodefilesEntry from '@/components/panels/Status/GcodefilesEntry.vue'
+import Vue from 'vue'
@Component({
- components: {
- Panel,
- StartPrintDialog,
- AddBatchToQueueDialog,
- },
+ components: { Panel, StatusPanelGcodefilesEntry },
})
export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixin) {
- mdiFile = mdiFile
- mdiPlay = mdiPlay
- mdiPlaylistPlus = mdiPlaylistPlus
- mdiFire = mdiFire
- mdiVideo3d = mdiVideo3d
- mdiCloudDownload = mdiCloudDownload
- mdiFileDocumentEditOutline = mdiFileDocumentEditOutline
- mdiRenameBox = mdiRenameBox
- mdiDelete = mdiDelete
- mdiCloseThick = mdiCloseThick
-
- private deleteDialog = false
- private showDialogBool = false
- private dialogFile: FileStateGcodefile = {
- isDirectory: false,
- filename: '',
- modified: new Date(),
- permissions: '',
- small_thumbnail: null,
- big_thumbnail: null,
- big_thumbnail_width: null,
- count_printed: 0,
- last_end_time: null,
- last_filament_used: null,
- last_print_duration: null,
- last_status: null,
- last_start_time: null,
- last_total_duration: null,
- preheat_gcode: null,
- }
- private currentPath = ''
- private contentTdWidth = 100
+ contentTdWidth = 100
declare $refs: {
- filesGcodeCard: any
- inputFieldRenameFile: HTMLInputElement
+ filesGcodeCard: Vue
}
- private contextMenu = {
- shown: false,
- touchTimer: undefined,
- x: 0,
- y: 0,
- item: { ...this.dialogFile },
+ get filesLimit() {
+ return this.$store.state.gui.uiSettings.dashboardFilesLimit ?? 5
}
- private dialogRenameFile: dialogRenameObject = {
- show: false,
- newName: '',
- item: { ...this.dialogFile },
+ get filesFilter() {
+ return this.$store.state.gui.uiSettings.dashboardFilesFilter ?? []
}
- dialogAddBatchToQueue: { isVisible: boolean; filename: string } = {
- isVisible: false,
- filename: '',
- }
-
- private countInputRules = [
- (value: string) => !!value || this.$t('JobQueue.InvalidCountEmpty'),
- (value: string) => parseInt(value) > 0 || this.$t('JobQueue.InvalidCountGreaterZero'),
- ]
-
get gcodeFiles() {
let gcodes = this.$store.getters['files/getAllGcodes'] ?? []
+
+ if (this.filesFilter.length > 0 && this.filesFilter.length < 3) {
+ gcodes = gcodes.filter((file: FileStateGcodefile) => {
+ if (this.filesFilter.includes('new') && file.last_status === null) return true
+ if (this.filesFilter.includes('completed') && file.last_status === 'completed') return true
+ if (
+ this.filesFilter.includes('failed') &&
+ file.last_status !== null &&
+ file.last_status !== 'completed'
+ )
+ return true
+
+ return false
+ })
+ }
+
gcodes = gcodes
- .slice()
.sort((a: FileStateGcodefile, b: FileStateGcodefile) => {
return b.modified.getTime() - a.modified.getTime()
})
- .slice(0, 5)
+ .slice(0, this.filesLimit)
const requestItems = gcodes.filter(
(file: FileStateGcodefile) => !file.metadataRequested && !file.metadataPulled
@@ -300,192 +82,6 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
return gcodes
}
- get filename() {
- const filename = this.contextMenu.item.filename.split('/')
- return filename[filename.length - 1]
- }
-
- get styleContentTdWidth() {
- return `width: ${this.contentTdWidth}px;`
- }
-
- get bigThumbnailBackground() {
- return this.$store.state.gui.uiSettings.bigThumbnailBackground ?? defaultBigThumbnailBackground
- }
-
- get bigThumbnailTooltipColor() {
- if (defaultBigThumbnailBackground.toLowerCase() === this.bigThumbnailBackground.toLowerCase()) {
- return undefined
- }
-
- return this.bigThumbnailBackground
- }
-
- showContextMenu(e: any, item: FileStateGcodefile) {
- 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
- })
- }
- }
-
- getDescription(item: FileStateGcodefile) {
- let output = ''
-
- output += this.$t('Panels.StatusPanel.Filament') + ': '
- if (item.filament_total || item.filament_weight_total) {
- if (item.filament_total) output += item.filament_total.toFixed() + ' mm'
- if (item.filament_total && item.filament_weight_total) output += ' / '
- if (item.filament_weight_total) output += item.filament_weight_total.toFixed(2) + ' g'
- } else output += '--'
-
- output += ', ' + this.$t('Panels.StatusPanel.PrintTime') + ': '
- if (item.estimated_time) output += this.formatPrintTime(item.estimated_time)
- else output += '--'
-
- return output
- }
-
- existMetadata(item: FileStateGcodefile) {
- return item?.metadataPulled
- }
-
- setFirst(currItems: any) {
- // first check that actually exists values
- if (currItems.length) {
- // toggle all to false
- currItems.forEach((x: any) => (x.isFirst = false))
- // just set first to true
- currItems[0].isFirst = true
- }
- }
-
- formatPrintTime(totalSeconds: number) {
- if (totalSeconds) {
- let output = ''
-
- const days = Math.floor(totalSeconds / (3600 * 24))
- if (days) {
- totalSeconds %= 3600 * 24
- output += days + 'd'
- }
-
- const hours = Math.floor(totalSeconds / 3600)
- totalSeconds %= 3600
- if (hours) output += ' ' + hours + 'h'
-
- const minutes = Math.floor(totalSeconds / 60)
- if (minutes) output += ' ' + minutes + 'm'
-
- const seconds = totalSeconds % 60
- if (seconds) output += ' ' + seconds.toFixed(0) + 's'
-
- return output
- }
-
- return '--'
- }
-
- getStatusIcon(status: string) {
- return this.$store.getters['server/history/getPrintStatusIcon'](status)
- }
-
- getStatusColor(status: string) {
- return this.$store.getters['server/history/getPrintStatusIconColor'](status)
- }
-
- showDialog(file: FileStateGcodefile) {
- this.currentPath =
- file.filename.lastIndexOf('/') >= 0 ? '/' + file.filename.slice(0, file.filename.lastIndexOf('/')) : ''
- this.dialogFile = { ...file }
- if (file.filename.lastIndexOf('/') >= 0) {
- this.dialogFile.filename = file.filename.slice(file.filename.lastIndexOf('/') + 1)
- }
- this.showDialogBool = true
- }
-
- closeDialog() {
- this.showDialogBool = false
- }
-
- addToQueue(item: FileStateGcodefile) {
- this.$store.dispatch('server/jobQueue/addToQueue', [item.filename])
- }
-
- openAddBatchToQueueDialog(item: FileStateGcodefile) {
- this.dialogAddBatchToQueue.isVisible = true
- this.dialogAddBatchToQueue.filename = item.filename
- }
-
- closeAddBatchToQueueDialog() {
- this.dialogAddBatchToQueue.isVisible = false
- }
-
- view3D(item: FileStateGcodefile) {
- this.$router.push({ path: '/viewer', query: { filename: 'gcodes/' + item.filename } })
- }
-
- downloadFile(item: FileStateGcodefile) {
- const href = this.apiUrl + '/server/files/gcodes/' + encodeURI(item.filename)
-
- window.open(href)
- }
-
- editFile(item: FileStateGcodefile) {
- const pos = item.filename.lastIndexOf('/')
- const path = pos > 0 ? item.filename.slice(0, pos + 1) : ''
- const filename = pos > 0 ? item.filename.slice(pos + 1) : item.filename
-
- this.$store.dispatch('editor/openFile', {
- root: 'gcodes',
- path,
- filename,
- size: item.size,
- permissions: item.permissions,
- })
- }
-
- renameFile(item: FileStateGcodefile) {
- this.dialogRenameFile.item = item
- const pos = item.filename.lastIndexOf('/')
- this.dialogRenameFile.newName = pos > 0 ? item.filename.slice(pos + 1) : item.filename
- this.dialogRenameFile.show = true
-
- setTimeout(() => {
- this.$refs.inputFieldRenameFile?.focus()
- }, 200)
- }
-
- renameFileAction() {
- this.dialogRenameFile.show = false
- const pos = this.dialogRenameFile.item.filename.lastIndexOf('/')
- const path = pos > 0 ? this.dialogRenameFile.item.filename.slice(0, pos + 1) : ''
-
- this.$socket.emit(
- 'server.files.move',
- {
- source: 'gcodes/' + this.dialogRenameFile.item.filename,
- dest: 'gcodes/' + path + this.dialogRenameFile.newName,
- },
- { action: 'files/getMove' }
- )
- }
-
- removeFile() {
- this.$socket.emit(
- 'server.files.delete_file',
- { path: 'gcodes/' + this.contextMenu.item.filename },
- { action: 'files/getDeleteFile' }
- )
-
- this.deleteDialog = false
- }
-
mounted() {
setTimeout(() => {
this.calcContentTdWidth()
@@ -493,7 +89,7 @@ export default class StatusPanelGcodefiles extends Mixins(BaseMixin, ControlMixi
}
calcContentTdWidth() {
- this.contentTdWidth = this.$refs.filesGcodeCard?.$el?.clientWidth - 48 - 48 - 32
+ this.contentTdWidth = this.$refs.filesGcodeCard.$el.clientWidth - 48 - 48 - 32
}
handleResize() {
diff --git a/src/components/panels/Status/GcodefilesEntry.vue b/src/components/panels/Status/GcodefilesEntry.vue
new file mode 100644
index 000000000..40ec4837a
--- /dev/null
+++ b/src/components/panels/Status/GcodefilesEntry.vue
@@ -0,0 +1,350 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ mdiFile }}
+
+
+
+
+
+
+
+ {{ mdiFile }}
+
+ |
+
+ {{ item.filename }}
+ {{ description }}
+ |
+
+
+
+
+ {{ statusIcon }}
+
+
+ {{ item.last_status.replace(/_/g, ' ') }}
+
+ |
+
+
+
+ {{ mdiPlay }}
+ {{ $t('Files.PrintStart') }}
+
+
+ {{ mdiPlaylistPlus }}
+ {{ $t('Files.AddToQueue') }}
+
+
+ {{ mdiPlaylistPlus }}
+ {{ $t('Files.AddBatchToQueue') }}
+
+
+ {{ mdiFire }}
+ {{ $t('Files.Preheat') }}
+
+
+ {{ mdiVideo3d }}
+ {{ $t('Files.View3D') }}
+
+
+ {{ mdiCloudDownload }}
+ {{ $t('Files.Download') }}
+
+
+ {{ mdiFileDocumentEditOutline }}
+ {{ $t('Files.EditFile') }}
+
+
+ {{ mdiRenameBox }}
+ {{ $t('Files.Rename') }}
+
+
+ {{ mdiDelete }}
+ {{ $t('Files.Delete') }}
+
+
+
+
+
+
+
+
+
+ {{ mdiCloseThick }}
+
+
+
+
+
+
+
+ {{ $t('Files.Cancel') }}
+ {{ $t('Files.Rename') }}
+
+
+
+
+
+
+
+ {{ mdiCloseThick }}
+
+
+
+ {{ $t('Files.DeleteSingleFileQuestion', { name: filename }) }}
+
+
+
+
+ {{ $t('Files.Cancel') }}
+
+
+ {{ $t('Files.Delete') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/panels/Status/History.vue b/src/components/panels/Status/History.vue
new file mode 100644
index 000000000..2ad17df2c
--- /dev/null
+++ b/src/components/panels/Status/History.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
{{ $t('Panels.StatusPanel.EmptyHistory') }}
+
+
+
+
+
+
+
diff --git a/src/components/panels/Status/HistoryEntry.vue b/src/components/panels/Status/HistoryEntry.vue
new file mode 100644
index 000000000..7d5af2cb7
--- /dev/null
+++ b/src/components/panels/Status/HistoryEntry.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ mdiFile }}
+
+
+
+
+
+ {{ mdiFile }}
+
+
+
+ {{ job.count }}x
+ {{ job.filename }}
+
+ {{ description }}
+
+
+
+
+
+
+ {{ statusIcon }}
+
+
+
+ {{ statusName }}
+
+
+
+
+
+ {{ mdiPrinter }}
+ {{ $t('History.Reprint') }}
+
+
+ {{ mdiPlaylistPlus }}
+ {{ $t('Files.AddToQueue') }}
+
+
+ {{ mdiPlaylistPlus }}
+ {{ $t('Files.AddBatchToQueue') }}
+
+
+ {{ mdiDelete }}
+ {{ $t('History.Delete') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/panels/StatusPanel.vue b/src/components/panels/StatusPanel.vue
index d0a3833bb..6334d6eef 100644
--- a/src/components/panels/StatusPanel.vue
+++ b/src/components/panels/StatusPanel.vue
@@ -89,11 +89,18 @@
- {{ $t('Panels.StatusPanel.Status') }}
- {{ $t('Panels.StatusPanel.Files') }}
+
+ {{ mdiSpeedometer }}
+
+
+ {{ mdiFileDocumentMultipleOutline }}
+
+
+ {{ mdiHistory }}
+
- {{ $t('Panels.StatusPanel.Jobqueue') }}
+ {{ mdiTrayFull }}
@@ -102,9 +109,12 @@
-
+
+
+
+
@@ -125,6 +135,7 @@ import MinSettingsPanel from '@/components/panels/MinSettingsPanel.vue'
import KlippyStatePanel from '@/components/panels/KlippyStatePanel.vue'
import StatusPanelPrintstatus from '@/components/panels/Status/Printstatus.vue'
import StatusPanelGcodefiles from '@/components/panels/Status/Gcodefiles.vue'
+import StatusPanelHistory from '@/components/panels/Status/History.vue'
import StatusPanelJobqueue from '@/components/panels/Status/Jobqueue.vue'
import StatusPanelExcludeObject from '@/components/panels/Status/ExcludeObject.vue'
import StatusPanelPrintstatusThumbnail from '@/components/panels/Status/PrintstatusThumbnail.vue'
@@ -133,16 +144,20 @@ import Panel from '@/components/ui/Panel.vue'
import {
mdiAlertOutline,
mdiBroom,
+ mdiCloseCircle,
+ mdiDotsVertical,
+ mdiFileDocumentMultipleOutline,
+ mdiHistory,
mdiInformation,
+ mdiLayersPlus,
+ mdiMessageProcessingOutline,
mdiPause,
mdiPlay,
mdiPrinter,
mdiSelectionRemove,
+ mdiSpeedometer,
mdiStop,
- mdiMessageProcessingOutline,
- mdiCloseCircle,
- mdiLayersPlus,
- mdiDotsVertical,
+ mdiTrayFull,
} from '@mdi/js'
import { PrinterStateMacro } from '@/store/printer/types'
import CancelJobDialog from '@/components/dialogs/CancelJobDialog.vue'
@@ -155,6 +170,7 @@ import CancelJobDialog from '@/components/dialogs/CancelJobDialog.vue'
Panel,
StatusPanelExcludeObject,
StatusPanelGcodefiles,
+ StatusPanelHistory,
StatusPanelJobqueue,
StatusPanelPrintstatus,
StatusPanelPrintstatusThumbnail,
@@ -162,11 +178,15 @@ import CancelJobDialog from '@/components/dialogs/CancelJobDialog.vue'
},
})
export default class StatusPanel extends Mixins(BaseMixin) {
- mdiInformation = mdiInformation
- mdiMessageProcessingOutline = mdiMessageProcessingOutline
+ mdiAlertOutline = mdiAlertOutline
mdiCloseCircle = mdiCloseCircle
mdiDotsVertical = mdiDotsVertical
- mdiAlertOutline = mdiAlertOutline
+ mdiFileDocumentMultipleOutline = mdiFileDocumentMultipleOutline
+ mdiInformation = mdiInformation
+ mdiHistory = mdiHistory
+ mdiMessageProcessingOutline = mdiMessageProcessingOutline
+ mdiSpeedometer = mdiSpeedometer
+ mdiTrayFull = mdiTrayFull
declare $refs: {
bigThumbnail: any
@@ -362,8 +382,22 @@ export default class StatusPanel extends Mixins(BaseMixin) {
return this.layer_count !== null && (this.existsSetPauseAtLayer || this.existsSetPauseNextLayer)
}
+ get displayFilesTab() {
+ const count = this.$store.state.gui.uiSettings.dashboardFilesLimit ?? 5
+
+ return count > 0
+ }
+
+ get displayHistoryTab() {
+ const count = this.$store.state.gui.uiSettings.dashboardHistoryLimit ?? 5
+
+ return count > 0
+ }
+
mounted() {
if (this.current_filename !== '') this.activeTab = 'status'
+ if (!this.displayFilesTab) this.activeTab = 'history'
+ if (!this.displayHistoryTab) this.activeTab = 'jobqueue'
}
@Watch('current_filename')
@@ -428,4 +462,8 @@ export default class StatusPanel extends Mixins(BaseMixin) {
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
}
+
+.theme--dark.v-tabs > .v-tabs-bar .v-tab:not(.v-tab--active) > .v-badge > .v-icon {
+ color: rgba(255, 255, 255, 0.6);
+}
diff --git a/src/components/panels/Temperature/TemperaturePanelList.vue b/src/components/panels/Temperature/TemperaturePanelList.vue
index c149fd388..ba13c35f3 100644
--- a/src/components/panels/Temperature/TemperaturePanelList.vue
+++ b/src/components/panels/Temperature/TemperaturePanelList.vue
@@ -27,7 +27,9 @@
:object-name="objectName"
:is-responsive-mobile="el.is.mobile ?? false" />
{
- const splits = fullName.split(' ')
- let name = splits[0]
- if (splits.length > 1) name = splits[1]
-
- return !name.startsWith('_')
- })
- .sort(this.sortObjectName)
+ return this.filterNamesAndSort(this.available_heaters)
}
get available_sensors() {
@@ -81,6 +75,10 @@ export default class TemperaturePanelList extends Mixins(BaseMixin) {
return this.$store.state.printer?.heaters?.available_monitors ?? []
}
+ get available_nevermores() {
+ return Object.keys(this.$store.state.printer).filter((name) => name.startsWith('nevermore'))
+ }
+
get monitors() {
return this.available_monitors.sort(this.sortObjectName)
}
@@ -91,10 +89,6 @@ export default class TemperaturePanelList extends Mixins(BaseMixin) {
.sort(this.sortObjectName)
}
- get existsNevermoreFilter() {
- return 'nevermore' in this.$store.state.printer
- }
-
get hideMcuHostSensors(): boolean {
return this.$store.state.gui.view.tempchart.hideMcuHostSensors ?? false
}
@@ -104,27 +98,25 @@ export default class TemperaturePanelList extends Mixins(BaseMixin) {
}
get temperature_sensors() {
- return this.available_sensors
- .filter((fullName: string) => {
- if (this.available_heaters.includes(fullName)) return false
- if (this.temperature_fans.includes(fullName)) return false
+ return this.filterNamesAndSort(this.available_sensors).filter((fullName: string) => {
+ if (this.available_heaters.includes(fullName)) return false
+ if (this.temperature_fans.includes(fullName)) return false
- // hide MCU & Host sensors, if the function is enabled
- if (this.hideMcuHostSensors && this.checkMcuHostSensor(fullName)) return false
+ // hide MCU & Host sensors, if the function is enabled
+ if (this.hideMcuHostSensors && this.checkMcuHostSensor(fullName)) return false
- const splits = fullName.split(' ')
- let name = splits[0]
- if (splits.length > 1) name = splits[1]
-
- return !name.startsWith('_')
- })
- .sort(this.sortObjectName)
+ return true
+ })
}
get heaterObjects() {
return [...this.filteredHeaters, ...this.temperature_fans]
}
+ get nevermoreObjects() {
+ return this.filterNamesAndSort(this.available_nevermores)
+ }
+
get settings() {
return this.$store.state.printer?.configfile?.settings ?? {}
}
@@ -136,22 +128,28 @@ export default class TemperaturePanelList extends Mixins(BaseMixin) {
return ['temperature_mcu', 'temperature_host'].includes(sensor_type)
}
- sortObjectName(a: string, b: string) {
- const splitsA = a.split(' ')
- let nameA = splitsA[0]
- if (splitsA.length > 1) nameA = splitsA[1]
- nameA = nameA.toUpperCase()
+ filterNamesAndSort(fullNames: string[]) {
+ return fullNames.filter(this.isVisibleName).sort(this.sortObjectName)
+ }
- const splitsB = b.split(' ')
- let nameB = splitsB[0]
- if (splitsB.length > 1) nameB = splitsB[1]
- nameB = nameB.toUpperCase()
+ isVisibleName(fullName: string) {
+ return !this.shortName(fullName).startsWith('_')
+ }
+
+ sortObjectName(a: string, b: string) {
+ const nameA = this.shortName(a).toUpperCase()
+ const nameB = this.shortName(b).toUpperCase()
if (nameA < nameB) return -1
if (nameA > nameB) return 1
return 0
}
+
+ shortName(fullName: string) {
+ const splits = fullName.split(' ')
+ return splits.length == 1 ? splits[0] : splits[1]
+ }
}
diff --git a/src/components/panels/Temperature/TemperaturePanelListItemEdit.vue b/src/components/panels/Temperature/TemperaturePanelListItemEdit.vue
index 9ac501c7a..87f07c5bf 100644
--- a/src/components/panels/Temperature/TemperaturePanelListItemEdit.vue
+++ b/src/components/panels/Temperature/TemperaturePanelListItemEdit.vue
@@ -67,7 +67,7 @@ export default class TemperaturePanelListItemEdit extends Mixins(BaseMixin) {
get additionalValues() {
if (this.objectName === 'z_thermal_adjust') return ['current_z_adjust']
- if (this.objectName === 'nevermore') return ['temperature', 'pressure', 'humidity', 'rpm']
+ if (this.objectName.startsWith('nevermore')) return ['temperature', 'pressure', 'humidity', 'rpm']
return Object.keys(this.printerObjectAdditionalSensor).filter((key) => key !== 'temperature')
}
diff --git a/src/components/panels/Temperature/TemperaturePanelListItemNevermore.vue b/src/components/panels/Temperature/TemperaturePanelListItemNevermore.vue
index 54679d6ec..003ac67fd 100644
--- a/src/components/panels/Temperature/TemperaturePanelListItemNevermore.vue
+++ b/src/components/panels/Temperature/TemperaturePanelListItemNevermore.vue
@@ -6,19 +6,19 @@
- Nevermore
+ {{ formatName }}
|
{{ rpm }} RPM
@@ -26,9 +26,9 @@
|
{{ $t('Settings.HeightmapTab.Heightmap') }}
-
+
+
+
+
+
-
+
@@ -39,6 +39,36 @@ import { mdiGrid } from '@mdi/js'
})
export default class SettingsHeightmapTab extends Mixins(BaseMixin) {
mdiGrid = mdiGrid
+
+ get availableOrientations() {
+ return [
+ {
+ text: this.$t('Settings.HeightmapTab.Orientations.RightFront'),
+ value: 'rightFront',
+ },
+ {
+ text: this.$t('Settings.HeightmapTab.Orientations.LeftFront'),
+ value: 'leftFront',
+ },
+ {
+ text: this.$t('Settings.HeightmapTab.Orientations.Front'),
+ value: 'front',
+ },
+ {
+ text: this.$t('Settings.HeightmapTab.Orientations.Top'),
+ value: 'top',
+ },
+ ]
+ }
+
+ get defaultOrientation() {
+ return this.$store.state.gui.heightmap.defaultOrientation
+ }
+
+ set defaultOrientation(newVal) {
+ this.$store.dispatch('gui/heightmap/saveSetting', { name: 'defaultOrientation', value: newVal })
+ }
+
get availableColorSchemes() {
return [
{
diff --git a/src/components/settings/SettingsUiSettingsTab.vue b/src/components/settings/SettingsUiSettingsTab.vue
index 14bb0f33e..a05410af7 100644
--- a/src/components/settings/SettingsUiSettingsTab.vue
+++ b/src/components/settings/SettingsUiSettingsTab.vue
@@ -282,6 +282,46 @@
:dynamic-slot-width="true">
+
+
+
+
+
+
+
+
+
+
+
+
@@ -615,6 +655,47 @@ export default class SettingsUiSettingsTab extends Mixins(BaseMixin, ThemeMixin)
this.$store.dispatch('gui/saveSetting', { name: 'uiSettings.hideUpdateWarnings', value: newVal })
}
+ get dashboardFilesLimit() {
+ return this.$store.state.gui.uiSettings.dashboardFilesLimit ?? 5
+ }
+
+ set dashboardFilesLimit(newVal) {
+ this.$store.dispatch('gui/saveSetting', { name: 'uiSettings.dashboardFilesLimit', value: newVal })
+ }
+
+ get dashboardFilesFilter() {
+ return this.$store.state.gui.uiSettings.dashboardFilesFilter ?? []
+ }
+
+ set dashboardFilesFilter(newVal) {
+ this.$store.dispatch('gui/saveSetting', { name: 'uiSettings.dashboardFilesFilter', value: newVal })
+ }
+
+ get dashboardFilesFilters() {
+ return [
+ {
+ text: this.$t('Settings.UiSettingsTab.DashboardFilesFilterNew'),
+ value: 'new',
+ },
+ {
+ text: this.$t('Settings.UiSettingsTab.DashboardFilesFilterFailed'),
+ value: 'failed',
+ },
+ {
+ text: this.$t('Settings.UiSettingsTab.DashboardFilesFilterCompleted'),
+ value: 'completed',
+ },
+ ]
+ }
+
+ get dashboardHistoryLimit() {
+ return this.$store.state.gui.uiSettings.dashboardHistoryLimit ?? 5
+ }
+
+ set dashboardHistoryLimit(newVal) {
+ this.$store.dispatch('gui/saveSetting', { name: 'uiSettings.dashboardHistoryLimit', value: newVal })
+ }
+
clearColorObject(color: any): string {
if (typeof color === 'object' && 'hex' in color) color = color.hex
if (color.length > 7) color = color.substr(0, 7)
diff --git a/src/components/webcams/WebcamWrapperItem.vue b/src/components/webcams/WebcamWrapperItem.vue
index 00d4a9078..caf299a05 100644
--- a/src/components/webcams/WebcamWrapperItem.vue
+++ b/src/components/webcams/WebcamWrapperItem.vue
@@ -19,7 +19,7 @@
-
+
diff --git a/src/components/webcams/streamers/Mjpegstreamer.vue b/src/components/webcams/streamers/Mjpegstreamer.vue
index 03706b94a..79232c8e1 100644
--- a/src/components/webcams/streamers/Mjpegstreamer.vue
+++ b/src/components/webcams/streamers/Mjpegstreamer.vue
@@ -4,6 +4,7 @@
v-show="status === 'connected'"
ref="image"
class="webcamImage"
+ draggable="false"
:style="webcamStyle"
:alt="camSettings.name"
src="#"
diff --git a/src/components/webcams/streamers/MjpegstreamerAdaptive.vue b/src/components/webcams/streamers/MjpegstreamerAdaptive.vue
index cac1ee5f8..12dd30a79 100644
--- a/src/components/webcams/streamers/MjpegstreamerAdaptive.vue
+++ b/src/components/webcams/streamers/MjpegstreamerAdaptive.vue
@@ -4,6 +4,7 @@
v-show="status === 'connected'"
ref="image"
class="webcamImage"
+ draggable="false"
:style="webcamStyle"
:alt="camSettings.name"
src="#"
diff --git a/src/components/webcams/streamers/Uv4lMjpeg.vue b/src/components/webcams/streamers/Uv4lMjpeg.vue
index 7b7912007..a1e11bc5d 100644
--- a/src/components/webcams/streamers/Uv4lMjpeg.vue
+++ b/src/components/webcams/streamers/Uv4lMjpeg.vue
@@ -5,6 +5,7 @@
v-observe-visibility="viewportVisibilityChanged"
:style="webcamStyle"
class="webcamImage"
+ draggable="false"
@load="onload" />
diff --git a/src/components/webcams/streamers/WebrtcCameraStreamer.vue b/src/components/webcams/streamers/WebrtcCameraStreamer.vue
index 334ff82e4..b3422bff8 100644
--- a/src/components/webcams/streamers/WebrtcCameraStreamer.vue
+++ b/src/components/webcams/streamers/WebrtcCameraStreamer.vue
@@ -11,7 +11,7 @@
- {{ status }}
+ {{ capitalize(status) }}
@@ -22,18 +22,28 @@ import { Component, Mixins, Prop, Ref, Watch } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
import WebcamMixin from '@/components/mixins/webcam'
+import { capitalize } from '@/plugins/helpers'
-@Component
+interface CameraStreamerResponse extends RTCSessionDescriptionInit {
+ id: string
+ iceServers?: RTCIceServer[]
+}
+
+@Component({
+ methods: { capitalize },
+})
export default class WebrtcCameraStreamer extends Mixins(BaseMixin, WebcamMixin) {
- private pc: RTCPeerConnection | null = null
- private useStun = false
- private remote_pc_id: string | null = null
- private aspectRatio: null | number = null
- private status: string = 'connecting'
- private restartTimer: number | null = null
+ capitalize = capitalize
+
+ pc: RTCPeerConnection | null = null
+ useStun = false
+ aspectRatio: null | number = null
+ status: string = 'connecting'
+ restartTimer: number | null = null
@Prop({ required: true }) readonly camSettings!: GuiWebcamStateWebcam
@Prop({ default: null }) declare readonly printerUrl: string | null
+ @Prop({ type: String, default: null }) readonly page!: string | null
@Ref() declare stream: HTMLVideoElement
get url() {
@@ -55,128 +65,178 @@ export default class WebrtcCameraStreamer extends Mixins(BaseMixin, WebcamMixin)
return output
}
- startStream() {
- const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
- const requestIceServers = this.useStun ? [{ urls: ['stun:stun.l.google.com:19302'] }] : null
-
- // This WebRTC signaling pattern is designed for camera-streamer, a common webcam server the supports WebRTC.
- fetch(this.url, {
- body: JSON.stringify({
- type: 'request',
- iceServers: requestIceServers,
- }),
- headers: {
- 'Content-Type': 'application/json',
- },
- method: 'POST',
- })
- .then((response) => response.json())
- .then((answer) => {
- let peerConnectionConfig: any = {
- sdpSemantics: 'unified-plan',
- }
- // It's important to set any ICE servers returned, which could include servers we requested or servers
- // setup by the server. But note that older versions of camera-streamer won't return this property.
- if (answer.iceServers) {
- peerConnectionConfig.iceServers = answer.iceServers
- }
- this.pc = new RTCPeerConnection(peerConnectionConfig)
- this.pc.addTransceiver('video', { direction: 'recvonly' })
- this.pc.addEventListener(
- 'track',
- (evt) => {
- if (evt.track.kind == 'video' && this.$refs.stream) {
- // @ts-ignore
- this.$refs.stream.srcObject = evt.streams[0]
- }
- },
- false
- )
- this.pc.addEventListener('connectionstatechange', () => {
- this.status = (this.pc?.connectionState ?? '').toString()
-
- // clear restartTimer if it is set
- if (this.restartTimer) window.clearTimeout(this.restartTimer)
-
- if (['failed', 'disconnected'].includes(this.status)) {
- // set restartTimer to restart stream after 5 seconds
- this.restartTimer = window.setTimeout(() => {
- this.restartStream()
- }, 5000)
- }
- })
- this.pc.addEventListener('icecandidate', (e) => {
- if (e.candidate) {
- return fetch(this.url, {
- body: JSON.stringify({
- type: 'remote_candidate',
- id: this.remote_pc_id,
- candidates: [e.candidate],
- }),
- headers: {
- 'Content-Type': 'application/json',
- },
- method: 'POST',
- }).catch(function (error) {
- window.console.error(error)
- })
- }
- })
-
- this.remote_pc_id = answer.id
- return this.pc?.setRemoteDescription(answer)
- })
- .then(() => this.pc?.createAnswer())
- .then((answer) => this.pc?.setLocalDescription(answer))
- .then(() => {
- const offer = this.pc?.localDescription
- return fetch(this.url, {
- body: JSON.stringify({
- type: offer?.type,
- id: this.remote_pc_id,
- sdp: offer?.sdp,
- }),
- headers: {
- 'Content-Type': 'application/json',
- },
- method: 'POST',
- })
+ get expanded(): boolean {
+ if (this.page !== 'dashboard') return true
+
+ return this.$store.getters['gui/getPanelExpand']('webcam-panel', this.viewport) ?? false
+ }
+
+ // start or stop the video when the expanded state changes
+ @Watch('expanded', { immediate: true })
+ expandChanged(newExpanded: boolean): void {
+ if (!newExpanded) {
+ this.terminate()
+ return
+ }
+
+ this.start()
+ }
+
+ // This WebRTC signaling pattern is designed for camera-streamer, a common webcam server the supports WebRTC.
+ async start() {
+ if (this.restartTimer) {
+ this.log('Clearing restart timer before starting stream')
+ window.clearTimeout(this.restartTimer)
+ }
+
+ if (!this.expanded) {
+ this.log('Not expanded, not starting stream')
+ return
+ }
+
+ this.log(`Requesting ICE servers from ${this.url}`)
+
+ try {
+ const requestIceServers = this.useStun ? [{ urls: ['stun:stun.l.google.com:19302'] }] : null
+ const response = await fetch(this.url, {
+ body: JSON.stringify({ type: 'request', iceServers: requestIceServers }),
+ method: 'POST',
})
- .then((response: any) => {
- if (isFirefox) this.status = 'connected'
- return response.json()
+ if (response.status !== 200) {
+ this.log(`Failed to start stream: ${response.status}`)
+ this.restartStream()
+ return
+ }
+
+ const answer = await response.json()
+ await this.onIceServers(answer)
+ } catch (e) {
+ this.log('Failed to start stream', e)
+ }
+ }
+
+ async onIceServers(iceResponse: CameraStreamerResponse) {
+ if (this.pc) this.pc.close()
+
+ // It's important to set any ICE servers returned, which could include servers we requested or servers
+ // setup by the server. But note that older versions of camera-streamer won't return this property.
+ let peerConnectionConfig: RTCConfiguration = {
+ iceServers: iceResponse.iceServers ?? [],
+ // https://webrtc.org/getting-started/unified-plan-transition-guide
+ // @ts-ignore
+ sdpSemantics: 'unified-plan',
+ }
+ this.pc = new RTCPeerConnection(peerConnectionConfig)
+
+ this.pc.addTransceiver('video', { direction: 'recvonly' })
+
+ this.pc.onicecandidate = (e: RTCPeerConnectionIceEvent) => this.onIceCandidate(e, iceResponse.id)
+ this.pc.onconnectionstatechange = () => this.onConnectionStateChange()
+ this.pc.ontrack = (e) => this.onTrack(e)
+
+ await this.pc?.setRemoteDescription(iceResponse)
+ const answer = await this.pc.createAnswer()
+ await this.pc.setLocalDescription(answer)
+
+ const offer = this.pc.localDescription
+ if (!offer) {
+ this.log('Failed to create offer')
+ this.restartStream()
+ return
+ }
+
+ try {
+ const response = await fetch(this.url, {
+ body: JSON.stringify({
+ type: offer?.type,
+ id: iceResponse.id,
+ sdp: offer?.sdp,
+ }),
+ headers: { 'Content-Type': 'application/json' },
+ method: 'POST',
})
- .catch((e) => {
- window.console.error(e)
+ if (response.status !== 200) {
+ this.log(`Failed to send offer: ${response.status}`)
+ this.restartStream()
+ }
+ } catch (e) {
+ this.log('Failed to send offer', e)
+ this.restartStream()
+ }
+ }
- // clear restartTimer if it is set
- if (this.restartTimer) window.clearTimeout(this.restartTimer)
+ async onIceCandidate(e: RTCPeerConnectionIceEvent, id: string) {
+ if (!e.candidate) return
- // set restartTimer to restart stream after 5 seconds
- this.restartTimer = window.setTimeout(() => {
- this.restartStream()
- }, 5000)
+ try {
+ const response = await fetch(this.url, {
+ body: JSON.stringify({
+ id,
+ type: 'remote_candidate',
+ candidates: [e.candidate],
+ }),
+ headers: { 'Content-Type': 'application/json' },
+ method: 'POST',
})
+ if (response.status !== 200) {
+ this.log(`Failed to send ICE candidate: ${response.status}`)
+ this.restartStream()
+ }
+ } catch (e) {
+ this.log('Failed to send ICE candidate', e)
+ this.restartStream()
+ }
}
- mounted() {
- this.startStream()
+ onConnectionStateChange() {
+ this.status = this.pc?.connectionState ?? 'connecting'
+
+ this.log(`State: ${this.status}`)
+
+ if (['failed', 'disconnected'].includes(this.status)) {
+ this.restartStream(5000)
+ }
+ }
+
+ onTrack(e: RTCTrackEvent) {
+ if (e.track.kind !== 'video') return
+
+ this.stream.srcObject = e.streams[0]
+ }
+
+ log(msg: string, obj?: any) {
+ const message = `[WebRTC camera-streamer] ${msg}`
+ if (obj) {
+ window.console.log(message, obj)
+ return
+ }
+
+ window.console.log(message)
}
beforeDestroy() {
- this.pc?.close()
+ this.terminate()
if (this.restartTimer) window.clearTimeout(this.restartTimer)
}
- restartStream() {
+ terminate() {
+ this.log('Terminating stream')
this.pc?.close()
- setTimeout(async () => {
- this.startStream()
- }, 500)
+ }
+
+ restartStream(delay = 500) {
+ this.terminate()
+
+ if (this.restartTimer) return
+
+ this.restartTimer = window.setTimeout(async () => {
+ this.restartTimer = null
+ await this.start()
+ }, delay)
}
@Watch('url')
- async changedUrl() {
+ changedUrl() {
this.restartStream()
}
}
diff --git a/src/components/webcams/streamers/WebrtcMediaMTX.vue b/src/components/webcams/streamers/WebrtcMediaMTX.vue
index f5eff6f20..8acc518c8 100644
--- a/src/components/webcams/streamers/WebrtcMediaMTX.vue
+++ b/src/components/webcams/streamers/WebrtcMediaMTX.vue
@@ -11,7 +11,7 @@
- {{ status }}
+ {{ capitalize(status) }}
@@ -22,6 +22,7 @@ import { Component, Mixins, Prop, Ref, Watch } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
import WebcamMixin from '@/components/mixins/webcam'
+import { capitalize } from '@/plugins/helpers'
interface OfferData {
iceUfrag: string
@@ -31,6 +32,8 @@ interface OfferData {
@Component
export default class WebrtcMediaMTX extends Mixins(BaseMixin, WebcamMixin) {
+ capitalize = capitalize
+
@Prop({ required: true }) readonly camSettings!: GuiWebcamStateWebcam
@Prop({ default: null }) readonly printerUrl!: string | null
@Prop({ type: String, default: null }) readonly page!: string | null
diff --git a/src/locales/de.json b/src/locales/de.json
index bc4ac382c..52f43740c 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -155,6 +155,7 @@
"CheckMoonrakerLog": "Wenn diese Meldung wiederholt erscheint, schaue bitte in die Logdatei unter:",
"Connecting": "Verbinde zu {host}",
"Failed": "Verbindung fehlgeschlagen",
+ "Help": "Hilfe",
"Initializing": "Initialisieren",
"TryAgain": "Erneut versuchen"
},
@@ -740,10 +741,8 @@
},
"Filament": "Filament",
"File": "Datei",
- "Files": "Dateien",
"Flow": "Fluss",
"Headline": "Status",
- "Jobqueue": "Warteschlange",
"JobqueueMoreFiles": "keine weiteren Aufträge | einen weiteren Auftrag | {count} weitere Aufträge",
"Layer": "Schicht",
"Max": "max",
@@ -768,7 +767,6 @@
"ResumePrint": "Druck fortführen",
"Slicer": "Slicer",
"Speed": "Geschwindigkeit",
- "Status": "Status",
"Total": "Gesamt",
"Unknown": "Unbekannt"
},
diff --git a/src/locales/en.json b/src/locales/en.json
index a729dfba9..c2d57aabf 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -156,6 +156,7 @@
"Connecting": "Connecting to {host}",
"ErrorMessage": "Error message: {message}",
"Failed": "Connection failed",
+ "Help": "Help",
"Initializing": "Initializing",
"TryAgain": "try again"
},
@@ -164,6 +165,7 @@
"Empty": "Empty",
"HideTemperatures": "Hide temperatures",
"HideTimelapse": "Hide Timelapse",
+ "Search": "Search",
"SendCode": "Send code...",
"SetupConsole": "Setup Console"
},
@@ -386,6 +388,7 @@
"EstimatedFilament": "Estimated Filament",
"EstimatedFilamentWeight": "Estimated Filament Weight",
"EstimatedTime": "Estimated Time",
+ "Filament": "Filament",
"FilamentBasedReminder": "Filament",
"FilamentBasedReminderDescription": "This reminder is based on the filament usage.",
"FilamentCalc": "Filament Calc",
@@ -433,6 +436,7 @@
"SelectedFilamentUsed": "Selected Filament Used",
"SelectedJobs": "Selected Jobs",
"SelectedPrinttime": "Selected Print Time",
+ "Settings": "Settings",
"Slicer": "Slicer",
"SlicerVersion": "Slicer Version",
"StartTime": "Start Time",
@@ -450,6 +454,7 @@
"server_exit": "Server exit"
},
"Table": "Table",
+ "Time": "Time",
"TitleExportHistory": "Export History",
"TotalDuration": "Total Time",
"TotalFilamentUsed": "Total Filament Used",
@@ -733,6 +738,7 @@
"ClearPrintStats": "Clear print stats",
"Difference": "Difference",
"EmptyGcodes": "No G-Code available.",
+ "EmptyHistory": "There is no job in the history.",
"EmptyJobqueue": "There is currently no file in the job queue.",
"Estimate": "Estimate",
"ETA": "ETA",
@@ -745,10 +751,8 @@
},
"Filament": "Filament",
"File": "File",
- "Files": "Files",
"Flow": "Flow",
"Headline": "Status",
- "Jobqueue": "Job Queue",
"JobqueueMoreFiles": "no more jobs | one more job | {count} more jobs",
"Layer": "Layer",
"Max": "max",
@@ -773,8 +777,8 @@
"ResumePrint": "Resume print",
"Slicer": "Slicer",
"Speed": "Speed",
- "Status": "Status",
"Total": "Total",
+ "TotalTime": "Total Time",
"Unknown": "Unknown"
},
"TemperaturePanel": {
@@ -1022,8 +1026,16 @@
},
"HeightmapTab": {
"ColorSchemes": "Color Schemes",
+ "DefaultOrientation": "Default Orientation",
+ "DefaultOrientationDescription": "Select the default orientation for the bed mesh visualization.",
"Heightmap": "Heightmap",
"IsDefault": "(Default)",
+ "Orientations": {
+ "Front": "Front",
+ "LeftFront": "Left Front",
+ "RightFront": "Right Front",
+ "Top": "Top"
+ },
"Schemes": {
"GrayScale": "Grayscale",
"Hot": "Hot",
@@ -1218,6 +1230,17 @@
"ConfirmOnEmergencyStopDescription": "Show a confirmation dialog on Emergency Stop",
"ConfirmOnPowerDeviceChange": "Require confirm on Device Power changes",
"ConfirmOnPowerDeviceChangeDescription": "Show a confirmation dialog on Device Power changes",
+ "DashboardFilesFilter": "Dashboard Files Filter",
+ "DashboardFilesFilterCompleted": "Completed",
+ "DashboardFilesFilterDescription": "Filter the files in the Dashbord Status Panel by their last status.",
+ "DashboardFilesFilterFailed": "Failed",
+ "DashboardFilesFilterNew": "New",
+ "DashboardFilesLimit": "Dashboard Files Limit",
+ "DashboardFilesLimitDescription": "Select the maximum number of files to display on the dashboard Status Panel. (0 hides the files tab)",
+ "DashboardFilesLimitLabel": "{count} files",
+ "DashboardHistoryLimit": "Dashboard History Limit",
+ "DashboardHistoryLimitDescription": "Select the maximum number of jobs to display on the dashboard in the Status Panel. (0 hides the history tab)",
+ "DashboardHistoryLimitLabel": "{count} jobs",
"DefaultNavigationState": "Navigation default state",
"DefaultNavigationStateAlwaysClosed": "always closed",
"DefaultNavigationStateAlwaysOpen": "always open",
diff --git a/src/locales/es.json b/src/locales/es.json
index a71309968..c4ea6c02d 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -144,11 +144,19 @@
"ScrewName": "Nombre de Tornillo",
"ScrewOutput": "{current} de {max}"
},
+ "CancelJobDialog": {
+ "AreYouSure": "¿Estás seguro?",
+ "CancelJob": "Cancelar trabajo",
+ "No": "No",
+ "Yes": "Sí"
+ },
"ConnectionDialog": {
"CannotConnectTo": "No se pudo conectar a ({host}) Moonraker.",
"CheckMoonrakerLog": "Si este mensaje aparece repetidamente, por favor dé un vistazo al archivo de registro ubicado en:",
"Connecting": "Conectando a {host}",
+ "ErrorMessage": "Mensaje de error: {message}",
"Failed": "Conexión Fallida",
+ "Help": "Ayuda",
"Initializing": "Inicializando",
"TryAgain": "Intentar nuevamente"
},
@@ -157,6 +165,7 @@
"Empty": "Vacío",
"HideTemperatures": "Ocultar temperaturas",
"HideTimelapse": "Ocultar timelapse",
+ "Search": "Buscar",
"SendCode": "Enviar código...",
"SetupConsole": "Configurar consola"
},
@@ -197,6 +206,7 @@
"Downloading": "Descargando",
"FailedSave": "¡{filename} no pudo cargarse!",
"FileReadOnly": "Sólo lectura",
+ "FileStructure": "Estructura del archivo",
"SaveClose": "Guardar y cerrar",
"SaveRestart": "Guardar y reiniciar",
"SuccessfullySaved": "{filename} guardado con éxito.",
@@ -431,6 +441,7 @@
"SelectedFilamentUsed": "Elija el filamento usado",
"SelectedJobs": "Tareas elegidas",
"SelectedPrinttime": "Tiempo de impresion elegido",
+ "Settings": "Ajustes",
"Slicer": "Laminador",
"SlicerVersion": "Versión del laminador",
"StartTime": "Hora de inicio",
@@ -674,6 +685,7 @@
"Headline": "Consola",
"HideTemperatures": "Ocultar temperaturas",
"HideTimelapse": "Ocultar timelapse",
+ "RawOutput": "Salida RAW (para depuración)",
"SendCode": "Enviar código...",
"SetupConsole": "Configurar consola"
},
@@ -824,6 +836,9 @@
},
"WebcamPanel": {
"All": "Todos",
+ "ConnectingTo": "Conectando a {url}",
+ "Disconnected": "Desconectado",
+ "ErrorWhileConnecting": "Error al conectar a {url}",
"FPS": "FPS",
"Headline": "Cámara web",
"NoWebcam": "No hay cámara web disponible. Agregue una cámara web en \"Configuración\" -> \"Cámaras web\".",
@@ -1024,8 +1039,16 @@
},
"HeightmapTab": {
"ColorSchemes": "Esquemas de colores",
+ "DefaultOrientation": "Orientación por defecto",
+ "DefaultOrientationDescription": "Seleccione la orientación por defecto para la visualización de la malla.",
"Heightmap": "Mapa de altura",
"IsDefault": "(Por defecto)",
+ "Orientations": {
+ "Front": "Delante",
+ "LeftFront": "Frontal izquierdo",
+ "RightFront": "Frontal derecho",
+ "Top": "Arriba"
+ },
"Schemes": {
"GrayScale": "Escala de grises",
"Hot": "Caliente",
@@ -1213,6 +1236,8 @@
"BoolBigThumbnailDescription": "Mostrar una miniatura grande en el panel de estado durante una impresión.",
"BoolHideUploadAndPrintButton": "Ocultar botón de Subir e Imprimir",
"BoolHideUploadAndPrintButtonDescription": "Mostrar u ocultar el botón de \"Upload and Print\" en la barra de arriba",
+ "ConfirmOnCancelJob": "Se requiere confirmación para cancelar el trabajo",
+ "ConfirmOnCancelJobDescription": "Mostrar un cuadro de diálogo de confirmación para cancelar el trabajo",
"ConfirmOnCoolDown": "Confirmar el enfriamiento",
"ConfirmOnCoolDownDescription": "Mostrar un diálogo de confirmación para el enfriamiento",
"ConfirmOnEmergencyStop": "Requerir confirmación en Parada de Emergencia",
diff --git a/src/locales/hu.json b/src/locales/hu.json
index 843120bba..6e1c8301f 100644
--- a/src/locales/hu.json
+++ b/src/locales/hu.json
@@ -29,7 +29,7 @@
},
"Never": "soha",
"NextReboot": "Következő újraindítás",
- "NoNotification": "Értesítés nem elérhető",
+ "NoNotification": "Nincsenek értesítések",
"Notifications": "Értesítések",
"OneDayShort": "1N",
"OneHourShort": "1Ó",
@@ -144,11 +144,19 @@
"ScrewName": "Csavar neve",
"ScrewOutput": "{current} / {max}"
},
+ "CancelJobDialog": {
+ "AreYouSure": "Biztos vagy benne?",
+ "CancelJob": "Munka törlése",
+ "No": "Nem",
+ "Yes": "Igen"
+ },
"ConnectionDialog": {
"CannotConnectTo": "Nem lehet csatlakozni a Moonrakerhez ({host}).",
"CheckMoonrakerLog": "Ha ez az üzenet többször is megjelenik, nézd meg a naplófájlt, itt:",
"Connecting": "Csatlakozás ehhez: {host}",
+ "ErrorMessage": "Hibaüzenet: {message}",
"Failed": "Kapcsolódás sikeretelen",
+ "Help": "Súgó",
"Initializing": "Inicializálás",
"TryAgain": "Próbáld újra"
},
@@ -197,6 +205,7 @@
"Downloading": "Letöltés",
"FailedSave": "Nem tölthető fel: {filename}!",
"FileReadOnly": "csak olvasható",
+ "FileStructure": "Fájl struktúra",
"SaveClose": "Ment és bezár",
"SaveRestart": "Ment és újraindít",
"SuccessfullySaved": "{filename} mentése sikeres.",
@@ -431,6 +440,7 @@
"SelectedFilamentUsed": "Kiválasztott használt nyomtatószál",
"SelectedJobs": "Kiválasztott Munkák",
"SelectedPrinttime": "Kiválasztott Nyomtatási Idő",
+ "Settings": "Beállítások",
"Slicer": "Szeletelő",
"SlicerVersion": "Slicer verzió",
"StartTime": "Kezdés",
@@ -676,6 +686,7 @@
"Headline": "Konzol",
"HideTemperatures": "Hőmérséklet elrejtése",
"HideTimelapse": "Idővonal elrejtése",
+ "RawOutput": "RAW-kimenet (hibakereséshez)",
"SendCode": "Kód küldése...",
"SetupConsole": "Konzol beállítása"
},
@@ -733,7 +744,7 @@
},
"StatusPanel": {
"CancelPrint": "Nyomtatás megszakítása",
- "ClearPrintStats": "Nyomt. statisztikák törlése",
+ "ClearPrintStats": "Nyomtatási statisztikák törlése",
"Difference": "Különbség",
"EmptyGcodes": "Nincs elérhető G-Code.",
"EmptyJobqueue": "Jelenleg nincs munka a várólistán.",
@@ -826,6 +837,9 @@
},
"WebcamPanel": {
"All": "Mind",
+ "ConnectingTo": "Csatlakozás a {url}",
+ "Disconnected": "Szétkapcsolt",
+ "ErrorWhileConnecting": "Hiba a kapcsolódás közben {url}",
"FPS": "FPS",
"Headline": "Webkamera",
"NoWebcam": "Nincs webkamera. Adj hozzá webkamerát a \"Felület beállításai\" -> \"Webkamerák\" menüpont alatt.",
@@ -1026,8 +1040,16 @@
},
"HeightmapTab": {
"ColorSchemes": "Színsémák",
+ "DefaultOrientation": "Alapértelmezett orientáció",
+ "DefaultOrientationDescription": "Válaszd ki az alapértelmezett orientációt az ágy háló vizualizálására.",
"Heightmap": "Magasságtérkép",
"IsDefault": "(Alapértelmezett)",
+ "Orientations": {
+ "Front": "Elülső",
+ "LeftFront": "Bal elülső",
+ "RightFront": "Jobb elülső",
+ "Top": "Felső"
+ },
"Schemes": {
"GrayScale": "Szürkeárnyalat",
"Hot": "Forró",
@@ -1215,6 +1237,8 @@
"BoolBigThumbnailDescription": "Nagy előnézet mutatása a státusz panelben a nyomtatás alatt.",
"BoolHideUploadAndPrintButton": "A feltöltés és nyomtatás gombok elrejtése",
"BoolHideUploadAndPrintButtonDescription": "Mutasd/Rejtsd el a \"Feltöltés és Nyomtatás\" gombot a felső menüben.",
+ "ConfirmOnCancelJob": "Megerősítést kér a Munka törlésekor",
+ "ConfirmOnCancelJobDescription": "Megerősítő párbeszédpanel megjelenítése a Munka törlésekor",
"ConfirmOnCoolDown": "A visszahűtés megerősítést kér",
"ConfirmOnCoolDownDescription": "Megerősítő párbeszédpanel megjelenítése visszahűtés esetén",
"ConfirmOnEmergencyStop": "A Vészleállításhoz megerősítés szükséges",
diff --git a/src/locales/it.json b/src/locales/it.json
index cf4572474..07bb41209 100644
--- a/src/locales/it.json
+++ b/src/locales/it.json
@@ -13,8 +13,11 @@
"DeprecatedOptionHeadline": "Opzione obsoleta di Klipper",
"DeprecatedValue": "Il valore '{value}' in '{option}' nella sezione '{section}' è obsoleto e sarà rimosso in una versione futura.",
"DeprecatedValueHeadline": "Valore obsoleto di Klipper",
+ "KlipperRuntimeWarning": "Avviso di runtime di Klipper",
"KlipperWarning": "Avviso di Klipper"
},
+ "MaintenanceReminder": "Promemoria per la manutenzione",
+ "MaintenanceReminderText": "La manutenzione di \"{name}\" è in scadenza.",
"MoonrakerWarnings": {
"MoonrakerComponent": "Moonraker: {component}",
"MoonrakerFailedComponentDescription": "È stato rilevato un errore durante il caricamento del componente '{component}' di Moonraker. Controllare il file di registro e risolvere il problema.",
@@ -28,7 +31,15 @@
"NextReboot": "prossimo riavvio",
"NoNotification": "Nessuna notifica disponibile",
"Notifications": "Notifiche",
- "Remind": "Ricorda:"
+ "OneDayShort": "1D",
+ "OneHourShort": "1H",
+ "OneWeekShort": "1W",
+ "Remind": "Ricorda:",
+ "ShowDetails": "mostra dettagli",
+ "TmcOtFlag": "Errore driver stepper: OT flag impostato",
+ "TmcOtFlagText": "Il driver dello stepper '{nome}' ha attivato il flag OT e ha smesso di funzionare. Ciò può essere causato da una corrente troppo elevata. Controllare le impostazioni del driver dello stepper e il raffreddamento.",
+ "TmcOtpwFlag": "Avviso driver stepper: flag OTPW impostato",
+ "TmcOtpwFlagText": "Il driver dello stepper '{name}' ha attivato il flag OTPW e potrebbe smettere di funzionare se si surriscalda ulteriormente. Ciò indica una condizione di sovratemperatura causata da una corrente troppo elevata. Controllare le impostazioni del driver dello stepper e il raffreddamento."
},
"NumberInput": {
"GreaterOrEqualError": "Deve essere maggiore o uguale a {min}!.",
@@ -36,6 +47,9 @@
"NoEmptyAllowedError": "Il valore non può essere nullo!"
},
"Printers": "Stampanti",
+ "TextfieldWithCopy": {
+ "Copied": "Copiato"
+ },
"TheServiceWorker": {
"DescriptionNeedUpdate": "La cache locale è obsoleta e deve essere aggiornata. Fare clic sul pulsante sottostante per aggiornare la cache.",
"TitleNeedUpdate": "PWA ha bisogno di aggiornamento",
@@ -130,11 +144,19 @@
"ScrewName": "Nome Screw",
"ScrewOutput": "{current} di {max}"
},
+ "CancelJobDialog": {
+ "AreYouSure": "Sei sicuro?",
+ "CancelJob": "Cancella Lavoro",
+ "No": "No",
+ "Yes": "Si"
+ },
"ConnectionDialog": {
"CannotConnectTo": "Impossibile connettersi a Moonraker ({host}).",
"CheckMoonrakerLog": "Se questo messaggio viene visualizzato ripetutamente, per favore dai un'occhiata al file di registro situato in:",
"Connecting": "Connessione a {host}",
+ "ErrorMessage": "Messaggio di errore: {message}",
"Failed": "Connessione fallita",
+ "Help": "Aiuto",
"Initializing": "Inizializzazione",
"TryAgain": "Riprova"
},
@@ -143,9 +165,29 @@
"Empty": "Vuoto",
"HideTemperatures": "Nascondi temperature",
"HideTimelapse": "Nascondi Timelapse",
- "SendCode": "Invia codice...",
+ "Search": "Cerca",
"SetupConsole": "Impostazione Console"
},
+ "CoolDownDialog": {
+ "AreYouSure": "Sei sicuro?",
+ "CoolDown": "Raffreddamento",
+ "No": "No",
+ "Yes": "Si"
+ },
+ "DevicesDialog": {
+ "CanBusInfo": "È possibile rilevare solo i nodi non assegnati. Si raccomanda di avere un solo dispositivo non assegnato collegato al CANBUS per evitare problemi di comunicazione. Per maggiori dettagli, fare clic sul link:",
+ "ClickRefresh": "Clicca sul pulsante AGGIORNA per cercare i dispositivi.",
+ "DevicePath": "Percorso del dispositivo",
+ "Formats": "Formati",
+ "Headline": "Dispositivi",
+ "HideSystemEntries": "Nascondere le voci di sistema",
+ "LibcameraId": "Libcamera ID",
+ "NoDeviceFound": "Nessun dispositivo trovato. Controllare la connessione e fare clic sul pulsante AGGIORNA.",
+ "PathByHardware": "Percorso per hardware",
+ "PathById": "Percorso per ID",
+ "Refresh": "aggiorna",
+ "Resolutions": "Risoluzioni"
+ },
"Dialogs": {
"StartPrint": {
"Cancel": "Cancella",
@@ -158,10 +200,12 @@
},
"Editor": {
"ConfigReference": "Configurazione di Riferimento",
+ "DeviceDialog": "Dispositivo",
"DontSave": "Non salvare",
"Downloading": "Scaricando",
"FailedSave": " Impossibile caricare {filename}!",
"FileReadOnly": "read-only",
+ "FileStructure": "Struttura del File",
"SaveClose": "Salva e Chiudi",
"SaveRestart": "Salva e Riavvia",
"SuccessfullySaved": "{filename} salvato con successo.",
@@ -198,7 +242,6 @@
"EditFile": "Modifica file",
"Empty": "Vuoto",
"ExtruderTemp": "Temp. Estrusore",
- "Filament": "Filamento",
"FilamentName": "Nome Filamento",
"FilamentType": "Tipo Filamento",
"FilamentUsage": "Utilizzo del filamento",
@@ -300,19 +343,15 @@
"InvalidNameAscii": "Il nome non è valido. Sono ammessi solo caratteri ascii.",
"InvalidNameEmpty": "Il valore non può essere nullo!",
"InvalidNameReserved": "Il profilo 'default' è riservato, scegli un altro nome.",
- "Later": "in seguito",
"Mesh": "Mesh",
"Name": "Nome",
"NoBedMeshHasBeenLoadedYet": "Nessuna bed-mesh è stata caricata.",
"NoProfile": "Nessun profilo disponibile",
- "Ok": "OK",
"Probed": "Analizzato",
"Profiles": "Profili",
"Remove": "eliminare",
- "RemoveSaveDescription": "Il profilo bed_mesh è stato registrato come cancellato. Fare clic su SAVE_CONFIG per rimuoverlo dalla stampante.cfg e riavviare Klipper.",
"Rename": "rinominare",
"RenameBedMeshProfile": "Rinomina Profilo Bed Mesh",
- "SAVE_CONFIG": "SAVE_CONFIG",
"ScaleGradient": "Scala gradiente",
"ScaleZMax": "Scala z-max.",
"TitleCalibrate": "Calibra nuova Bed Mesh",
@@ -321,23 +360,37 @@
"Wireframe": "Wireframe"
},
"History": {
+ "AddANote": "Aggiungi una nota",
+ "AddMaintenance": "Aggiungi Manutenzione",
"AddNote": "Aggiungi nota",
+ "AddToQueueSuccessful": "File {filename} aggiunto alla coda",
"AllJobs": "Tutto",
"AvgPrinttime": "Tempo di stampa medio",
"Cancel": "Cancella",
"Chart": "Grafico",
"CreateNote": "Crea Nota",
+ "DateBasedReminder": "Data",
+ "DateBasedReminderDescription": "Questo promemoria si basa sulla data.",
+ "Days": "giorni",
"Delete": "Elimina",
"DeleteSelectedQuestion": "Vuoi davvero eliminare i {count} lavori selezionati?",
"DeleteSingleJobQuestion": "Vuoi davvero eliminare il lavoro?",
"Details": "Dettagli",
+ "EditMaintenance": "Modifica Manutenzione",
"EditNote": "Modifica Nota",
"Empty": "vuota",
"EndTime": "Ora di fine",
+ "EntryCreatedAt": "Creato il {date}.",
+ "EntryNextPerform": "Prossima esecuzione:",
+ "EntryPerformedAt": "Eseguito il {date}.",
+ "EntrySince": "Utilizzato dal:",
"EstimatedFilament": "Filamento stimato",
"EstimatedFilamentWeight": "Peso del Filamento stimato",
"EstimatedTime": "Tempo stimato",
- "FilamentCalc": "Calcolo del Filamento",
+ "Filament": "Filamento",
+ "FilamentBasedReminder": "Filamento",
+ "FilamentBasedReminderDescription": "Questo promemoria si basa sull'utilizzo del filamento.",
+ "FilamentCalc": "Calcolo Filamento",
"FilamentUsage": "Utilizzo del Filamento",
"FilamentUsed": "Filamento Utilizzato",
"Filename": "Nome File",
@@ -347,24 +400,42 @@
"FirstLayerHeight": "Altezza primo Layer",
"HistoryFilamentUsage": "Filamento",
"HistoryPrinttimeAVG": "Stampe",
+ "Hours": "ore",
+ "InvalidNameEmpty": "Nome non valido. Il nome può essere vuoto!",
"JobDetails": "Dettagli del Processo di stampa",
"Jobs": "Processi di stampa",
"LastModified": "Ultima Modifica",
"LayerHeight": "Altezza del Layer",
"LoadCompleteHistory": "Carica la cronologia completa",
"LongestPrinttime": "Tempo di stampa più lungo",
+ "Maintenance": "Maintenance",
+ "MaintenanceEntries": "Voci di manutenzione",
+ "Meter": "contatore",
+ "Name": "Nome",
+ "NoReminder": "Nessun promemoria",
"Note": "Nota",
"ObjectHeight": "Altezza Oggetto",
+ "OneTime": "una sola volta",
+ "Perform": "eseguire",
+ "Performed": "eseguito",
+ "PerformedAndReschedule": "eseguito e riprogrammato",
+ "PerformMaintenance": "Eseguire la manutenzionee",
"PrintDuration": "Tempo Stampa",
"PrintHistory": "Cronologia Stampa",
+ "PrintJobs": "Lavori di stampa",
"PrintTime": "Tempo Stampa",
"PrinttimeAvg": "Tempo di stampa medio",
+ "PrinttimeBasedReminder": "Tempo di Stampa",
+ "PrinttimeBasedReminderDescription": "Questo promemoria si basa sul tempo di stampa.",
+ "Reminder": "Promemoria",
+ "Repeat": "Ripeti",
"Reprint": "Ristampa",
"Save": "salva",
"Search": "cerca",
"SelectedFilamentUsed": "Utilizzo del Filamento selezionato",
"SelectedJobs": "Lavori selezionati",
"SelectedPrinttime": "Tempo di stampa selezionato",
+ "Settings": "Impostazioni",
"Slicer": "Slicer",
"SlicerVersion": "Versione Slicer",
"StartTime": "Ora Inizio",
@@ -382,15 +453,15 @@
"server_exit": "Uscita dal server"
},
"Table": "Tabella",
+ "Time": "Durata",
"TitleExportHistory": "Esporta Cronologia",
- "TotalDuration": "Tempo Totale",
+ "TotalDuration": "Durata Totale",
"TotalFilamentUsed": "Filamento Totale Utilizzato",
"TotalJobs": "Processi Totali",
- "TotalPrinttime": "Tempo di Stampa Totale",
- "TotalTime": "Tempo Totale"
+ "TotalPrinttime": "Durata di Stampa Totale",
+ "TotalTime": "Durata Totale"
},
"JobQueue": {
- "AllJobs": "Tutti i Lavori",
"Cancel": "Cancella",
"ChangeCount": "Cambia conteggio",
"Count": "Conteggio",
@@ -398,10 +469,10 @@
"InvalidCountEmpty": "Il valore non può essere nullo!",
"InvalidCountGreaterZero": "Il valore deve essere maggiore di 0!",
"JobQueue": "Coda dei Lavori",
- "Jobs": "Lavori",
"Pause": "Pausa",
"RemoveFromQueue": "Rimuovi dalla coda",
- "Start": "Inizia"
+ "Start": "Inizia",
+ "StartPrint": "Comincia Lavoro"
},
"Machine": {
"ConfigFilesPanel": {
@@ -576,7 +647,9 @@
"KlippyStatePanel": {
"CheckKlippyAndUdsAddress": "Controllare se il servizio Klipper è in esecuzione e se klippy_uds_address è configurato correttamente nel Moonraker.conf.",
"FirmwareRestart": "Riavvio Firmware",
+ "KlipperLog": "Klipper Log",
"MoonrakerCannotConnect": "Moonraker non riesce a connettersi a Klipper!",
+ "MoonrakerLog": "Moonraker Log",
"PowerOn": "Accensione",
"PrinterSwitchedOff": "La stampante è spenta",
"PrinterSwitchedOffDescription": "La stampante è attualmente spenta e Klipper non può connettersi. Per accendere la stampante, fare clic sul pulsante qui sotto:",
@@ -602,6 +675,7 @@
"Headline": "Console",
"HideTemperatures": "Nascondi Temperature",
"HideTimelapse": "Nascondi Timelapse",
+ "RawOutput": "RAW-Output (for debugging)",
"SendCode": "Invia codice...",
"SetupConsole": "Impostazioni Console"
},
@@ -751,6 +825,9 @@
},
"WebcamPanel": {
"All": "Tutto",
+ "ConnectingTo": "Connessione a {url}",
+ "Disconnected": "Disconnesso",
+ "ErrorWhileConnecting": "Errore durante la connessione a {url}",
"FPS": "FPS",
"Headline": "Webcam",
"NoWebcam": "Nessuna webcam disponibile. Aggiungi una webcam da \"Impostazioni dell'Interfaccia\" -> \"Webcams\".",
@@ -806,6 +883,8 @@
"HostnameInvalid": "Hostname/IP non valido",
"HostnameIp": "Hostname/IP",
"HostnameRequired": "Hostname richiesto",
+ "Name": "Nome",
+ "Path": "Percorso",
"Port": "Porta",
"PortRequired": "Porta richiesta",
"RememberToAdd": "Ricordati di aggiungere {cors} in moonraker.conf all'interno di 'cors_domains'.",
@@ -882,7 +961,7 @@
"ConfirmUnsavedChanges": "Chiedi di salvare o scartare modifiche non salvate",
"ConfirmUnsavedChangesDescription": "Se abilitato, l'editor necessita di una conferma per salvare o scartare le modifiche apportate. Se disabilitato, le modifiche saranno scartate silenziosamente.",
"Editor": "Editor",
- "KlipperRestartMethod": "Klipper restart method",
+ "KlipperRestartMethod": "Metodo di riavvio Klipper",
"KlipperRestartMethodDescription": "Selezionare il metodo di riavvio da utilizzare in 'Salva e riavvia' quando si modificano i file di configurazione di Klipper.",
"Spaces": "Spazio: {count}",
"TabSize": "Spaziatura del TAB",
@@ -922,6 +1001,7 @@
"DbConsoleHistory": "Cronologia Console",
"DbHistoryJobs": "Cronologia Lavori",
"DbHistoryTotals": "Cronologia Totali",
+ "DbMaintenance": "Manutenzione",
"DbNavigation": "Navigazione",
"DbTimelapseSettings": "Impostazioni Timelapse",
"DbView": "Vedi Impostazioni ",
@@ -937,15 +1017,23 @@
"Language": "Lingua",
"MainsailSettingsMoonrakerDb": "Impostazioni di Mainsail nel Moonraker DB",
"PrinterName": "Nome della stampante",
- "Reset": "reimposta",
+ "Reset": "Reimposta",
"Restore": "Ripristina",
"RestoreDialog": "Seleziona tutte le sezioni che vuoi ripristinare:",
"TimeFormat": "Formato Data"
},
"HeightmapTab": {
- "ColorSchemes": "Schemi Colore",
- "Heightmap": "Mappa dell'Altezza",
+ "ColorSchemes": "Schema Colore",
+ "DefaultOrientation": "Orientamento predefinito",
+ "DefaultOrientationDescription": "Selezionare l'orientamento predefinito per la visualizzazione della maglia del letto.",
+ "Heightmap": "Mappa Altimetrica",
"IsDefault": "(Default)",
+ "Orientations": {
+ "Front": "Frontale",
+ "LeftFront": "Frontale SX",
+ "RightFront": "Frontale DX",
+ "Top": "Alto"
+ },
"Schemes": {
"GrayScale": "Scala di Grigi",
"Hot": "Hot",
@@ -1039,6 +1127,9 @@
"AddPrinter": "Aggiungi Stampante",
"EditPrinter": "Modifica Stampante",
"Hostname": "Hostname",
+ "Name": "Nome",
+ "NameDescription": "Questo nome non sarà visualizzato nella GUI e sarà utilizzato solo per i reindirizzamenti..",
+ "Path": "Percorso",
"Port": "Porta",
"RemotePrinters": "Stampanti Remote",
"UpdatePrinter": "Aggiorna Stampante",
@@ -1049,7 +1140,9 @@
"Autorender": "Autorender",
"AutorenderDescription": "Se abilitato, il timelapse sarà automaticamente processato alla fine della stampa.",
"Camera": "Camera",
- "CameraDescription": "Seleziona la webcam da utilizzare",
+ "CameraDescriptionWithSnapshotUrl": "Selezionare la telecamera da utilizzare (con l'URL dell'istantanea)",
+ "CameraWarningAlreadySet": "Questo valore è già impostato nel file di configurazione di Moonraker.",
+ "CameraWarningAlreadySetSmall": "l'url dell'istantanea nella sezione [timelapse].",
"ConstantRateFactor": "Fattore di velocità costante",
"ConstantRateFactorDescription": "Questo configura la qualità vs grandezza del video. Il raggio della scala del CRF è 0-51, dove 0 è lossless, 23 è il default e 51 è la qualità peggiore possibile. Un valore più basso porta generalmente ad una qualità maggiore e un raggio consigliato è di 17-28. Considera 17 o 18 come visualmente lossless.",
"duplicatelastframe": "Duplica Ultimo Frame",
@@ -1067,6 +1160,7 @@
"HyperlapseCycleDescription": "Una schermata sarà catturata ogni tot secondi",
"Mode": "Modalità",
"ModeDescription": "Seleziona tra Layermacro e Hyperlapse",
+ "NoWebcamFound": "Nessuna Webcam disponibile",
"OutputFramerate": "Output Framerate",
"OutputFramerateDescription": "Definisce il Framerate del video. Nota: questo sarà ignorato se variable_fps è ablititato",
"Parkhead": "Park Toolhead",
@@ -1097,6 +1191,7 @@
"RulesZeroAndPositive": "Il valore deve essere uguale o maggiore di 0!",
"SaveFrames": "Salva Frames",
"SaveFramesDescription": "Salva i Frame in un file zip per rendering esterno",
+ "SelectWebcam": "Seleziona webcam...",
"StreamDelayCompensation": "Compensazione Ritardo Stream",
"StreamDelayCompensationDescription": "Ritarda cattura frame",
"Targetlength": "Lunghezza target",
@@ -1125,10 +1220,14 @@
"BoolBigThumbnailDescription": "Mostra una grande anteprima nel pannello di stato durante una stampa.",
"BoolHideUploadAndPrintButton": "Nascondi Bottone Carica e Stampa",
"BoolHideUploadAndPrintButtonDescription": "Mostra o nascondi il bottone \"Carica e Stampa\" nella barra in alto.",
+ "ConfirmOnCancelJob": "Richiedere conferma per Annullamento Lavoro",
+ "ConfirmOnCancelJobDescription": "Mostra finestra di dialogo per Annullamento Lavoro",
+ "ConfirmOnCoolDown": "Richiedie conferma per il Raffreddamento",
+ "ConfirmOnCoolDownDescription": "Mostra finestra di dialogo per il Raffreddamento",
"ConfirmOnEmergencyStop": "Richiedi conferma all'arresto di emergenza",
- "ConfirmOnEmergencyStopDescription": "Mostra dialogo di conferma all'arresto di emergenza",
- "ConfirmOnPowerDeviceChange": "Richiedi conferma alle modifiche di alimentazione dispositivo",
- "ConfirmOnPowerDeviceChangeDescription": "Mostra un dialogo di conferma per alle modifiche di alimentazione dispositivo",
+ "ConfirmOnEmergencyStopDescription": "Mostra finestra di dialogo per l'Arresto di Emergenza",
+ "ConfirmOnPowerDeviceChange": "Richiedi conferma alle modifiche di Alimentazione Dispositivo",
+ "ConfirmOnPowerDeviceChangeDescription": "Mostra finestra di dialogo per le modifiche di Alimentazione Dispositivo",
"DefaultNavigationState": "Stato predefinito della navigazione",
"DefaultNavigationStateAlwaysClosed": "sempre chiuso",
"DefaultNavigationStateAlwaysOpen": "sempre aperto",
@@ -1152,6 +1251,8 @@
"Logo": "Logo",
"ManualProbeDialog": "Finestra di dialogo per il Manual Probe",
"ManualProbeDialogDescription": "Mostra dialoghi di aiuto il PROBE_CALIBRATE o lo Z_ENDSTOP_CALIBRATE.",
+ "Mode": "Modalità",
+ "ModeDescription": "Modificare l'aspetto generale dell'applicazione.",
"NavigationStyle": "Stile navigazione",
"NavigationStyleDescription": "Cambia l'aspetto di navigazione",
"NavigationStyleIconsAndText": "Icone + Testo",
@@ -1159,6 +1260,10 @@
"PowerDeviceName": "Dispositivo Alimentazione Stampante",
"PowerDeviceNameDescription": "Selezionare quale dispositivo di alimentazione Moonraker deve essere utilizzato per accendere la stampante.",
"Primary": "Primario",
+ "PrintstatusThumbnailZoom": "Mostra miniature di grandi dimensioni",
+ "PrintstatusThumbnailZoomDescription": "Ciò disattiverà l'effetto zoom della miniatura nel pannello di stato.",
+ "ProgressAsFavicon": "Mostra i progressi come favicon",
+ "ProgressAsFaviconDescription": "Cambia la favicon del logo Mainsail in un cerchio di progresso.",
"ScrewsTiltAdjustDialog": "Finestra di dialogo per lo Screws Tilt Adjust",
"ScrewsTiltAdjustDialogDescription": "Mostra dialoghi di aiuto per lo SCREWS_TILT_CALCULATE.",
"TempchartHeight": "Altezza grafico della temperatura",
diff --git a/src/locales/nl.json b/src/locales/nl.json
index e7ae50452..4870708e7 100644
--- a/src/locales/nl.json
+++ b/src/locales/nl.json
@@ -1,6 +1,10 @@
{
"App": {
"Notifications": {
+ "BrowserWarnings": {
+ "Description": "{name} is verouderd en niet volledig ondersteund. De huidige versie is {version}, maar Mainsail vereist versie {minVersion} of hoger.",
+ "Headline": "Verouderde Browser"
+ },
"DependencyDescription": "De huidige {name} versie ondersteunt niet alle functies van Mainsail. Update {name} naar ten minste {neededVersion}.",
"DependencyName": "Afhankelijkheid: {name}",
"DismissAll": "Dismiss all",
@@ -9,11 +13,16 @@
"DeprecatedOptionHeadline": "Verouderde Klipper optie",
"DeprecatedValue": "Waarde '{value}' in optie '{option}' in sectie '{section}' is verouderd en wordt in een toekomstige versie verwijderd.",
"DeprecatedValueHeadline": "Verouderde Klipper waarde",
+ "KlipperRuntimeWarning": "Klipper runtime waarschuwing",
"KlipperWarning": "Klipper waarschuwing"
},
+ "MaintenanceReminder": "Onderhoud herinnering",
+ "MaintenanceReminderText": "Onderhoud \"{name}\" is nodig.",
"MoonrakerWarnings": {
"MoonrakerComponent": "Moonraker: {component}",
"MoonrakerFailedComponentDescription": "Bij het laden van de moonraker component '{component}' is een fout opgetreden. Controleer de logs en verhelp het probleem.",
+ "MoonrakerFailedInitComponentDescription": "Een fout werd ontdekt tijdens het initialiseren van het moonraker component '{component}'. Controleer de log file en verhelp het probleem.",
+ "MoonrakerInitComponent": "Init. Moonraker: {component}",
"MoonrakerWarning": "Moonraker waarschuwing",
"UnparsedConfigOption": "Onbekende config optie '{option}: {value}' gedetecteerd in sectie [{section}]. Dit kan een optie zijn die niet langer beschikbaar is of een module die niet juist geladen is. In de toekomst zal dit een foutmeldig geven bij het opstarten.",
"UnparsedConfigSection": "Onbekende config sectie [{section}] gedetecteerd. Dit kan module zijn die niet juist geladen is. In de toekomst zal dit een foutmeldig geven bij het opstarten."
@@ -25,7 +34,12 @@
"OneDayShort": "1D",
"OneHourShort": "1U",
"OneWeekShort": "1W",
- "Remind": "Herinnering:"
+ "Remind": "Herinnering:",
+ "ShowDetails": "toon details",
+ "TmcOtFlag": "Stepper driver fout: OT flag gezet",
+ "TmcOtFlagText": "De stepper driver '{name}' heeft de OT flag getriggerd en is gestopt met werken. Dit kan veroorzaakt zijn door te hoge stroom. Controleer de stepper drivers en koeling.",
+ "TmcOtpwFlag": "Stepper driver waarschuwing: OTPW flag gezet",
+ "TmcOtpwFlagText": "De stepper driver '{name}' heeft de OTPW flag getriggerd en kan stoppen met werken als hij nog heter wordt. Dit is een indicatie van een overhitting. Dit kan veroorzaakt worden door een te hoge stroom. Controleer de driver settings en koeling."
},
"NumberInput": {
"GreaterOrEqualError": "Moet groter of gelijk zijn dan {min}!",
@@ -37,6 +51,8 @@
"Copied": "Gekopieerd"
},
"TheServiceWorker": {
+ "DescriptionNeedUpdate": "De lokale cache is verouderd en moet geupdate worden. Klik de knop hieronder om de cache te updaten.",
+ "TitleNeedUpdate": "PWA moet geupdate worden",
"Update": "Werk bij"
},
"ThrottledStates": {
@@ -61,6 +77,7 @@
"Complete": "Kompleet - {filename}",
"Error": "FOUT",
"Pause": "Pauzeer print",
+ "PrinterOff": "Printer UIT",
"Printing": "{percent}% Printen - {filename}",
"PrintingETA": "{percent}% Printen - ETA: {eta} - {filename}"
},
@@ -76,14 +93,14 @@
"Cancel": "Annuleer",
"ConfirmationDialog": {
"Description": {
- "HostReboot": "Wanneer je nu de host reboot, zal de huidige print mislukken.",
- "HostShutdown": "Wanneer je nu de host afsluit, zal de huidige print mislukken.",
- "KlipperFirmwareRestart": "Wanneer je nu de Klipper firmware herstart, zal de huidige print mislukken.",
- "KlipperRestart": "Wanneer je nu Klipper herstart, zal de huidige print mislukken.",
- "KlipperStop": "Wanneer je nu Klipper stopt, zal de huidige print mislukken.",
- "ServiceRestart": "Wanneer je nu deze service herstart, is de kans groot dat de huidige print zal mislukken.",
- "ServiceStart": "Wanneer je nu deze service start, is de kans groot dat de huidige print zal mislukken.",
- "ServiceStop": "Wanneer je nu deze service stopt, is de kans groot dat de huidige print zal mislukken."
+ "HostReboot": "Wanneer je nu de host reboot, zal de huidige print mislukken!",
+ "HostShutdown": "Wanneer je nu de host afsluit, zal de huidige print mislukken!",
+ "KlipperFirmwareRestart": "Wanneer je nu de Klipper firmware herstart, zal de huidige print mislukken!",
+ "KlipperRestart": "Wanneer je nu Klipper herstart, zal de huidige print mislukken!",
+ "KlipperStop": "Wanneer je nu Klipper stopt, zal de huidige print mislukken!",
+ "ServiceRestart": "Wanneer je nu deze service herstart, is de kans groot dat de huidige print zal mislukken!",
+ "ServiceStart": "Wanneer je nu deze service start, is de kans groot dat de huidige print zal mislukken!",
+ "ServiceStop": "Wanneer je nu deze service stopt, is de kans groot dat de huidige print zal mislukken!"
},
"Title": {
"HostReboot": "Host reboot",
@@ -110,7 +127,7 @@
"UpdateDialog": {
"Close": "Sluiten",
"Empty": "Leeg",
- "Recovering": "Herstellen van {software}",
+ "Recovering": "Herstellen van {software}...",
"RecoveringDone": "Herstellen van {software} voltooid!",
"Updating": "Updating {software}..",
"UpdatingDone": "Updaten van {software} voltooid!"
@@ -127,10 +144,17 @@
"ScrewName": "Schroef Naam",
"ScrewOutput": "{current} van {max}"
},
+ "CancelJobDialog": {
+ "AreYouSure": "Weet je het zeker?",
+ "CancelJob": "Annuleer Job",
+ "No": "Nee",
+ "Yes": "Ja"
+ },
"ConnectionDialog": {
"CannotConnectTo": "Kan niet verbinden met Moonraker ({host}).",
"CheckMoonrakerLog": "Als deze melding vaker getoond wordt, kijk in de logs op:",
"Connecting": "Verbinden met {host}",
+ "ErrorMessage": "Foutmelding: {message}",
"Failed": "Verbinding mislukt",
"Initializing": "Initialiseren",
"TryAgain": "probeer nogmaals"
@@ -144,12 +168,13 @@
"SetupConsole": "Instellingen"
},
"CoolDownDialog": {
+ "AreYouSure": "Weet je het zeker?",
"CoolDown": "Koel af",
"No": "Nee",
"Yes": "Ja"
},
"DevicesDialog": {
- "Formats": "Formats",
+ "Formats": "Formaten",
"Headline": "Apparaten",
"Refresh": "Herlaad",
"Resolutions": "Resoluties"
@@ -252,7 +277,7 @@
},
"FullscreenUpload": {
"CannotUploadFile": "Kan bestand niet uploaden!",
- "DropFilesToUploadFiles": "Sleep bestand hier om te uploaden."
+ "DropFilesToUploadFiles": "Sleep bestand hier om te uploaden"
},
"GCodeViewer": {
"ClearLoadedFile": "Leeg",
@@ -306,7 +331,7 @@
"Later": "Later",
"Mesh": "Mesh",
"Name": "Naam",
- "NoBedMeshHasBeenLoadedYet": "Er is nog geen bed_mesh ingeladen",
+ "NoBedMeshHasBeenLoadedYet": "Er is nog geen bed_mesh ingeladen.",
"NoProfile": "Geen profiel beschikbaar",
"Ok": "Ok",
"Probed": "Geprobed",
@@ -317,7 +342,7 @@
"RenameBedMeshProfile": "Hernoem Bed Mesh Profiel",
"SAVE_CONFIG": "SAVE_CONFIG",
"ScaleGradient": "Kleurverloop schalen",
- "ScaleZMax": "Schaal z-max",
+ "ScaleZMax": "Schaal z-max.",
"TitleCalibrate": "Kalibreer nieuwe bed mesh",
"TitleClear": "Verijwder bed mesh",
"TitleHomeAll": "Home alles",
@@ -364,8 +389,8 @@
"Note": "Notitie",
"ObjectHeight": "Object Hoogte",
"OneTime": "Een keer",
- "Perform": "Voeruit",
- "Performed": "Voerde uit",
+ "Perform": "Voer uit",
+ "Performed": "Uitgevoerd",
"PrintDuration": "Print duur",
"PrintHistory": "Print Geschiedenis",
"PrintTime": "Printtijd",
@@ -634,7 +659,7 @@
"Flow": "Flow",
"Headline": "Status",
"Jobqueue": "Wachtrij",
- "JobqueueMoreFiles": "geen jobs meer | nog een job | {count} jobs",
+ "JobqueueMoreFiles": "geen jobs meer | nog een job | {count} jobs",
"Layer": "Laag",
"Max": "max",
"ObjectHeight": "Objecthoogte",
@@ -748,7 +773,7 @@
},
"SelectPrinterDialog": {
"AddPrinter": "Voeg printer toe",
- "AddPrintersToJson": "Voeg de printers toe aan de config.json",
+ "AddPrintersToJson": "Voeg de printers toe aan de config.json.",
"CannotConnectTo": "Kan niet verbinden met {host}.",
"ChangePrinter": "Wijzig printer",
"Connecting": "Verbinden met {host}",
@@ -760,7 +785,7 @@
"HostnameRequired": "Hostname is verplicht",
"Port": "Poort",
"PortRequired": "Poort is verplicht",
- "RememberToAdd": "Vergeet niet om {cors} in moonraker.conf toe te voegen binnen 'cors_domains'",
+ "RememberToAdd": "Vergeet niet om {cors} in moonraker.conf toe te voegen binnen 'cors_domains'.",
"SelectPrinter": "Selecteer printer",
"TryAgain": "probeer nogmaals",
"UpdatePrinter": "Update Printer",
@@ -800,7 +825,7 @@
"InvertXMovement": "Inverteer X beweging",
"InvertYMovement": "Inverteer Y beweging",
"InvertZMovement": "Inverteer Z beweging",
- "IsDefault": "(standaard)",
+ "IsDefault": " (standaard)",
"MaximumValues": "Maximale waarden: {maximum}",
"MaximumValuesVisibility": "Maximum van {maximum} waarden is geadviseerd voor beste overzicht",
"MinimumValues": "Minimale waarden: {minimum}",
@@ -863,7 +888,7 @@
"FileRelative": "Bestandslocatie (relatief)",
"Slicer": "Slicer (M73)"
},
- "CannotReadJson": "Kan het backup bestand niet lezen/verwerken. ",
+ "CannotReadJson": "Kan het backup bestand niet lezen/verwerken.",
"DateFormat": "Datumformaat",
"DbConsoleHistory": "Console Geschiedenis",
"DbHistoryJobs": "Geschiedenis Jobs",
@@ -904,7 +929,7 @@
"Add": "voeg toe",
"AddGroup": "voeg groep toe",
"AvailableMacros": "Beschikbare Macros",
- "ChangeMacroColor": "Verander de kleur van de knop",
+ "ChangeMacroColor": "Verander de kleur van de knop.",
"Color": "Kleur",
"CountMacros": "geen Macros toegevoegd | {count} Macro | {count} Macros",
"Custom": "custom",
@@ -974,7 +999,7 @@
"PresetInfo": "Je moet een minimum doeltemperatuur of custom G-Code instellen.",
"PresetNamePlaceholder": "Voorbeeld naam (verplicht)",
"StoreButton": "Sla preset op",
- "UpdateButton": "Update preset.",
+ "UpdateButton": "Update preset",
"UpdateCooldown": "Update afkoelen"
},
"RemotePrintersTab": {
@@ -1010,7 +1035,7 @@
"Mode": "Modus",
"ModeDescription": "Kies tussen Layermacro en Hyperlapse (tijd gebaseerde) modus",
"OutputFramerate": "Uitvoer Framerate",
- "OutputFramerateDescription": "Definieert de framerate van de video. Note: dit wordt genegeerd wanneer variable_fps is ingeschakeld",
+ "OutputFramerateDescription": "Definieert de framerate van de video. Note: dit wordt genegeerd wanneer variable_fps is ingeschakeld",
"Parkhead": "Parkhead",
"ParkheadDescription": "Indien ingeschakeld, wordt de printkop geparkeerd voor een foto te nemen.",
"Parkpos": "Parkeer postitie",
@@ -1035,11 +1060,11 @@
"SaveFrames": "Sla frames op",
"SaveFramesDescription": "Sla de frames op in een zip-bestand voor externe rendering",
"StreamDelayCompensation": "Stream Delay Compensatie",
- "StreamDelayCompensationDescription": "Vertraag de beeldopname.",
+ "StreamDelayCompensationDescription": "Vertraag de beeldopname",
"Targetlength": "Doel lengte",
"TargetlengthDescription": "De beoogde lengte wanneer variabele FPS is ingeschakeld",
"TimeFormatCode": "Tijd Format Code",
- "TimeFormatCodeDescription": "Dit bepaalt hoe de timestamp van het uitvoer bestand moet worden geëncodeerd.",
+ "TimeFormatCodeDescription": "Dit bepaalt hoe de timestamp van het uitvoer bestand moet worden geëncodeerd",
"Timelapse": "Timelapse",
"TravelSpeed": "Bewegingssnelheid",
"TravelSpeedDescription": "Bewegingssnelheid tijdens het bewegen van en naar de parkeerpositie",
@@ -1056,9 +1081,9 @@
},
"UiSettingsTab": {
"BoolBigThumbnail": "Grote thumbnail",
- "BoolBigThumbnailDescription": "Toon een grote thumbnail in het statuspaneel tijdens de print",
+ "BoolBigThumbnailDescription": "Toon een grote thumbnail in het statuspaneel tijdens de print.",
"BoolHideUploadAndPrintButton": "Verberg Upload en Print knop",
- "BoolHideUploadAndPrintButtonDescription": "Toon of verberg de \"Upload en Print\" knop in de bovenbalk",
+ "BoolHideUploadAndPrintButtonDescription": "Toon of verberg de \"Upload en Print\" knop in de bovenbalk.",
"ConfirmOnEmergencyStop": "Vraag om bevestiging bij Noodstop",
"ConfirmOnEmergencyStopDescription": "Toon een dialoogvenster bij een Noodstop",
"ConfirmOnPowerDeviceChange": "Bevesting bij wijzigen van Stroomvoorziening van apparaten",
diff --git a/src/locales/tr.json b/src/locales/tr.json
index 7b44299e8..a55d9725f 100644
--- a/src/locales/tr.json
+++ b/src/locales/tr.json
@@ -1,6 +1,10 @@
{
"App": {
"Notifications": {
+ "BrowserWarnings": {
+ "Description": "{name} eski sürümdür ve tam olarak desteklenmez. Mevcut sürüm {version} olarak gözükmektedir. Mainsail, sürüm {minVersion} veya üzerini gerektirir.",
+ "Headline": "Eski sürüm tarayıcı"
+ },
"DependencyDescription": "Geçerli {name} sürümü, Mainsail'in tüm özelliklerini desteklemiyor. {name} ürününü en az {neededVersion} sürümüne güncelleyin.",
"DependencyName": "Bağımlılık: {name}",
"DismissAll": "Hepsini reddet",
diff --git a/src/locales/zh_TW.json b/src/locales/zh_TW.json
index 3762d26f4..05353e9de 100644
--- a/src/locales/zh_TW.json
+++ b/src/locales/zh_TW.json
@@ -1,6 +1,11 @@
{
"App": {
"Notifications": {
+ "BrowserWarnings": {
+ "Description": "{name} 已過時且不完全支援。目前的版本是 {version},但 Mainsail 需要 {minVersion} 或更高版本。",
+ "Headline": "過時的瀏覽器"
+ },
+ "DependencyDescription": "目前的 {name} 版本不支援 Mainsail 的所有功能。請將 {name} 更新至至少 {neededVersion} 版本。",
"DependencyName": "依賴項: {name}",
"DismissAll": "關閉所有",
"KlipperWarnings": {
@@ -10,17 +15,44 @@
"DeprecatedValueHeadline": "棄用的 Klipper 值",
"KlipperWarning": "Klipper警告"
},
+ "MaintenanceReminder": "維護提醒",
"MoonrakerWarnings": {
"MoonrakerComponent": "Moonraker: {component}",
"MoonrakerFailedComponentDescription": "載入 moonraker 組件“{component}”時檢測到錯誤。請檢查日誌檔案並解決問題。",
- "MoonrakerWarning": "Moonraker 警告"
+ "MoonrakerFailedInitComponentDescription": "初始化 Moonraker 元件「{component}」時檢測到錯誤。請檢查日誌文件並修正問題。",
+ "MoonrakerInitComponent": "初始化 Moonraker:{component}",
+ "MoonrakerWarning": "Moonraker 警告",
+ "UnparsedConfigOption": "在 [{section}] 區段檢測到未解析的配置選項「{option}: {value}」。這可能是已不再提供的選項,或是由於模組加載失敗所導致。未來這樣的情況將會導致啟動錯誤。",
+ "UnparsedConfigSection": "檢測到未解析的配置區段 [{section}]。這可能是由於元件加載失敗所導致。未來這樣的情況將會導致啟動錯誤。"
},
+ "Never": "絕不",
"NextReboot": "下次重啟",
"NoNotification": "沒有可用的通知",
"Notifications": "通知",
- "Remind": "提醒:"
+ "OneDayShort": "一天",
+ "OneHourShort": "一小時",
+ "OneWeekShort": "一周",
+ "Remind": "提醒:",
+ "ShowDetails": "顯示詳細資料",
+ "TmcOtFlag": "步進馬達錯誤:已設定OT旗標",
+ "TmcOtFlagText": "步進馬達「{name}」已觸發 OT 旗標並停止工作。這可能是電流過高所導致。請檢查步進馬達的設定及散熱情況。",
+ "TmcOtpwFlag": "步進馬達警告:已觸發 OTPW 旗標",
+ "TmcOtpwFlagText": "步進馬達 '{name}' 已觸發 OTPW 旗標,如果溫度繼續上升,可能會停止工作。這表示溫度過高的狀況。這可能是由於電流過高引起的。請檢查步進馬達設置和冷卻系統。"
+ },
+ "NumberInput": {
+ "GreaterOrEqualError": "必須大於或等於 {min}!",
+ "MustBeBetweenError": "必須介於 {min} 和 {max} 之間!",
+ "NoEmptyAllowedError": "輸入不能為空白!"
},
"Printers": "列印機列表",
+ "TextfieldWithCopy": {
+ "Copied": "已複製"
+ },
+ "TheServiceWorker": {
+ "DescriptionNeedUpdate": "本機快取已過時,需要更新。請點選下面的按鈕進行更新。",
+ "TitleNeedUpdate": "PWA 需要更新",
+ "Update": "更新"
+ },
"ThrottledStates": {
"DescriptionCurrentlyThrottled": "樹莓派ARM核心目前已被限制.",
"DescriptionFrequencyCapped": "樹莓派ARM最大頻率目前限制為1.2 GHz.",
@@ -44,7 +76,8 @@
"Error": "錯誤",
"Pause": "暫停列印",
"PrinterOff": "列印機關閉",
- "Printing": "{percent}% 列印中 - {filename}"
+ "Printing": "{percent}% 列印中 - {filename}",
+ "PrintingETA": "{percent}% 列印中 - 預計完成時間: {eta} - {filename}"
},
"TopBar": {
"CannotUploadTheFile": "無法上傳該檔案!",
@@ -71,7 +104,10 @@
"HostReboot": "主機重啟",
"HostShutdown": "主機關機",
"KlipperFirmwareRestart": "Klipper 韌體重新啟動",
- "KlipperRestart": "Klipper重新啟動"
+ "KlipperRestart": "Klipper重新啟動",
+ "ServiceRestart": "服務重啟",
+ "ServiceStart": "服務啟動",
+ "ServiceStop": "服務停止"
}
},
"HostControl": "主機控制",
@@ -80,6 +116,7 @@
"KlipperRestart": "Klipper 重啟",
"PowerDevices": "功率元件",
"Reboot": "重啟",
+ "Restart": "重新啟動",
"ServiceControl": "服務控制",
"Shutdown": "關機",
"Start": "開始",
@@ -981,8 +1018,9 @@
},
"UiSettingsTab": {
"BedScrewsDialogDescription": "顯示 BED_SCREWS_ADJUST 的幫助對話框。",
- "BoolBigThumbnail": "大縮略圖",
- "BoolBigThumbnailDescription": "列印期間在狀態面板中顯示一個大縮略圖.",
+ "BigThumbnailBackground": "大縮圖背景色",
+ "BoolBigThumbnail": "大縮圖",
+ "BoolBigThumbnailDescription": "列印期間在狀態面板中顯示大縮圖。",
"BoolHideUploadAndPrintButton": "隱藏上傳和列印按鈕",
"BoolHideUploadAndPrintButtonDescription": "顯示或隱藏頂部欄中的\"上傳和列印\"按鈕。",
"ConfirmOnEmergencyStop": "需要確認緊急停止",
@@ -1005,6 +1043,8 @@
"Logo": "Logo顏色",
"ManualProbeDialog": "手動探針助手對話框",
"ManualProbeDialogDescription": "顯示 PROBE_CALIBRATE 或 Z_ENDSTOP_CALIBRATE 的幫助對話框。",
+ "Mode": "模式",
+ "ModeDescription": "變更應用程式的整體外觀和感覺。",
"NavigationStyle": "導航欄風格",
"NavigationStyleDescription": "更改導航欄外觀",
"NavigationStyleIconsAndText": "圖標 + 文字",
@@ -1012,7 +1052,10 @@
"PowerDeviceName": "列印機電源裝置",
"PowerDeviceNameDescription": "選擇應使用哪個 Moonraker 電源設備為列印機供電。",
"Primary": "高亮顏色",
+ "PrintstatusThumbnailZoom": "大縮圖縮放",
+ "PrintstatusThumbnailZoomDescription": "這將停用狀態面板中縮圖的縮放效果。",
"ScrewsTiltAdjustDialogDescription": "顯示 SCREWS_TILT_CALCULATE 的幫助程序對話框。",
+ "ThemeDescription": "自訂特定風格的介面外觀。",
"UiSettings": "使用者介面設定"
},
"Update": "更新",
diff --git a/src/pages/Console.vue b/src/pages/Console.vue
index 39a5da20b..a567ac320 100644
--- a/src/pages/Console.vue
+++ b/src/pages/Console.vue
@@ -2,35 +2,14 @@
-
+
{{ mdiTrashCan }}
-
+
+ @change="toggleFilter(index, filter)" />