Skip to content

Commit a4979b8

Browse files
authored
✨ Add issue tree view (#141)
Layout: 1. group incidents by message (top level) and file (2nd level) 2. within message group the files are sorted based on the entire path 3. within file group the incidents are sorted based on line number Actions: 1. top bar a) open Analysis webview b) expand all nodes 2. context: a) open details in Analysis webview (currently just opens the webview) b) expand all child nodes 3. one-click expand for nodes with only one child 4. open Analysis webview when extension is loaded (first time the perspective is accessed) Refactorings: 1. move Analysis web view to the editor section (similar to Resolution webview) 2. disable full screen toggling for Analysis webview 3. embed initial state data in the HTML to ensure that first message won't be missed Reference-Url: #140 --------- Signed-off-by: Radoslaw Szwajkowski <[email protected]>
1 parent d80d925 commit a4979b8

14 files changed

+630
-127
lines changed

shared/src/types/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Uri } from "vscode";
22

3+
export type WebviewType = "sidebar" | "resolution";
4+
35
export type Severity = "High" | "Medium" | "Low";
46

57
export interface Incident {

vscode/package.json

+45-17
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,28 @@
3535
"icon": "$(key)"
3636
},
3737
{
38-
"command": "konveyor.toggleFullScreen",
39-
"title": "Toggle Fullscreen",
38+
"command": "konveyor.showAnalysisPanel",
39+
"title": "Open Konveyor Analysis View",
4040
"category": "Konveyor",
41-
"icon": "$(fullscreen)"
41+
"icon": "$(book)"
42+
},
43+
{
44+
"command": "konveyor.expandAllIssues",
45+
"title": "Expand All",
46+
"category": "Konveyor",
47+
"icon": "$(expand-all)"
48+
},
49+
{
50+
"command": "konveyor.expandSingleIssue",
51+
"title": "Expand All",
52+
"category": "Konveyor",
53+
"icon": "$(expand-all)"
54+
},
55+
{
56+
"command": "konveyor.openAnalysisDetails",
57+
"title": "Open Details",
58+
"category": "Konveyor",
59+
"icon": "$(book)"
4260
},
4361
{
4462
"command": "konveyor.overrideAnalyzerBinaries",
@@ -222,10 +240,8 @@
222240
"views": {
223241
"konveyor": [
224242
{
225-
"type": "webview",
226-
"id": "konveyor.konveyorAnalysisView",
227-
"name": "Konveyor Analysis View",
228-
"visibility": "visible"
243+
"id": "konveyor.issueView",
244+
"name": "Konveyor Issues"
229245
},
230246
{
231247
"id": "konveyor.diffView",
@@ -236,9 +252,14 @@
236252
"menus": {
237253
"view/title": [
238254
{
239-
"command": "konveyor.toggleFullScreen",
255+
"command": "konveyor.showAnalysisPanel",
240256
"group": "navigation@1",
241-
"when": "view == konveyor.konveyorAnalysisView"
257+
"when": "view == konveyor.issueView"
258+
},
259+
{
260+
"command": "konveyor.expandAllIssues",
261+
"group": "navigation@2",
262+
"when": "view == konveyor.issueView"
242263
},
243264
{
244265
"command": "konveyor.applyAll",
@@ -257,6 +278,16 @@
257278
}
258279
],
259280
"view/item/context": [
281+
{
282+
"command": "konveyor.expandSingleIssue",
283+
"group": "inline@2",
284+
"when": "view == konveyor.issueView && viewItem == incident-type-item"
285+
},
286+
{
287+
"command": "konveyor.openAnalysisDetails",
288+
"group": "inline@1",
289+
"when": "view == konveyor.issueView && viewItem == incident-type-item"
290+
},
260291
{
261292
"command": "konveyor.applyFile",
262293
"group": "inline",
@@ -288,13 +319,6 @@
288319
"when": "view == konveyor.diffView && viewItem == file-item"
289320
}
290321
],
291-
"editor/title": [
292-
{
293-
"command": "konveyor.toggleFullScreen",
294-
"group": "navigation@1",
295-
"when": "activeWebviewPanelId == konveyor.konveyorAnalysisView"
296-
}
297-
],
298322
"diffEditor/gutter/selection": [
299323
{
300324
"command": "konveyor.diffView.applySelectionInline",
@@ -327,6 +351,10 @@
327351
],
328352
"konveyor.submenu": [],
329353
"commandPalette": [
354+
{
355+
"command": "konveyor.expandSingleIssue",
356+
"when": "never"
357+
},
330358
{
331359
"command": "konveyor.loadRuleSets",
332360
"when": "never"
@@ -609,4 +637,4 @@
609637
"dependencies": {
610638
"diff": "^7.0.0"
611639
}
612-
}
640+
}

vscode/src/KonveyorGUIWebviewViewProvider.ts

+55-44
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
window,
1414
} from "vscode";
1515
import { getNonce } from "./utilities/getNonce";
16+
import { ExtensionData, WebviewType } from "@editor-extensions/shared";
17+
import { Immutable } from "immer";
1618

1719
export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
1820
public static readonly SIDEBAR_VIEW_TYPE = "konveyor.konveyorAnalysisView";
@@ -28,60 +30,60 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
2830

2931
constructor(
3032
private readonly _extensionState: ExtensionState,
31-
private readonly _viewType: string,
33+
private readonly _viewType: WebviewType,
3234
) {}
3335

36+
isAnalysisView() {
37+
return this._viewType === "sidebar";
38+
}
39+
3440
public resolveWebviewView(
3541
webviewView: WebviewView,
3642
_context: WebviewViewResolveContext,
3743
_token: CancellationToken,
3844
): void | Thenable<void> {
3945
this._view = webviewView;
40-
this.initializeWebview(webviewView.webview);
46+
this.initializeWebview(webviewView.webview, this._extensionState.data);
4147
}
4248

4349
public createWebviewPanel(): void {
44-
if (!this._panel) {
45-
this._panel = window.createWebviewPanel(
46-
KonveyorGUIWebviewViewProvider.RESOLUTION_VIEW_TYPE,
47-
"Resolution Details",
48-
ViewColumn.One,
49-
{
50-
enableScripts: true,
51-
localResourceRoots: [this._extensionState.extensionContext.extensionUri],
52-
retainContextWhenHidden: true,
53-
},
54-
);
55-
56-
this.initializeWebview(this._panel.webview);
50+
if (this._panel) {
51+
return;
52+
}
53+
this._panel = window.createWebviewPanel(
54+
this.isAnalysisView()
55+
? KonveyorGUIWebviewViewProvider.SIDEBAR_VIEW_TYPE
56+
: KonveyorGUIWebviewViewProvider.RESOLUTION_VIEW_TYPE,
57+
this.isAnalysisView() ? "Konveyor Analysis View" : "Resolution Details",
58+
ViewColumn.One,
59+
{
60+
enableScripts: true,
61+
localResourceRoots: [this._extensionState.extensionContext.extensionUri],
62+
retainContextWhenHidden: true,
63+
},
64+
);
5765

58-
if (this._viewType === KonveyorGUIWebviewViewProvider.RESOLUTION_VIEW_TYPE) {
59-
const savedData = this._extensionState.data.resolutionPanelData;
60-
if (savedData) {
61-
this._panel.webview.postMessage(this._extensionState.data);
62-
}
63-
}
66+
this.initializeWebview(this._panel.webview, this._extensionState.data);
6467

65-
this._panel.onDidDispose(() => {
66-
this.handleResolutionViewClosed();
67-
this._panel = undefined;
68-
this._isWebviewReady = false;
69-
this._isPanelReady = false;
70-
});
71-
}
68+
this._panel.onDidDispose(() => {
69+
this.handleViewClosed();
70+
this._panel = undefined;
71+
this._isWebviewReady = false;
72+
this._isPanelReady = false;
73+
});
7274
}
7375

74-
private handleResolutionViewClosed(): void {
76+
private handleViewClosed(): void {
7577
// Assuming the analysis webview is tracked and can be accessed via the ExtensionState or similar
76-
const sidebarProvider = this._extensionState.webviewProviders.get("sidebar");
77-
if (sidebarProvider?.webview && sidebarProvider._isWebviewReady) {
78-
// sidebarProvider.webview.postMessage({
79-
// type: "solutionConfirmation",
80-
// data: { confirmed: true, solution: null },
81-
// });
82-
} else {
83-
console.error("Analysis webview is not ready or not available.");
84-
}
78+
// const sidebarProvider = this._extensionState.webviewProviders.get("sidebar");
79+
// if (sidebarProvider?.webview && sidebarProvider._isWebviewReady) {
80+
// sidebarProvider.webview.postMessage({
81+
// type: "solutionConfirmation",
82+
// data: { confirmed: true, solution: null },
83+
// });
84+
// } else {
85+
// console.error("Analysis webview is not ready or not available.");
86+
// }
8587
}
8688

8789
public showWebviewPanel(): void {
@@ -92,7 +94,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
9294
}
9395
}
9496

95-
private initializeWebview(webview: Webview): void {
97+
private initializeWebview(webview: Webview, data: Immutable<ExtensionData>): void {
9698
const isProd = process.env.NODE_ENV === "production";
9799
const extensionUri = this._extensionState.extensionContext.extensionUri;
98100

@@ -108,11 +110,11 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
108110
localResourceRoots: isProd ? [assetsUri] : [extensionUri],
109111
};
110112

111-
webview.html = this.getHtmlForWebview(webview);
113+
webview.html = this.getHtmlForWebview(webview, data);
112114
this._setWebviewMessageListener(webview);
113115
}
114116

115-
public getHtmlForWebview(webview: Webview): string {
117+
public getHtmlForWebview(webview: Webview, data: Immutable<ExtensionData>): string {
116118
const stylesUri = this._getStylesUri(webview);
117119
const scriptUri = this._getScriptUri(webview);
118120
const nonce = getNonce();
@@ -129,6 +131,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
129131
const vscode = acquireVsCodeApi();
130132
window.vscode = vscode;
131133
window.viewType = "${this._viewType}";
134+
window.konveyorInitialData = ${JSON.stringify(data)};
132135
</script>
133136
</head>
134137
<body>
@@ -218,7 +221,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
218221
this._isPanelReady = true;
219222
while (this._messageQueue.length > 0) {
220223
const queuedMessage = this._messageQueue.shift();
221-
webview.postMessage(queuedMessage);
224+
this.sendMessage(queuedMessage, webview);
222225
}
223226
}
224227
},
@@ -235,11 +238,19 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
235238
}
236239
}
237240
}
241+
private sendMessage(message: any, webview: Webview) {
242+
webview.postMessage(message).then((deliveryStatus) => {
243+
if (!deliveryStatus) {
244+
console.error(`Message to Konveyor webview '${this._viewType}' not delivered`);
245+
}
246+
});
247+
}
248+
238249
public sendMessageToWebview(message: any): void {
239250
if (this._view?.webview && this._isWebviewReady) {
240-
this._view.webview.postMessage(message);
251+
this.sendMessage(message, this._view.webview);
241252
} else if (this._panel && this._isPanelReady) {
242-
this._panel.webview.postMessage(message);
253+
this.sendMessage(message, this._panel.webview);
243254
} else {
244255
this._messageQueue.push(message);
245256
}

0 commit comments

Comments
 (0)