From f896c4856d48390d77d3e7e7a6f79ce7444cd87d Mon Sep 17 00:00:00 2001 From: angelozerr Date: Thu, 14 Jan 2021 11:07:56 +0100 Subject: [PATCH] Improve selection of cluster Fixes #62 Signed-off-by: azerr --- CHANGELOG.md | 1 + package.json | 4 ++-- src/constants.ts | 5 +++++ src/explorer/kafkaExplorer.ts | 23 ++++++++++++++++++++++- src/explorer/models/cluster.ts | 28 ++++++++++++++++++++++++---- src/explorer/models/kafka.ts | 9 ++++++++- src/settings/clusters.ts | 6 ++++-- 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acac9b1..8d0ccb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to Kafka extension will be documented in this file. - Internal topics are now hidden by default. See [#29](https://github.com/jlandersen/vscode-kafka/issues/29) and [#74](https://github.com/jlandersen/vscode-kafka/pull/74). - Elements are now sorted alphabetically in the Kafka explorer. See [#63](https://github.com/jlandersen/vscode-kafka/issues/63). - Clusters are now sorted in the cluster selection wizard. See [#83](https://github.com/jlandersen/vscode-kafka/issues/83). +- Selection of cluster is now visible in the explorer and the `Select Cluster` menu is displayed only for unselected clusters. See [#82](https://github.com/jlandersen/vscode-kafka/issues/82). ## [0.10.0] - 2021-01-02 ### Added diff --git a/package.json b/package.json index 7748042..24c929b 100644 --- a/package.json +++ b/package.json @@ -316,12 +316,12 @@ }, { "command": "vscode-kafka.explorer.deleteselected", - "when": "view == kafkaExplorer && viewItem =~ /^cluster$|^topic$/ && !listMultiSelection", + "when": "view == kafkaExplorer && viewItem =~ /^cluster$|^selectedCluster$|^topic$/ && !listMultiSelection", "group": "inline" }, { "command": "vscode-kafka.explorer.deleteselected", - "when": "view == kafkaExplorer && viewItem =~ /^cluster$|^topic$/ && !listMultiSelection", + "when": "view == kafkaExplorer && viewItem =~ /^cluster$|^selectedCluster$|^topic$/ && !listMultiSelection", "group": "3_modification" } ], diff --git a/src/constants.ts b/src/constants.ts index b4e9d2c..62b03b9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -48,6 +48,11 @@ export class Icons { } } + +export enum GlyphChars { + Check = '\u2713' +} + export class CommonMessages { public static showNoSelectedCluster(): void { vscode.window.showInformationMessage("No cluster selected"); diff --git a/src/explorer/kafkaExplorer.ts b/src/explorer/kafkaExplorer.ts index 1e21a4e..c319fea 100644 --- a/src/explorer/kafkaExplorer.ts +++ b/src/explorer/kafkaExplorer.ts @@ -8,6 +8,7 @@ import { KafkaModel } from "./models/kafka"; import { ClusterItem } from "./models/cluster"; import { EOL } from 'os'; import { TopicItem } from "./models/topics"; +import { SelectedClusterChangedEvent } from "../settings/clusters"; const TREEVIEW_ID = 'kafkaExplorer'; @@ -39,8 +40,10 @@ export class KafkaExplorer implements vscode.Disposable, vscode.TreeDataProvider treeDataProvider: this, canSelectMany: true }); + this.clusterSettings.onDidChangeSelected((e) => { + this.updateClusterSelection(e); + }); } - public refresh(): void { // reset the kafka model this.root = null; @@ -155,4 +158,22 @@ export class KafkaExplorer implements vscode.Disposable, vscode.TreeDataProvider } } } + + private async updateClusterSelection(e: SelectedClusterChangedEvent): Promise { + // Refresh the label of the old selected cluster + this.refreshClusterItem(e.oldClusterId); + // Refresh the label of the new selected cluster + this.refreshClusterItem(e.newClusterId); + } + + private async refreshClusterItem(clusterId: string | undefined): Promise { + if (!clusterId) { + return; + } + const clusterItem = await this.root?.findClusterItemById(clusterId); + if (clusterItem != undefined) { + this.onDidChangeTreeDataEvent.fire(clusterItem); + } + } + } diff --git a/src/explorer/models/cluster.ts b/src/explorer/models/cluster.ts index 880dd55..7bef204 100644 --- a/src/explorer/models/cluster.ts +++ b/src/explorer/models/cluster.ts @@ -8,6 +8,7 @@ import { TopicGroupItem, TopicItem } from "./topics"; import { ConsumerGroupsItem } from "./consumerGroups"; import { KafkaModel } from "./kafka"; import { Disposable } from "vscode"; +import { GlyphChars } from "../../constants"; const TOPIC_INDEX = 1; @@ -15,7 +16,7 @@ export class ClusterItem extends NodeBase implements Disposable { public contextValue = "cluster"; public collapsibleState = vscode.TreeItemCollapsibleState.Collapsed; - constructor(public client: Client, public cluster: Cluster, parent: KafkaModel) { + constructor(public client: Client, public readonly cluster: Cluster, parent: KafkaModel) { super(parent); this.label = cluster.name; this.description = cluster.bootstrap; @@ -32,6 +33,25 @@ export class ClusterItem extends NodeBase implements Disposable { return super.getParent(); } + getTreeItem(): vscode.TreeItem { + const treeItem = super.getTreeItem(); + // to prevent from tree expansion after a refresh, we need to force the id to a static value + // because we change the label according if cluster is selected or not. + treeItem.id = this.cluster.name; + // update label and contextValue (used by contextual menu) according the selection state + if (this.selected) { + treeItem.contextValue = 'selectedCluster'; + treeItem.label = GlyphChars.Check + ' ' + treeItem.label; + } else { + treeItem.contextValue = 'cluster'; + } + return treeItem; + } + + public get selected(): boolean { + return (this.getParent().clusterSettings.selected?.name === this.cluster.name); + } + public dispose(): void { this.client.dispose(); } @@ -60,14 +80,14 @@ export class NoClusterItem extends NodeBase { super(parent); this.label = 'Click here to add a cluster'; } - getTreeItem():vscode.TreeItem { + getTreeItem(): vscode.TreeItem { return { label: this.label, contextValue: this.contextValue, description: this.description, - command : { + command: { title: 'Add a cluster', - command:"vscode-kafka.explorer.addcluster" + command: "vscode-kafka.explorer.addcluster" } } } diff --git a/src/explorer/models/kafka.ts b/src/explorer/models/kafka.ts index 1bc2b2e..ff4a691 100644 --- a/src/explorer/models/kafka.ts +++ b/src/explorer/models/kafka.ts @@ -10,7 +10,7 @@ export class KafkaModel extends NodeBase implements Disposable { public collapsibleState = TreeItemCollapsibleState.Collapsed; constructor( - protected clusterSettings: ClusterSettings, + public readonly clusterSettings: ClusterSettings, protected clientAccessor: ClientAccessor) { super(undefined); } @@ -35,4 +35,11 @@ export class KafkaModel extends NodeBase implements Disposable { clusters.find(child => (child).cluster.name === clusterName) ); } + + async findClusterItemById(clusterId: string): Promise { + return this.getChildren() + .then(clusters => + clusters.find(child => (child).cluster.id === clusterId) + ); + } } diff --git a/src/settings/clusters.ts b/src/settings/clusters.ts index b4e6375..60a5e62 100644 --- a/src/settings/clusters.ts +++ b/src/settings/clusters.ts @@ -2,7 +2,8 @@ import * as vscode from "vscode"; import { Cluster } from "../client"; import { Context } from "../context"; -interface SelectedClusterChangedEvent { +export interface SelectedClusterChangedEvent { + oldClusterId?: string, newClusterId?: string; } @@ -72,8 +73,9 @@ class MementoClusterSettings implements ClusterSettings { } set selected(value: Cluster | undefined) { + const oldClusterId = this.selected?.id; this.storage.update(this.selectedClusterIdStorageKey, value?.id); - this.onDidChangeSelectedEmitter.fire({ newClusterId: value?.id }); + this.onDidChangeSelectedEmitter.fire({ oldClusterId : oldClusterId, newClusterId: value?.id }); } getAll(): Cluster[] {