Skip to content

Commit 5a90523

Browse files
Copilottimheuer
andcommitted
Implement column sorting functionality for RESX data grid
Co-authored-by: timheuer <[email protected]>
1 parent d90d778 commit 5a90523

File tree

1 file changed

+129
-4
lines changed

1 file changed

+129
-4
lines changed

src/webview/webview.js

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ const vscode = acquireVsCodeApi();
44
provideVSCodeDesignSystem().register(vsCodeDataGrid(), vsCodeDataGridRow(), vsCodeDataGridCell(), vsCodeButton());
55
let currentRowData = null;
66

7+
// Sorting state
8+
let currentSortColumn = null;
9+
let currentSortDirection = 'asc'; // 'asc' or 'desc'
10+
711
(function () {
812

913
var addNewButton = document.getElementById("add-resource-button");
@@ -52,6 +56,107 @@ let currentRowData = null;
5256
cell.addEventListener("click", handleClickClosure);
5357
cell.addEventListener("blur", handleBlurClosure);
5458
});
59+
60+
// Add sorting functionality to column headers
61+
initColumnSorting();
62+
}
63+
64+
function initColumnSorting() {
65+
// Use MutationObserver to watch for header creation since the grid generates them dynamically
66+
const observer = new MutationObserver(() => {
67+
attachHeaderSorting();
68+
});
69+
70+
observer.observe(grid, { childList: true, subtree: true });
71+
72+
// Try to attach immediately in case headers already exist
73+
setTimeout(() => attachHeaderSorting(), 100);
74+
}
75+
76+
function attachHeaderSorting() {
77+
const headerCells = grid.querySelectorAll('[role="columnheader"]');
78+
headerCells.forEach((header, index) => {
79+
// Only attach if not already attached
80+
if (!header.hasAttribute('data-sort-attached')) {
81+
header.setAttribute('data-sort-attached', 'true');
82+
header.style.cursor = 'pointer';
83+
header.style.userSelect = 'none';
84+
85+
// Add visual indicator area
86+
if (!header.querySelector('.sort-indicator')) {
87+
const indicator = document.createElement('span');
88+
indicator.className = 'sort-indicator';
89+
indicator.style.marginLeft = '5px';
90+
indicator.style.fontSize = '12px';
91+
header.appendChild(indicator);
92+
}
93+
94+
header.addEventListener('click', (e) => {
95+
e.preventDefault();
96+
e.stopPropagation();
97+
98+
const columnKey = getColumnKeyFromHeader(header, index);
99+
if (columnKey) {
100+
sortByColumn(columnKey);
101+
}
102+
});
103+
}
104+
});
105+
}
106+
107+
function getColumnKeyFromHeader(header, index) {
108+
// Map header index to column key based on typical grid structure
109+
const columnKeys = ['Key', 'Value', 'Comment'];
110+
return columnKeys[index] || null;
111+
}
112+
113+
function sortByColumn(columnKey) {
114+
if (!grid.rowsData || grid.rowsData.length === 0) {
115+
return;
116+
}
117+
118+
// Determine sort direction
119+
if (currentSortColumn === columnKey) {
120+
currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc';
121+
} else {
122+
currentSortColumn = columnKey;
123+
currentSortDirection = 'asc';
124+
}
125+
126+
// Sort the data
127+
const sortedData = [...grid.rowsData].sort((a, b) => {
128+
const aValue = (a[columnKey] || '').toString().toLowerCase();
129+
const bValue = (b[columnKey] || '').toString().toLowerCase();
130+
131+
const comparison = aValue.localeCompare(bValue);
132+
return currentSortDirection === 'asc' ? comparison : -comparison;
133+
});
134+
135+
// Update grid data
136+
grid.rowsData = sortedData;
137+
138+
// Update visual indicators
139+
updateSortIndicators();
140+
141+
// Refresh the resx data to maintain data integrity
142+
refreshResxData();
143+
}
144+
145+
function updateSortIndicators() {
146+
const headerCells = grid.querySelectorAll('[role="columnheader"]');
147+
headerCells.forEach((header, index) => {
148+
const indicator = header.querySelector('.sort-indicator');
149+
if (indicator) {
150+
const columnKey = getColumnKeyFromHeader(header, index);
151+
if (columnKey === currentSortColumn) {
152+
indicator.textContent = currentSortDirection === 'asc' ? '▲' : '▼';
153+
indicator.style.opacity = '1';
154+
} else {
155+
indicator.textContent = '';
156+
indicator.style.opacity = '0.3';
157+
}
158+
}
159+
});
55160
}
56161

57162
// Handle keyboard events on a given cell
@@ -121,7 +226,13 @@ let currentRowData = null;
121226
const index = grid.rowsData.indexOf(currentRowData);
122227
if (index > -1) {
123228
grid.rowsData.splice(index, 1);
124-
refreshResxData();
229+
230+
// Apply current sorting if any
231+
if (currentSortColumn) {
232+
sortByColumn(currentSortColumn);
233+
} else {
234+
refreshResxData();
235+
}
125236
}
126237
}
127238
else {
@@ -141,9 +252,15 @@ let currentRowData = null;
141252
}
142253
// eslint-disable-next-line @typescript-eslint/naming-convention
143254
grid.rowsData.push({ Key: message.key, Value: message.value, Comment: message.comment });
144-
refreshResxData();
145-
// Force grid to update by reassigning the rowsData
146-
grid.rowsData = [...grid.rowsData];
255+
256+
// Apply current sorting if any
257+
if (currentSortColumn) {
258+
sortByColumn(currentSortColumn);
259+
} else {
260+
refreshResxData();
261+
// Force grid to update by reassigning the rowsData
262+
grid.rowsData = [...grid.rowsData];
263+
}
147264
}
148265
else {
149266
// create vscode notification
@@ -215,6 +332,14 @@ let currentRowData = null;
215332
}
216333

217334
grid.rowsData = resxValues;
335+
336+
// Apply current sorting if any
337+
if (currentSortColumn) {
338+
sortByColumn(currentSortColumn);
339+
} else {
340+
// Ensure sort indicators are updated even without sorting
341+
setTimeout(() => updateSortIndicators(), 100);
342+
}
218343
}
219344

220345
const state = vscode.getState();

0 commit comments

Comments
 (0)