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

Merged
merged 47 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 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
3217e24
introduce WorkspaceContentService to handle workspace file loading
thewahome Nov 22, 2024
b512399
call wrapper function instead of service
thewahome Nov 22, 2024
d46bdc2
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 22, 2024
762484a
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 22, 2024
23da950
test delete workspace command
thewahome Nov 25, 2024
5c3f71c
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 25, 2024
cff3ebd
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 25, 2024
d4a3d9e
add confirmation message before deleting
thewahome Nov 26, 2024
b1f58e5
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 26, 2024
bdc2f24
fix failing test due to warning message
thewahome Nov 26, 2024
92493e6
refine tests to cater for yes/no dialog
thewahome Nov 27, 2024
57a49f2
Merge branch 'main' into task/extension/show-plugins-and-clients-in-p…
thewahome Nov 27, 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,80 @@
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 type = workspaceTreeItem.category && isPluginType(workspaceTreeItem.category) ? "plugin" : "client";
const yesAnswer: vscode.MessageItem = { title: vscode.l10n.t("Yes") };
const noAnswer: vscode.MessageItem = { title: vscode.l10n.t("No") };

const response = await vscode.window.showWarningMessage(
vscode.l10n.t("Do you want to delete this item?"),
yesAnswer,
noAnswer
);

if (response?.title === yesAnswer.title) {
const result = await this.deleteItem(type, 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> {
const itemName = workspaceTreeItem.label;
const result = await vscode.window.withProgress({
thewahome marked this conversation as resolved.
Show resolved Hide resolved
location: vscode.ProgressLocation.Notification,
cancellable: false,
title: vscode.l10n.t(`Removing ${type}...`)
}, async (progress, _) => {
const start = performance.now();
const result = type === "plugin" ? await removePlugin(
this._context,
itemName,
false,
) : await removeClient(
this._context,
itemName,
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}.remove${type}.completed`, {
"pluginType": itemName,
"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
15 changes: 12 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 @@ -27,10 +28,12 @@ import { UriHandler } from './handlers/uriHandler';
import {
ClientOrPluginProperties
} from "./kiotaInterop";
import { WorkspaceContentService } from './modules/workspace';
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";
Expand All @@ -50,11 +53,14 @@ export async function activate(
kiotaOutputChannel = vscode.window.createOutputChannel("Kiota", {
log: true,
});
const openApiTreeProvider = new OpenApiTreeProvider(context, () => getExtensionSettings(extensionId));
const sharedService = SharedService.getInstance();
const workspaceContentService = new WorkspaceContentService();
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(workspaceContentService, sharedService);

const setWorkspaceGenerationContext = (params: Partial<WorkspaceGenerationContext>) => {
workspaceGenerationContext = { ...workspaceGenerationContext, ...params };
Expand All @@ -76,9 +82,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 +132,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: 9 additions & 0 deletions vscode/microsoft-kiota/src/modules/workspace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ClientOrPluginProperties } from "../../kiotaInterop";
import WorkspaceContentService from "./workspaceContentService";

export interface WorkspaceContent {
version: string;
clients: Record<string, ClientOrPluginProperties>;
plugins: Record<string, ClientOrPluginProperties>;
}
export { WorkspaceContentService };
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

import { WorkspaceContent } from ".";
import { KIOTA_WORKSPACE_FILE } from "../../constants";
import { getWorkspaceJsonPath } from '../../util';

class WorkspaceContentService {
constructor() { }

public async load(): Promise<WorkspaceContent | undefined> {
const isWorkspacePresent = await this.isKiotaWorkspaceFilePresent();
if (!isWorkspacePresent) {
return;
}
try {
const workspaceJson = vscode.workspace.textDocuments.find(doc => doc.fileName.endsWith(KIOTA_WORKSPACE_FILE));
if (!workspaceJson) {
throw new Error('Workspace file not found');
}
const content = workspaceJson.getText();
return JSON.parse(content);
} catch (error) {
console.error('Error loading workspace.json:', error);
}
}

async isKiotaWorkspaceFilePresent(): Promise<boolean> {
if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) {
return false;
}
const workspaceFileDir = path.resolve(getWorkspaceJsonPath());
try {
await fs.promises.access(workspaceFileDir);
} catch (error) {
return false;
}
return true;
}
}

export default WorkspaceContentService;
Loading
Loading