Skip to content

Commit

Permalink
Use immer to extension state
Browse files Browse the repository at this point in the history
Signed-off-by: Radoslaw Szwajkowski <[email protected]>
  • Loading branch information
rszwajko committed Nov 21, 2024
1 parent 92a488b commit 9a46955
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 67 deletions.
11 changes: 11 additions & 0 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"js-yaml": "^4.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"uuid": "^10.0.0"
"uuid": "^10.0.0",
"immer": "10.1.1"
}
}
4 changes: 2 additions & 2 deletions vscode/src/KonveyorGUIWebviewViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {
this.initializeWebview(this._panel.webview);

if (this._viewType === KonveyorGUIWebviewViewProvider.RESOLUTION_VIEW_TYPE) {
const savedData = this._extensionState.sharedState.get("resolutionPanelData");
const savedData = this._extensionState.data.resolutionPanelData;
if (savedData) {
this._panel.webview.postMessage({ type: "loadResolutionState", data: savedData });
}
Expand Down Expand Up @@ -201,7 +201,7 @@ export class KonveyorGUIWebviewViewProvider implements WebviewViewProvider {

private _loadInitialContent(webview: Webview) {
if (this._isWebviewReady && webview) {
const data = this._extensionState.ruleSets;
const data = this._extensionState.data.ruleSets;
webview.postMessage({
type: "loadStoredAnalysis",
data,
Expand Down
23 changes: 10 additions & 13 deletions vscode/src/data/loadResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,37 @@ import {
RULE_SET_DATA_FILE_PREFIX,
SOLUTION_DATA_FILE_PREFIX,
} from "../utilities";
import { Immutable } from "immer";

export const loadRuleSets = (state: ExtensionState, ruleSets: RuleSet[]): void => {
writeDataFile(ruleSets, RULE_SET_DATA_FILE_PREFIX);
state.ruleSets = ruleSets;
state.diagnosticCollection.set(processIncidents(ruleSets));
const sidebarProvider = state.webviewProviders?.get("sidebar");
sidebarProvider?.webview?.postMessage({
type: "loadStoredAnalysis",
data: ruleSets,
state.mutateData((draft) => {
draft.ruleSets = ruleSets;
});
};
export const cleanRuleSets = (state: ExtensionState) => {
state.ruleSets = [];
state.diagnosticCollection.clear();
const sidebarProvider = state.webviewProviders?.get("sidebar");
sidebarProvider?.webview?.postMessage({
type: "loadStoredAnalysis",
data: undefined,
state.mutateData((draft) => {
draft.ruleSets = [];
});
};

export const loadSolution = async (state: ExtensionState, solution: GetSolutionResult) => {
writeDataFile(solution, SOLUTION_DATA_FILE_PREFIX);
const localChanges = toLocalChanges(solution);
doLoadSolution(state, localChanges);
state.localChanges = localChanges;
state.mutateData((draft) => {
draft.localChanges = localChanges;
});
};

export const reloadLastResolutions = async (state: ExtensionState) => {
doLoadSolution(state, state.localChanges);
doLoadSolution(state, state.data.localChanges);
window.showInformationMessage(`Loaded last available resolutions`);
};

const doLoadSolution = async (state: ExtensionState, localChanges: LocalChange[]) => {
const doLoadSolution = async (state: ExtensionState, localChanges: Immutable<LocalChange[]>) => {
state.memFs.removeAll(KONVEYOR_SCHEME);
await writeSolutionsToMemFs(localChanges, state);
const locations = localChanges.map(
Expand Down
3 changes: 2 additions & 1 deletion vscode/src/data/virtualStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Diff from "diff";
import path from "path";

import { KONVEYOR_SCHEME, fromRelativeToKonveyor } from "../utilities";
import { Immutable } from "immer";

export const toLocalChanges = (solution: GetSolutionResult) =>
solution.changes.map(({ modified, original, diff }) => ({
Expand All @@ -17,7 +18,7 @@ export const toLocalChanges = (solution: GetSolutionResult) =>
}));

export const writeSolutionsToMemFs = async (
localChanges: LocalChange[],
localChanges: Immutable<LocalChange[]>,
{ memFs }: ExtensionState,
) => {
// TODO: implement logic for deleted/added files
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/diffView/copyCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FileItem, toUri } from "./fileModel";
import { ExtensionState } from "src/extensionState";

export async function copyDiff(item: FileItem | vscode.Uri | unknown, state: ExtensionState) {
const localChanges = state.localChanges;
const localChanges = state.data.localChanges;
const uri = toUri(item);
if (!uri) {
console.error("Failed to copy diff. Unknown URI.", item, uri);
Expand Down
4 changes: 2 additions & 2 deletions vscode/src/diffView/solutionCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { fromRelativeToKonveyor, KONVEYOR_READ_ONLY_SCHEME } from "../utilities"
import { FileItem, toUri } from "./fileModel";

export const applyAll = async (state: ExtensionState) => {
const localChanges = state.localChanges;
const localChanges = state.data.localChanges;
await Promise.all(
localChanges.map(({ originalUri, modifiedUri }) =>
vscode.workspace.fs.copy(modifiedUri, originalUri, { overwrite: true }),
Expand All @@ -21,7 +21,7 @@ export const applyAll = async (state: ExtensionState) => {
};

export const discardAll = async (state: ExtensionState) => {
const localChanges = state.localChanges;
const localChanges = state.data.localChanges;
await Promise.all(
localChanges.map(({ originalUri, modifiedUri }) =>
vscode.workspace.fs.copy(originalUri, modifiedUri, { overwrite: true }),
Expand Down
31 changes: 27 additions & 4 deletions vscode/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
import * as vscode from "vscode";
import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider";
import { registerAllCommands as registerAllCommands } from "./commands";
import { ExtensionState, SharedState } from "./extensionState";
import { ExtensionData, ExtensionState } from "./extensionState";
import { ViolationCodeActionProvider } from "./ViolationCodeActionProvider";
import { AnalyzerClient } from "./client/analyzerClient";
import { registerDiffView, KonveyorFileModel } from "./diffView";
import { MemFS } from "./data";
import { Immutable, produce } from "immer";

class VsCodeExtension {
private state: ExtensionState;
private data: Immutable<ExtensionData>;
private _onDidChange = new vscode.EventEmitter<Immutable<ExtensionData>>();
readonly onDidChangeData = this._onDidChange.event;

constructor(context: vscode.ExtensionContext) {
this.data = produce(
{ localChanges: [], ruleSets: [], resolutionPanelData: undefined },
() => {},
);
const getData = () => this.data;
const setData = (data: Immutable<ExtensionData>) => {
this.data = data;
this._onDidChange.fire(this.data);
};

this.state = {
analyzerClient: new AnalyzerClient(context),
sharedState: new SharedState(),
webviewProviders: new Map<string, KonveyorGUIWebviewViewProvider>(),
extensionContext: context,
diagnosticCollection: vscode.languages.createDiagnosticCollection("konveyor"),
memFs: new MemFS(),
fileModel: new KonveyorFileModel(),
localChanges: [],
ruleSets: [],
get data() {
return getData();
},
mutateData: (recipe: (draft: ExtensionData) => void) => {
setData(produce(getData(), recipe));
},
};

this.initializeExtension(context);
Expand Down Expand Up @@ -55,6 +72,12 @@ class VsCodeExtension {
const resolutionViewProvider = new KonveyorGUIWebviewViewProvider(this.state, "resolution");
this.state.webviewProviders.set("resolution", resolutionViewProvider);

[sidebarProvider, resolutionViewProvider].forEach((provider) =>
this.onDidChangeData((data) =>
provider.sendMessageToWebview({ type: "onDidChangeData", value: data }),
),
);

context.subscriptions.push(
vscode.window.registerWebviewViewProvider(
KonveyorGUIWebviewViewProvider.SIDEBAR_VIEW_TYPE,
Expand Down
37 changes: 7 additions & 30 deletions vscode/src/extensionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,21 @@ import { MemFS } from "./data/fileSystemProvider";
import { KonveyorGUIWebviewViewProvider } from "./KonveyorGUIWebviewViewProvider";
import * as vscode from "vscode";
import { LocalChange, RuleSet } from "@editor-extensions/shared";
import { EventEmitter } from "vscode";
import { Immutable } from "immer";

type SharedStateEventData = any; // Or use a specific type if needed

export class SharedState {
private state: Map<string, any> = new Map();
private emitter: EventEmitter<SharedStateEventData> = new EventEmitter<SharedStateEventData>();

get(key: string) {
return this.state.get(key);
}

set(key: string, value: any) {
this.state.set(key, value);
this.emitter.fire({ key, value }); // Emit an event for the key when data is set
}

// Subscribe to an event for a specific key
on(callback: (data: { key: string; value: SharedStateEventData }) => void) {
// Listen for events and pass data to the callback
this.emitter.event(callback);
}

// Remove a listener for the event
off(callback: (data: { key: string; value: SharedStateEventData }) => void) {
// Remove the specific listener callback
this.emitter.event(callback);
}
export interface ExtensionData {
localChanges: LocalChange[];
ruleSets: RuleSet[];
resolutionPanelData: any;
}

export interface ExtensionState {
analyzerClient: AnalyzerClient;
sharedState: SharedState;
webviewProviders: Map<string, KonveyorGUIWebviewViewProvider>;
extensionContext: vscode.ExtensionContext;
diagnosticCollection: vscode.DiagnosticCollection;
memFs: MemFS;
fileModel: KonveyorFileModel;
localChanges: LocalChange[];
ruleSets: RuleSet[];
data: Immutable<ExtensionData>;
mutateData: (recipe: (draft: ExtensionData) => void) => void;
}
15 changes: 2 additions & 13 deletions vscode/src/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from "vscode";
import { ExtensionState } from "./extensionState";
import { loadStateFromDataFolder } from "./data";
import { Change, GetSolutionResult } from "@editor-extensions/shared";
import { Change } from "@editor-extensions/shared";
import { fromRelativeToKonveyor } from "./utilities";
import path from "path";

Expand All @@ -10,18 +10,7 @@ export function setupWebviewMessageListener(webview: vscode.Webview, state: Exte
switch (message.command) {
case "getSolution": {
const { violation, incident } = message;
const [analysisResults, solution] = await loadStateFromDataFolder();

const mockSolution: GetSolutionResult = {
errors: [],
changes: [
{
original: "src/main/java/com/redhat/coolstore/service/CatalogService.java",
modified: "src/main/java/com/redhat/coolstore/service/CatalogService.java",
diff: "diff --git a/src/main/java/com/redhat/coolstore/service/CatalogService.java b/src/main/java/com/redhat/coolstore/service/CatalogService.java\nindex 422a3f4..9a6feff 100644\n--- a/src/main/java/com/redhat/coolstore/service/CatalogService.java\n+++ b/src/main/java/com/redhat/coolstore/service/CatalogService.java\n@@ -9,12 +9,12 @@ import javax.persistence.criteria.CriteriaBuilder;\n import javax.persistence.criteria.CriteriaQuery;\n import javax.persistence.criteria.Root;\n \n-import javax.ejb.Stateless;\n+import jakarta.enterprise.context.ApplicationScoped;\n import javax.persistence.EntityManager;\n \n import com.redhat.coolstore.model.*;\n \n-@Stateless\n+@ApplicationScoped\n public class CatalogService {\n \n @Inject\n",
},
],
};
const [, solution] = await loadStateFromDataFolder();

vscode.commands.executeCommand("konveyor.diffView.focus");
vscode.commands.executeCommand("konveyor.showResolutionPanel");
Expand Down

0 comments on commit 9a46955

Please sign in to comment.