Skip to content

Commit 032a18b

Browse files
committed
KNOWAGE-9921
- persist ID through saving the dashboard, do not re-generate when opening the dashboard again
1 parent f8a790b commit 032a18b

2 files changed

Lines changed: 30 additions & 22 deletions

File tree

src/modules/documentExecution/dashboard/widget/WidgetEditor/helpers/tableWidget/TableWidgetBackendSaveHelper.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
1-
import { ITableWidgetColumnGroups, ITableWidgetConditionalStyles, ITableWidgetConfiguration, IWidgetCrossNavigation, ITableWidgetHeaders, IWidgetInteractions, IWidgetSelection, ITableWidgetSettings, ITableWidgetVisualization, IWidget, IWidgetColumn, ITableWidgetTooltipStyle, ITableWidgetColumnStyles } from '../../../../Dashboard'
2-
3-
const columnIdNameMap = {}
1+
import { ITableWidgetColumnGroups, ITableWidgetConditionalStyles, ITableWidgetConfiguration, IWidgetCrossNavigation, ITableWidgetHeaders, IWidgetInteractions, IWidgetSelection, ITableWidgetSettings, ITableWidgetVisualization, IWidget, ITableWidgetTooltipStyle, ITableWidgetColumnStyles } from '../../../../Dashboard'
42

53
export function formatTableWidgetForSave(widget: IWidget) {
64
if (!widget) return
75

8-
loadColumnIdNameMap(widget)
9-
formatTableSelectedColumns(widget.columns)
6+
// Per-column settings (styles, precision, alignment, visualization types, tooltips,
7+
// column groups, header rules, sorting, selection, cross navigation) are persisted
8+
// using the column's stable `id`, NOT its physical field name (`columnName`).
9+
//
10+
// The id is what keeps two columns built from the SAME field distinct — e.g. the same
11+
// UNIT_SALES field used as two measures with different aggregations/aliases. Collapsing
12+
// targets to columnName merged those columns together on reload, so styles were shared
13+
// and one alias overwrote the other. We therefore keep `column.id` on the saved model
14+
// (see addColumnIdsToWidgetColumns / formatDashboardTableWidgetAfterLoading on load).
1015
formatTableSettings(widget.settings)
1116
}
1217

13-
function formatTableSelectedColumns(columns: IWidgetColumn[]) {
14-
if (!columns) return
15-
columns.forEach((column: IWidgetColumn) => {
16-
delete column.id
17-
})
18-
}
19-
20-
const loadColumnIdNameMap = (widget: IWidget) => {
21-
widget.columns?.forEach((column: IWidgetColumn) => {
22-
if (column.id) columnIdNameMap[column.id] = column.columnName
23-
})
24-
}
25-
18+
// Targets already reference the column `id` in the in-memory model, so persistence is an
19+
// identity mapping. Kept as a single indirection point so the save/load token format stays
20+
// symmetric with getColumnId() in TableWidgetFunctions.ts.
2621
const getColumnName = (columnId: string) => {
27-
return columnId ? columnIdNameMap[columnId] : ''
22+
return columnId || ''
2823
}
2924

3025
const formatTableSettings = (widgetSettings: ITableWidgetSettings) => {

src/modules/documentExecution/dashboard/widget/WidgetEditor/helpers/tableWidget/TableWidgetFunctions.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ export const removeColumnGroupFromModel = (widgetModel: IWidget, columnGroup: IT
115115

116116
export default removeColumnFromTableWidgetModel
117117

118+
// Legacy fallback map: dashboards saved before per-column settings were persisted by `id`
119+
// stored their targets as `columnName`. That key is not unique when the same field is reused,
120+
// which is exactly the bug this replaces — so it is only consulted for tokens that are not
121+
// already ids. Reset per widget because it is module-level and must not leak between widgets.
118122
const columnNameIdMap = {}
123+
const columnIdSet = new Set<string>()
119124

120125
export function formatDashboardTableWidgetAfterLoading(widget: IWidget) {
121126
if (!widget) return
@@ -125,13 +130,21 @@ export function formatDashboardTableWidgetAfterLoading(widget: IWidget) {
125130
}
126131

127132
const loadColumnNameIdMap = (widget: IWidget) => {
133+
for (const key in columnNameIdMap) delete columnNameIdMap[key]
134+
columnIdSet.clear()
128135
widget.columns?.forEach((column: IWidgetColumn) => {
129-
if (column.columnName) columnNameIdMap[column.columnName] = column.id
136+
if (column.id) columnIdSet.add(column.id)
137+
// First occurrence wins: duplicate columnNames were already ambiguous in the legacy format.
138+
if (column.columnName && columnNameIdMap[column.columnName] === undefined) columnNameIdMap[column.columnName] = column.id
130139
})
131140
}
132141

133-
const getColumnId = (columnName: string) => {
134-
return columnName ? columnNameIdMap[columnName] : ''
142+
const getColumnId = (token: string) => {
143+
if (!token) return ''
144+
// Current format: the token is already the column's stable id.
145+
if (columnIdSet.has(token)) return token
146+
// Legacy format: the token is a columnName that needs mapping to an id.
147+
return columnNameIdMap[token] ?? ''
135148
}
136149

137150
const formatTableSettings = (widgetSettings: ITableWidgetSettings) => {

0 commit comments

Comments
 (0)