Skip to content

Commit

Permalink
✨ Add server status component (#127)
Browse files Browse the repository at this point in the history
- Disable analysis and getSolution if server is not running
- Move server status and prevent blocking analysis sidebar when server
is starting
- Fix webview ready message to follow "type" convention
- Change startAnalysis to runAnalysis across all files



https://github.com/user-attachments/assets/d68bb713-8fde-482a-94fa-f4cbc3860086

---------

Signed-off-by: Ian Bolton <[email protected]>
  • Loading branch information
ibolton336 authored Dec 4, 2024
1 parent 9e3c6f3 commit 5ed6df1
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 96 deletions.
8 changes: 5 additions & 3 deletions shared/src/types/actions.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
export const SET_STATE = "SET_STATE";
export const START_ANALYSIS = "START_ANALYSIS";
export const RUN_ANALYSIS = "RUN_ANALYSIS";
export const START_SERVER = "START_SERVER";
export const CANCEL_SOLUTION = "CANCEL_SOLUTION";
export const GET_SOLUTION = "GET_SOLUTION";
export const OPEN_FILE = "OPEN_FILE";
export const VIEW_FIX = "VIEW_FIX";
export const APPLY_FILE = "APPLY_FILE";
export const DISCARD_FILE = "DISCARD_FILE";
export const WEBVIEW_READY = "WEBVIEW_READY";

export type WebviewActionType =
| typeof SET_STATE
| typeof START_ANALYSIS
| typeof RUN_ANALYSIS
| typeof START_SERVER
| typeof CANCEL_SOLUTION
| typeof GET_SOLUTION
| typeof OPEN_FILE
| typeof VIEW_FIX
| typeof APPLY_FILE
| typeof DISCARD_FILE;
| typeof DISCARD_FILE
| typeof WEBVIEW_READY;

export interface WebviewAction<S, T> {
type: S;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Start Analyzer
# Start Server

Start using the rules-based analysis engine.
Start kai server. Under the hood it is using the rules-based analysis engine.

Remember to configure your analysis settings beforehand for the best results:

Set up custom rules if needed.
Configure label selector directly or through choosing sources and targets.
These settings can be modified in the Konveyor extension settings or through the walkthrough steps you've already completed.
These settings can be modified in the Konveyor extension settings or through the walkthrough steps you've already completed.
12 changes: 6 additions & 6 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
"title": "Open Kai config.toml"
},
{
"command": "konveyor.startAnalyzer",
"title": "Start Analyzer",
"command": "konveyor.startServer",
"title": "Start Server",
"category": "Konveyor",
"icon": "$(play)"
},
Expand Down Expand Up @@ -508,12 +508,12 @@
}
},
{
"id": "start-analyzer",
"title": "Start Analyzer",
"description": "Start the analyzer\n[Start Analyzer](command:konveyor.startAnalyzer)",
"id": "start-server",
"title": "Start Server",
"description": "Start the analyzer\n[Start Analyzer](command:konveyor.startServer)",
"completionEvents": [],
"media": {
"markdown": "media/walkthroughs/start-analyzer.md"
"markdown": "media/walkthroughs/start-server.md"
}
}
]
Expand Down
10 changes: 2 additions & 8 deletions vscode/src/KonveyorGUIWebviewViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
${this._getReactRefreshScript(nonce)}
<script nonce="${nonce}">
window.addEventListener('DOMContentLoaded', function() {
window.vscode.postMessage({ command: 'webviewReady' });
window.vscode.postMessage({ type: 'WEBVIEW_READY' });
});
</script>
<script type="module" nonce="${nonce}" src="${scriptUri}"></script>
Expand Down Expand Up @@ -213,7 +213,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {

webview.onDidReceiveMessage(
(message) => {
if (message.command === "webviewReady") {
if (message.type === "WEBVIEW_READY") {
this._isWebviewReady = true;
this._isPanelReady = true;
while (this._messageQueue.length > 0) {
Expand All @@ -237,16 +237,10 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
}
public sendMessageToWebview(message: any): void {
if (this._view?.webview && this._isWebviewReady) {
// If the webview is ready, immediately send the message
console.log("Sending message to webview:", message);
this._view.webview.postMessage(message);
} else if (this._panel && this._isPanelReady) {
// For panel case, send the message if the panel is ready
console.log("Sending message to panel:", message);
this._panel.webview.postMessage(message);
} else {
// Queue the message until the webview or panel is ready
console.log("Queuing message until webview or panel is ready:", message);
this._messageQueue.push(message);
}
}
Expand Down
33 changes: 14 additions & 19 deletions vscode/src/client/analyzerClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ChildProcessWithoutNullStreams, exec as callbackExec, spawn } from "child_process";
import util from "node:util";
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import * as vscode from "vscode";
import * as os from "os";
import * as fs from "fs";
Expand All @@ -23,7 +22,6 @@ import {
updateUseDefaultRuleSets,
} from "../utilities";

const exec = util.promisify(callbackExec);
export class AnalyzerClient {
private kaiRpcServer: ChildProcessWithoutNullStreams | null = null;
private outputChannel: vscode.OutputChannel;
Expand Down Expand Up @@ -63,19 +61,15 @@ export class AnalyzerClient {
return;
}

try {
Promise.all([exec("java -version"), exec("mvn -version")]);
} catch {
vscode.window.showErrorMessage("Java or Maven is missing. Please install it to continue.");
return;
}

this.fireStateChange("starting");
this.outputChannel.appendLine(`Starting the server ...`);

this.kaiRpcServer = spawn(this.getKaiRpcServerPath(), this.getKaiRpcServerArgs(), {
cwd: this.extContext!.extensionPath,
env: { ...process.env, GENAI_KEY: "BWAHAHA" },
env: {
...process.env,
GENAI_KEY: "BWAHAHA",
},
});

this.kaiRpcServer.stderr.on("data", (data) => {
Expand Down Expand Up @@ -169,7 +163,9 @@ export class AnalyzerClient {
for (let attempt = 0; attempt < 10; attempt++) {
this.outputChannel.appendLine("Sending 'initialize' request.");
try {
progress.report({ message: "Sending 'initialize' request to RPC Server" });
progress.report({
message: "Sending 'initialize' request to RPC Server",
});
const response = await this.rpcConnection!.sendRequest<void>(
"initialize",
initializeParams,
Expand Down Expand Up @@ -261,8 +257,6 @@ export class AnalyzerClient {
ruleset_name: violation.category || "default_ruleset", // You may adjust the default value as necessary
violation_name: violation.description || "default_violation", // You may adjust the default value as necessary
};
console.log("what is the violation? ", violation);
console.log("what is the incident? ", incident);

try {
const response: SolutionResponse = await this.rpcConnection!.sendRequest(
Expand All @@ -276,11 +270,11 @@ export class AnalyzerClient {
},
);

console.log("response", response, incident, state);
vscode.commands.executeCommand("konveyor.loadSolution", response, { incident, violation });
vscode.commands.executeCommand("konveyor.loadSolution", response, {
incident,
violation,
});
} catch (err: any) {
console.log("response err", err);
console.log("err incident", incident);
this.outputChannel.appendLine(`Error during getSolution: ${err.message}`);
vscode.window.showErrorMessage("Get solution failed. See the output channel for details.");
}
Expand Down Expand Up @@ -487,11 +481,12 @@ file_log_level = "debug"
log_dir = "${log_dir}"
[models]
provider = "ChatIBMGenAI"
provider = "ChatIBMGenAI
[models.args]
model_id = "meta-llama/llama-3-70b-instruct"
parameters.max_new_tokens = "2048"
`;
}
}
3 changes: 2 additions & 1 deletion vscode/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const commandsMap: (state: ExtensionState) => {
const { extensionContext } = state;
const sidebarProvider = state.webviewProviders?.get("sidebar");
return {
"konveyor.startAnalyzer": async () => {
"konveyor.startServer": async () => {
const analyzerClient = state.analyzerClient;
if (!(await analyzerClient.canAnalyzeInteractive())) {
return;
Expand All @@ -56,6 +56,7 @@ const commandsMap: (state: ExtensionState) => {
await analyzerClient.initialize();
},
"konveyor.runAnalysis": async () => {
console.log("run analysis command called");
const analyzerClient = state.analyzerClient;
if (!analyzerClient || !analyzerClient.canAnalyze()) {
window.showErrorMessage("Analyzer must be started and configured before run!");
Expand Down
3 changes: 0 additions & 3 deletions vscode/src/data/loadResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ export const cleanRuleSets = (state: ExtensionState) => {
};

export const loadSolution = async (state: ExtensionState, solution: Solution, scope?: Scope) => {
console.log("what is solution here in loadSolution", solution);

await writeDataFile(solution, SOLUTION_DATA_FILE_PREFIX);
await doLoadSolution(
state,
Expand Down Expand Up @@ -61,7 +59,6 @@ const doLoadSolution = async (
scope?: Immutable<Scope>,
) => {
state.memFs.removeAll(KONVEYOR_SCHEME);
console.log("what are localChanges here in doLoadSolution", localChanges);
await writeSolutionsToMemFs(localChanges, state);
state.mutateData((draft) => {
draft.localChanges = localChanges;
Expand Down
3 changes: 0 additions & 3 deletions vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class VsCodeExtension {
);
const getData = () => this.data;
const setData = (data: Immutable<ExtensionData>) => {
console.log("setting data now", data);
this.data = data;
this._onDidChange.fire(this.data);
};
Expand Down Expand Up @@ -87,8 +86,6 @@ class VsCodeExtension {

[sidebarProvider, resolutionViewProvider].forEach((provider) =>
this.onDidChangeData((data) => {
console.log("State changed, sending data to webview:", data); // Log the state being sent

provider.sendMessageToWebview(data);
}),
);
Expand Down
12 changes: 9 additions & 3 deletions vscode/src/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import {
LocalChange,
OPEN_FILE,
Scope,
START_ANALYSIS,
RUN_ANALYSIS,
START_SERVER,
VIEW_FIX,
WEBVIEW_READY,
WebviewAction,
WebviewActionType,
} from "@editor-extensions/shared";
Expand All @@ -21,6 +22,9 @@ export function setupWebviewMessageListener(webview: vscode.Webview, state: Exte
const actions: {
[name: string]: (payload: any) => void;
} = {
[WEBVIEW_READY]() {
console.log("Webview is ready");
},
[GET_SOLUTION](scope: Scope) {
vscode.commands.executeCommand("konveyor.getSolution", scope.incident, scope.violation);

Expand Down Expand Up @@ -56,7 +60,8 @@ const actions: {
// action.isPreferred = true;
// vscode.commands.executeCommand("vscode.executeCodeActionProvider", message.documentUri, message.range, action);
// },
[START_ANALYSIS]() {
[RUN_ANALYSIS]() {
console.log("Running analysis...");
vscode.commands.executeCommand("konveyor.runAnalysis");
},
async [OPEN_FILE]({ file, line }) {
Expand All @@ -75,11 +80,12 @@ const actions: {
}
},
[START_SERVER]() {
vscode.commands.executeCommand("konveyor.startAnalyzer");
vscode.commands.executeCommand("konveyor.startServer");
},
};

export const messageHandler = async (message: WebviewAction<WebviewActionType, unknown>) => {
console.log("Received message inside message handler...", message);
const handler = actions?.[message?.type];
if (handler) {
await handler(message.payload);
Expand Down
61 changes: 19 additions & 42 deletions webview-ui/src/components/AnalysisPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import ProgressIndicator from "./ProgressIndicator";
import ViolationIncidentsList from "./ViolationIncidentsList";
import { Incident } from "@editor-extensions/shared";
import { useExtensionState } from "../hooks/useExtensionState";
import { WarningTriangleIcon } from "@patternfly/react-icons";
import { cancelSolution, getSolution, openFile, startServer } from "../hooks/actions";
import { cancelSolution, getSolution, openFile, startServer, runAnalysis } from "../hooks/actions";
import { ServerStatusToggle } from "./ServerStatusToggle/ServerStatusToggle";

const AnalysisPage: React.FC = () => {
const [state, dispatch] = useExtensionState();
Expand All @@ -49,10 +49,17 @@ const AnalysisPage: React.FC = () => {
dispatch(openFile(incident.uri, incident.lineNumber));
};

const startAnalysis = () => dispatch(startAnalysis());
const runAnalysisRequest = () => dispatch(runAnalysis());

const cancelSolutionRequest = () => dispatch(cancelSolution());

const handleServerToggle = () => {
if (!serverRunning) {
dispatch(startServer());
}
// Add stopServer action when available
};

const violations = useMemo(() => {
if (!analysisResults?.length) {
return [];
Expand All @@ -68,45 +75,14 @@ const AnalysisPage: React.FC = () => {
const hasViolations = violations.length > 0;
const hasAnalysisResults = analysisResults !== undefined;

if (isStartingServer) {
return (
<Backdrop>
<div style={{ textAlign: "center", paddingTop: "15rem" }}>
<Spinner size="lg" />
<Title headingLevel="h2" size="lg">
Starting server...
</Title>
</div>
</Backdrop>
);
}

if (!serverRunning && !hasViolations) {
return (
<Page>
<PageSection>
<EmptyState icon={WarningTriangleIcon}>
<Title headingLevel="h2" size="lg">
Server Not Running
</Title>
<EmptyStateBody>
The server is not running. Please start the server to run an analysis.
</EmptyStateBody>
<Button
className={spacing.mtMd}
variant={ButtonVariant.primary}
onClick={() => dispatch(startServer())}
>
Start Server
</Button>
</EmptyState>
</PageSection>
</Page>
);
}

return (
<Page>
<ServerStatusToggle
isRunning={serverRunning}
isStarting={isStartingServer}
onToggle={handleServerToggle}
/>

{errorMessage && (
<PageSection padding={{ default: "noPadding" }}>
<AlertGroup isToast>
Expand Down Expand Up @@ -143,9 +119,9 @@ const AnalysisPage: React.FC = () => {
<StackItem>
<Button
variant={ButtonVariant.primary}
onClick={startAnalysis}
onClick={runAnalysisRequest}
isLoading={isAnalyzing}
isDisabled={isAnalyzing || isStartingServer}
isDisabled={isAnalyzing || isStartingServer || !serverRunning}
>
{isAnalyzing ? "Analyzing..." : "Run Analysis"}
</Button>
Expand Down Expand Up @@ -178,6 +154,7 @@ const AnalysisPage: React.FC = () => {

{hasViolations && !isAnalyzing && (
<ViolationIncidentsList
isRunning={serverRunning}
violations={violations}
focusedIncident={focusedIncident}
onIncidentSelect={handleIncidentSelect}
Expand Down
Loading

0 comments on commit 5ed6df1

Please sign in to comment.