From 3604c677bc6c53eba613fd7f51d84bb167f0496c Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Tue, 22 Oct 2024 00:51:32 +0200 Subject: [PATCH 01/41] refactor: refactor Console & MiniConsole (#2031) --- src/components/inputs/ConsoleTextarea.vue | 138 ++++++++++++ src/components/mixins/console.ts | 63 ++++++ src/components/panels/MiniconsolePanel.vue | 234 ++------------------- src/pages/Console.vue | 221 ++----------------- src/store/gui/console/mutations.ts | 16 +- 5 files changed, 244 insertions(+), 428 deletions(-) create mode 100644 src/components/inputs/ConsoleTextarea.vue create mode 100644 src/components/mixins/console.ts diff --git a/src/components/inputs/ConsoleTextarea.vue b/src/components/inputs/ConsoleTextarea.vue new file mode 100644 index 000000000..8663a9286 --- /dev/null +++ b/src/components/inputs/ConsoleTextarea.vue @@ -0,0 +1,138 @@ + + + + diff --git a/src/components/mixins/console.ts b/src/components/mixins/console.ts new file mode 100644 index 000000000..1709f6e89 --- /dev/null +++ b/src/components/mixins/console.ts @@ -0,0 +1,63 @@ +import Vue from 'vue' +import Component from 'vue-class-component' +import { CommandHelp } from '@/store/printer/types' +import { GuiConsoleStateFilter } from '@/store/gui/console/types' + +@Component +export default class ConsoleMixin extends Vue { + get helplist(): CommandHelp[] { + return this.$store.state.printer.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/panels/MiniconsolePanel.vue b/src/components/panels/MiniconsolePanel.vue index 8a5168dc6..98c6499d7 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/pages/Console.vue b/src/pages/Console.vue index 39a5da20b..a9ca31d6d 100644 --- a/src/pages/Console.vue +++ b/src/pages/Console.vue @@ -2,35 +2,14 @@
- + {{ mdiTrashCan }} - + + @change="toggleFilter(index, filter)" /> diff --git a/src/components/console/CommandHelpModalEntry.vue b/src/components/console/CommandHelpModalEntry.vue new file mode 100644 index 000000000..ceb00aa35 --- /dev/null +++ b/src/components/console/CommandHelpModalEntry.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/console/ConsoleTable.vue b/src/components/console/ConsoleTable.vue index 284d5570d..917976c59 100644 --- a/src/components/console/ConsoleTable.vue +++ b/src/components/console/ConsoleTable.vue @@ -13,7 +13,7 @@ :key="index" class="consoleTableRow" :event="event" - @command-click="commandClick"> + @command-click="commandClick" />
diff --git a/src/components/inputs/ConsoleTextarea.vue b/src/components/inputs/ConsoleTextarea.vue index 8663a9286..604772121 100644 --- a/src/components/inputs/ConsoleTextarea.vue +++ b/src/components/inputs/ConsoleTextarea.vue @@ -100,8 +100,8 @@ export default class ConsoleTextarea extends Mixins(BaseMixin, ConsoleMixin) { const lastNewlineIndex = beforeCursor.lastIndexOf('\n') const currentLine = beforeCursor.substring(lastNewlineIndex + 1) - const currentLineLowerCase = currentLine.toLowerCase() - const commands = this.helplist.filter((element) => element.commandLow.startsWith(currentLineLowerCase)) + const currentLineUpperCase = currentLine.toUpperCase() + const commands = this.helplist.filter((element) => element.command.startsWith(currentLineUpperCase)) if (commands.length === 0) return @@ -116,8 +116,7 @@ export default class ConsoleTextarea extends Mixins(BaseMixin, ConsoleMixin) { let output = '' commands.forEach( - (command) => - (output += `${command.command}: ${command.description}
`) + (command) => (output += `${command.command}: ${command.help}
`) ) this.$store.dispatch('server/addEvent', { message: output, type: 'autocomplete' }) diff --git a/src/components/mixins/console.ts b/src/components/mixins/console.ts index 1709f6e89..e337bb658 100644 --- a/src/components/mixins/console.ts +++ b/src/components/mixins/console.ts @@ -1,12 +1,18 @@ import Vue from 'vue' import Component from 'vue-class-component' -import { CommandHelp } from '@/store/printer/types' import { GuiConsoleStateFilter } from '@/store/gui/console/types' @Component export default class ConsoleMixin extends Vue { - get helplist(): CommandHelp[] { - return this.$store.state.printer.helplist ?? [] + 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() { diff --git a/src/components/panels/MiniconsolePanel.vue b/src/components/panels/MiniconsolePanel.vue index 98c6499d7..93178fad7 100644 --- a/src/components/panels/MiniconsolePanel.vue +++ b/src/components/panels/MiniconsolePanel.vue @@ -91,7 +91,7 @@ import BaseMixin from '@/components/mixins/base' import ConsoleTable from '@/components/console/ConsoleTable.vue' import Panel from '@/components/ui/Panel.vue' import { mdiCog, mdiConsoleLine, mdiTrashCan } from '@mdi/js' -import CommandHelpModal from '@/components/CommandHelpModal.vue' +import CommandHelpModal from '@/components/console/CommandHelpModal.vue' import ConsoleMixin from '@/components/mixins/console' import ConsoleTextarea from '@/components/inputs/ConsoleTextarea.vue' diff --git a/src/locales/en.json b/src/locales/en.json index 6b0505e25..cc631c4b0 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -165,6 +165,7 @@ "Empty": "Empty", "HideTemperatures": "Hide temperatures", "HideTimelapse": "Hide Timelapse", + "Search": "Search", "SendCode": "Send code...", "SetupConsole": "Setup Console" }, diff --git a/src/pages/Console.vue b/src/pages/Console.vue index a9ca31d6d..a567ac320 100644 --- a/src/pages/Console.vue +++ b/src/pages/Console.vue @@ -83,7 +83,7 @@ import { Component, Mixins, Ref, Watch } from 'vue-property-decorator' import BaseMixin from '@/components/mixins/base' import ConsoleTable from '@/components/console/ConsoleTable.vue' -import CommandHelpModal from '@/components/CommandHelpModal.vue' +import CommandHelpModal from '@/components/console/CommandHelpModal.vue' import { mdiCog, mdiTrashCan } from '@mdi/js' import ConsoleMixin from '@/components/mixins/console' import ConsoleTextarea from '@/components/inputs/ConsoleTextarea.vue' diff --git a/src/plugins/webSocketClient.ts b/src/plugins/webSocketClient.ts index e1618eac5..8f423b8dc 100644 --- a/src/plugins/webSocketClient.ts +++ b/src/plugins/webSocketClient.ts @@ -179,7 +179,7 @@ export class WebSocketClient { ) } - async emitAndWait(method: string, params: Params, options: emitOptions = {}): Promise { + async emitAndWait(method: string, params: Params | undefined = undefined, options: emitOptions = {}): Promise { return new Promise((resolve, reject) => { if (this.instance?.readyState !== WebSocket.OPEN) reject() diff --git a/src/store/printer/actions.ts b/src/store/printer/actions.ts index 646953616..eea47a360 100644 --- a/src/store/printer/actions.ts +++ b/src/store/printer/actions.ts @@ -16,14 +16,13 @@ export const actions: ActionTree = { dispatch('socket/addInitModule', 'printer/info', { root: true }) dispatch('socket/addInitModule', 'printer/initSubscripts', { root: true }) - dispatch('socket/addInitModule', 'printer/initHelpList', { root: true }) dispatch('socket/addInitModule', 'printer/initTempHistory', { root: true }) dispatch('socket/addInitModule', 'server/gcode_store', { root: true }) Vue.$socket.emit('printer.info', {}, { action: 'printer/getInfo' }) - Vue.$socket.emit('printer.objects.list', {}, { action: 'printer/initSubscripts' }) - Vue.$socket.emit('printer.gcode.help', {}, { action: 'printer/initHelpList' }) Vue.$socket.emit('server.gcode_store', {}, { action: 'server/getGcodeStore' }) + + dispatch('initSubscripts') }, getInfo({ commit, dispatch }, payload) { @@ -46,7 +45,9 @@ export const actions: ActionTree = { dispatch('socket/removeInitModule', 'printer/info', { root: true }) }, - initSubscripts({ dispatch }, payload) { + async initSubscripts({ dispatch }) { + const payload = await Vue.$socket.emitAndWait('printer.objects.list') + let subscripts = {} const blocklist = ['menu'] @@ -56,31 +57,25 @@ export const actions: ActionTree = { if (!blocklist.includes(nameSplit[0])) subscripts = { ...subscripts, [key]: null } }) - if (Object.keys(subscripts).length > 0) - Vue.$socket.emit('printer.objects.subscribe', { objects: subscripts }, { action: 'printer/getInitData' }) - else - Vue.$socket.emit( - 'server.temperature_store', - { include_monitors: true }, - { action: 'printer/tempHistory/init' } - ) + if (Object.keys(subscripts).length > 0) { + const result = await Vue.$socket.emitAndWait('printer.objects.subscribe', { objects: subscripts }, {}) - dispatch('socket/removeInitModule', 'printer/initSubscripts', { root: true }) - }, + // reset screws_tilt_adjust if it exists + if ('screws_tilt_adjust' in result.status) { + result.status.screws_tilt_adjust.error = false + result.status.screws_tilt_adjust.results = {} + } - getInitData({ dispatch }, payload) { - if ('screws_tilt_adjust' in payload.status) { - payload.status.screws_tilt_adjust.error = false - payload.status.screws_tilt_adjust.results = {} - } + dispatch('getData', result) - dispatch('getData', payload) + setTimeout(() => { + dispatch('initExtruderCanExtrude') + }, 200) + } Vue.$socket.emit('server.temperature_store', { include_monitors: true }, { action: 'printer/tempHistory/init' }) - setTimeout(() => { - dispatch('initExtruderCanExtrude') - }, 200) + dispatch('socket/removeInitModule', 'printer/initSubscripts', { root: true }) }, getData({ commit, dispatch, state }, payload) { @@ -135,7 +130,13 @@ export const actions: ActionTree = { commit('setData', payload) }, - initExtruderCanExtrude({ state }) { + async initGcodes({ commit }) { + const gcodes = await Vue.$socket.emitAndWait('printer.objects.query', { objects: { gcode: ['commands'] } }, {}) + + commit('setData', gcodes.status) + }, + + async initExtruderCanExtrude({ dispatch, state }) { const extruderList: string[] = Object.keys(state).filter((name) => name.startsWith('extruder')) const reInitList: { [key: string]: string[] } = {} @@ -143,13 +144,8 @@ export const actions: ActionTree = { reInitList[extruderName] = ['can_extrude'] }) - Vue.$socket.emit('printer.objects.query', { objects: reInitList }, { action: 'printer/getData' }) - }, - - initHelpList({ commit, dispatch }, payload) { - commit('setHelplist', payload) - - dispatch('socket/removeInitModule', 'printer/initHelpList', { root: true }) + const result = await Vue.$socket.emitAndWait('printer.objects.query', { objects: reInitList }, {}) + dispatch('getData', result.status) }, getEndstopStatus({ commit }, payload) { @@ -165,9 +161,10 @@ export const actions: ActionTree = { if (payload.toLowerCase().trim() === 'm112') { Vue.$socket.emit('printer.emergency_stop', {}, { loading: 'sendGcode' }) - } else { - Vue.$socket.emit('printer.gcode.script', { script: payload }, { loading: 'sendGcode' }) + return } + + Vue.$socket.emit('printer.gcode.script', { script: payload }, { loading: 'sendGcode' }) }, clearScrewsTiltAdjust({ commit }) { diff --git a/src/store/printer/mutations.ts b/src/store/printer/mutations.ts index 77a1b0232..19e3100d4 100644 --- a/src/store/printer/mutations.ts +++ b/src/store/printer/mutations.ts @@ -2,7 +2,6 @@ import Vue from 'vue' import { getDefaultState } from './index' import { MutationTree } from 'vuex' import { PrinterState } from '@/store/printer/types' -import { setDataDeep } from '@/plugins/helpers' export const mutations: MutationTree = { reset(state) { @@ -20,7 +19,20 @@ export const mutations: MutationTree = { }, setData(state, payload) { - setDataDeep(state, payload) + Object.keys(payload).forEach((key) => { + const value = payload[key] + + if (typeof value !== 'object' || value === null || !(key in state)) { + Vue.set(state, key, value) + return + } + + if (typeof value === 'object') { + Object.keys(value).forEach((subkey) => { + Vue.set(state[key], subkey, value[subkey]) + }) + } + }) }, setBedMeshProfiles(state, payload) { @@ -29,20 +41,6 @@ export const mutations: MutationTree = { } }, - setHelplist(state, payload) { - const helplist = [] - - for (const [command, description] of Object.entries(payload)) { - helplist.push({ - commandLow: command.toLowerCase(), - command: command, - description: description, - }) - } - - Vue.set(state, 'helplist', helplist) - }, - clearCurrentFile(state) { Vue.set(state, 'current_file', {}) }, diff --git a/src/store/printer/types.ts b/src/store/printer/types.ts index 6b08e5410..6ebc84717 100644 --- a/src/store/printer/types.ts +++ b/src/store/printer/types.ts @@ -6,21 +6,9 @@ export interface VTextareaType extends HTMLInputElement { } } -export interface CommandHelp { - command: string - commandLow: string - description?: string | Record -} - -export interface ConsoleCommandHelp { - command: CommandHelp | null - original: string -} - export interface PrinterState { // eslint-disable-next-line [key: string]: any - helplist?: CommandHelp[] tempHistory?: PrinterTempHistoryState } diff --git a/src/store/server/actions.ts b/src/store/server/actions.ts index a32a32a2b..a1423fd2a 100644 --- a/src/store/server/actions.ts +++ b/src/store/server/actions.ts @@ -170,6 +170,7 @@ export const actions: ActionTree = { dispatch('stopKlippyConnectedInterval') commit('setKlippyConnected') + dispatch('printer/initGcodes', null, { root: true }) dispatch('checkKlippyState', { state: payload.klippy_state, state_message: null }) }, From ae7f8f14d9f99a896f0bbd2df743502d4a14ae69 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Thu, 7 Nov 2024 10:49:22 +0100 Subject: [PATCH 09/41] fix: fix color picker for PCA9632 (#2028) * fix: fix color picker for PCA9632 Signed-off-by: Stefan Dej * refactor: remove fallback and set value only when it is an Array or String Signed-off-by: Stefan Dej --------- Signed-off-by: Stefan Dej --- src/store/printer/getters.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/store/printer/getters.ts b/src/store/printer/getters.ts index ba0204e27..ce9b15fa9 100644 --- a/src/store/printer/getters.ts +++ b/src/store/printer/getters.ts @@ -228,7 +228,13 @@ export const getters: GetterTree = { let singleChannelTarget = null const colorData = object.state.color_data ?? [] - if ('color_order' in object.settings) colorOrder = object.settings.color_order[0] ?? '' + if ('color_order' in object.settings) { + if (typeof object.settings.color_order === 'string') { + colorOrder = object.settings.color_order + } else if (Array.isArray(object.settings.color_order) && object.settings.color_order.length > 0) { + colorOrder = object.settings.color_order[0] + } + } if (object.type === 'led') { colorOrder = '' From a81672f2a6bf6b61b05f2a9ca8cdc6c8a02c259d Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Thu, 7 Nov 2024 10:50:13 +0100 Subject: [PATCH 10/41] fix(notifications): fix dismiss function for tmc warnings (#1956) * fix(notifications): fix dismiss function for tmc warnings Signed-off-by: Stefan Dej * refactor: remove magic number in getNotificationsOverheadDrivers getter Signed-off-by: Stefan Dej --------- Signed-off-by: Stefan Dej --- src/store/gui/notifications/getters.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/store/gui/notifications/getters.ts b/src/store/gui/notifications/getters.ts index 6bd197bed..ccde3ea86 100644 --- a/src/store/gui/notifications/getters.ts +++ b/src/store/gui/notifications/getters.ts @@ -436,7 +436,17 @@ export const getters: GetterTree = { } }) - return notifications + // get all dismissed tmcwarnings and convert it to a string[] + const tmcwarningsDismisses = getters['getDismissByCategory']('tmcwarning').map( + (dismiss: GuiNotificationStateDismissEntry) => { + return `tmcwarning/${dismiss.id}` + } + ) + + // return filtered tmcwarnings + return notifications.filter((entry) => { + return !tmcwarningsDismisses.includes(entry.id) + }) }, getDismiss: (state, getters, rootState) => { From fbeecb0169abe6e86882c5c19640fa9114c7e49b Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Sat, 9 Nov 2024 01:11:53 +0100 Subject: [PATCH 11/41] feat(History): add option to show stats in different values (#2007) * refactor: refactor getters in HistoryAllPrintStatus Signed-off-by: Stefan Dej * feat: add option to switch the stats between amount, filament and time Signed-off-by: Stefan Dej * feat: add option to switch the stats between amount, filament and time Signed-off-by: Stefan Dej * refactor: extract HistoryStatsValueNames to history types Signed-off-by: Stefan Dej * refactor: remove complexity in historyStatsMixin Signed-off-by: Stefan Dej * refactor: extract some logic into a separate methods Signed-off-by: Stefan Dej * refactor: rename option amount to jobs Signed-off-by: Stefan Dej * fix: fix status groups in print history filter Signed-off-by: Stefan Dej * fix: fix decimals in filament length output of HistoryAllPrintStatusTableItem Signed-off-by: Stefan Dej * refactor: remove unused imports Signed-off-by: Stefan Dej * fix: add minAngle to chart Signed-off-by: Stefan Dej --------- Signed-off-by: Stefan Dej --- .../charts/HistoryAllPrintStatusChart.vue | 63 ++++---- .../charts/HistoryAllPrintStatusTable.vue | 44 ++---- .../charts/HistoryAllPrintStatusTableItem.vue | 36 +++++ src/components/mixins/historyStats.ts | 124 ++++++++++++++++ src/components/panels/HistoryListPanel.vue | 10 +- .../panels/HistoryStatisticsPanel.vue | 29 +++- src/locales/en.json | 2 + src/store/server/history/getters.ts | 134 +----------------- src/store/server/history/types.ts | 4 + 9 files changed, 236 insertions(+), 210 deletions(-) create mode 100644 src/components/charts/HistoryAllPrintStatusTableItem.vue create mode 100644 src/components/mixins/historyStats.ts diff --git a/src/components/charts/HistoryAllPrintStatusChart.vue b/src/components/charts/HistoryAllPrintStatusChart.vue index 0b32dbac4..e2a3927d5 100644 --- a/src/components/charts/HistoryAllPrintStatusChart.vue +++ b/src/components/charts/HistoryAllPrintStatusChart.vue @@ -5,25 +5,27 @@ :option="chartOptions" :autoresize="true" :init-options="{ renderer: 'svg' }" - style="height: 200px; width: 100%"> + style="height: 200px; width: 100%" /> diff --git a/src/components/charts/HistoryAllPrintStatusTableItem.vue b/src/components/charts/HistoryAllPrintStatusTableItem.vue new file mode 100644 index 000000000..eca1159e5 --- /dev/null +++ b/src/components/charts/HistoryAllPrintStatusTableItem.vue @@ -0,0 +1,36 @@ + + + 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/panels/HistoryListPanel.vue b/src/components/panels/HistoryListPanel.vue index f25ac602f..eca41eb34 100644 --- a/src/components/panels/HistoryListPanel.vue +++ b/src/components/panels/HistoryListPanel.vue @@ -89,11 +89,8 @@ @change="showPrintJobs = !showPrintJobs" /> - - {{ $t('Panels.StatusPanel.Status') }} - {{ $t('Panels.StatusPanel.Files') }} + + {{ mdiSpeedometer }} + + + {{ mdiFileDocumentMultipleOutline }} + - {{ $t('Panels.StatusPanel.Jobqueue') }} + {{ mdiTrayFull }} @@ -133,16 +137,19 @@ import Panel from '@/components/ui/Panel.vue' import { mdiAlertOutline, mdiBroom, + mdiCloseCircle, + mdiDotsVertical, + mdiFileDocumentMultipleOutline, 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' @@ -162,11 +169,14 @@ 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 + mdiMessageProcessingOutline = mdiMessageProcessingOutline + mdiSpeedometer = mdiSpeedometer + mdiTrayFull = mdiTrayFull declare $refs: { bigThumbnail: any @@ -435,4 +445,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/locales/de.json b/src/locales/de.json index 6369e0dab..52f43740c 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -741,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", @@ -769,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 3af1b9df3..1108500a1 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -748,10 +748,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", @@ -776,7 +774,6 @@ "ResumePrint": "Resume print", "Slicer": "Slicer", "Speed": "Speed", - "Status": "Status", "Total": "Total", "Unknown": "Unknown" }, From 08060611154a3251be02f237a037862c196f865e Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Thu, 28 Nov 2024 22:51:10 +0100 Subject: [PATCH 39/41] feat(StatusPanel): add option to show history in StatusPanel (#2055) Co-authored-by: rackrick <45207681+rackrick@users.noreply.github.com> --- src/components/panels/Status/History.vue | 77 +++++ src/components/panels/Status/HistoryEntry.vue | 264 ++++++++++++++++++ src/components/panels/StatusPanel.vue | 19 +- .../settings/SettingsUiSettingsTab.vue | 22 ++ src/locales/en.json | 5 + src/store/gui/index.ts | 1 + src/store/gui/types.ts | 1 + src/store/server/history/types.ts | 4 + 8 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 src/components/panels/Status/History.vue create mode 100644 src/components/panels/Status/HistoryEntry.vue 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 @@ + + + + + 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 @@ + + + + + diff --git a/src/components/panels/StatusPanel.vue b/src/components/panels/StatusPanel.vue index 07b61d81d..6334d6eef 100644 --- a/src/components/panels/StatusPanel.vue +++ b/src/components/panels/StatusPanel.vue @@ -95,6 +95,9 @@ {{ mdiFileDocumentMultipleOutline }} + + {{ mdiHistory }} + {{ mdiTrayFull }} @@ -109,6 +112,9 @@ + + + @@ -129,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' @@ -140,6 +147,7 @@ import { mdiCloseCircle, mdiDotsVertical, mdiFileDocumentMultipleOutline, + mdiHistory, mdiInformation, mdiLayersPlus, mdiMessageProcessingOutline, @@ -162,6 +170,7 @@ import CancelJobDialog from '@/components/dialogs/CancelJobDialog.vue' Panel, StatusPanelExcludeObject, StatusPanelGcodefiles, + StatusPanelHistory, StatusPanelJobqueue, StatusPanelPrintstatus, StatusPanelPrintstatusThumbnail, @@ -174,6 +183,7 @@ export default class StatusPanel extends Mixins(BaseMixin) { mdiDotsVertical = mdiDotsVertical mdiFileDocumentMultipleOutline = mdiFileDocumentMultipleOutline mdiInformation = mdiInformation + mdiHistory = mdiHistory mdiMessageProcessingOutline = mdiMessageProcessingOutline mdiSpeedometer = mdiSpeedometer mdiTrayFull = mdiTrayFull @@ -378,9 +388,16 @@ export default class StatusPanel extends Mixins(BaseMixin) { 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 = 'jobqueue' + if (!this.displayFilesTab) this.activeTab = 'history' + if (!this.displayHistoryTab) this.activeTab = 'jobqueue' } @Watch('current_filename') diff --git a/src/components/settings/SettingsUiSettingsTab.vue b/src/components/settings/SettingsUiSettingsTab.vue index 0d420a506..a05410af7 100644 --- a/src/components/settings/SettingsUiSettingsTab.vue +++ b/src/components/settings/SettingsUiSettingsTab.vue @@ -308,6 +308,20 @@ dense outlined /> + + + +
@@ -674,6 +688,14 @@ export default class SettingsUiSettingsTab extends Mixins(BaseMixin, ThemeMixin) ] } + 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/locales/en.json b/src/locales/en.json index 1108500a1..f65256eb8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -736,6 +736,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", @@ -775,6 +776,7 @@ "Slicer": "Slicer", "Speed": "Speed", "Total": "Total", + "TotalTime": "Total Time", "Unknown": "Unknown" }, "TemperaturePanel": { @@ -1234,6 +1236,9 @@ "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/store/gui/index.ts b/src/store/gui/index.ts index a9ffed150..a7f011147 100644 --- a/src/store/gui/index.ts +++ b/src/store/gui/index.ts @@ -185,6 +185,7 @@ export const getDefaultState = (): GuiState => { printstatusThumbnailZoom: true, dashboardFilesLimit: 5, dashboardFilesFilter: ['new', 'failed', 'completed'], + dashboardHistoryLimit: 5, }, view: { blockFileUpload: false, diff --git a/src/store/gui/types.ts b/src/store/gui/types.ts index e7f871344..ed8f0dcda 100644 --- a/src/store/gui/types.ts +++ b/src/store/gui/types.ts @@ -127,6 +127,7 @@ export interface GuiState { printstatusThumbnailZoom: boolean dashboardFilesLimit: number dashboardFilesFilter: GuiStateUiSettingsDashboardFilesFilter[] + dashboardHistoryLimit: number } view: { blockFileUpload: boolean diff --git a/src/store/server/history/types.ts b/src/store/server/history/types.ts index 9cc07f8cd..090ae9649 100644 --- a/src/store/server/history/types.ts +++ b/src/store/server/history/types.ts @@ -91,3 +91,7 @@ export interface ServerHistoryStateAllPrintStatusEntry { } export type HistoryStatsValueNames = 'jobs' | 'filament' | 'time' + +export interface ServerHistoryStateJobWithCount extends ServerHistoryStateJob { + count: number +} From 0758af1b219e2e6b43ee223d4f72cc15449ee23a Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Thu, 28 Nov 2024 23:28:13 +0100 Subject: [PATCH 40/41] fix(Webcam): make webcam view non-draggable (#2057) Co-authored-by: Stefan Dej --- src/components/webcams/streamers/Mjpegstreamer.vue | 1 + src/components/webcams/streamers/MjpegstreamerAdaptive.vue | 1 + src/components/webcams/streamers/Uv4lMjpeg.vue | 1 + 3 files changed, 3 insertions(+) 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" /> From 33efe920cee3659ffd84cdac5f63b7a3764f2238 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Sun, 1 Dec 2024 16:52:54 +0100 Subject: [PATCH 41/41] fix: fix save z offset in toolhead panel (#2060) --- src/components/mixins/zoffset.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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() {