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

commit cd12854604434f93294fc42a1dd0d450fdaa9607
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Sun Mar 1 12:53:44 2026 -0500

    Fix Topology for 4.18.0
---
 karavan-vscode/webview/App.tsx                     |   8 +-
 .../karavan/app/navigation/ProjectFunctionHook.tsx | 196 +++++++++++++++++++++
 .../project/project-topology/TopologyTab.tsx       |   2 -
 .../project/project-topology/TopologyToolbar.tsx   | 102 -----------
 4 files changed, 201 insertions(+), 107 deletions(-)

diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx
index a7e8de3e..db8f4a2b 100644
--- a/karavan-vscode/webview/App.tsx
+++ b/karavan-vscode/webview/App.tsx
@@ -30,6 +30,8 @@ import { TopologyTab } from 
"@features/project/project-topology/TopologyTab";
 import { DocumentationPage } from "@features/documentation/DocumentationPage";
 import { KaravanDesigner } from "@features/project/designer/KaravanDesigner";
 import { EventBus } from "@features/project/designer/utils/EventBus";
+import {ProjectFunctionHook} from "@app/navigation/ProjectFunctionHook";
+import {ProjectProvider} from "@features/project/ProjectContext";
 
 interface Props {
 }
@@ -262,9 +264,9 @@ class App extends React.Component<Props, State> {
           <DocumentationPage />
         }
         {loaded && page === "topology" &&
-          <TopologyTab 
-            asyncApiJson={undefined}
-          />
+          <ProjectProvider useProjectHook={ProjectFunctionHook}>
+            <TopologyTab asyncApiJson={undefined}/>
+          </ProjectProvider>
         }
       </div>
     )
diff --git 
a/karavan-vscode/webview/karavan/app/navigation/ProjectFunctionHook.tsx 
b/karavan-vscode/webview/karavan/app/navigation/ProjectFunctionHook.tsx
new file mode 100644
index 00000000..2f204d7a
--- /dev/null
+++ b/karavan-vscode/webview/karavan/app/navigation/ProjectFunctionHook.tsx
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ProjectFile} from "@models/ProjectModels";
+import {DslMetaModel} from "@features/project/designer/utils/DslMetaModel";
+import {v4 as uuidv4} from "uuid";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
+import {Integration} from "@karavan-core/model/IntegrationDefinition";
+import {FILE_WORDS_SEPARATOR, KARAVAN_DOT_EXTENSION, KARAVAN_FILENAME, 
OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
+import {RouteConfigurationDefinition} from 
"@karavan-core/model/CamelDefinition";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {CamelDefinitionApi} from "@karavan-core/api/CamelDefinitionApi";
+import {useDesignerStore, useSelectorStore} from 
"@features/project/designer/DesignerStore";
+import {shallow} from "zustand/shallow";
+import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore, 
useWizardStore} from "@stores/ProjectStore";
+import {toSpecialRouteId} from 
"@features/project/designer/utils/ValidatorUtils";
+
+export function ProjectFunctionHook() {
+
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const [files] = useFilesStore((s) => [s.files], shallow);
+    const [isRouteTemplate] = useSelectorStore((s) => [s.isRouteTemplate], 
shallow)
+    const [setFile] = useFileStore((s) => [s.setFile], shallow);
+    const [setShowWizard] = useWizardStore((s) => [s.setShowWizard], shallow)
+    const [setDesignerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch], 
shallow)
+    const [project, tabIndex, setTabIndex, refreshTrace, fetchCamelStatuses] =
+        useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex, 
s.refreshTrace, s.fetchCamelStatuses], shallow);
+
+    function createRouteConfiguration() {
+        const integration = 
Integration.createNew(KARAVAN_FILENAME.ROUTE_CONFIGURATION);
+        const routeConfiguration = new RouteConfigurationDefinition();
+        const i = 
CamelDefinitionApiExt.addRouteConfigurationToIntegration(integration, 
routeConfiguration);
+        const yaml = CamelDefinitionYaml.integrationToYaml(i);
+        const file = new ProjectFile(KARAVAN_FILENAME.ROUTE_CONFIGURATION, 
project.projectId, yaml, Date.now());
+        saveNewFile(file, true, 'routes')
+    }
+
+    function generateParamUri(dsl: DslMetaModel) {
+        const uuid = uuidv4().substring(0, 3)
+        const uri = dsl.uri + FILE_WORDS_SEPARATOR +
+            (dsl.properties && Object.keys(dsl.properties).length > 0
+                ? Object.values(dsl.properties).join(FILE_WORDS_SEPARATOR)
+                : uuid);
+        return uri
+            .replace(/[^a-zA-Z0-9]/g, '-')
+            .replace(/-+/g, '-')
+            .replace(/^-|-$/g, '');
+    }
+
+    function createNewRouteFile(dsl: DslMetaModel, parentId: string, 
position?: number | undefined, fileName?: string) {
+        try {
+            if (dsl.dsl === 'FromDefinition' && dsl.uri) {
+                const paramsUri = generateParamUri(dsl);
+                const fullUri = `From${FILE_WORDS_SEPARATOR}${paramsUri}`
+
+                const name = 
toSpecialRouteId(`from${FILE_WORDS_SEPARATOR}${fullUri}`);
+                const fName = (fileName != undefined ? fileName : name) + 
KARAVAN_DOT_EXTENSION.CAMEL_YAML;
+                const route = CamelUi.createRouteFromComponent(dsl.uri, 
dsl.properties, '');
+                const integration = Integration.createNew(fName);
+                let i;
+                if (isRouteTemplate) {
+                    const keys = dsl.properties ? Object.keys(dsl.properties) 
: [];
+                    const key = keys.at(0);
+                    const routeId = dsl.properties?.[key] + "Route";
+                    const templateId = dsl.properties?.[key] + "RouteTemplate";
+                    const route = CamelUi.createRouteFromComponent(dsl.uri, 
dsl.properties, '');
+                    route.id = routeId
+                    route.nodePrefixId = routeId
+                    const routeTemplate = 
CamelDefinitionApi.createRouteTemplateDefinition({id: templateId, route: 
route});
+                    i = 
CamelDefinitionApiExt.addRouteTemplateToIntegration(integration, routeTemplate);
+                } else {
+                    i = 
CamelDefinitionApiExt.addStepToIntegration(integration, route, '');
+                }
+
+                const yaml = CamelDefinitionYaml.integrationToYaml(i);
+                const file = new ProjectFile(fName, project.projectId, yaml, 
Date.now());
+                saveNewFile(file, true, 'routes')
+            }
+        } catch (e: any) {
+            console.error(e);
+            EventBus.sendAlert("Error creating file", e.message, "danger");
+        }
+    }
+
+    function createNewRestFile() {
+        try {
+            const fileExists = files.find(f => f.name === 
"rest-api.camel.yaml") !== undefined;
+            const uuid = uuidv4().substring(0, 3)
+            const fileName = 'rest-api' + (fileExists ? FILE_WORDS_SEPARATOR + 
uuid : '') + '.camel.yaml';
+            const nodePrefixId = 'rest-' + uuid;
+            const rest = CamelDefinitionApi.createRestDefinition({
+                id: nodePrefixId,
+                description: 'Service Example',
+                path: 'example',
+                consumes: 'application/json',
+                produces: 'application/json',
+                get: [CamelDefinitionApi.createGetDefinition({to: 
'direct:getExample', description: 'GET Example'})],
+                post: [CamelDefinitionApi.createPostDefinition({to: 
'direct:postExample', description: 'POST Example'})],
+                delete: [CamelDefinitionApi.createDeleteDefinition({to: 
'direct:deleteExample', description: 'DELETE Example'})],
+            });
+            const restConfiguration = 
CamelDefinitionApi.createRestConfigurationDefinition({
+                inlineRoutes: false,
+            });
+            const integration = Integration.createNew(fileName);
+            let i = CamelDefinitionApiExt.addRestToIntegration(integration, 
rest);
+            i = CamelDefinitionApiExt.addRestToIntegration(i, 
restConfiguration);
+            const yaml = CamelDefinitionYaml.integrationToYaml(i);
+            const file = new ProjectFile(fileName, project.projectId, yaml, 
Date.now());
+            saveNewFile(file, true, 'rest')
+        } catch (e: any) {
+            EventBus.sendAlert("Error creating file", e.message, "danger");
+        }
+    }
+
+    function createNewKamelet() {
+        setFile('create', undefined, 'kamelet')
+    }
+
+    function createNewBean() {
+        setShowWizard(true)
+    }
+
+    function createOpenApiRestFile() {
+        try {
+            const fileName = 'openapi-rest-config.camel.yaml';
+            const rest = CamelDefinitionApi.createRestDefinition({
+                id: 'openApiRestService',
+                openApi: 
CamelDefinitionApi.createOpenApiDefinition({specification: 'classpath://' + 
OPENAPI_FILE_NAME_JSON})
+            });
+            const restConfiguration = 
CamelDefinitionApi.createRestConfigurationDefinition({
+                inlineRoutes: false,
+            });
+            const integration = Integration.createNew(fileName);
+            let i = CamelDefinitionApiExt.addRestToIntegration(integration, 
rest);
+            i = CamelDefinitionApiExt.addRestToIntegration(i, 
restConfiguration);
+            const yaml = CamelDefinitionYaml.integrationToYaml(i);
+            const file = new ProjectFile(fileName, project.projectId, yaml, 
Date.now());
+            saveNewFile(file, false)
+        } catch (e: any) {
+            EventBus.sendAlert("Error creating file", e.message, "danger");
+        }
+    }
+
+    function createOpenApiJsonFile() {
+
+    }
+
+    function createAsyncApi() {
+
+    }
+
+    function createOpenApi() {
+
+    }
+
+    function saveNewFile(file: ProjectFile, openFile: boolean, designerTab?: 
"routes" | "rest" | "beans" | "kamelet") {
+        
+    }
+
+    async function saveFiles(projectId: string, filesToSave: ProjectFile[], 
afterSuccess?: () => void) {
+
+        // 1. Fetch all existing files for the project once
+        
+    }
+
+    function saveFile(file: ProjectFile, afterSuccess?: () => void) {
+        
+    }
+
+    function refreshData() {
+        
+    }
+
+    function refreshSharedData() {
+    
+    }
+
+    return {createNewRouteFile, createOpenApiRestFile, createNewBean, 
createNewKamelet, createRouteConfiguration, refreshSharedData,
+         project, createNewRestFile, refreshData, createAsyncApi, 
createOpenApi}
+}
diff --git 
a/karavan-vscode/webview/karavan/features/project/project-topology/TopologyTab.tsx
 
b/karavan-vscode/webview/karavan/features/project/project-topology/TopologyTab.tsx
index 9d100619..433ec661 100644
--- 
a/karavan-vscode/webview/karavan/features/project/project-topology/TopologyTab.tsx
+++ 
b/karavan-vscode/webview/karavan/features/project/project-topology/TopologyTab.tsx
@@ -49,7 +49,6 @@ import {useFilesStore, useProjectStore} from 
"@stores/ProjectStore";
 import {NODE_POSITIONED_EVENT} from "@patternfly/react-topology/src/types";
 import {OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
 import {runInAction} from "mobx";
-import {TopologyToolbar} from 
"@features/project/project-topology/TopologyToolbar";
 import {TopologyElkLayout} from 
"@features/project/project-topology/TopologyElkLayout";
 
 interface Props {
@@ -170,7 +169,6 @@ export function TopologyTab(props: Props) {
 
     return (
         <>
-            <TopologyToolbar/>
             <TopologyView
                 className="topology-panel"
                 controlBar={
diff --git 
a/karavan-vscode/webview/karavan/features/project/project-topology/TopologyToolbar.tsx
 
b/karavan-vscode/webview/karavan/features/project/project-topology/TopologyToolbar.tsx
deleted file mode 100644
index ead29fef..00000000
--- 
a/karavan-vscode/webview/karavan/features/project/project-topology/TopologyToolbar.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import * as React from 'react';
-import {MouseEventHandler, ReactElement} from 'react';
-import {Button} from '@patternfly/react-core';
-import {shallow} from "zustand/shallow";
-import {useAppConfigStore} from '@stores/ProjectStore';
-import {useTopologyHook} from 
'@features/project/project-topology/useTopologyHook';
-import {useRouteDesignerHook} from 
"@features/project/designer/route/useRouteDesignerHook";
-import {APPLICATION_PROPERTIES, DOCKER_COMPOSE, DOCKER_STACK} from 
"@models/ProjectModels";
-import {ProjectTitle} from "@features/project/ProjectTitle";
-import {useProjectFunctions} from "@features/project/ProjectContext";
-import {AddLarge} from "@carbon/icons-react";
-
-export function TopologyToolbar() {
-
-    const [config] = useAppConfigStore((s) => [s.config], shallow);
-    const isDev = config.environment === 'dev';
-
-    const {
-        createNewBean,
-        createRouteConfiguration,
-        createOpenApi,
-        createNewKamelet,
-        project
-    } = useProjectFunctions();
-    const {openSelector} = useRouteDesignerHook();
-
-    const {selectFile} = useTopologyHook();
-
-    function getInfraButton(): ReactElement {
-        const isKubernetes = config.infrastructure === 'kubernetes';
-        const swarmMode = config.swarmMode;
-        const fileName = isKubernetes
-            ? 'deployment.jkube.yaml'
-            : (swarmMode ? DOCKER_STACK : DOCKER_COMPOSE);
-
-        return (
-            <div>
-                <Button variant={"tertiary"}
-                        className='bean-button'
-                        // icon={<OutlinedFileAltIcon/>}
-                        onClick={() => {
-                            selectFile(fileName)
-                        }}
-                >
-                    {isKubernetes ? "Deployment" : "Compose"}
-                </Button>
-            </div>
-        )
-    }
-
-    function getButton(caption: string,
-                       variant?: 'primary' | 'secondary' | 'tertiary' | 
'danger' | 'warning' | 'link' | 'plain' | 'control' | 'stateful',
-                       icon?: ReactElement,
-                       onClick?: MouseEventHandler<any> | undefined): 
ReactElement {
-        return (
-            <div>
-                <Button className="dev-action-button "
-                        isDisabled={!isDev}
-                        icon={icon}
-                        variant={variant}
-                        onClick={onClick}
-                >
-                    {caption}
-                </Button>
-            </div>
-        )
-    }
-
-
-    return (
-        <div className='topology-toolbar'>
-            <div className="group-switch">
-                <ProjectTitle/>
-            </div>
-
-            {getButton("Route", 'primary', <AddLarge className='carbon'/>, 
event => openSelector(undefined, undefined))}
-            {getButton("Route Configuration", 'secondary', <AddLarge 
className='carbon'/>, event => createRouteConfiguration())}
-            {getButton("Route Template", 'secondary', <AddLarge 
className='carbon'/>, event => openSelector(undefined, undefined, true, 
undefined, true))}
-            {getButton("Kamelet", 'tertiary', <AddLarge className='carbon'/>, 
event => createNewKamelet())}
-            {getButton("Bean", 'tertiary', <AddLarge className='carbon'/>, 
event => createNewBean())}
-            {getButton("Properties", 'tertiary', undefined, event => 
selectFile(APPLICATION_PROPERTIES))}
-            {getInfraButton()}
-        </div>
-    )
-}
\ No newline at end of file

Reply via email to