You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2022/06/14 22:33:16 UTC

[camel-karavan] branch main updated: Fix #367 (#369)

This is an automated email from the ASF dual-hosted git repository.

marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git


The following commit(s) were added to refs/heads/main by this push:
     new d828ba2  Fix #367 (#369)
d828ba2 is described below

commit d828ba218e57f63f76f95e800605ba85bba46c36
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Tue Jun 14 18:33:10 2022 -0400

    Fix #367 (#369)
---
 karavan-vscode/src/designerView.ts                 | 144 +++++++++++---------
 karavan-vscode/src/extension.ts                    | 139 +++++++++++--------
 karavan-vscode/src/helpView.ts                     |  24 ++--
 karavan-vscode/src/integrationView.ts              |  50 ++++---
 karavan-vscode/src/{commands.ts => jbang.ts}       |  48 +++----
 karavan-vscode/src/openapiView.ts                  |  56 ++++----
 karavan-vscode/src/utils.ts                        | 147 +++++++++++++--------
 karavan-vscode/webview/builder/PropertiesTable.tsx |  26 ++--
 8 files changed, 368 insertions(+), 266 deletions(-)

diff --git a/karavan-vscode/src/designerView.ts b/karavan-vscode/src/designerView.ts
index af8059e..aa89553 100644
--- a/karavan-vscode/src/designerView.ts
+++ b/karavan-vscode/src/designerView.ts
@@ -14,42 +14,43 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import * as vscode from "vscode";
-import * as fs from "fs";
+import { workspace, Uri, window, commands, WebviewPanel, ExtensionContext, ViewColumn, WebviewPanelOnDidChangeViewStateEvent } from "vscode";
 import * as path from "path";
 import * as utils from "./utils";
-import * as commands from "./commands";
+import * as jbang from "./jbang";
 import { CamelDefinitionYaml } from "karavan-core/lib/api/CamelDefinitionYaml";
 import { Integration } from "karavan-core/lib/model/IntegrationDefinition";
 
 const KARAVAN_LOADED = "karavan:loaded";
-const KARAVAN_PANELS: Map<string, vscode.WebviewPanel> = new Map<string, vscode.WebviewPanel>();
+const KARAVAN_PANELS: Map<string, WebviewPanel> = new Map<string, WebviewPanel>();
 const extension = '.properties';
 
 export class DesignerView {
 
-    constructor(private context: vscode.ExtensionContext, private webviewContent: string, private rootPath?: string) {
+    constructor(private context: ExtensionContext, private webviewContent: string, private rootPath?: string) {
 
     }
 
     karavanOpen(fullPath: string, tab?: string) {
-        const yaml = fs.readFileSync(path.resolve(fullPath)).toString('utf8');
-        const filename = path.basename(fullPath);
-        const relativePath = utils.getRalativePath(fullPath);
-        const integration = utils.parceYaml(filename, yaml);
+        utils.readFile(path.resolve(fullPath)).then(readData => {
+            const yaml = Buffer.from(readData).toString('utf8');
+            const filename = path.basename(fullPath);
+            const relativePath = utils.getRalativePath(fullPath);
+            const integration = utils.parceYaml(filename, yaml);
 
-        if (integration[0]) {
-            this.openKaravanWebView(filename, relativePath, fullPath, integration[1], tab);
-        } else {
-            vscode.window.showErrorMessage("File is not Camel Integration!")
-        }
+            if (integration[0]) {
+                this.openKaravanWebView(filename, relativePath, fullPath, integration[1], tab);
+            } else {
+                window.showErrorMessage("File is not Camel Integration!")
+            }
+        })
     }
 
     jbangRun(fullPath: string) {
         const filename = this.getFilename(fullPath);
-        if (filename && this.rootPath){
+        if (filename && this.rootPath) {
             this.selectProfile(this.rootPath, filename);
-        }        
+        }
     }
 
     getFilename(fullPath: string) {
@@ -59,37 +60,40 @@ export class DesignerView {
                 return filename;
             }
         } else {
-            const yaml = fs.readFileSync(path.resolve(fullPath)).toString('utf8');
-            const relativePath = utils.getRalativePath(fullPath);
-            const filename = path.basename(fullPath);
-            const integration = utils.parceYaml(filename, yaml);
-            if (integration[0] && this.rootPath) {
-                return relativePath;
-            } else {
-                vscode.window.showErrorMessage("File is not Camel Integration!")
-            }
+            utils.readFile(path.resolve(fullPath)).then(readData => {
+                const yaml = Buffer.from(readData).toString('utf8');
+                const relativePath = utils.getRalativePath(fullPath);
+                const filename = path.basename(fullPath);
+                const integration = utils.parceYaml(filename, yaml);
+                if (integration[0] && this.rootPath) {
+                    return relativePath;
+                } else {
+                    window.showErrorMessage("File is not Camel Integration!")
+                }
+            });
         }
     }
 
     selectProfile(rootPath: string, filename?: string) {
         if (this.rootPath) {
-            const profiles: string [] = utils.getProfiles();
-            if (profiles && profiles.length > 0){
-                vscode.window.showQuickPick(profiles).then((profile) => {
-                    if (!profile) {
-                        return
-                    } else {
-                        commands.camelJbangRun(rootPath, profile, filename);
-                    }
-                })
-            } else {
-                commands.camelJbangRun(rootPath, "application", filename);
-            }
+            utils.getProfiles().then(profiles => {
+                if (profiles && profiles.length > 0) {
+                    window.showQuickPick(profiles).then((profile) => {
+                        if (!profile) {
+                            return
+                        } else {
+                            jbang.camelJbangRun(rootPath, profile, filename);
+                        }
+                    })
+                } else {
+                    jbang.camelJbangRun(rootPath, "application", filename);
+                }
+            });
         }
     }
 
     createIntegration(crd: boolean, rootPath?: string) {
-        vscode.window
+        window
             .showInputBox({
                 title: crd ? "Create Camel Integration CRD" : "Create Camel Integration YAML",
                 ignoreFocusOut: true,
@@ -109,32 +113,32 @@ export class DesignerView {
                     const yaml = CamelDefinitionYaml.integrationToYaml(i);
                     const filename = name.toLocaleLowerCase().endsWith('.yaml') ? name : name + '.yaml';
                     const relativePath = (this.rootPath ? rootPath?.replace(this.rootPath, "") : rootPath) + path.sep + filename;
-                    const fullPath =  (rootPath ? rootPath : this.rootPath) + path.sep + filename;
+                    const fullPath = (rootPath ? rootPath : this.rootPath) + path.sep + filename;
                     utils.save(relativePath, yaml);
                     this.openKaravanWebView(filename, filename, fullPath, yaml);
-                    vscode.commands.executeCommand('integrations.refresh');
+                    commands.executeCommand('integrations.refresh');
                 }
             });
     }
 
-    openKaravanWebView(filename: string, relativePath: string, fullPath: string,  yaml?: string, tab?: string) {
+    openKaravanWebView(filename: string, relativePath: string, fullPath: string, yaml?: string, tab?: string) {
         console.log("openKaravanWebView");
         if (!KARAVAN_PANELS.has(relativePath)) {
             // Karavan webview
-            const panel = vscode.window.createWebviewPanel(
+            const panel = window.createWebviewPanel(
                 "karavan",
                 filename,
-                vscode.ViewColumn.One,
+                ViewColumn.One,
                 {
                     enableScripts: true,
                     retainContextWhenHidden: true,
                     localResourceRoots: [
-                        vscode.Uri.joinPath(this.context.extensionUri, "dist"),
+                        Uri.joinPath(this.context.extensionUri, "dist"),
                     ],
                 }
             );
             panel.webview.html = this.webviewContent;
-            panel.iconPath = vscode.Uri.joinPath(
+            panel.iconPath = Uri.joinPath(
                 this.context.extensionUri,
                 "icons/karavan.svg"
             );
@@ -152,7 +156,7 @@ export class DesignerView {
                             break;
                         case 'disableStartHelp':
                             utils.disableStartHelp();
-                            break;    
+                            break;
                     }
                 },
                 undefined,
@@ -164,7 +168,7 @@ export class DesignerView {
             }, null, this.context.subscriptions);
 
             // Handle reopen
-            panel.onDidChangeViewState((e: vscode.WebviewPanelOnDidChangeViewStateEvent) => {
+            panel.onDidChangeViewState((e: WebviewPanelOnDidChangeViewStateEvent) => {
                 console.log(e);
                 if (e.webviewPanel.active || e.webviewPanel.reveal) {
                     e.webviewPanel.webview.postMessage({ command: 'activate', tab: tab });
@@ -174,7 +178,7 @@ export class DesignerView {
             });
 
             KARAVAN_PANELS.set(relativePath, panel);
-            vscode.commands.executeCommand("setContext", KARAVAN_LOADED, true);
+            commands.executeCommand("setContext", KARAVAN_LOADED, true);
         } else {
             const panel = KARAVAN_PANELS.get(relativePath);
             panel?.reveal(undefined, true);
@@ -182,24 +186,38 @@ export class DesignerView {
         }
     }
 
-    sendData(panel: vscode.WebviewPanel, filename: string, relativePath: string, fullPath: string, reread: boolean, yaml?: string, tab?: string) {
-
-        // Read and send Kamelets
-        panel.webview.postMessage({ command: 'kamelets', kamelets: utils.readKamelets(this.context) });
-
-        // Read and send Components
-        panel.webview.postMessage({ command: 'components', components: utils.readComponents(this.context) });
-
-        // Send showStartHelp
-        const showStartHelp = vscode.workspace.getConfiguration().get("Karavan.showStartHelp");
-        panel.webview.postMessage({ command: 'showStartHelp', showStartHelp: showStartHelp});
+    sendData(panel: WebviewPanel, filename: string, relativePath: string, fullPath: string, reread: boolean, yaml?: string, tab?: string) {
+        Promise.all([
+            // Read Kamelets
+            utils.readKamelets(this.context),
+            // Read components
+            utils.readComponents(this.context)
+        ]).then(results => {
+            // Send Kamelets
+            panel.webview.postMessage({ command: 'kamelets', kamelets: results[0] });
+            // Send components
+            panel.webview.postMessage({ command: 'components', components: results[1] });
+            // Send showStartHelp
+            const showStartHelp = workspace.getConfiguration().get("Karavan.showStartHelp");
+            panel.webview.postMessage({ command: 'showStartHelp', showStartHelp: showStartHelp });
+            // Send integration
+            this.sendIntegrationData(panel, filename, relativePath, fullPath, reread, yaml, tab)
+        })
+    }
 
+    sendIntegrationData(panel: WebviewPanel, filename: string, relativePath: string, fullPath: string, reread: boolean, yaml?: string, tab?: string) {
         // Read file if required
-        if (reread){
-            yaml = fs.readFileSync(path.resolve(fullPath)).toString('utf8');
+        if (reread) {
+            utils.readFile(path.resolve(fullPath)).then(readData => {
+                const yaml = Buffer.from(readData).toString('utf8');
+                // Send integration
+                panel.webview.postMessage({ command: 'open', page: "designer", filename: filename, relativePath: relativePath, yaml: yaml, tab: tab });
+            });
+        } else {
+            // Send integration
+            panel.webview.postMessage({ command: 'open', page: "designer", filename: filename, relativePath: relativePath, yaml: yaml, tab: tab });
         }
-        // Send integration
-        panel.webview.postMessage({ command: 'open', page: "designer", filename: filename, relativePath: relativePath, yaml: yaml, tab: tab });
+
     }
 
 }
\ No newline at end of file
diff --git a/karavan-vscode/src/extension.ts b/karavan-vscode/src/extension.ts
index 4fd268a..b1baa2f 100644
--- a/karavan-vscode/src/extension.ts
+++ b/karavan-vscode/src/extension.ts
@@ -14,82 +14,104 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import vscode, { window } from 'vscode';
-import * as fs from "fs";
+import { ExtensionContext, Uri, window, workspace, commands } from 'vscode';
 import { DesignerView } from "./designerView";
 import { IntegrationView } from "./integrationView";
 import { HelpView } from "./helpView";
 import { selectFileName, inputFileName, OpenApiView, OpenApiItem } from "./openapiView";
 import * as path from "path";
-import * as commands from "./commands";
+import * as jbang from "./jbang";
 import * as utils from "./utils";
+import * as fs from "fs";
 
 const KARAVAN_LOADED = "karavan:loaded";
 
-export function activate(context: vscode.ExtensionContext) {
-    const webviewContent = fs
-        .readFileSync(
-            vscode.Uri.joinPath(context.extensionUri, "dist/index.html").fsPath,
-            { encoding: "utf-8" }
-        )
-        .replace(
-            "styleUri",
-            vscode.Uri.joinPath(context.extensionUri, "/dist/main.css")
-                .with({ scheme: "vscode-resource" })
-                .toString()
-        )
-        .replace(
-            "scriptUri",
-            vscode.Uri.joinPath(context.extensionUri, "/dist/webview.js")
-                .with({ scheme: "vscode-resource" })
-                .toString()
-        );
-
-    const rootPath = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0))
-        ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined;
+export function activate(context: ExtensionContext) {
+    const webviewContent = `<!DOCTYPE html>
+    <html lang="en">
+    
+    <head>
+      <meta charset="utf-8" />
+      <meta name="viewport" content="width=device-width, initial-scale=1" />
+      <link href="styleUri" rel="stylesheet" type="text/css" />
+    </head>
+    
+    <body>
+      <noscript>You need to enable JavaScript to run this app.</noscript>
+      <div id="root">
+        <div class="pf-c-page karavan">
+          <main class="pf-c-page__main" tabindex="-1">
+            <section class="pf-c-page__main-section pf-m-dark-200 loading-page"><svg
+                class="pf-c-spinner pf-m-xl progress-stepper" role="progressbar" aria-valuetext="Loading..."
+                viewBox="0 0 100 100" style="--pf-c-spinner--diameter:80px" aria-label="Loading...">
+                <circle class="pf-c-spinner__path" cx="50" cy="50" r="45" fill="none"></circle>
+              </svg></section>
+          </main>
+        </div>
+      </div>
+      <script>
+      </script>
+      <script src="scriptUri"></script>
+    </body>
+    
+    </html>`
+            .replace(
+                "styleUri",
+                Uri.joinPath(context.extensionUri, "/dist/main.css")
+                    .with({ scheme: "vscode-resource" })
+                    .toString()
+            )
+            .replace(
+                "scriptUri",
+                Uri.joinPath(context.extensionUri, "/dist/webview.js")
+                    .with({ scheme: "vscode-resource" })
+                    .toString()
+            );
+    const rootPath = (workspace.workspaceFolders && (workspace.workspaceFolders.length > 0))
+        ? workspace.workspaceFolders[0].uri.fsPath : undefined;
 
     // Register views    
     const designer = new DesignerView(context, webviewContent, rootPath);
 
     const integrationView = new IntegrationView(designer, rootPath);
-    vscode.window.registerTreeDataProvider('integrations', integrationView);
-    vscode.commands.registerCommand('integrations.refresh', () => integrationView.refresh());
+    window.registerTreeDataProvider('integrations', integrationView);
+    commands.registerCommand('integrations.refresh', () => integrationView.refresh());
 
     const openapiView = new OpenApiView(designer, rootPath);
-    vscode.window.registerTreeDataProvider('openapi', openapiView);
-    vscode.commands.registerCommand('openapi.refresh', () => openapiView.refresh());
+    window.registerTreeDataProvider('openapi', openapiView);
+    commands.registerCommand('openapi.refresh', () => openapiView.refresh());
 
     const helpView = new HelpView(context, webviewContent);
-    vscode.window.registerTreeDataProvider('help', helpView);
-    vscode.commands.registerCommand('karavan.openKamelets', () => helpView.openKaravanWebView("kamelets"));
-    vscode.commands.registerCommand('karavan.openComponents', () => helpView.openKaravanWebView("components"));
-    vscode.commands.registerCommand('karavan.openEip', () => helpView.openKaravanWebView("eip"));
+    window.registerTreeDataProvider('help', helpView);
+    commands.registerCommand('karavan.openKamelets', () => helpView.openKaravanWebView("kamelets"));
+    commands.registerCommand('karavan.openComponents', () => helpView.openKaravanWebView("components"));
+    commands.registerCommand('karavan.openEip', () => helpView.openKaravanWebView("eip"));
 
     // Create new Integration CRD command
-    const createCrd = vscode.commands.registerCommand("karavan.create-crd", (...args: any[]) => {
+    const createCrd = commands.registerCommand("karavan.create-crd", (...args: any[]) => {
         if (args.length > 0) designer.createIntegration(true, args[0].fsPath)
         else designer.createIntegration(true, rootPath)
     });
     context.subscriptions.push(createCrd);
 
     // Create new Integration YAML command
-    const createYaml = vscode.commands.registerCommand("karavan.create-yaml", (...args: any[]) => designer.createIntegration(false, args[0].fsPath));
+    const createYaml = commands.registerCommand("karavan.create-yaml", (...args: any[]) => designer.createIntegration(false, args[0].fsPath));
     context.subscriptions.push(createYaml);
 
     // Open integration in designer command
-    const open = vscode.commands.registerCommand("karavan.open", (...args: any[]) => designer.karavanOpen(args[0].fsPath, args[0].tab));
+    const open = commands.registerCommand("karavan.open", (...args: any[]) => designer.karavanOpen(args[0].fsPath, args[0].tab));
     context.subscriptions.push(open);
 
     // Open integration in editor command
-    const openFile = vscode.commands.registerCommand("karavan.open-file", (...args: any[]) => {
-        let uri = vscode.Uri.file(args[0].fsPath);
-        vscode.window.showTextDocument(uri, { preserveFocus: false, preview: false });
+    const openFile = commands.registerCommand("karavan.open-file", (...args: any[]) => {
+        let uri = Uri.file(args[0].fsPath);
+        window.showTextDocument(uri, { preserveFocus: false, preview: false });
     });
     context.subscriptions.push(openFile);
 
     // Export to Quarkus or Spring
     const exportOptions = ["Quarkus", "Spring"];
-    const exportCommand = vscode.commands.registerCommand("karavan.jbang-export", (...args: any[]) => {
+    const exportCommand = commands.registerCommand("karavan.jbang-export", (...args: any[]) => {
         window.showQuickPick(exportOptions, { title: "Select Runtime", canPickMany: false }).then((value) => {
             if (value) inputExportFolder(value, rootPath);
         })
@@ -97,28 +119,29 @@ export function activate(context: vscode.ExtensionContext) {
     context.subscriptions.push(exportCommand);
 
     // Run Integration in designer command
-    const run = vscode.commands.registerCommand("karavan.jbang-run-file", (...args: any[]) => designer.jbangRun(args[0].fsPath));
+    const run = commands.registerCommand("karavan.jbang-run-file", (...args: any[]) => designer.jbangRun(args[0].fsPath));
     context.subscriptions.push(run);
 
     // Run project
-    const runProjectCommand = vscode.commands.registerCommand("karavan.jbang-run-project", (...args: any[]) => {
+    const runProjectCommand = commands.registerCommand("karavan.jbang-run-project", (...args: any[]) => {
         console.log("RUN PROJECT")
-        const profiles = utils.getProfiles(rootPath);
-        console.log("profiles", profiles)
-        if (profiles && profiles.length > 0) {
-            profiles.push("Default");
-            window.showQuickPick(profiles, { title: "Select Profile", canPickMany: false }).then((value) => {
-                if (value && rootPath) commands.camelJbangRun(rootPath, value !== "Default" ? value : undefined);
-            })
-        } else {
-            if (rootPath) commands.camelJbangRun(rootPath);
-        }
+        utils.getProfiles(rootPath).then(profiles => {
+            console.log("profiles", profiles)
+            if (profiles && profiles.length > 0) {
+                profiles.push("Default");
+                window.showQuickPick(profiles, { title: "Select Profile", canPickMany: false }).then((value) => {
+                    if (value && rootPath) jbang.camelJbangRun(rootPath, value !== "Default" ? value : undefined);
+                })
+            } else {
+                if (rootPath) jbang.camelJbangRun(rootPath);
+            }
+        })
     });
     context.subscriptions.push(runProjectCommand);
 
     // Generate RST API from OpenAPI specification command
     const generateOptions = ["Create new CRD", "Create new YAML", "Add to existing file"];
-    const generateRest = vscode.commands.registerCommand('karavan.generate-rest', async (...args: any[]) => {
+    const generateRest = commands.registerCommand('karavan.generate-rest', async (...args: any[]) => {
         const openApi: OpenApiItem = args[0];
         window.showQuickPick(generateOptions, { title: "Select REST Generator options", canPickMany: false }).then((value) => {
             switch (value) {
@@ -131,8 +154,8 @@ export function activate(context: vscode.ExtensionContext) {
     context.subscriptions.push(generateRest);
 
     // Create issue command
-    vscode.commands.registerCommand('karavan.reportIssue', () => {
-        vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://github.com/apache/camel-karavan/issues/new?title=[VS+Code]New+report&template=issue_template.md'));
+    commands.registerCommand('karavan.reportIssue', () => {
+        commands.executeCommand('open', Uri.parse('https://github.com/apache/camel-karavan/issues/new?title=[VS+Code]New+report&template=issue_template.md'));
     });
 }
 
@@ -140,7 +163,7 @@ export function activate(context: vscode.ExtensionContext) {
  * export into folder
  */
 export async function inputExportFolder(runtime: string, rootPath?: string) {
-    vscode.window.showInputBox({
+    window.showInputBox({
         title: "Export project with " + runtime,
         ignoreFocusOut: true,
         prompt: "Export folder name",
@@ -163,7 +186,7 @@ export async function inputExportFolder(runtime: string, rootPath?: string) {
  * export with gav
  */
 export async function inputExportGav(runtime: string, folder: string) {
-    vscode.window.showInputBox({
+    window.showInputBox({
         title: "Export project with " + runtime,
         ignoreFocusOut: true,
         prompt: "groupId:artifactId:version",
@@ -176,13 +199,13 @@ export async function inputExportGav(runtime: string, folder: string) {
         }
     }).then(gav => {
         if (gav) {
-            commands.camelJbangExport(runtime.toLowerCase(), folder, gav);
+            jbang.camelJbangExport(runtime.toLowerCase(), folder, gav);
         }
     });
 }
 
 export function deactivate() {
-    vscode.commands.executeCommand("setContext", KARAVAN_LOADED, false);
+    commands.executeCommand("setContext", KARAVAN_LOADED, false);
 }
 
 
diff --git a/karavan-vscode/src/helpView.ts b/karavan-vscode/src/helpView.ts
index 4bf321b..70dec55 100644
--- a/karavan-vscode/src/helpView.ts
+++ b/karavan-vscode/src/helpView.ts
@@ -33,10 +33,10 @@ export class HelpView implements vscode.TreeDataProvider<HelpItem> {
 	}
 	getChildren(element?: HelpItem): vscode.ProviderResult<HelpItem[]> {
 		const helpItems: HelpItem[] = [];
-		helpItems.push(new HelpItem("Enterprise Integration Patterns", "Enterprise Integration Patterns", "eip", 'combine',  { command: 'karavan.openEip' , title: ''}));
+		helpItems.push(new HelpItem("Enterprise Integration Patterns", "Enterprise Integration Patterns", "eip", 'combine', { command: 'karavan.openEip', title: '' }));
 		helpItems.push(new HelpItem("Kamelet catalog", "Kamelet Catalog", "kamelets", 'extensions', { command: 'karavan.openKamelets', title: '' }));
 		helpItems.push(new HelpItem("Component catalog", "Component Catalog", "component", 'extensions', { command: 'karavan.openComponents', title: '' }));
-		helpItems.push(new HelpItem("Report issue", "Report Issue", "issue", 'comment', { command: 'karavan.reportIssue' , title: ''}));
+		helpItems.push(new HelpItem("Report issue", "Report Issue", "issue", 'comment', { command: 'karavan.reportIssue', title: '' }));
 		return Promise.resolve(helpItems);
 	}
 
@@ -95,15 +95,19 @@ export class HelpView implements vscode.TreeDataProvider<HelpItem> {
 		}
 	}
 
-	sendData(panel: vscode.WebviewPanel, page: string) {
+	 sendData(panel: vscode.WebviewPanel, page: string) {
 		// Read and send Kamelets
-		if (page === 'kamelets') panel.webview.postMessage({ command: 'kamelets', kamelets: utils.readKamelets(this.context) });
-
-		// Read and send Components
-		if (page === 'components') panel.webview.postMessage({ command: 'components', components: utils.readComponents(this.context) });
-
-		// Send integration
-		panel.webview.postMessage({ command: 'open', page: page });
+		utils.readKamelets(this.context).then(kamelets => {
+			if (page === 'kamelets') panel.webview.postMessage({ command: 'kamelets', kamelets: kamelets });
+		}).finally(() => {
+			utils.readComponents(this.context).then(components => {
+				// Read and send Components
+				if (page === 'components') panel.webview.postMessage({ command: 'components', components: components });
+			}).finally(() => {
+				// Send integration
+				panel.webview.postMessage({ command: 'open', page: page });
+			})
+		})
 	}
 }
 
diff --git a/karavan-vscode/src/integrationView.ts b/karavan-vscode/src/integrationView.ts
index e1188f4..25a9225 100644
--- a/karavan-vscode/src/integrationView.ts
+++ b/karavan-vscode/src/integrationView.ts
@@ -14,40 +14,52 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import * as vscode from "vscode";
+import { workspace, TreeDataProvider, EventEmitter, Event, TreeItem, ProviderResult, Command, ThemeIcon, TreeItemCollapsibleState } from "vscode";
 import * as path from "path";
 import * as utils from "./utils";
-import * as fs from "fs";
 import { CamelDefinitionYaml } from "karavan-core/lib/api/CamelDefinitionYaml";
 import { DesignerView } from "./designerView";
 import { Integration } from "karavan-core/lib/model/IntegrationDefinition";
 
-export class IntegrationView implements vscode.TreeDataProvider<IntegrationItem> {
+export class IntegrationView implements TreeDataProvider<IntegrationItem> {
 
 	constructor(private designer: DesignerView, private rootPath: string | undefined) {
 
 	}
-	private _onDidChangeTreeData: vscode.EventEmitter<IntegrationItem | undefined | void> = new vscode.EventEmitter<IntegrationItem | undefined | void>();
-	readonly onDidChangeTreeData: vscode.Event<IntegrationItem | undefined | void> = this._onDidChangeTreeData.event;
+	private _onDidChangeTreeData: EventEmitter<IntegrationItem | undefined | void> = new EventEmitter<IntegrationItem | undefined | void>();
+	readonly onDidChangeTreeData: Event<IntegrationItem | undefined | void> = this._onDidChangeTreeData.event;
 
-	getTreeItem(element: IntegrationItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
+	getTreeItem(element: IntegrationItem): TreeItem | Thenable<TreeItem> {
 		return element;
 	}
-	getChildren(element?: IntegrationItem): vscode.ProviderResult<IntegrationItem[]> {
-		const integrations: IntegrationItem[] = [];
+	getChildren(element?: IntegrationItem): ProviderResult<IntegrationItem[]> {
 		if (element === undefined && this.rootPath) {
-			utils.getIntegrationFiles(this.rootPath).forEach(f => {
-				const yaml = fs.readFileSync(path.resolve(f)).toString('utf8');
-				const filename = path.basename(f);
-				const i = CamelDefinitionYaml.yamlToIntegration(filename, yaml);
-				integrations.push(new IntegrationItem(i.metadata.name, f, i.crd ? "CRD" : "", i, { command: 'karavan.open', title: '', arguments: [{ fsPath: f }] }));
-			})
+			return this.getIntegrations(this.rootPath);
 		} else if (element && element.integration) {
+			const integrations: IntegrationItem[] = [];
 			element.integration.spec.flows?.forEach(f => {
 				integrations.push(new IntegrationItem(f.dslName.replace("Definition", ""), "", f.id, undefined, undefined));
 			})
+			return integrations;
+		}
+		return Promise.resolve([]);
+	}
+
+	async getIntegrations(dir: string) {
+		const result:IntegrationItem[] = []
+		const files = await utils.getYamlFiles(dir);
+		for (let x in files){
+			const filename = files[x];
+			const readData = await utils.readFile(path.resolve(filename));
+			const yaml = Buffer.from(readData).toString('utf8');
+			if (!filename.startsWith(dir + path.sep + "target") && CamelDefinitionYaml.yamlIsIntegration(yaml)){
+				const basename = path.basename(filename);
+				const i = CamelDefinitionYaml.yamlToIntegration(basename, yaml);
+				result.push(new IntegrationItem(i.metadata.name, filename, i.crd ? "CRD" : "", i, { command: 'karavan.open', title: '', arguments: [{ fsPath: filename }] }));
+			}
+			
 		}
-		return Promise.resolve(integrations);
+		return result;
 	}
 
 	refresh(): void {
@@ -55,23 +67,23 @@ export class IntegrationView implements vscode.TreeDataProvider<IntegrationItem>
 	}
 }
 
-export class IntegrationItem extends vscode.TreeItem {
+export class IntegrationItem extends TreeItem {
 
 	constructor(
 		public readonly title: string,
 		public readonly fsPath: string,
 		public readonly description: string,
 		public readonly integration?: Integration,
-		public readonly command?: vscode.Command
+		public readonly command?: Command
 	) {
-		super(title, integration ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
+		super(title, integration ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None);
 		this.tooltip = this.fsPath;
 	}
 
 	iconPath = this.integration ? {
 		light: path.join(__filename, '..', '..', 'icons', 'light', this.integration?.crd ? 'crd.svg' : 'karavan.svg'),
 		dark: path.join(__filename, '..', '..', 'icons', 'dark', this.integration?.crd ? 'crd.svg' : 'karavan.svg')
-	} : vscode.ThemeIcon.File;
+	} : ThemeIcon.File;
 
 	contextValue = this.integration ? 'integration' : "route";
 }
\ No newline at end of file
diff --git a/karavan-vscode/src/commands.ts b/karavan-vscode/src/jbang.ts
similarity index 72%
rename from karavan-vscode/src/commands.ts
rename to karavan-vscode/src/jbang.ts
index 3aa04c0..c34a8bd 100644
--- a/karavan-vscode/src/commands.ts
+++ b/karavan-vscode/src/jbang.ts
@@ -14,40 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import * as vscode from "vscode";
-import * as fs from "fs";
+import { workspace, window, Terminal } from "vscode";
 import * as path from "path";
 import * as shell from 'shelljs';
 import { CamelDefinitionYaml } from "karavan-core/lib/api/CamelDefinitionYaml";
-import { ProjectModel } from "karavan-core/lib/model/ProjectModel";
+import * as utils from "./utils";
 
-const TERMINALS: Map<string, vscode.Terminal> = new Map<string, vscode.Terminal>();
+const TERMINALS: Map<string, Terminal> = new Map<string, Terminal>();
 
-export function camelJbangGenerate(rootPath: string, openApiFullPath: string, fullPath: string, add: boolean, crd?: boolean, generateRoutes?: boolean) {
+export async function camelJbangGenerate(rootPath: string, openApiFullPath: string, fullPath: string, add: boolean, crd?: boolean, generateRoutes?: boolean) {
     let command = prepareCommand("generate rest -i " + openApiFullPath, "application"); // TODO: set profile configurable
     if (generateRoutes === true) command = command + " --routes";
     executeJbangCommand(rootPath, command, (code, stdout, stderr) => {
         console.log('Exit code:', code);
         if (code === 0) {
-            // console.log('Program output:', stdout);
             const filename = path.basename(fullPath);
             let yaml;
             if (add) {
-                const camelYaml = fs.readFileSync(path.resolve(fullPath)).toString('utf8');
-                yaml = createYaml(filename, stdout, camelYaml, undefined);
+                utils.readFile(fullPath).then(readData => {
+                    const camelYaml = Buffer.from(readData).toString('utf8');
+                    yaml = createYaml(filename, stdout, camelYaml, undefined);
+                    utils.write(fullPath, yaml);
+                });
             } else {
                 yaml = createYaml(filename, stdout, undefined, crd);
+                utils.write(fullPath, yaml);
             }
-            const uriFile: vscode.Uri = vscode.Uri.file(fullPath);
-            fs.writeFile(uriFile.fsPath, yaml, err => {
-                if (err) vscode.window.showErrorMessage("Error: " + err?.message);
-                else {
-                    vscode.commands.executeCommand('integrations.refresh')
-                        .then(x => vscode.commands.executeCommand('karavan.open', { fsPath: fullPath, tab: 'rest' }));
-                }
-            });
         } else {
-            vscode.window.showErrorMessage(stderr);
+            window.showErrorMessage(stderr);
         }
     });
 }
@@ -78,33 +72,33 @@ export function cacheClear(rootPath: string, callback: (code: number) => any) {
 }
 
 function prepareCommand(command: string, profile?: string): string {
-    const version = vscode.workspace.getConfiguration().get("camel.version");
+    const version = workspace.getConfiguration().get("camel.version");
     const p = profile ? " --profile " + profile : "";
     return "jbang -Dcamel.jbang.version=" + version + " camel@apache/camel " + command + p;
 }
 
 export function camelJbangRun(rootPath: string, profile?: string, filename?: string) {
-    const maxMessages: number = vscode.workspace.getConfiguration().get("camel.maxMessages") || -1;
-    const cmd = (filename ? "run " + filename : "run * " ) + (maxMessages > -1 ? " --max-messages=" + maxMessages : "");
+    const maxMessages: number = workspace.getConfiguration().get("camel.maxMessages") || -1;
+    const cmd = (filename ? "run " + filename : "run * ") + (maxMessages > -1 ? " --max-messages=" + maxMessages : "");
     const command = prepareCommand(cmd, profile);
     const terminalId = "run_" + profile + "_" + filename;
     const existTerminal = TERMINALS.get(terminalId);
     if (existTerminal) existTerminal.dispose();
-    const terminal = vscode.window.createTerminal('Camel run: ' + filename ? filename : "project");
+    const terminal = window.createTerminal('Camel run: ' + filename ? filename : "project");
     TERMINALS.set(terminalId, terminal);
     terminal.show();
     terminal.sendText(command);
 }
 
 export function camelJbangExport(runtime: string, directory: string, gav: string) {
-    const cmd = "export " + runtime 
-            + (directory !== undefined ? " --directory="+directory : "")
-            + (gav !== undefined ? " --gav=" + gav : "");
+    const cmd = "export " + runtime
+        + (directory !== undefined ? " --directory=" + directory : "")
+        + (gav !== undefined ? " --gav=" + gav : "");
     const command = prepareCommand(cmd);
     const terminalId = "export " + runtime;
     const existTerminal = TERMINALS.get(terminalId);
     if (existTerminal) existTerminal.dispose();
-    const terminal = vscode.window.createTerminal('Camel export');
+    const terminal = window.createTerminal('Camel export');
     TERMINALS.set(terminalId, terminal);
     terminal.show();
     terminal.sendText(command);
@@ -120,12 +114,12 @@ function executeJbangCommand(rootPath: string, command: string, callback: (code:
             if (code === 0) {
                 // vscode.window.showInformationMessage(stdout);
             } else {
-                vscode.window.showErrorMessage(stderr);
+                window.showErrorMessage(stderr);
             }
             callback(code, stdout, stderr);
         });
     } else {
-        vscode.window.showErrorMessage("JBang not found!");
+        window.showErrorMessage("JBang not found!");
     }
 }
 
diff --git a/karavan-vscode/src/openapiView.ts b/karavan-vscode/src/openapiView.ts
index f0c34b6..437cdd5 100644
--- a/karavan-vscode/src/openapiView.ts
+++ b/karavan-vscode/src/openapiView.ts
@@ -14,40 +14,46 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import vscode, { window } from "vscode";
+import { Command, EventEmitter, ProviderResult, TreeDataProvider, TreeItem, TreeItemCollapsibleState, window, Event } from "vscode";
 import * as path from "path";
 import * as utils from "./utils";
-import * as commands from "./commands";
-import * as fs from "fs";
+import * as jbang from "./jbang";
 import { ThemeIcon } from "vscode";
-import { CamelDefinitionYaml } from "karavan-core/lib/api/CamelDefinitionYaml";
 import { DesignerView } from "./designerView";
-import { Integration } from "karavan-core/lib/model/IntegrationDefinition";
 
-export class OpenApiView implements vscode.TreeDataProvider<OpenApiItem> {
+export class OpenApiView implements TreeDataProvider<OpenApiItem> {
 
 	constructor(private designer: DesignerView, private rootPath: string | undefined) {
 
 	}
-	private _onDidChangeTreeData: vscode.EventEmitter<OpenApiItem | undefined | void> = new vscode.EventEmitter<OpenApiItem | undefined | void>();
-	readonly onDidChangeTreeData: vscode.Event<OpenApiItem | undefined | void> = this._onDidChangeTreeData.event;
+	private _onDidChangeTreeData: EventEmitter<OpenApiItem | undefined | void> = new EventEmitter<OpenApiItem | undefined | void>();
+	readonly onDidChangeTreeData: Event<OpenApiItem | undefined | void> = this._onDidChangeTreeData.event;
 
-	getTreeItem(element: OpenApiItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
+	getTreeItem(element: OpenApiItem): TreeItem | Thenable<TreeItem> {
 		return element;
 	}
-	getChildren(element?: OpenApiItem): vscode.ProviderResult<OpenApiItem[]> {
-		const openapis: OpenApiItem[] = [];
+	getChildren(element?: OpenApiItem): ProviderResult<OpenApiItem[]> {
 		if (this.rootPath) {
-			utils.getJsonFiles(this.rootPath).forEach(f => {
-				const json = fs.readFileSync(path.resolve(f)).toString('utf8');
-				const api = JSON.parse(json);
-				if (api.openapi) {
-					const filename = path.basename(f);
-					openapis.push(new OpenApiItem(filename, f, api?.info?.title, { command: 'karavan.open-file', title: 'Open file', arguments: [{ fsPath: f }] }));
-				}
-			})
+			return this.getOpenApiItems(this.rootPath);
+		} else {
+			return Promise.resolve([]);
 		}
-		return Promise.resolve(openapis);
+	}
+
+	async getOpenApiItems(dir: string) {
+		const result:OpenApiItem[] = []
+		const files = await utils.getJsonFiles(dir);
+		for (let x in files){
+			const filename = files[x];
+			const readData = await utils.readFile(path.resolve(filename));
+			const json = Buffer.from(readData).toString('utf8');
+			const api = JSON.parse(json);
+			if (api.openapi) {
+				const basename = path.basename(filename);
+				result.push(new OpenApiItem(basename, filename, api?.info?.title, { command: 'karavan.open-file', title: 'Open file', arguments: [{ fsPath: filename }] }));
+			}
+		}
+		return result;
 	}
 
 	refresh(): void {
@@ -55,15 +61,15 @@ export class OpenApiView implements vscode.TreeDataProvider<OpenApiItem> {
 	}
 }
 
-export class OpenApiItem extends vscode.TreeItem {
+export class OpenApiItem extends TreeItem {
 
 	constructor(
 		public readonly title: string,
 		public readonly fsPath: string,
 		public readonly description: string,
-		public readonly command?: vscode.Command
+		public readonly command?: Command
 	) {
-		super(title, vscode.TreeItemCollapsibleState.None);
+		super(title, TreeItemCollapsibleState.None);
 		this.tooltip = this.fsPath;
 	}
 
@@ -82,7 +88,7 @@ export async function selectRouteGeneration(rootPath: string, openApiFullPath: s
 		placeHolder: 'Select option',
 	}).then(option => {
 		const generateRoutes: boolean = option !== undefined && option === options[0];
-		commands.camelJbangGenerate(rootPath, openApiFullPath, fullPath, add, crd, generateRoutes);
+		jbang.camelJbangGenerate(rootPath, openApiFullPath, fullPath, add, crd, generateRoutes);
 	});
 }
 
@@ -107,7 +113,7 @@ export async function selectFileName(rootPath?: string, openApi?: OpenApiItem) {
  * Create new file and add REST API
  */
 export async function inputFileName(crd: boolean, rootPath?: string, openApi?: OpenApiItem) {
-	vscode.window.showInputBox({
+	window.showInputBox({
 		title: "Generate REST API from " + openApi?.title,
 		ignoreFocusOut: true,
 		prompt: "Integration file name",
diff --git a/karavan-vscode/src/utils.ts b/karavan-vscode/src/utils.ts
index 4d55663..73f11a5 100644
--- a/karavan-vscode/src/utils.ts
+++ b/karavan-vscode/src/utils.ts
@@ -14,56 +14,61 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import * as vscode from "vscode";
-import * as fs from "fs";
 import * as path from "path";
-import * as shell from 'shelljs';
+import { workspace, Uri, window, ExtensionContext, FileType} from "vscode";
 import { CamelDefinitionYaml } from "karavan-core/lib/api/CamelDefinitionYaml";
-import { ProjectModel } from "karavan-core/lib/model/ProjectModel";
 import { ProjectModelApi } from "karavan-core/lib/api/ProjectModelApi";
 
 export function save(relativePath: string, text: string) {
-    if (vscode.workspace.workspaceFolders) {
-        const uriFolder: vscode.Uri = vscode.workspace.workspaceFolders[0].uri;
-        const uriFile: vscode.Uri = vscode.Uri.file(path.join(uriFolder.path, relativePath));
-        fs.writeFile(uriFile.fsPath, text, err => {
-            if (err) vscode.window.showErrorMessage("Error: " + err?.message);
-        });
+    if (workspace.workspaceFolders) {
+        const uriFolder: Uri = workspace.workspaceFolders[0].uri;
+        write(path.join(uriFolder.path, relativePath), text);
     }
 }
 
 export function deleteFile(fullPath: string) {
-    if (vscode.workspace.workspaceFolders) {
-        fs.rmSync(path.resolve(fullPath));
+    if (workspace.workspaceFolders) {
+        const uriFile: Uri = Uri.file(path.resolve(fullPath));
+        workspace.fs.delete(uriFile);
     }
 }
 
 export function getRalativePath(fullPath: string): string {
-    const root = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.path : "";
-    const normalizedRoot = vscode.Uri.file(root).fsPath;
+    const root = workspace.workspaceFolders ? workspace.workspaceFolders[0].uri.path : "";
+    const normalizedRoot = Uri.file(root).fsPath;
     const relativePath = path.resolve(fullPath).replace(normalizedRoot + path.sep, '');
     return relativePath;
 }
 
-export function readKamelets(context: vscode.ExtensionContext): string[] {
+export async function readKamelets(context: ExtensionContext) {
     const dir = path.join(context.extensionPath, 'kamelets');
-    const yamls: string[] = fs.readdirSync(dir).filter(file => file.endsWith("yaml")).map(file => fs.readFileSync(dir + "/" + file, 'utf-8'));
-    try {
-        const kameletsPath: string | undefined = vscode.workspace.getConfiguration().get("Karavan.kameletsPath");
-        if (kameletsPath && kameletsPath.trim().length > 0) {
-            const kameletsDir = path.isAbsolute(kameletsPath) ? kameletsPath : path.resolve(kameletsPath);
-            const customKamelets: string[] = fs.readdirSync(kameletsDir).filter(file => file.endsWith("yaml")).map(file => fs.readFileSync(kameletsDir + "/" + file, 'utf-8'));
-            if (customKamelets && customKamelets.length > 0) yamls.push(...customKamelets);
-        }
-    } catch (e) {
-
+    const yamls: string[] = await readFilesInDirByExtension(dir, "yaml");
+    const kameletsPath: string | undefined = workspace.getConfiguration().get("Karavan.kameletsPath");
+    if (kameletsPath && kameletsPath.trim().length > 0) {
+        const kameletsDir = path.isAbsolute(kameletsPath) ? kameletsPath : path.resolve(kameletsPath);
+        const customKamelets: string[] = await readFilesInDirByExtension(kameletsDir, "yaml");
+        if (customKamelets && customKamelets.length > 0) yamls.push(...customKamelets);
     }
     return yamls;
 }
 
-export function readComponents(context: vscode.ExtensionContext): string[] {
+async function readFilesInDirByExtension(dir: string, extension: string) {
+    const result: string[] = [];
+    const dirs: [string, FileType][] = await readDirectory(dir);
+    for (let d in dirs) {
+        const filename = dirs[d][0];
+        if (filename.endsWith(extension)){
+            const file = await readFile(dir + "/" + filename);
+            const code = Buffer.from(file).toString('utf8');
+            result.push(code);
+        }
+    }
+    return result;
+}
+
+export async function readComponents(context: ExtensionContext) {
     const dir = path.join(context.extensionPath, 'components');
-    const jsons: string[] = fs.readdirSync(dir).filter(file => file.endsWith("json")).map(file => fs.readFileSync(dir + "/" + file, 'utf-8'));
+    const jsons: string[] = await readFilesInDirByExtension(dir, "json");
     return jsons;
 }
 
@@ -77,7 +82,7 @@ export function parceYaml(filename: string, yaml: string): [boolean, string?] {
 }
 
 export function disableStartHelp() {
-    const config = vscode.workspace.getConfiguration();
+    const config = workspace.getConfiguration();
     config.update("Karavan.showStartHelp", false);
 }
 
@@ -91,60 +96,98 @@ export function nameFromTitle(title: string): string {
     return title.replace(/[^a-z0-9+]+/gi, "-").toLowerCase();
 }
 
-export function getAllFiles(dirPath, arrayOfFiles: string[]): string[] {
-    const files = fs.readdirSync(dirPath)
+export async function getAllFiles(dirPath, arrayOfFiles: string[]) {
+    const files = await readDirectory(dirPath)
 
-    arrayOfFiles = arrayOfFiles || []
+    arrayOfFiles = arrayOfFiles || [];
 
-    files.forEach(function (file) {
-        if (fs.statSync(dirPath + "/" + file).isDirectory()) {
-            arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles)
+    for (let x in files){
+        const filename = files[x][0];
+        const type = files[x][1];
+        if (type === FileType.Directory) {
+            arrayOfFiles = await getAllFiles(dirPath + "/" + filename, arrayOfFiles)
         } else {
-            arrayOfFiles.push(path.join(dirPath, "/", file))
+            arrayOfFiles.push(path.join(dirPath, "/", filename))
         }
-    })
+    }
     return arrayOfFiles
 }
 
-export function getYamlFiles(baseDir: string): string[] {
+export async function getYamlFiles(baseDir: string) {
     const result: string[] = [];
-    getAllFiles(baseDir, []).filter(f => f.endsWith(".yaml")).forEach(f => {
+    (await getAllFiles(baseDir, [])).filter(f => f.endsWith(".yaml")).forEach(f => {
         result.push(f);
     })
     return result;
 }
 
-export function getPropertyFiles(baseDir: string): string[] {
+export async function getPropertyFiles(baseDir: string) {
     const result: string[] = [];
-    getAllFiles(baseDir, []).filter(f => f.endsWith(".properties")).forEach(f => {
+    (await getAllFiles(baseDir, [])).filter(f => f.endsWith(".properties")).forEach(f => {
         result.push(f);
     })
     return result;
 }
 
-export function getJsonFiles(baseDir: string): string[] {
+export async function getJsonFiles(baseDir: string) {
     const result: string[] = [];
-    getAllFiles(baseDir, []).filter(f => f.endsWith(".json")).forEach(f => {
+    (await getAllFiles(baseDir, [])).filter(f => f.endsWith(".json")).forEach(f => {
         result.push(f);
     })
     return result;
 }
 
-export function getIntegrationFiles(baseDir: string): string[] {
-    return getYamlFiles(baseDir).filter(f => {
-        const yaml = fs.readFileSync(path.resolve(f)).toString('utf8');
-        return !f.startsWith(baseDir + path.sep + "target") && CamelDefinitionYaml.yamlIsIntegration(yaml);
-    });
+export async function getIntegrationFiles(baseDir: string) {
+    const result: string[] = []
+    const files = await getYamlFiles(baseDir);
+    for (let x in files){
+        const filename = files[x];
+        const readData = await readFile(path.resolve(filename));
+        const yaml = Buffer.from(readData).toString('utf8');
+        if (!filename.startsWith(baseDir + path.sep + "target") && CamelDefinitionYaml.yamlIsIntegration(yaml)){
+            result.push(yaml);
+        }
+    }
+    return result;
 }
 
 
-export function getProperties(rootPath?: string): string {
-    if (rootPath) return fs.readFileSync(path.resolve(rootPath, "application.properties")).toString('utf8');
-    else return fs.readFileSync(path.resolve("application.properties")).toString('utf8');
+export async function getProperties(rootPath?: string) {
+    if (rootPath) {
+        const readData = await readFile(path.resolve(rootPath, "application.properties"));
+        return Buffer.from(readData).toString('utf8');
+    } else {
+        const readData = await readFile(path.resolve("application.properties"));
+        return Buffer.from(readData).toString('utf8');
+    }
 }
 
-export function getProfiles(rootPath?: string): string[] {
-    const text = getProperties(rootPath);
+export async function getProfiles(rootPath?: string) {
+    const text = await getProperties(rootPath);
     const project = ProjectModelApi.propertiesToProject(text);
     return ProjectModelApi.getProfiles(project.properties);
+}
+
+export async function stat(fullPath: string) {
+    const uriFile: Uri = Uri.file(fullPath);
+    return  workspace.fs.stat(uriFile);
+}
+
+export async function readDirectory(fullPath: string) {
+    const uriFile: Uri = Uri.file(fullPath);
+    return workspace.fs.readDirectory(uriFile);
+}
+
+export async function readFile(fullPath: string) {
+    const uriFile: Uri = Uri.file(fullPath);
+    return workspace.fs.readFile(uriFile);
+}
+
+export async function write(fullPath: string, code: string) {
+    const uriFile: Uri = Uri.file(fullPath);
+    workspace.fs.writeFile(uriFile, Buffer.from(code, 'utf8'))
+    .then(
+        value => {}, 
+        reason => window.showErrorMessage("Error: " + reason) 
+    );
 }
\ No newline at end of file
diff --git a/karavan-vscode/webview/builder/PropertiesTable.tsx b/karavan-vscode/webview/builder/PropertiesTable.tsx
index 9ea6569..27d5a88 100644
--- a/karavan-vscode/webview/builder/PropertiesTable.tsx
+++ b/karavan-vscode/webview/builder/PropertiesTable.tsx
@@ -78,8 +78,8 @@ export class PropertiesTable extends React.Component<Props, State> {
         </Modal>)
     }
 
-    getTextInputField(property: ProjectProperty, field: "key" | "value") {
-        return (<TextInput isRequired={true} className="text-field" type={"text"} id={"key"} name={"key"}
+    getTextInputField(property: ProjectProperty, field: "key" | "value", readOnly: boolean) {
+        return (<TextInput isDisabled={readOnly} isRequired={true} className="text-field" type={"text"} id={"key"} name={"key"}
                            value={field === "key" ? property.key : property.value}
                            onChange={val => this.changeProperty(property, field, val)}/>)
     }
@@ -99,16 +99,18 @@ export class PropertiesTable extends React.Component<Props, State> {
                             </Tr>
                         </Thead>
                         <Tbody>
-                            {properties.map((property, idx: number) => (
-                                <Tr key={property.id}>
-                                    <Td noPadding width={20} dataLabel="key">{this.getTextInputField(property, "key")}</Td>
-                                    <Td noPadding width={10} dataLabel="value">{this.getTextInputField(property, "value")}</Td>
-                                    <Td noPadding isActionCell dataLabel="delete">
-                                        <Button variant={"plain"} icon={<DeleteIcon/>} className={"delete-button"}
-                                                onClick={event => this.startDelete(property.id)}/>
-                                    </Td>
-                                </Tr>
-                            ))}
+                            {properties.map((property, idx: number) => {
+                                const readOnly = ["camel.jbang.gav", "camel.jbang.runtime"].includes(property.key);
+                                return (
+                                    <Tr key={property.id}>
+                                        <Td noPadding width={20} dataLabel="key">{this.getTextInputField(property, "key", readOnly)}</Td>
+                                        <Td noPadding width={10} dataLabel="value">{this.getTextInputField(property, "value", readOnly)}</Td>
+                                        <Td noPadding isActionCell dataLabel="delete">
+                                            {!readOnly && <Button variant={"plain"} icon={<DeleteIcon/>} className={"delete-button"}
+                                                                  onClick={event => this.startDelete(property.id)}/>}
+                                        </Td>
+                                    </Tr>
+                                )})}
                         </Tbody>
                     </TableComposable>}
                 <Panel>