From b23c2a8f41b07cd8cace0da6f0d6000a72030fe0 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Fri, 6 Nov 2026 00:34:20 +0100 Subject: [PATCH] fix(store): keep table.views in sync with store.views The navigation renders a table's views from table.views, while most of the app reads store.views. Both start out holding the same view objects, but setView replaces the entry in store.views with the object the server returned and leaves table.views pointing at the old one, so the two collections diverge on the first rename. Visible effects: - Renaming a view updates the title everywhere except the navigation entry below its table, which keeps the old title until a reload. - Deleting a view removes it from store.views only. The navigation still lists it, and Dashboard.vue reads table.views to build the per-view share counts, so it then calls .filter() on the columns of a view that no longer exists. Mirror both writes in the parent table inside setView and removeView, so every caller gets the sync rather than each one repeating it. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: Andy Scherzinger --- cypress/component/store/tablesStore.cy.js | 25 +++++++++++++++++++++++ src/store/store.js | 11 ++++++++++ 2 files changed, 36 insertions(+) diff --git a/cypress/component/store/tablesStore.cy.js b/cypress/component/store/tablesStore.cy.js index 024e49cd72..58b2525e03 100644 --- a/cypress/component/store/tablesStore.cy.js +++ b/cypress/component/store/tablesStore.cy.js @@ -44,4 +44,29 @@ describe('tables store setters', () => { expect(store.contexts.map(context => context.id)).to.deep.equal([1, 2]) expect(hasStrayIndex(store.contexts)).to.equal(false) }) + + it('setView keeps the copy inside table.views in sync', () => { + const store = useTablesStore() + const view = { id: 7, tableId: 4, title: 'Board' } + store.setTables([{ id: 4, title: 'T', views: [view] }]) + store.setViews([view]) + + store.setView({ id: 7, tableId: 4, title: 'Board renamed' }) + + expect(store.views[0].title).to.equal('Board renamed') + expect(store.tables[0].views[0].title).to.equal('Board renamed') + }) + + it('removeView drops the view from table.views as well', () => { + cy.intercept('DELETE', '**/apps/tables/view/7', { statusCode: 200, body: true }).as('del') + const store = useTablesStore() + const view = { id: 7, tableId: 4, title: 'Board' } + store.setTables([{ id: 4, title: 'T', views: [view] }]) + store.setViews([view]) + + cy.wrap(null).then(() => store.removeView({ viewId: 7 })).then(() => { + expect(store.views).to.have.length(0) + expect(store.tables[0].views).to.have.length(0) + }) + }) }) diff --git a/src/store/store.js b/src/store/store.js index eea587f898..9fc1d47052 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -126,6 +126,12 @@ export const useTablesStore = defineStore('store', { if (index !== -1) { this.views[index] = view } + + const tableViews = this.tables.find(t => t.id === view.tableId)?.views + const tableIndex = tableViews?.findIndex(v => v.id === view.id) ?? -1 + if (tableIndex !== -1) { + tableViews[tableIndex] = view + } }, setContext(context) { const index = this.contexts.findIndex(c => c.id === context.id) @@ -262,6 +268,11 @@ export const useTablesStore = defineStore('store', { const views = this.views const index = views.findIndex(v => v.id === viewId) if (index !== -1) { + const tableViews = this.tables.find(t => t.id === views[index].tableId)?.views + const tableIndex = tableViews?.findIndex(v => v.id === viewId) ?? -1 + if (tableIndex !== -1) { + tableViews.splice(tableIndex, 1) + } views.splice(index, 1) } this.setViews([...views])