Skip to content

Commit

Permalink
Add 'vscode-kafka.api.saveclusters' and 'vscode-kafka.api.deleteclust…
Browse files Browse the repository at this point in the history
…ers' command

Signed-off-by: Fred Bricon <[email protected]>
  • Loading branch information
fbricon committed Jul 6, 2021
1 parent 62e0954 commit b280e14
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to `Tools for Apache Kafka®` are documented in this file.
- Hover support in `.kafka` files. See [#149](https://github.com/jlandersen/vscode-kafka/issues/149).
- String encoding serialization support. See [#181](https://github.com/jlandersen/vscode-kafka/issues/181).
- Refresh Cluster Provider API when extensions are installed/uninstalled. See [#137](https://github.com/jlandersen/vscode-kafka/issues/137).
- Expose new internal commands (`vscode-kafka.api.saveclusters` and `vscode-kafka.api.deleteclusters`) to programmatically add/delete clusters (from 3rd party extensions). See [#182](https://github.com/jlandersen/vscode-kafka/issues/182).

## [0.12.0] - 2021-04-26
### Added
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"activationEvents": [
"onCommand:vscode-kafka.open.docs.home",
"onCommand:vscode-kafka.open.docs.page",
"onCommand:vscode-kafka.api.saveclusters",
"onCommand:vscode-kafka.api.deleteclusters",
"onCommand:vscode-kafka.explorer.addcluster",
"onCommand:vscode-kafka.explorer.selectcluster",
"onCommand:vscode-kafka.cluster.delete",
Expand Down
97 changes: 78 additions & 19 deletions src/commands/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,71 @@
import * as vscode from "vscode";
import { dump } from "js-yaml";
import { Broker, ClientAccessor } from "../client";
import * as vscode from "vscode";
import { Broker, ClientAccessor, Cluster } from "../client";
import { KafkaExplorer } from "../explorer";
import { BrokerItem } from "../explorer/models/brokers";
import { OutputChannelProvider } from "../providers";
import { pickBroker, pickClient, pickCluster } from "./common";
import { ClusterSettings } from "../settings";
import { KafkaExplorer } from "../explorer";
import { addClusterWizard } from "../wizards/clusters";
import { showErrorMessage } from "../wizards/multiStepInput";
import { pickBroker, pickClient, pickCluster, getNames } from "./common";



export class SaveClusterCommandHandler {

constructor(protected clusterSettings: ClusterSettings, protected explorer: KafkaExplorer) {
}

async execute(clusters: Cluster[]): Promise<void> {
if (clusters.length === 0) {
return;
}
try {
// Save collected clusters in settings.
let createdClusterNames = getNames(clusters);
for (const cluster of clusters) {
this.clusterSettings.upsert(cluster);
}
vscode.window.showInformationMessage(`${clusters.length > 1 ? `${clusters.length} clusters` : 'Cluster'} ${createdClusterNames} created successfully`);

// Refresh the explorer
this.explorer.refresh();

// Selecting the created cluster is done with TreeView#reveal
// 1. Show the treeview of the explorer (otherwise reveal will not work)
this.explorer.show();
// 2. the reveal() call must occur within a timeout(),
// while waiting for a fix in https://github.com/microsoft/vscode/issues/114149
setTimeout(() => {
if (clusters) {
this.explorer.selectClusterByName(clusters[0].name);
}
}, 1000);
}
catch (error) {
showErrorMessage(`Error while creating cluster`, error);
}
}
}

/**
* Adds a new cluster to the collection.
*/
export class AddClusterCommandHandler {
constructor(private clusterSettings: ClusterSettings, private explorer: KafkaExplorer) {
export class AddClusterCommandHandler extends SaveClusterCommandHandler {

constructor(clusterSettings: ClusterSettings, explorer: KafkaExplorer) {
super(clusterSettings, explorer);
}

async execute(): Promise<void> {
addClusterWizard(this.clusterSettings, this.explorer);
const clusters = await addClusterWizard(this.clusterSettings, this.explorer);
super.execute(clusters);
}
}

export interface DeleteClusterRequest {
clusterIds : string | string[] | undefined
confirm: boolean
}

/**
Expand All @@ -31,20 +78,32 @@ export class DeleteClusterCommandHandler {
constructor(private clusterSettings: ClusterSettings, private clientAccessor: ClientAccessor, private explorer: KafkaExplorer) {
}

async execute(clusterId?: string): Promise<void> {
const cluster = clusterId ? this.clusterSettings.get(clusterId) : await pickCluster(this.clusterSettings);
if (!cluster) {
return;
async execute(deleteRequest: DeleteClusterRequest): Promise<void> {
const clusterIds = deleteRequest.clusterIds;
let clusters:(Cluster|undefined)[] = [];
if (Array.isArray(clusterIds)) {
clusters = clusterIds.map(id => this.clusterSettings.get(id)).filter(c=> c !== undefined);
} else {
const cluster = clusterIds ? this.clusterSettings.get(clusterIds) : await pickCluster(this.clusterSettings);
if (cluster) {
clusters.push(cluster);
}
}

const deleteConfirmation = await vscode.window.showWarningMessage(`Are you sure you want to delete cluster '${cluster.name}'?`, 'Cancel', 'Delete');
if (deleteConfirmation !== 'Delete') {
if (clusters.length === 0) {
return;
}

this.clusterSettings.remove(cluster.id);
this.clientAccessor.remove(cluster.id);
this.explorer.refresh();
if (deleteRequest.confirm) {
const clusterNames = getNames(clusters);
const deleteConfirmation = await vscode.window.showWarningMessage(`Are you sure you want to delete cluster${clusters.length === 1?'':'s'} ${clusterNames}?`, 'Cancel', 'Delete');
if (deleteConfirmation !== 'Delete') {
return;
}
}
clusters.forEach(cluster => {
this.clusterSettings.remove(cluster!.id);
this.clientAccessor.remove(cluster!.id);
this.explorer.refresh();
});
}
}

Expand Down Expand Up @@ -122,4 +181,4 @@ export class DumpClusterMetadataCommandHandler {
channel.append(dump(data));
channel.show();
}
}
}
14 changes: 14 additions & 0 deletions src/commands/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,17 @@ export async function pickBroker(clientAccessor: ClientAccessor): Promise<Broker
const pickedBroker = await vscode.window.showQuickPick(brokerQuickPickItems);
return pickedBroker?.broker;
}

export function getNames(clusters: (Cluster|undefined)[]): string {
let names = '';
for (const cluster of clusters) {
if (names !== '') {
names += '\', \'';
}
names += cluster!.name;
}
if (names !== '') {
names = '\''+names+'\'';
}
return names;
}
55 changes: 32 additions & 23 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
import * as path from 'path';
import * as vscode from "vscode";

import { getClientAccessor, ConsumerCollection } from "./client";
import { Cluster, ConsumerCollection, getClientAccessor } from "./client";
import { ProducerCollection } from "./client/producer";
import {
AddClusterCommandHandler,
ClearConsumerViewCommandHandler,
CreateTopicCommandHandler,
DeleteClusterCommandHandler,
DeleteClusterRequest,
DeleteConsumerGroupCommand,
DeleteConsumerGroupCommandHandler,
DeleteTopicCommandHandler,
DumpBrokerMetadataCommandHandler,
DumpClusterMetadataCommandHandler,
DumpTopicMetadataCommandHandler,
handleErrors,
LaunchConsumerCommand,
ListConsumersCommandHandler,
ProduceRecordCommand,
ProduceRecordCommandHandler,
SaveClusterCommandHandler,
SelectClusterCommandHandler,
StartConsumerCommandHandler,
StopConsumerCommandHandler,
ToggleConsumerCommandHandler,
AddClusterCommandHandler,
DeleteClusterCommandHandler,
SelectClusterCommandHandler,
handleErrors,
ClearConsumerViewCommandHandler,
DeleteConsumerGroupCommandHandler,
DeleteConsumerGroupCommand,
LaunchConsumerCommand,
ProduceRecordCommand
ToggleConsumerCommandHandler
} from "./commands";
import { Context } from "./context";
import { markdownPreviewProvider } from "./docs/markdownPreviewProvider";
import { BrokerItem, KafkaExplorer, TopicItem } from "./explorer";
import { ConsumerVirtualTextDocumentProvider, OutputChannelProvider } from "./providers";
import { getClusterSettings, getWorkspaceSettings } from "./settings";
import { ClusterItem } from "./explorer/models/cluster";
import { TopicGroupItem } from "./explorer/models/topics";
import { ConsumerStatusBarItem } from "./views/consumerStatusBarItem";
import { SelectedClusterStatusBarItem } from "./views/selectedClusterStatusBarItem";
import { NodeBase } from "./explorer/models/nodeBase";
import * as path from 'path';
import { markdownPreviewProvider } from "./docs/markdownPreviewProvider";
import { getDefaultKafkaExtensionParticipant, refreshClusterProviderDefinitions } from "./kafka-extensions/registry";
import { TopicGroupItem } from "./explorer/models/topics";
import { KafkaExtensionParticipant } from "./kafka-extensions/api";
import { ProducerCollection } from "./client/producer";
import { getDefaultKafkaExtensionParticipant, refreshClusterProviderDefinitions } from "./kafka-extensions/registry";
import { startLanguageClient } from "./kafka-file/kafkaFileClient";
import { ConsumerVirtualTextDocumentProvider, OutputChannelProvider } from "./providers";
import { getClusterSettings, getWorkspaceSettings } from "./settings";
import { ConsumerStatusBarItem } from "./views/consumerStatusBarItem";
import { SelectedClusterStatusBarItem } from "./views/selectedClusterStatusBarItem";


export function activate(context: vscode.ExtensionContext): KafkaExtensionParticipant {
Context.register(context);
Expand Down Expand Up @@ -74,6 +76,7 @@ export function activate(context: vscode.ExtensionContext): KafkaExtensionPartic
const clearConsumerViewCommandHandler = new ClearConsumerViewCommandHandler(consumerVirtualTextDocumentProvider);
const deleteConsumerGroupCommandHandler = new DeleteConsumerGroupCommandHandler(clientAccessor, explorer);
const addClusterCommandHandler = new AddClusterCommandHandler(clusterSettings, explorer);
const saveClusterCommandHandler = new SaveClusterCommandHandler(clusterSettings, explorer);
const deleteClusterCommandHandler = new DeleteClusterCommandHandler(clusterSettings, clientAccessor, explorer);
const selectClusterCommandHandler = new SelectClusterCommandHandler(clusterSettings);
const dumpTopicMetadataCommandHandler = new DumpTopicMetadataCommandHandler(clientAccessor, outputChannelProvider);
Expand All @@ -94,7 +97,7 @@ export function activate(context: vscode.ExtensionContext): KafkaExtensionPartic
handleErrors((clusterItem?: ClusterItem) => selectClusterCommandHandler.execute(clusterItem?.cluster.id))));
context.subscriptions.push(vscode.commands.registerCommand(
DeleteClusterCommandHandler.commandId,
handleErrors((clusterItem?: ClusterItem) => deleteClusterCommandHandler.execute(clusterItem?.cluster.id))));
handleErrors((clusterItem?: ClusterItem) => deleteClusterCommandHandler.execute({ clusterIds: clusterItem?.cluster.id, confirm: true}))));
context.subscriptions.push(vscode.commands.registerCommand(
"vscode-kafka.explorer.dumptopicmetadata",
(topic?: TopicItem) => dumpTopicMetadataCommandHandler.execute(topic)));
Expand Down Expand Up @@ -138,7 +141,13 @@ export function activate(context: vscode.ExtensionContext): KafkaExtensionPartic
return vscode.commands.executeCommand("workbench.extensions.search", "@tag:kafka-provider");
}
));

context.subscriptions.push(vscode.commands.registerCommand(
"vscode-kafka.api.saveclusters",
handleErrors((clusters: Cluster[]) => saveClusterCommandHandler.execute(clusters))));
context.subscriptions.push(vscode.commands.registerCommand(
"vscode-kafka.api.deleteclusters",
handleErrors((deleteRequest: DeleteClusterRequest) => deleteClusterCommandHandler.execute(deleteRequest))));

registerVSCodeKafkaDocumentationCommands(context);

// .kafka file related
Expand Down
50 changes: 5 additions & 45 deletions src/wizards/clusters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { KafkaExplorer } from "../explorer/kafkaExplorer";
import { ClusterProvider, getClusterProviders } from "../kafka-extensions/registry";
import { ClusterSettings } from "../settings/clusters";
import { MultiStepInput, showErrorMessage, State } from "./multiStepInput";
import { validateBroker, validateClusterName, validateAuthentificationUserName } from "./validators";
import { validateAuthentificationUserName, validateBroker, validateClusterName } from "./validators";

interface AddClusterState extends State, ConnectionOptions {
name: string;
}

const DEFAULT_STEPS = 4;

export async function addClusterWizard(clusterSettings: ClusterSettings, explorer: KafkaExplorer): Promise<void> {
export async function addClusterWizard(clusterSettings: ClusterSettings, explorer: KafkaExplorer): Promise<Cluster[]> {

async function pickClusterProvider(): Promise<ClusterProvider | undefined> {
const providers = getClusterProviders();
Expand All @@ -37,51 +37,12 @@ export async function addClusterWizard(clusterSettings: ClusterSettings, explore
// eg (configure cluster via a custom wizard, import clusters from a repository, etc)
const provider = await pickClusterProvider();
if (!provider) {
return;
return [];
}

// Collect clusters...
let clusters: Cluster[] | undefined;
try {
clusters = await provider.collectClusters(clusterSettings);
if (!clusters || clusters.length === 0) {
return;
}
}
catch (error) {
showErrorMessage(`Error while collecting cluster(s)`, error);
return;
}

try {
// Save collected clusters in settings.
let createdClusterNames = '';
for (const cluster of clusters) {
clusterSettings.upsert(cluster);
if (createdClusterNames !== '') {
createdClusterNames += '\', \'';
}
createdClusterNames += cluster.name;
}
window.showInformationMessage(`${clusters.length > 1 ? `${clusters.length} clusters` : 'Cluster'} '${createdClusterNames}' created successfully`);

// Refresh the explorer
explorer.refresh();

// Selecting the created cluster is done with TreeView#reveal
// 1. Show the treeview of the explorer (otherwise reveal will not work)
explorer.show();
// 2. the reveal() call must occur within a timeout(),
// while waiting for a fix in https://github.com/microsoft/vscode/issues/114149
setTimeout(() => {
if (clusters) {
explorer.selectClusterByName(clusters[0].name);
}
}, 1000);
}
catch (error) {
showErrorMessage(`Error while creating cluster`, error);
}
const results = await provider.collectClusters(clusterSettings);
return results? results:[];
}

const DEFAULT_BROKER = 'localhost:9092';
Expand Down Expand Up @@ -231,4 +192,3 @@ export async function configureDefaultClusters(clusterSettings: ClusterSettings)
];
}


0 comments on commit b280e14

Please sign in to comment.