Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: show plugins and clients in panel #5784

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
04a13a8
load workspace content inside tree
thewahome Nov 13, 2024
2c31d69
expand node if item is available
Nov 14, 2024
7465f16
expand if items exist
Nov 14, 2024
3a01185
add view action buttons to the items
thewahome Nov 14, 2024
fd4b56f
activate selecting the path from the tree
thewahome Nov 15, 2024
9b7ec58
reorder panels in view
thewahome Nov 15, 2024
14259aa
When no clients or plugins, open root collapsed
thewahome Nov 15, 2024
2287b59
only show the category if it has items
thewahome Nov 15, 2024
52c0bba
access properties from extension command
thewahome Nov 15, 2024
ffe44e8
show open folder icon when plugin/client selected
thewahome Nov 15, 2024
1aadd1f
reuse the regeneration command
thewahome Nov 15, 2024
7fbaeea
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 15, 2024
b285a33
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 18, 2024
711294c
[partial] delete workspace item
thewahome Nov 18, 2024
ab673e5
reuse item generation
Nov 19, 2024
232f108
support workspace tree provider
thewahome Nov 19, 2024
5096870
don't clean output
thewahome Nov 19, 2024
4ee59e7
add remove client async and remove plugin async functions to the RPC …
thewahome Nov 19, 2024
0a6763f
connect to kiota rpc functions
thewahome Nov 19, 2024
a104372
isolate in folder
thewahome Nov 19, 2024
bca6af0
remove regeneration, change icon, call select
thewahome Nov 19, 2024
693033a
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 20, 2024
cc8b44f
add logging dependency
thewahome Nov 20, 2024
72460cd
refresh view after deleting workspace item
thewahome Nov 20, 2024
8983f71
load works[ace content on refresh
thewahome Nov 20, 2024
96095f0
bump version numbrt to match kiota with changes
thewahome Nov 20, 2024
95f03bc
use string formating
thewahome Nov 20, 2024
ce5afbe
show no clients or plugins available message
thewahome Nov 20, 2024
b10cd3f
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 20, 2024
00a381f
use translated button names
thewahome Nov 20, 2024
737146b
Merge branch 'task/extension/show-plugins-and-clients-in-panel' of ht…
thewahome Nov 20, 2024
cb9f26b
change error message
thewahome Nov 20, 2024
084c1ac
remove unnecessary console log
thewahome Nov 20, 2024
c951ffe
chore: removes duplication in server removal implementation
baywet Nov 21, 2024
ddecb7d
consolidate plugin and client deletion into a single method
thewahome Nov 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/kiota/Rpc/IServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ internal interface IServer
Task<LanguagesInformation> InfoForDescriptionAsync(string descriptionPath, bool clearCache, CancellationToken cancellationToken);
Task<List<LogEntry>> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, ConsumerOperation operation, CancellationToken cancellationToken);
Task<List<LogEntry>> MigrateFromLockFileAsync(string lockDirectoryPath, CancellationToken cancellationToken);
Task<List<LogEntry>> RemoveClientAsync(string clientName, bool cleanOutput, CancellationToken cancellationToken);
Task<List<LogEntry>> RemovePluginAsync(string pluginName, bool cleanOutput, CancellationToken cancellationToken);
}
25 changes: 25 additions & 0 deletions src/kiota/Rpc/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,29 @@ private static string NormalizeSlashesInPath(string path)
return path.Replace('/', '\\');
return path.Replace('\\', '/');
}

public Task<List<LogEntry>> RemoveClientAsync(string clientName, bool cleanOutput, CancellationToken cancellationToken)
=> RemoveClientOrPluginAsync(clientName, cleanOutput, "Client", (workspaceManagementService, clientName, cleanOutput, cancellationToken) => workspaceManagementService.RemoveClientAsync(clientName, cleanOutput, cancellationToken), cancellationToken);

private static async Task<List<LogEntry>> RemoveClientOrPluginAsync(string clientName, bool cleanOutput, string typeName, Func<WorkspaceManagementService, string, bool, CancellationToken, Task> removal, CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrEmpty(clientName);
ArgumentException.ThrowIfNullOrEmpty(typeName);
ArgumentNullException.ThrowIfNull(removal);
var logger = new ForwardedLogger<KiotaBuilder>();
try
{
var workspaceManagementService = new WorkspaceManagementService(logger, httpClient, IsConfigPreviewEnabled.Value);
await removal(workspaceManagementService, clientName, cleanOutput, cancellationToken).ConfigureAwait(false);
logger.LogInformation("{TypeName} {ClientName} removed successfully!", typeName, clientName);
}
catch (Exception ex)
{
logger.LogCritical(ex, "error removing the {TypeName}: {ExceptionMessage}", typeName.ToLowerInvariant(), ex.Message);
}
return logger.LogEntries;
}

public async Task<List<LogEntry>> RemovePluginAsync(string pluginName, bool cleanOutput, CancellationToken cancellationToken)
=> await RemoveClientOrPluginAsync(pluginName, cleanOutput, "Plugin", (workspaceManagementService, pluginName, cleanOutput, cancellationToken) => workspaceManagementService.RemovePluginAsync(pluginName, cleanOutput, cancellationToken), cancellationToken);
}
4 changes: 2 additions & 2 deletions vscode/microsoft-kiota/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 30 additions & 6 deletions vscode/microsoft-kiota/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"displayName": "Microsoft Kiota",
"publisher": "ms-graph",
"description": "Client generator for HTTP REST APIs described by OpenAPI which helps eliminate the need to take a dependency on a different API client for every API that you need to call, as well as limiting the generation to the exact API surface area you're interested in, thanks to a filtering capability.",
"version": "1.18.100000001",
"kiotaVersion": "1.18.0",
"version": "1.21.100000001",
"kiotaVersion": "1.21.0",
"telemetryInstrumentationKey": "4c6357e0-daf9-42b5-bdfb-67878f8957b5",
"icon": "images/logo.png",
"engines": {
Expand Down Expand Up @@ -217,12 +217,14 @@
"views": {
"kiota-openapi-explorer": [
{
"id": "kiota.openApiExplorer",
"name": "%kiota.openApiExplorer.name%"
"id": "kiota.workspace",
"name": "%kiota.workspace.name%",
"order": 1
},
{
"id": "kiota.workspace",
"name": "%kiota.workspace.name%"
"id": "kiota.openApiExplorer",
"name": "%kiota.openApiExplorer.name%",
"order": 2
}
],
"kiota-dependencies-info": [
Expand Down Expand Up @@ -301,6 +303,16 @@
"command": "kiota.openApiExplorer.removeAllFromSelectedEndpoints",
"when": "view == kiota.openApiExplorer && viewItem != clientNameOrPluginName",
"group": "inline@5"
},
{
"command": "kiota.workspace.selectItem",
"when": "viewItem == item",
"group": "inline@1"
},
{
"command": "kiota.workspace.deleteItem",
"when": "viewItem == item",
"group": "inline@2"
}
],
"commandPalette": [
Expand Down Expand Up @@ -437,6 +449,18 @@
{
"command": "kiota.migrateFromLockFile",
"title": "%kiota.migrateClients.title%"
},
{
"command": "kiota.workspace.selectItem",
"title": "%kiota.openApiExplorer.editPaths.title%",
"category": "Kiota",
"icon": "$(bracket)"
},
{
"command": "kiota.workspace.deleteItem",
"title": "%kiota.openApiExplorer.removeFromSelectedEndpoints.title%",
"category": "Kiota",
"icon": "$(trash)"
}
],
"languages": [
Expand Down
2 changes: 1 addition & 1 deletion vscode/microsoft-kiota/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"kiota.openApiExplorer.openFile.title": "Open file",
"kiota.workspace.name": "My Workspace",
"kiota.openApiExplorer.regenerateButton.title": "Re-generate",
"kiota.openApiExplorer.editPaths.title": "Edit paths",
"kiota.openApiExplorer.editPaths.title": "Select",
"kiota.openApiExplorer.refresh.title": "Refresh",
"kiota.migrateClients.title": "Migrate API clients"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import TelemetryReporter from "@vscode/extension-telemetry";
import * as vscode from "vscode";

import { extensionId } from "../../constants";
import { getLogEntriesForLevel, KiotaLogEntry, LogLevel } from "../../kiotaInterop";
import { WorkspaceTreeItem } from "../../providers/workspaceTreeProvider";
import { isPluginType } from "../../util";
import { exportLogsAndShowErrors } from "../../utilities/logging";
import { Command } from "../Command";
import { removeClient, removePlugin } from "./removeItem";

export class DeleteWorkspaceItemCommand extends Command {
constructor(
private _context: vscode.ExtensionContext,
private _kiotaOutputChannel: vscode.LogOutputChannel
) {
super();
}

public getName(): string {
return `${extensionId}.workspace.deleteItem`;
}

public async execute(workspaceTreeItem: WorkspaceTreeItem): Promise<void> {
const result = await this.deleteItem(isPluginType(workspaceTreeItem.category!) ? "plugin" : "client", workspaceTreeItem);
if (result) {
const isSuccess = result.some(k => k.message.includes('removed successfully'));
if (isSuccess) {
void vscode.window.showInformationMessage(vscode.l10n.t('{0} removed successfully.', workspaceTreeItem.label));
await vscode.commands.executeCommand('kiota.workspace.refresh');
} else {
await exportLogsAndShowErrors(result, this._kiotaOutputChannel);
}
}
}

private async deleteItem(type: string, workspaceTreeItem: WorkspaceTreeItem): Promise<KiotaLogEntry[] | undefined> {
if (type === "plugin") {
return await this.deletePlugin(workspaceTreeItem.label);
} else {
return await this.deleteClient(workspaceTreeItem.label);
}
}

private async deletePlugin(pluginName: string): Promise<KiotaLogEntry[] | undefined> {
const result = await vscode.window.withProgress({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lots of duplication between the two methods, I think we have an opportunity to refactor and reduce duplication here.

location: vscode.ProgressLocation.Notification,
cancellable: false,
title: vscode.l10n.t("Removing plugin...")
}, async (progress, _) => {
const start = performance.now();
const result = await removePlugin(
this._context,
pluginName!,
false,
);
const duration = performance.now() - start;
const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0;
const reporter = new TelemetryReporter(this._context.extension.packageJSON.telemetryInstrumentationKey);
reporter.sendRawTelemetryEvent(`${extensionId}.removePlugin.completed`, {
"pluginType": pluginName,
"errorsCount": errorsCount.toString(),
}, {
"duration": duration,
});
return result;
});
return result;
}
private async deleteClient(clientName: string): Promise<KiotaLogEntry[] | undefined> {
const result = await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
cancellable: false,
title: vscode.l10n.t("Removing client...")
}, async (progress, _) => {
const start = performance.now();
const result = await removeClient(
this._context,
clientName,
false,
);
const duration = performance.now() - start;
const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0;
const reporter = new TelemetryReporter(this._context.extension.packageJSON.telemetryInstrumentationKey);
reporter.sendRawTelemetryEvent(`${extensionId}.removeClient.completed`, {
"client": clientName,
"errorsCount": errorsCount.toString(),
}, {
"duration": duration,
});
return result;
});
return result;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as vscode from "vscode";
import * as rpc from "vscode-jsonrpc/node";

import { connectToKiota, KiotaLogEntry } from "../../kiotaInterop";

export function removePlugin(context: vscode.ExtensionContext, pluginName: string, cleanOutput: boolean): Promise<KiotaLogEntry[] | undefined> {
return connectToKiota(context, async (connection) => {
const request = new rpc.RequestType2<string, boolean, KiotaLogEntry[], void>(
"RemovePlugin"
);
const result = await connection.sendRequest(
request,
pluginName,
cleanOutput
);
return result;
});
};

export function removeClient(context: vscode.ExtensionContext, clientName: string, cleanOutput: boolean): Promise<KiotaLogEntry[] | undefined> {
return connectToKiota(context, async (connection) => {
const request = new rpc.RequestType2<string, boolean, KiotaLogEntry[], void>(
"RemoveClient"
);
const result = await connection.sendRequest(
request,
clientName,
cleanOutput
);
return result;
});
};
8 changes: 4 additions & 4 deletions vscode/microsoft-kiota/src/commands/editPathsCommand.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as vscode from "vscode";

import { extensionId, treeViewId } from "../constants";
import { ClientOrPluginProperties } from "../kiotaInterop";
import { OpenApiTreeProvider } from "../providers/openApiTreeProvider";
Expand All @@ -8,11 +10,8 @@ import { Command } from "./Command";

export class EditPathsCommand extends Command {

private _openApiTreeProvider: OpenApiTreeProvider;

public constructor(openApiTreeProvider: OpenApiTreeProvider) {
public constructor(private _openApiTreeProvider: OpenApiTreeProvider) {
super();
this._openApiTreeProvider = openApiTreeProvider;
}

public getName(): string {
Expand All @@ -23,6 +22,7 @@ export class EditPathsCommand extends Command {
await this.loadEditPaths(clientOrPluginKey!, clientOrPluginObject!);
this._openApiTreeProvider.resetInitialState();
await updateTreeViewIcons(treeViewId, false, true);
await vscode.commands.executeCommand('kiota.workspace.refresh');
}

private async loadEditPaths(clientOrPluginKey: string, clientOrPluginObject: ClientOrPluginProperties) {
Expand Down
14 changes: 11 additions & 3 deletions vscode/microsoft-kiota/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import TelemetryReporter from '@vscode/extension-telemetry';
import * as vscode from "vscode";

import { CloseDescriptionCommand } from './commands/closeDescriptionCommand';
import { DeleteWorkspaceItemCommand } from './commands/deleteWorkspaceItem/deleteWorkspaceItemCommand';
import { EditPathsCommand } from './commands/editPathsCommand';
import { GenerateClientCommand } from './commands/generate/generateClientCommand';
import { displayGenerationResults } from './commands/generate/generation-util';
Expand All @@ -30,10 +31,12 @@ import {
import { CodeLensProvider } from './providers/codelensProvider';
import { DependenciesViewProvider } from "./providers/dependenciesViewProvider";
import { OpenApiTreeNode, OpenApiTreeProvider } from "./providers/openApiTreeProvider";
import { loadTreeView } from './providers/workspaceTreeProvider';
import { SharedService } from './providers/sharedService';
import { loadTreeView, WorkspaceTreeItem, WorkspaceTreeProvider } from './providers/workspaceTreeProvider';
import { getExtensionSettings } from "./types/extensionSettings";
import { GeneratedOutputState } from './types/GeneratedOutputState';
import { WorkspaceGenerationContext } from "./types/WorkspaceGenerationContext";
import { isKiotaWorkspaceFilePresent } from './util';
import { IntegrationParams } from './utilities/deep-linking';
import { loadWorkspaceFile } from './utilities/file';
import { updateStatusBarItem } from './utilities/status';
Expand All @@ -50,11 +53,13 @@ export async function activate(
kiotaOutputChannel = vscode.window.createOutputChannel("Kiota", {
log: true,
});
const openApiTreeProvider = new OpenApiTreeProvider(context, () => getExtensionSettings(extensionId));
const sharedService = SharedService.getInstance();
const openApiTreeProvider = new OpenApiTreeProvider(context, () => getExtensionSettings(extensionId), sharedService);
const dependenciesInfoProvider = new DependenciesViewProvider(
context.extensionUri
);
const reporter = new TelemetryReporter(context.extension.packageJSON.telemetryInstrumentationKey);
const workspaceTreeProvider = new WorkspaceTreeProvider(await isKiotaWorkspaceFilePresent(), sharedService);

const setWorkspaceGenerationContext = (params: Partial<WorkspaceGenerationContext>) => {
workspaceGenerationContext = { ...workspaceGenerationContext, ...params };
Expand All @@ -76,9 +81,10 @@ export async function activate(
const closeDescriptionCommand = new CloseDescriptionCommand(openApiTreeProvider);
const statusCommand = new StatusCommand();
const selectLockCommand = new SelectLockCommand(openApiTreeProvider);
const deleteWorkspaceItemCommand = new DeleteWorkspaceItemCommand(context, kiotaOutputChannel);
const updateClientsCommand = new UpdateClientsCommand(context, kiotaOutputChannel);

await loadTreeView(context);
await loadTreeView(context, workspaceTreeProvider);
await checkForLockFileAndPrompt(context);
let codeLensProvider = new CodeLensProvider();
context.subscriptions.push(
Expand Down Expand Up @@ -125,6 +131,8 @@ export async function activate(
await regenerateCommand.execute({ clientOrPluginKey, clientOrPluginObject, generationType });
}),
registerCommandWithTelemetry(reporter, migrateFromLockFileCommand.getName(), async (uri: vscode.Uri) => await migrateFromLockFileCommand.execute(uri)),
registerCommandWithTelemetry(reporter, deleteWorkspaceItemCommand.getName(), async (workspaceTreeItem: WorkspaceTreeItem) => await deleteWorkspaceItemCommand.execute(workspaceTreeItem)),

);

// create a new status bar item that we can now manage
Expand Down
9 changes: 7 additions & 2 deletions vscode/microsoft-kiota/src/providers/openApiTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,24 @@ import {
} from '../kiotaInterop';
import { ExtensionSettings } from '../types/extensionSettings';
import { updateTreeViewIcons } from '../util';
import { SharedService } from './sharedService';

export class OpenApiTreeProvider implements vscode.TreeDataProvider<OpenApiTreeNode> {
private _onDidChangeTreeData: vscode.EventEmitter<OpenApiTreeNode | undefined | null | void> = new vscode.EventEmitter<OpenApiTreeNode | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<OpenApiTreeNode | undefined | null | void> = this._onDidChangeTreeData.event;
public apiTitle?: string;
private initialStateHash: string = '';

constructor(
private readonly context: vscode.ExtensionContext,
private readonly settingsGetter: () => ExtensionSettings,
private readonly sharedService: SharedService,
private _descriptionUrl?: string,
public includeFilters: string[] = [],
public excludeFilters: string[] = []) {

public excludeFilters: string[] = [],
) {
}

private _workspaceFilePath?: string;
private _workspaceFile?: ConfigurationFile | Partial<ConfigurationFile> = {};
public get isWorkspaceFileLoaded(): boolean {
Expand Down Expand Up @@ -332,6 +336,7 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider<OpenApiTreeN
});
if (result) {
this.apiTitle = result.apiTitle;
this.sharedService.set('clientOrPluginKey', clientNameOrPluginName);
if (result.rootNode) {
if (this.includeFilters.length === 0) {
this.setAllSelected(result.rootNode, false);
Expand Down
Loading
Loading