diff --git a/package.json b/package.json
index 98954665..065330d2 100644
--- a/package.json
+++ b/package.json
@@ -416,6 +416,21 @@
"category": "KX",
"command": "kdb.toggleParameterCache",
"title": "KX: Toggle parameter cache"
+ },
+ {
+ "category": "KX",
+ "command": "kdb.renameLabel",
+ "title": "Rename label"
+ },
+ {
+ "category": "KX",
+ "command": "kdb.editLabelColor",
+ "title": "Edit label color"
+ },
+ {
+ "category": "KX",
+ "command": "kdb.deleteLabel",
+ "title": "Delete label"
}
],
"keybindings": [
@@ -692,7 +707,7 @@
},
{
"command": "kdb.editConnection",
- "when": "view == kdb-servers",
+ "when": "view == kdb-servers && (viewItem in kdb.rootNodes || viewItem in kdb.insightsNodes)",
"group": "connection@4"
},
{
@@ -754,6 +769,21 @@
"command": "kdb.deleteFile",
"when": "(view == kdb-datasource-explorer || view == kdb-scratchpad-explorer) && viewItem == artifact",
"group": "kdbWorkspace@2"
+ },
+ {
+ "command": "kdb.renameLabel",
+ "when": "view == kdb-servers && viewItem == label",
+ "group": "label@1"
+ },
+ {
+ "command": "kdb.editLabelColor",
+ "when": "view == kdb-servers && viewItem == label",
+ "group": "label@2"
+ },
+ {
+ "command": "kdb.deleteLabel",
+ "when": "view == kdb-servers && viewItem == label",
+ "group": "label@3"
}
],
"editor/title/run": [
diff --git a/resources/dark/labels/label-blue.svg b/resources/dark/labels/label-blue.svg
new file mode 100644
index 00000000..75d121a1
--- /dev/null
+++ b/resources/dark/labels/label-blue.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/dark/labels/label-cyan.svg b/resources/dark/labels/label-cyan.svg
new file mode 100644
index 00000000..4c007822
--- /dev/null
+++ b/resources/dark/labels/label-cyan.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/dark/labels/label-green.svg b/resources/dark/labels/label-green.svg
new file mode 100644
index 00000000..0871bbe6
--- /dev/null
+++ b/resources/dark/labels/label-green.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/dark/labels/label-magenta.svg b/resources/dark/labels/label-magenta.svg
new file mode 100644
index 00000000..8c351912
--- /dev/null
+++ b/resources/dark/labels/label-magenta.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/dark/labels/label-red.svg b/resources/dark/labels/label-red.svg
new file mode 100644
index 00000000..f1ea352c
--- /dev/null
+++ b/resources/dark/labels/label-red.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/dark/labels/label-white.svg b/resources/dark/labels/label-white.svg
new file mode 100644
index 00000000..bc052168
--- /dev/null
+++ b/resources/dark/labels/label-white.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/resources/dark/labels/label-yellow.svg b/resources/dark/labels/label-yellow.svg
new file mode 100644
index 00000000..b3ba5b22
--- /dev/null
+++ b/resources/dark/labels/label-yellow.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-blue.svg b/resources/light/labels/label-blue.svg
new file mode 100644
index 00000000..411c4ed1
--- /dev/null
+++ b/resources/light/labels/label-blue.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-cyan.svg b/resources/light/labels/label-cyan.svg
new file mode 100644
index 00000000..f4630608
--- /dev/null
+++ b/resources/light/labels/label-cyan.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-green.svg b/resources/light/labels/label-green.svg
new file mode 100644
index 00000000..a8da7eab
--- /dev/null
+++ b/resources/light/labels/label-green.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-magenta.svg b/resources/light/labels/label-magenta.svg
new file mode 100644
index 00000000..e0f47686
--- /dev/null
+++ b/resources/light/labels/label-magenta.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-red.svg b/resources/light/labels/label-red.svg
new file mode 100644
index 00000000..f1ea352c
--- /dev/null
+++ b/resources/light/labels/label-red.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/light/labels/label-white.svg b/resources/light/labels/label-white.svg
new file mode 100644
index 00000000..bc052168
--- /dev/null
+++ b/resources/light/labels/label-white.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/resources/light/labels/label-yellow.svg b/resources/light/labels/label-yellow.svg
new file mode 100644
index 00000000..c7b3ae6b
--- /dev/null
+++ b/resources/light/labels/label-yellow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/commands/workspaceCommand.ts b/src/commands/workspaceCommand.ts
index c182ba77..4b739f94 100644
--- a/src/commands/workspaceCommand.ts
+++ b/src/commands/workspaceCommand.ts
@@ -28,7 +28,7 @@ import {
} from "vscode";
import { ext } from "../extensionVariables";
import { ConnectionManagementService } from "../services/connectionManagerService";
-import { InsightsNode, KdbNode } from "../services/kdbTreeProvider";
+import { InsightsNode, KdbNode, LabelNode } from "../services/kdbTreeProvider";
import { runQuery } from "./serverCommand";
import { ExecutionTypes } from "../models/execution";
import { importOldDsFiles, oldFilesExists } from "../utils/dataSource";
@@ -96,17 +96,37 @@ function getServers() {
}
/* istanbul ignore next */
-export async function getConnectionForServer(server: string) {
+export async function getConnectionForServer(
+ server: string,
+): Promise {
if (server) {
- const servers = await ext.serverProvider.getChildren();
- return servers.find((item) => {
- if (item instanceof InsightsNode) {
- return item.details.alias === server;
- } else if (item instanceof KdbNode) {
- return item.details.serverAlias === server;
+ const nodes = await ext.serverProvider.getChildren();
+ const orphan = nodes.find((node) => {
+ if (node instanceof InsightsNode) {
+ return node.details.alias === server;
+ } else if (node instanceof KdbNode) {
+ return node.details.serverAlias === server;
}
return false;
- }) as KdbNode | InsightsNode;
+ }) as InsightsNode | KdbNode;
+ if (orphan) {
+ return orphan;
+ }
+ const labels = nodes.filter((server) => server instanceof LabelNode);
+ for (const label of labels) {
+ const item = (label as LabelNode).children.find((node) => {
+ const name =
+ node instanceof InsightsNode
+ ? node.details.alias
+ : node instanceof KdbNode
+ ? node.details.serverAlias
+ : "";
+ return name === server;
+ }) as InsightsNode | KdbNode;
+ if (item) {
+ return item;
+ }
+ }
}
}
diff --git a/src/extension.ts b/src/extension.ts
index 13e4e964..e0bcd150 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -106,8 +106,11 @@ import { QuickFixProvider } from "./services/quickFixProvider";
import { connectClientCommands } from "./commands/clientCommands";
import {
createNewLabel,
+ deleteLabel,
getWorkspaceLabels,
getWorkspaceLabelsConnMap,
+ renameLabel,
+ setLabelColor,
} from "./utils/connLabel";
let client: LanguageClient;
@@ -506,6 +509,60 @@ export async function activate(context: ExtensionContext) {
ext.serverProvider.reload();
}
}),
+ commands.registerCommand("kdb.renameLabel", async (item) => {
+ if (item) {
+ const name = await window.showInputBox({
+ prompt: "Enter label name",
+ value: item.label,
+ });
+ if (name) {
+ renameLabel(item.label, name);
+ }
+ }
+ }),
+ commands.registerCommand("kdb.editLabelColor", async (item) => {
+ if (item) {
+ const colors = ext.labelColors.map((color) => ({
+ label: color.name,
+ iconPath: {
+ light: Uri.file(
+ path.join(
+ __filename,
+ "..",
+ "..",
+ "resources",
+ "light",
+ "labels",
+ `label-${color.name.toLowerCase()}.svg`,
+ ),
+ ),
+ dark: Uri.file(
+ path.join(
+ __filename,
+ "..",
+ "..",
+ "resources",
+ "dark",
+ "labels",
+ `label-${color.name.toLowerCase()}.svg`,
+ ),
+ ),
+ },
+ }));
+ const picked = await window.showQuickPick(colors, {
+ title: "Select label color",
+ placeHolder: item.source.color.name,
+ });
+ if (picked) {
+ setLabelColor(item.label, picked.label);
+ }
+ }
+ }),
+ commands.registerCommand("kdb.deleteLabel", (item) => {
+ if (item) {
+ deleteLabel(item.label);
+ }
+ }),
);
checkOldDatasourceFiles();
diff --git a/src/services/kdbTreeProvider.ts b/src/services/kdbTreeProvider.ts
index cb74b1c4..2eb52bbd 100644
--- a/src/services/kdbTreeProvider.ts
+++ b/src/services/kdbTreeProvider.ts
@@ -41,6 +41,12 @@ import {
} from "../utils/core";
import { ConnectionManagementService } from "./connectionManagerService";
import { InsightsConnection } from "../classes/insightsConnection";
+import {
+ getWorkspaceLabels,
+ getWorkspaceLabelsConnMap,
+ retrieveConnLabelsNames,
+} from "../utils/connLabel";
+import { Labels } from "../models/labels";
export class KdbTreeProvider implements TreeDataProvider {
private _onDidChangeTreeData: EventEmitter<
@@ -92,15 +98,38 @@ export class KdbTreeProvider implements TreeDataProvider {
}
async getChildren(element?: TreeItem): Promise {
- if (!this.serverList) {
- return Promise.resolve([]);
- }
- if (!this.insightsList) {
- return Promise.resolve([]);
+ if (!this.serverList || !this.insightsList) {
+ return [];
}
if (!element) {
- return Promise.resolve(this.getMergedElements(element));
+ getWorkspaceLabels();
+ getWorkspaceLabelsConnMap();
+
+ const orphans: TreeItem[] = [];
+ const nodes = ext.connLabelList.map((label) => new LabelNode(label));
+ const items = this.getMergedElements(element);
+
+ let orphan, found;
+ for (const item of items) {
+ orphan = true;
+ if (item instanceof KdbNode || item instanceof InsightsNode) {
+ const labels = retrieveConnLabelsNames(item);
+ for (const label of labels) {
+ found = nodes.find((node) => label === node.source.name);
+ if (found) {
+ found.children.push(item);
+ orphan = false;
+ }
+ }
+ }
+ if (orphan) {
+ orphans.push(item);
+ }
+ }
+ return [...orphans, ...nodes];
+ } else if (element instanceof LabelNode) {
+ return element.children;
} else if (
element.contextValue !== undefined &&
ext.kdbrootNodes.indexOf(element.contextValue) !== -1
@@ -785,3 +814,33 @@ export class QServerNode extends TreeItem {
};
contextValue = this.label;
}
+
+export class LabelNode extends TreeItem {
+ readonly children: TreeItem[] = [];
+
+ constructor(public readonly source: Labels) {
+ super(source.name, TreeItemCollapsibleState.Collapsed);
+ this.contextValue = "label";
+ }
+
+ iconPath = {
+ light: path.join(
+ __filename,
+ "..",
+ "..",
+ "resources",
+ "light",
+ "labels",
+ `label-${this.source.color.name.toLowerCase()}.svg`,
+ ),
+ dark: path.join(
+ __filename,
+ "..",
+ "..",
+ "resources",
+ "dark",
+ "labels",
+ `label-${this.source.color.name.toLowerCase()}.svg`,
+ ),
+ };
+}
diff --git a/src/utils/connLabel.ts b/src/utils/connLabel.ts
index 76b293bc..5907b1d2 100644
--- a/src/utils/connLabel.ts
+++ b/src/utils/connLabel.ts
@@ -124,3 +124,49 @@ export function retrieveConnLabelsNames(
});
return labels;
}
+
+export function renameLabel(name: string, newName: string) {
+ getWorkspaceLabels();
+ const found = ext.connLabelList.find((item) => item.name === name);
+ if (found) {
+ found.name = newName;
+ }
+ getWorkspaceLabelsConnMap();
+ const target = ext.labelConnMapList.find((item) => item.labelName === name);
+ if (target) {
+ target.labelName = newName;
+ }
+ workspace
+ .getConfiguration()
+ .update("kdb.labelsConnectionMap", ext.labelConnMapList, true)
+ .then(() =>
+ workspace
+ .getConfiguration()
+ .update("kdb.connectionLabels", ext.connLabelList, true),
+ );
+}
+
+export function setLabelColor(name: string, color: string) {
+ getWorkspaceLabels();
+ const found = ext.connLabelList.find((item) => item.name === name);
+ if (found) {
+ const target = ext.labelColors.find((value) => value.name === color);
+ if (target) {
+ found.color = target;
+ }
+ }
+ workspace
+ .getConfiguration()
+ .update("kdb.connectionLabels", ext.connLabelList, true);
+}
+
+export function deleteLabel(name: string) {
+ getWorkspaceLabels();
+ const found = ext.connLabelList.find((item) => item.name === name);
+ if (found) {
+ ext.connLabelList.splice(ext.connLabelList.indexOf(found), 1);
+ }
+ workspace
+ .getConfiguration()
+ .update("kdb.connectionLabels", ext.connLabelList, true);
+}
diff --git a/test/suite/services.test.ts b/test/suite/services.test.ts
index 2be3b0c3..93816d5e 100644
--- a/test/suite/services.test.ts
+++ b/test/suite/services.test.ts
@@ -39,6 +39,7 @@ import {
InsightsNode,
KdbNode,
KdbTreeProvider,
+ LabelNode,
MetaObjectPayloadNode,
QCategoryNode,
QNamespaceNode,
@@ -63,6 +64,7 @@ import * as utils from "../../src/utils/getUri";
import { MetaInfoType, MetaObject } from "../../src/models/meta";
import { CompletionProvider } from "../../src/services/completionProvider";
import { MetaContentProvider } from "../../src/services/metaContentProvider";
+import { ConnectionLabel, Labels } from "../../src/models/labels";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const codeFlow = require("../../src/services/kdbInsights/codeFlowLogin");
@@ -605,6 +607,18 @@ describe("kdbTreeProvider", () => {
);
});
+ it("Should return a new LabelNode", () => {
+ const labelNode = new LabelNode({
+ name: "White",
+ color: { name: "White", colorHex: "#CCCCCC" },
+ });
+ assert.strictEqual(
+ labelNode.label,
+ "White",
+ "LabelNode node creation failed",
+ );
+ });
+
describe("InsightsMetaNode", () => {
it("should initialize fields correctly", () => {
const node = new InsightsMetaNode(
@@ -709,6 +723,24 @@ describe("kdbTreeProvider", () => {
const result = await kdbProvider.getChildren(metaNode);
assert.notStrictEqual(result, undefined);
});
+
+ it("should return label node", async () => {
+ const labels: Labels[] = [
+ { name: "label1", color: { name: "red", colorHex: "#FF0000" } },
+ ];
+ const conns: ConnectionLabel[] = [
+ {
+ labelName: "label1",
+ connections: ["testServerAlias", "testInsightsAlias"],
+ },
+ ];
+ sinon.stub(workspace, "getConfiguration").value(() => ({
+ get: (v: string) => (v === "kdb.connectionLabels" ? labels : conns),
+ }));
+ const provider = new KdbTreeProvider(servers, insights);
+ const result = await provider.getChildren();
+ assert.strictEqual(result.length, 1);
+ });
});
});
diff --git a/test/suite/utils.test.ts b/test/suite/utils.test.ts
index aa41407b..0a57a533 100644
--- a/test/suite/utils.test.ts
+++ b/test/suite/utils.test.ts
@@ -1745,5 +1745,43 @@ describe("Utils", () => {
assert.deepStrictEqual(labels, ["label1"]);
});
+
+ it("should rename a label", () => {
+ const labels: Labels[] = [
+ { name: "label1", color: { name: "red", colorHex: "#FF0000" } },
+ ];
+ getConfigurationStub.returns({
+ get: sinon.stub().returns(labels),
+ update: sinon.stub().returns(Promise.resolve()),
+ });
+ LabelsUtils.renameLabel("label1", "label2");
+ assert.strictEqual(ext.connLabelList.length, 1);
+ assert.deepStrictEqual(ext.connLabelList[0].name, "label2");
+ });
+
+ it("should set label color", () => {
+ const labels: Labels[] = [
+ { name: "label1", color: { name: "red", colorHex: "#FF0000" } },
+ ];
+ getConfigurationStub.returns({
+ get: sinon.stub().returns(labels),
+ update: sinon.stub().returns(Promise.resolve()),
+ });
+ LabelsUtils.setLabelColor("label1", "Blue");
+ assert.strictEqual(ext.connLabelList.length, 1);
+ assert.deepStrictEqual(ext.connLabelList[0].color.name, "Blue");
+ });
+
+ it("should delete label", () => {
+ const labels: Labels[] = [
+ { name: "label1", color: { name: "red", colorHex: "#FF0000" } },
+ ];
+ getConfigurationStub.returns({
+ get: sinon.stub().returns(labels),
+ update: sinon.stub().returns(Promise.resolve()),
+ });
+ LabelsUtils.deleteLabel("label1");
+ assert.strictEqual(ext.connLabelList.length, 0);
+ });
});
});