From 13515b25227ab2a4c6c8857ee7a6b490881f8bca Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 09:40:47 +0200 Subject: [PATCH 1/4] Bugfix: after a drag and drop operation, when resizing the page, the moved item stays in the drop position even if it has had a position in the resized layout --- public/js/components/Drop/Grid.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/public/js/components/Drop/Grid.js b/public/js/components/Drop/Grid.js index 6d9777c28..d4d8c90d9 100644 --- a/public/js/components/Drop/Grid.js +++ b/public/js/components/Drop/Grid.js @@ -233,6 +233,14 @@ export default { if (value == oldValue) return; + /** NOTE(chris): tempPositionUpdates depends on the cols not to be + * updated. So if they do we reset to get a clean value. In case the + * drag and drop operation is still motion on the next tick this + * will be correct again and if there is no such operation we clean + * up. + */ + this.tempPositionUpdates = null; + this.reinitGrid(); }, rows: { @@ -246,6 +254,11 @@ export default { }, indexedItems: { handler(value) { + /** NOTE(chris): there was an update of the items, so in case + * it came from a drag and drop operation we need to clean up + */ + this.tempPositionUpdates = null; + this.reinitGrid(); }, immediate: true, From d824334538bd7f12df511413c601a18c6906196c Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 09:42:18 +0200 Subject: [PATCH 2/4] Hiding widgets should look like deleting and recovering is moved to the "add widget" popup --- public/js/components/Dashboard/Dashboard.js | 43 +++++++++++---- public/js/components/Dashboard/Item.js | 28 +--------- public/js/components/Dashboard/Section.js | 19 +------ .../js/components/Dashboard/Widget/Picker.js | 55 +++++++++++++++---- 4 files changed, 81 insertions(+), 64 deletions(-) diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js index bf45ad227..b88765856 100644 --- a/public/js/components/Dashboard/Dashboard.js +++ b/public/js/components/Dashboard/Dashboard.js @@ -62,6 +62,9 @@ export default { return [type, result]; })); + }, + hiddenWidgets() { + return this.widgets.filter(widget => widget.hidden); } }, methods: { @@ -69,6 +72,9 @@ export default { this.$refs.widgetpicker .getWidget() .then(widget_id => { + if (widget_id.hidden) + this.widgetUnhide(widget_id, widget.place); + widget.widget = widget_id; // NOTE(chris): min size widget.place = Object.fromEntries(Object.entries(widget.place).map(([key, value]) => { @@ -131,17 +137,6 @@ export default { this.widgets.forEach((widget, i) => { if (failed.includes(widget.id)) { this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id])); - /** NOTE(chris): if you wanna hide or unhide a - * preset and it fails: switch around the hidden - * value to revert it properly (checkboxes can't - * really handle it otherwise) - */ - if (payload[widget.id].hidden !== undefined) { - this.widgets[i].hidden = payload[widget.id].hidden; - this.$nextTick(() => { - this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id])); - }); - } } else if (payload[widget.id]) { payload[widget.id].id = widget.id; payload[widget.id].index = widget.index; @@ -160,6 +155,31 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, + widgetUnhide(orig, place) { + place = Object.fromEntries(Object.entries(place).map(([key, value]) => { + value.w = this.sizeLimits[orig.widget].width.min; + value.h = this.sizeLimits[orig.widget].height.min; + // NOTE(chris): unpin pinned widgets because they got a new placement + value.pinned = false; + return [key, value]; + })); + // NOTE(chris): clear placement in other screensizes + Object.keys(orig.place).forEach(key => { + if (!place[key]) { + place[key] = { + x: undefined, + y: undefined, + pinned: false + }; + } + }); + let payload = {}; + payload[orig.id] = { + hidden: false, + place + }; + return this.widgetUpdate(payload); + }, async fetchViewData() { let viewDataResult = await this.$api.call(ApiDashboard.getViewData()); const viewData = viewDataResult.data; @@ -223,6 +243,7 @@ export default { ` } diff --git a/public/js/components/Dashboard/Item.js b/public/js/components/Dashboard/Item.js index 20c195178..160b34e91 100644 --- a/public/js/components/Dashboard/Item.js +++ b/public/js/components/Dashboard/Item.js @@ -36,7 +36,6 @@ export default { "width", "height", "custom", - "hidden", "editMode", "loading", // widget got added and is waiting for backend to save in db "item_data", @@ -115,14 +114,6 @@ export default { }, ready() { return this.component && this.arguments !== null; - }, - visible: { - get() { - return !this.hidden; - }, - set(value) { - this.$emit('remove', this.hidden); - } } }, methods: { @@ -202,10 +193,8 @@ export default { }, template: /*html*/ `
@@ -299,9 +288,9 @@ export default { > - + - - -
- -
-
diff --git a/public/js/components/Dashboard/Section.js b/public/js/components/Dashboard/Section.js index e8c56fd4e..b55eefb7a 100644 --- a/public/js/components/Dashboard/Section.js +++ b/public/js/components/Dashboard/Section.js @@ -124,8 +124,6 @@ export default { return { ...item, ...placement, weight }; }); - if (this.editModeIsActive) - return placedItems; return placedItems.filter(item => !item.hidden); } }, @@ -141,22 +139,12 @@ export default { handleConfigClosed() { this.configOpened = false }, - removeWidget(item, revert) { + removeWidget(item) { if (item.custom) { BsConfirm.popup(this.$p.t('dashboard', 'alert_deleteWidget')).then(() => this.$emit('widgetRemove', item.id, this.name)); } else { let update = {}; - update[item.id] = { hidden: !revert }; - - if (!revert) { - // NOTE(chris): move to last line - update[item.id].place = []; - let y = this.gridHeight; - if (this.additionalRow) - y--; - update[item.id].place[this.gridWidth] = { x: 0, y }; - } - + update[item.id] = { hidden: true }; this.updatePreset(update); } }, @@ -251,13 +239,12 @@ export default { :loading="item.loading" :config="item.config" :custom="item.custom" - :hidden="item.hidden" :editMode="editModeIsActive" :place="item.place[gridWidth]" :widget-template="indexedWidgetsTemplates[item.widget]" :source="adminMode ? null : item.source || 'custom'" @change="saveConfig($event, item)" - @remove="removeWidget(item, $event)" + @remove="removeWidget(item)" @config-opened="handleConfigOpened" @config-closed="handleConfigClosed" @pin-item="updatePositions" diff --git a/public/js/components/Dashboard/Widget/Picker.js b/public/js/components/Dashboard/Widget/Picker.js index 260b95874..284eb551c 100644 --- a/public/js/components/Dashboard/Widget/Picker.js +++ b/public/js/components/Dashboard/Widget/Picker.js @@ -7,11 +7,21 @@ export default { WidgetIcon, }, props: [ - "widgets" + "widgets", + "hiddenWidgets" ], data: () => ({ callbacks: {} }), + computed: { + hasAnyWidgets() { + if (!this.widgets) + return false; + if (!this.widgets.length && !this.hiddenWidgets?.length) + return false; + return true; + } + }, methods: { getWidget() { return new Promise((resolve,reject) => { @@ -37,23 +47,46 @@ export default {
From 2f86a1b0171738b58baef4a114d82115e1967cb3 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 10:46:08 +0200 Subject: [PATCH 4/4] Changing the edit button into a toggle --- public/js/components/Dashboard/Dashboard.js | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js index b88765856..e390f16d4 100644 --- a/public/js/components/Dashboard/Dashboard.js +++ b/public/js/components/Dashboard/Dashboard.js @@ -224,15 +224,23 @@ export default { }, template: /* html */`
-

- {{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }} - -

+
+

+ {{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }} +

+
+ + +
+