diff --git a/package-lock.json b/package-lock.json index 4e36204f..e6236a62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@vscode/webview-ui-toolkit": "^1.4.0", "@windozer/node-q": "^2.6.0", "ag-grid-community": "^31.3.1", - "axios": "^1.7.0", + "axios": "^1.7.2", "chevrotain": "^10.5.0", "csv-parser": "^3.0.0", "extract-zip": "^2.0.1", @@ -1670,9 +1670,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.0.tgz", - "integrity": "sha512-IiB0wQeKyPRdsFVhBgIo31FbzOyf2M6wYl7/NVutFwFBRMiAbjNiydJIHKeLmPugF4kJLfA1uWZ82Is2QzqqFA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index 58c6fc73..eadb4f7c 100644 --- a/package.json +++ b/package.json @@ -276,6 +276,11 @@ "command": "kdb.connect", "title": "Connect server" }, + { + "category": "KX", + "command": "kdb.connect.via.dialog", + "title": "Connect server" + }, { "category": "KX", "command": "kdb.active.connection", @@ -292,11 +297,6 @@ "command": "kdb.enableTLS", "title": "Enable TLS" }, - { - "category": "KX", - "command": "kdb.insightsConnect", - "title": "Connect to Insights" - }, { "category": "KX", "command": "kdb.insightsRemove", @@ -521,10 +521,6 @@ ], "menus": { "commandPalette": [ - { - "command": "kdb.insightsConnect", - "when": "false" - }, { "command": "kdb.insightsRemove", "when": "false" @@ -549,6 +545,10 @@ "command": "kdb.connect", "when": "false" }, + { + "command": "kdb.connect.via.dialog", + "when": "false" + }, { "command": "kdb.active.connection", "when": "false" @@ -634,7 +634,7 @@ "view/item/context": [ { "command": "kdb.connect", - "when": "view == kdb-servers && viewItem not in kdb.connected && viewItem in kdb.rootNodes", + "when": "view == kdb-servers && viewItem not in kdb.connected", "group": "connection@1" }, { @@ -652,11 +652,6 @@ "when": "view == kdb-servers && viewItem not in kdb.insightsNodes && viewItem in kdb.kdbNodesWithoutTls && viewItem not in kdb.local", "group": "connection@4" }, - { - "command": "kdb.insightsConnect", - "when": "view == kdb-servers && viewItem not in kdb.connected && viewItem in kdb.insightsNodes", - "group": "connection@0" - }, { "command": "kdb.insightsRemove", "when": "view == kdb-servers && viewItem in kdb.insightsNodes", @@ -837,7 +832,7 @@ "@vscode/webview-ui-toolkit": "^1.4.0", "@windozer/node-q": "^2.6.0", "ag-grid-community": "^31.3.1", - "axios": "^1.7.0", + "axios": "^1.7.2", "chevrotain": "^10.5.0", "csv-parser": "^3.0.0", "extract-zip": "^2.0.1", diff --git a/src/commands/dataSourceCommand.ts b/src/commands/dataSourceCommand.ts index ce5275b7..24196eae 100644 --- a/src/commands/dataSourceCommand.ts +++ b/src/commands/dataSourceCommand.ts @@ -45,6 +45,7 @@ import { Telemetry } from "../utils/telemetryClient"; import { LocalConnection } from "../classes/localConnection"; import { ConnectionManagementService } from "../services/connectionManagerService"; import { InsightsConnection } from "../classes/insightsConnection"; +import { offerConnectAction } from "../utils/core"; export async function addDataSource(): Promise { const kdbDataSourcesFolderPath = createKdbDataSourcesFolder(); @@ -92,7 +93,7 @@ export async function populateScratchpad( selectedConnection instanceof LocalConnection || !selectedConnection ) { - window.showErrorMessage("No Insights active connection found"); + offerConnectAction(connLabel); DataSourcesPanel.running = false; return; } @@ -123,7 +124,8 @@ export async function runDataSource( try { if (selectedConnection instanceof LocalConnection || !selectedConnection) { - throw new Error("The selected Insights Connection is not connected"); + offerConnectAction(connLabel); + return; } selectedConnection.getMeta(); if (!selectedConnection?.meta?.payload.assembly) { diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index 274e65b7..6a928b7e 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -258,13 +258,14 @@ export async function removeConnection(viewItem: KdbNode | InsightsNode) { await connMngService.removeConnection(viewItem); } -export async function connect(viewItem: KdbNode | InsightsNode): Promise { +export async function connect(connLabel: string): Promise { const connMngService = new ConnectionManagementService(); commands.executeCommand("kdb-results.focus"); ExecutionConsole.start(); - // handle cleaning up existing connection - if (ext.activeConnection !== undefined) { - DataSourcesPanel.close(); + const viewItem = connMngService.retrieveConnection(connLabel); + if (viewItem === undefined) { + window.showErrorMessage("Connection not found"); + return; } const isKdbNode = viewItem instanceof KdbNode; @@ -334,7 +335,7 @@ export async function executeQuery( if (connLabel === "") { if (ext.activeConnection === undefined) { window.showErrorMessage( - "No active connection founded. Connect to one connection.", + "No active connection found. Connect to one connection.", ); //TODO ADD ERROR TO CONSOLE HERE return undefined; diff --git a/src/commands/workspaceCommand.ts b/src/commands/workspaceCommand.ts index 8c96e662..609ce94d 100644 --- a/src/commands/workspaceCommand.ts +++ b/src/commands/workspaceCommand.ts @@ -32,6 +32,7 @@ import { InsightsNode, KdbNode } from "../services/kdbTreeProvider"; import { runQuery } from "./serverCommand"; import { ExecutionTypes } from "../models/execution"; import { importOldDsFiles, oldFilesExists } from "../utils/dataSource"; +import { offerConnectAction } from "../utils/core"; const connectionService = new ConnectionManagementService(); @@ -228,6 +229,7 @@ export async function activateConnectionForServer(server: string) { /* istanbul ignore next */ export async function runActiveEditor(type?: ExecutionTypes) { if (ext.activeTextEditor) { + const connMngService = new ConnectionManagementService(); const uri = ext.activeTextEditor.document.uri; const isWorkbook = uri.path.endsWith(".kdb.q"); @@ -238,6 +240,10 @@ export async function runActiveEditor(type?: ExecutionTypes) { if (!server) { server = ""; } + if (!connMngService.isConnected(server) && isScratchpad(uri)) { + offerConnectAction(server); + return; + } const executorName = ext.activeTextEditor.document.fileName .split("/") .pop(); diff --git a/src/extension.ts b/src/extension.ts index 1120b4fc..29c92ef8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -185,9 +185,18 @@ export async function activate(context: ExtensionContext) { commands.registerCommand("kdb.datasource.import.ds", async () => { await importOldDSFiles(); }), - commands.registerCommand("kdb.connect", async (viewItem: KdbNode) => { - await connect(viewItem); - }), + commands.registerCommand( + "kdb.connect", + async (viewItem: KdbNode | InsightsNode) => { + await connect(viewItem.label); + }, + ), + commands.registerCommand( + "kdb.connect.via.dialog", + async (connLabel: string) => { + await connect(connLabel); + }, + ), commands.registerCommand( "kdb.active.connection", async (viewItem: KdbNode) => { @@ -197,12 +206,6 @@ export async function activate(context: ExtensionContext) { commands.registerCommand("kdb.enableTLS", async (viewItem: KdbNode) => { await enableTLS(viewItem.children[0]); }), - commands.registerCommand( - "kdb.insightsConnect", - async (viewItem: InsightsNode) => { - await connect(viewItem); - }, - ), commands.registerCommand( "kdb.insightsRemove", async (viewItem: InsightsNode) => { diff --git a/src/services/connectionManagerService.ts b/src/services/connectionManagerService.ts index d5b7f40f..0d326b9f 100644 --- a/src/services/connectionManagerService.ts +++ b/src/services/connectionManagerService.ts @@ -329,7 +329,7 @@ export class ConnectionManagementService { } } - public async refreshGetMetas(): Promise { + public async refreshAllGetMetas(): Promise { if (ext.connectedConnectionList.length > 0) { const promises = ext.connectedConnectionList.map(async (connection) => { if (connection instanceof InsightsConnection) { @@ -339,4 +339,11 @@ export class ConnectionManagementService { await Promise.all(promises); } } + + public async refreshGetMeta(connLabel: string): Promise { + const connection = this.retrieveConnectedConnection(connLabel); + if (connection instanceof InsightsConnection) { + await connection.getMeta(); + } + } } diff --git a/src/services/dataSourceEditorProvider.ts b/src/services/dataSourceEditorProvider.ts index 42bcaf80..90caa2d8 100644 --- a/src/services/dataSourceEditorProvider.ts +++ b/src/services/dataSourceEditorProvider.ts @@ -40,6 +40,7 @@ import { import { InsightsConnection } from "../classes/insightsConnection"; import { MetaObjectPayload } from "../models/meta"; import { ConnectionManagementService } from "./connectionManagerService"; +import { offerConnectAction } from "../utils/core"; export class DataSourceEditorProvider implements CustomTextEditorProvider { public filenname = ""; @@ -134,6 +135,7 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { changeDocumentSubscription.dispose(); }); + /* istanbul ignore next */ webview.onDidReceiveMessage(async (msg: DataSourceMessage2) => { switch (msg.command) { case DataSourceCommand.Server: @@ -156,8 +158,12 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider { break; case DataSourceCommand.Refresh: const connMngService = new ConnectionManagementService(); - await connMngService.refreshGetMetas(); const selectedServer = getServerForUri(document.uri) || ""; + if (!connMngService.isConnected(selectedServer)) { + offerConnectAction(selectedServer); + break; + } + await connMngService.refreshGetMeta(selectedServer); this.cache.delete(selectedServer); updateWebview(); break; diff --git a/src/utils/core.ts b/src/utils/core.ts index 80248166..3f2866cb 100644 --- a/src/utils/core.ts +++ b/src/utils/core.ts @@ -250,6 +250,21 @@ export function getServerAlias(serverList: ServerDetails[]): void { }); } +/* istanbul ignore next */ +export function offerConnectAction(connLabel: string): void { + window + .showInformationMessage( + `You aren't connected to ${connLabel}, would you like to connect?`, + "Connect", + "Cancel", + ) + .then(async (result) => { + if (result === "Connect") { + await commands.executeCommand("kdb.connect.via.dialog", connLabel); + } + }); +} + export function getInsightsAlias(insightsList: InsightDetails[]): void { insightsList.forEach((x) => { ext.kdbConnectionAliasList.push(x.alias); diff --git a/test/suite/commands.test.ts b/test/suite/commands.test.ts index fa310e8d..900b7cfe 100644 --- a/test/suite/commands.test.ts +++ b/test/suite/commands.test.ts @@ -1729,6 +1729,28 @@ describe("serverCommand", () => { assert.ok(updateServersStub.notCalled); }).timeout(5000); }); + + describe("connect", () => { + const connService = new ConnectionManagementService(); + const _console = vscode.window.createOutputChannel("q Console Output"); + const executionConsole = new ExecutionConsole(_console); + let windowErrorStub, retrieveConnectionStub: sinon.SinonStub; + + beforeEach(() => { + windowErrorStub = sinon.stub(vscode.window, "showErrorMessage"); + retrieveConnectionStub = sinon.stub(connService, "retrieveConnection"); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should show error message if connection not found", async () => { + retrieveConnectionStub.returns(undefined); + await serverCommand.connect("test"); + windowErrorStub.calledOnce; + }); + }); }); describe("walkthroughCommand", () => { diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts index eb03773e..6a41fda8 100644 --- a/test/suite/services.test.ts +++ b/test/suite/services.test.ts @@ -1053,7 +1053,7 @@ describe("connectionManagerService", () => { }); }); - describe("refreshGetMetas", () => { + describe("refreshAllGetMetas && refreshGetMeta", () => { let getMetaStub: sinon.SinonStub; beforeEach(() => { getMetaStub = sinon.stub(insightsConn, "getMeta"); @@ -1063,14 +1063,24 @@ describe("connectionManagerService", () => { ext.connectedConnectionList.length = 0; }); - it("Should not refresh getMetas if connection is not InsightsConnection", async () => { - await connectionManagerService.refreshGetMetas(); + it("Should not refreshAllgetMetas if connection is not InsightsConnection", async () => { + await connectionManagerService.refreshAllGetMetas(); sinon.assert.notCalled(getMetaStub); }); - it("Should refresh getMetas if connection is InsightsConnection", async () => { + it("Should refreshAllgetMetas if connection is InsightsConnection", async () => { ext.connectedConnectionList.push(insightsConn); - await connectionManagerService.refreshGetMetas(); + await connectionManagerService.refreshAllGetMetas(); + sinon.assert.calledOnce(getMetaStub); + }); + it("Should not refreshGetMeta if connection is not InsightsConnection", async () => { + await connectionManagerService.refreshGetMeta("test"); + sinon.assert.notCalled(getMetaStub); + }); + + it("Should refreshGetMeta if connection is InsightsConnection", async () => { + ext.connectedConnectionList.push(insightsConn); + await connectionManagerService.refreshGetMeta(insightsConn.connLabel); sinon.assert.calledOnce(getMetaStub); }); });