diff --git a/CHANGELOG.md b/CHANGELOG.md index 16d7dc17..e79a57f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to the **kdb VS Code extension** are documented in this file. +# v1.9.0 + +### Enhancements + +### Fixes + +- Fix for results tab flickering , improving of UX +- Fix for Issue [#382](https://github.com/KxSystems/kx-vscode/issues/382) + # v1.8.0 ### Enhancements diff --git a/package.json b/package.json index 8b958450..d5e669de 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "kdb", "description": "IDE support for kdb product suite including the q programming language", "publisher": "KX", - "version": "1.8.0", + "version": "1.9.0", "engines": { "vscode": "^1.86.0" }, diff --git a/src/services/resultsPanelProvider.ts b/src/services/resultsPanelProvider.ts index 31dcf05a..145584c7 100644 --- a/src/services/resultsPanelProvider.ts +++ b/src/services/resultsPanelProvider.ts @@ -174,26 +174,52 @@ export class KdbResultsViewProvider implements WebviewViewProvider { convertToGrid(results: any, isInsights: boolean): any { const queryResult = isInsights ? results.rows : results; - const columnDefs = this.generateCoumnDefs(results, isInsights); let rowData = []; - if (!isInsights && typeof results[0] === "string") { - rowData = []; + let columnDefs = []; + + if (Array.isArray(queryResult[0])) { + if (typeof queryResult[0][0] === "object") { + rowData = queryResult[0].map((_, index) => { + const row: any = {}; + queryResult.forEach((subArray: any[]) => { + Object.assign(row, subArray[index]); + }); + return row; + }); + } else { + rowData = queryResult.map((element: any) => ({ value: element })); + } + } else { + rowData = queryResult; + } + + if (isInsights) { + results.rows = rowData; + columnDefs = this.generateCoumnDefs(results, isInsights); } else { - rowData = queryResult.map((row: any) => { - for (const key in row) { - if (Object.prototype.hasOwnProperty.call(row, key)) { - row[key] = - row[key] !== undefined && row[key] !== null - ? this.sanitizeString(row[key]) - : ""; - } - } - return row; + columnDefs = this.generateCoumnDefs(rowData, isInsights); + } + + if ( + !columnDefs.some( + (col: any) => col.field.toString().toLowerCase() === "index", + ) + ) { + rowData = rowData.map((row: any, index: any) => ({ + index: index + 1, + ...row, + })); + columnDefs.unshift({ + field: "index", + headerName: "Index", + cellDataType: "number", }); } + if (rowData.length > 0) { ext.resultPanelCSV = this.convertToCsv(rowData).join("\n"); } + return { defaultColDef: { sortable: true, @@ -202,8 +228,8 @@ export class KdbResultsViewProvider implements WebviewViewProvider { flex: 1, minWidth: 100, }, - rowData, - columnDefs, + rowData: rowData, + columnDefs: columnDefs, domLayout: "autoHeight", pagination: true, paginationPageSize: 100, @@ -212,6 +238,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { suppressContextMenu: true, suppressDragLeaveHidesColumns: true, tooltipShowDelay: 200, + loading: true, }; } @@ -304,7 +331,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { "ag-grid-community.min.js", )}"> - +
@@ -321,7 +348,7 @@ export class KdbResultsViewProvider implements WebviewViewProvider { function restoreColumnWidths(columnWidths) { if (!gridApi || !columnWidths) return; - gridApi.applyColumnState({state: columnWidths}); + gridApi.applyColumnState({state: columnWidths, applyOrder: true,}); } window.addEventListener('message', event => { @@ -333,8 +360,14 @@ export class KdbResultsViewProvider implements WebviewViewProvider { const resultsDiv = document.querySelector('#results .content-wrapper'); resultsDiv.innerHTML = ''; gridDiv.innerHTML = ''; + const rowData = gridOptions.rowData; + gridOptions.rowData = []; gridApi = agGrid.createGrid(gridDiv, gridOptions); restoreColumnWidths(columnWidths); + setTimeout(() => { + gridApi.setGridOption("rowData", rowData); + gridApi.setGridOption("loading", false); + }, 500); document.getElementById("results").scrollIntoView(); } else if (message.command === 'setResultsContent') { const resultsContent = message.results; diff --git a/test/suite/panels.test.ts b/test/suite/panels.test.ts index fe9d4e20..20d6196f 100644 --- a/test/suite/panels.test.ts +++ b/test/suite/panels.test.ts @@ -178,7 +178,7 @@ describe("WebPanels", () => { }); describe("convertToGrid()", () => { - it("should convert results to grid format for inisights", () => { + it("should convert results to grid format for insights", () => { const results = { rows: [ { prop1: "value1", prop2: "value2" }, @@ -196,10 +196,11 @@ describe("WebPanels", () => { minWidth: 100, }, rowData: [ - { prop1: "value1", prop2: "value2" }, - { prop1: "value3", prop2: "value4" }, + { index: 1, prop1: "value1", prop2: "value2" }, + { index: 2, prop1: "value3", prop2: "value4" }, ], columnDefs: [ + { field: "index", headerName: "Index", cellDataType: "number" }, { field: "prop1", headerName: "prop1", @@ -221,6 +222,7 @@ describe("WebPanels", () => { suppressContextMenu: true, suppressDragLeaveHidesColumns: true, tooltipShowDelay: 200, + loading: true, }); // Mock ext.connectionNode @@ -234,7 +236,7 @@ describe("WebPanels", () => { stub.restore(); }); - it("should convert results to grid format with empty rows ", () => { + it("should convert results to grid format with empty rows", () => { const results = { rows: [], meta: { prop1: "type1", prop2: "type2" }, @@ -250,6 +252,7 @@ describe("WebPanels", () => { }, rowData: [], columnDefs: [ + { field: "index", headerName: "Index", cellDataType: "number" }, { field: "prop1", headerName: "prop1", @@ -271,6 +274,112 @@ describe("WebPanels", () => { suppressContextMenu: true, suppressDragLeaveHidesColumns: true, tooltipShowDelay: 200, + loading: true, + }); + + // Mock ext.connectionNode + const stub = sinon.stub(ext, "activeConnection"); + stub.get(() => insightsConn); + + const output = resultsPanel.convertToGrid(results, true); + assert.equal(JSON.stringify(output), expectedOutput); + + // Restore the stub + stub.restore(); + }); + + it("should convert results to grid format when queryResult[0] is an array of objects", () => { + const results = { + rows: [ + [{ sym: "a" }, { sym: "b" }, { sym: "c" }], + [{ val: 1 }, { val: 2 }, { val: 3 }], + ], + meta: { sym: "type1", val: "type2" }, + }; + + const expectedOutput = JSON.stringify({ + defaultColDef: { + sortable: true, + resizable: true, + filter: true, + flex: 1, + minWidth: 100, + }, + rowData: [ + { index: 1, sym: "a", val: 1 }, + { index: 2, sym: "b", val: 2 }, + { index: 3, sym: "c", val: 3 }, + ], + columnDefs: [ + { field: "index", headerName: "Index", cellDataType: "number" }, + { + field: "sym", + headerName: "sym", + headerTooltip: "type1", + cellDataType: "text", + }, + { + field: "val", + headerName: "val", + headerTooltip: "type2", + cellDataType: "text", + }, + ], + domLayout: "autoHeight", + pagination: true, + paginationPageSize: 100, + enableCellTextSelection: true, + ensureDomOrder: true, + suppressContextMenu: true, + suppressDragLeaveHidesColumns: true, + tooltipShowDelay: 200, + loading: true, + }); + + // Mock ext.connectionNode + const stub = sinon.stub(ext, "activeConnection"); + stub.get(() => insightsConn); + + const output = resultsPanel.convertToGrid(results, true); + assert.equal(JSON.stringify(output), expectedOutput); + + // Restore the stub + stub.restore(); + }); + + it("should convert results to grid format when queryResult[0] is an array of non-objects", () => { + const results = { + rows: [[1, 2, 3]], + meta: { value: "type1" }, + }; + + const expectedOutput = JSON.stringify({ + defaultColDef: { + sortable: true, + resizable: true, + filter: true, + flex: 1, + minWidth: 100, + }, + rowData: [{ index: 1, value: [1, 2, 3] }], + columnDefs: [ + { field: "index", headerName: "Index", cellDataType: "number" }, + { + field: "value", + headerName: "value", + headerTooltip: "type1", + cellDataType: "text", + }, + ], + domLayout: "autoHeight", + pagination: true, + paginationPageSize: 100, + enableCellTextSelection: true, + ensureDomOrder: true, + suppressContextMenu: true, + suppressDragLeaveHidesColumns: true, + tooltipShowDelay: 200, + loading: true, }); // Mock ext.connectionNode