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 062e344ac57ab322d7f21c6c3d8aa5fc3250bb2d
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Fri Apr 19 15:40:31 2024 -0400

    Kamelet for project
---
 .../src/project/files/CreateIntegrationModal.tsx   | 38 +++++++-----
 .../src/main/webui/src/project/files/FilesTab.tsx  | 13 +---
 .../main/webui/src/project/files/FilesToolbar.tsx  |  9 ++-
 .../test/avro-serialize-action.kamelet.yaml        | 70 ++++++++++++++++++++++
 karavan-core/test/integrationToYaml.spec.ts        | 60 +++++++++++++++++++
 5 files changed, 163 insertions(+), 27 deletions(-)

diff --git 
a/karavan-app/src/main/webui/src/project/files/CreateIntegrationModal.tsx 
b/karavan-app/src/main/webui/src/project/files/CreateIntegrationModal.tsx
index 34647d0c..c6a91b0d 100644
--- a/karavan-app/src/main/webui/src/project/files/CreateIntegrationModal.tsx
+++ b/karavan-app/src/main/webui/src/project/files/CreateIntegrationModal.tsx
@@ -27,7 +27,7 @@ import {
 import '../../designer/karavan.css';
 import {KameletTypes} from "karavan-core/lib/model/IntegrationDefinition";
 import {useFileStore, useProjectStore} from "../../api/ProjectStore";
-import {getProjectFileTypeName, ProjectFile, ProjectFileTypes} from 
"../../api/ProjectModels";
+import {getProjectFileTypeName, ProjectFile} from "../../api/ProjectModels";
 import {ProjectService} from "../../api/ProjectService";
 import {shallow} from "zustand/shallow";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
@@ -62,6 +62,8 @@ export function CreateIntegrationModal() {
         reset(new ProjectFile('', project.projectId, '', 0));
         setBackendError(undefined);
         setReset(true);
+        setSelectedKamelet(undefined);
+        setKameletType('source')
     }, [reset, operation]);
 
     React.useEffect(() => {
@@ -85,8 +87,8 @@ export function CreateIntegrationModal() {
         })
     }
 
-    function onSuccess (file: ProjectFile) {
-        EventBus.sendAlert( "Success", "File successfully created", "success");
+    function onSuccess(file: ProjectFile) {
+        EventBus.sendAlert("Success", "File successfully created", "success");
         ProjectService.refreshProjectData(project.projectId);
         if (file.code) {
             setFile('select', file, designerTab);
@@ -103,12 +105,14 @@ export function CreateIntegrationModal() {
 
     const isKamelet = designerTab === 'kamelet';
 
-    const listOfValues: Value[] = KameletApi.getKamelets()
-        .filter(k => k.metadata.labels["camel.apache.org/kamelet.type"] === 
kameletType)
-        .map(k => {
-            const v: Value = {value: k.metadata.name, children: 
k.spec.definition.title}
-            return v;
-        })
+    function listOfValues(type: KameletTypes): Value[] {
+        return KameletApi.getKamelets()
+            .filter(k => k.metadata.labels["camel.apache.org/kamelet.type"] 
=== type)
+            .map(k => {
+                const v: Value = {value: k.metadata.name, children: 
k.spec.definition.title}
+                return v;
+            })
+    }
 
     function getFileExtension() {
         return designerTab === 'kamelet' ? '.kamelet.yaml' : '.camel.yaml';
@@ -152,19 +156,21 @@ export function CreateIntegrationModal() {
                         })}
                     </ToggleGroup>
                 </FormGroup>}
-                {getTextFieldSuffix('name', 'Name',  getFileSuffix(), true, {
+                {getTextFieldSuffix('name', 'Name', getFileSuffix(), true, {
                     regex: v => isValidFileName(v) || 'Only characters, 
numbers and dashes allowed',
                     length: v => v.length > 3 || 'File name should be longer 
that 3 characters',
                     name: v => !['templates', 'kamelets', 
'karavan'].includes(v) || "'templates', 'kamelets', 'karavan' can't be used as 
project",
                 })}
-                {isKamelet && <FormGroup label="Copy from" fieldId="kamelet">
-                    <TypeaheadSelect listOfValues={listOfValues} 
onSelect={value => {
-                        setSelectedKamelet(value)
-                    }}/>
-                </FormGroup>}
+                {isKamelet &&
+                    <FormGroup label="Copy from" fieldId="kamelet">
+                        <TypeaheadSelect key={kameletType} 
listOfValues={listOfValues(kameletType)} onSelect={value => {
+                            setSelectedKamelet(value)
+                        }}/>
+                    </FormGroup>
+                }
                 {backendError &&
                     <FormAlert>
-                        <Alert variant="danger" title={backendError} 
aria-live="polite" isInline />
+                        <Alert variant="danger" title={backendError} 
aria-live="polite" isInline/>
                     </FormAlert>
                 }
             </Form>
diff --git a/karavan-app/src/main/webui/src/project/files/FilesTab.tsx 
b/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
index 681b67bc..f5868cd8 100644
--- a/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
+++ b/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
@@ -39,7 +39,6 @@ import {useFilesStore, useFileStore, useProjectStore} from 
"../../api/ProjectSto
 import {
     getProjectFileTypeTitle,
     ProjectFile,
-    ProjectFileTypes
 } from "../../api/ProjectModels";
 import {FileToolbar} from "./FilesToolbar";
 import DownloadIcon from 
"@patternfly/react-icons/dist/esm/icons/download-icon";
@@ -48,6 +47,7 @@ import {CreateFileModal} from "./CreateFileModal";
 import {DeleteFileModal} from "./DeleteFileModal";
 import {UploadFileModal} from "./UploadFileModal";
 import {shallow} from "zustand/shallow";
+import {CreateIntegrationModal} from "./CreateIntegrationModal";
 
 export function FilesTab () {
 
@@ -76,10 +76,6 @@ export function FilesTab () {
         }
     }
 
-    function isBuildIn(): boolean {
-        return ['kamelets', 'templates', 
'services'].includes(project.projectId);
-    }
-
     function canDeleteFiles(): boolean {
         return !['templates', 'services'].includes(project.projectId);
     }
@@ -88,10 +84,6 @@ export function FilesTab () {
         return project.projectId === 'kamelets';
     }
 
-    const types = isBuildIn()
-        ? (isKameletsProject() ? ['KAMELET'] : ['CODE', 'PROPERTIES'])
-        : ProjectFileTypes.filter(p => !['PROPERTIES', 
'KAMELET'].includes(p.name)).map(p => p.name);
-
     return (
         <PageSection className="project-tab-panel" padding={{default: 
"padding"}}>
             <Panel>
@@ -163,7 +155,8 @@ export function FilesTab () {
                 </Table>
             </div>
             <UploadFileModal/>
-            <CreateFileModal/>
+            {!isKameletsProject() && <CreateFileModal/>}
+            {isKameletsProject() && <CreateIntegrationModal/>}
             <DeleteFileModal />
         </PageSection>
     )
diff --git a/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx 
b/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
index bfcfa645..7f50fa10 100644
--- a/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
+++ b/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
@@ -129,6 +129,9 @@ export function FileToolbar () {
         return project ? files.filter(f => f.lastUpdate > 
project.lastCommitTimestamp).length > 0 : false;
     }
 
+    function isKameletsProject(): boolean {
+        return project.projectId === 'kamelets';
+    }
 
     function getDate(lastUpdate: number): string {
         if (lastUpdate) {
@@ -193,10 +196,14 @@ export function FileToolbar () {
                 </Button>
             </Tooltip>
         </FlexItem>
-        {canAddFiles() && <FlexItem>
+        {canAddFiles() && !isKameletsProject() && <FlexItem>
             <Button className="dev-action-button" size="sm" 
variant={"primary"} icon={<PlusIcon/>}
                     onClick={e => setFile("create")}>Create</Button>
         </FlexItem>}
+        {canAddFiles() && isKameletsProject() && <FlexItem>
+            <Button className="dev-action-button" size="sm" 
variant={"primary"} icon={<PlusIcon/>}
+                    onClick={e => setFile("create", undefined, 
'kamelet')}>Create</Button>
+        </FlexItem>}
         {canAddFiles() && <FlexItem>
             <Button className="dev-action-button" size="sm" 
variant="secondary" icon={<UploadIcon/>}
                     onClick={e => setFile("upload")}>Upload</Button>
diff --git a/karavan-core/test/avro-serialize-action.kamelet.yaml 
b/karavan-core/test/avro-serialize-action.kamelet.yaml
new file mode 100644
index 00000000..71a80e1a
--- /dev/null
+++ b/karavan-core/test/avro-serialize-action.kamelet.yaml
@@ -0,0 +1,70 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+  name: avro-serialize-action
+  annotations:
+    camel.apache.org/kamelet.support.level: "Stable"
+    camel.apache.org/catalog.version: "4.6.0-SNAPSHOT"
+    camel.apache.org/kamelet.icon: 
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG
 [...]
+    camel.apache.org/provider: "Apache Software Foundation"
+    camel.apache.org/kamelet.group: "Actions"
+    camel.apache.org/kamelet.namespace: "Transformation"
+  labels:
+    camel.apache.org/kamelet.type: "action"
+spec:
+  definition:
+    title: "Avro Serialize Action"
+    description: "Serialize payload to Avro"
+    type: object
+    properties:
+      schema:
+        title: Schema
+        description: The Avro schema to use during serialization (as 
single-line, using JSON format)
+        type: string
+        example: '{"type": "record", "namespace": "com.example", "name": 
"FullName", "fields": [{"name": "first", "type": "string"},{"name": "last", 
"type": "string"}]}'
+      validate:
+        title: Validate
+        description: Indicates if the content must be validated against the 
schema
+        type: boolean
+        default: true
+  dependencies:
+    - "camel:kamelet"
+    - "camel:core"
+    - "camel:jackson-avro"
+  template:
+    beans:
+      - name: schemaResolver
+        type: 
"#class:org.apache.camel.component.jackson.avro.transform.AvroSchemaResolver"
+        property:
+          - key: validate
+            value: '{{validate}}'
+          - key: schema
+            value: '{{schema:}}'
+    from:
+      uri: kamelet:source
+      steps:
+        - marshal:
+            avro:
+              library: Jackson
+              unmarshalType: com.fasterxml.jackson.databind.JsonNode
+              schemaResolver: "#bean:{{schemaResolver}}"
+        - setHeader:
+            name: "Content-Type"
+            constant: "application/avro"
\ No newline at end of file
diff --git a/karavan-core/test/integrationToYaml.spec.ts 
b/karavan-core/test/integrationToYaml.spec.ts
new file mode 100644
index 00000000..3369a717
--- /dev/null
+++ b/karavan-core/test/integrationToYaml.spec.ts
@@ -0,0 +1,60 @@
+/*
+ * 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 {expect} from 'chai';
+import * as fs from 'fs';
+import 'mocha';
+import {CamelDefinitionYaml} from "../src/core/api/CamelDefinitionYaml";
+import {FilterDefinition, ToDefinition} from 
"../src/core/model/CamelDefinition";
+import { RouteDefinition} from "../src/core/model/CamelDefinition";
+
+describe('CRD YAML to Integration', () => {
+
+
+
+    it('YAML <-> Object 1', () => {
+        const yaml = 
fs.readFileSync('test/integration1.yaml',{encoding:'utf8', flag:'r'});
+        const i = CamelDefinitionYaml.yamlToIntegration("test1.yaml", yaml);
+        expect(i.metadata.name).to.equal('test1.yaml');
+        expect(i.kind).to.equal('Integration');
+        expect(i.spec.flows?.length).to.equal(1);
+        expect(i.type).to.equal('crd');
+        if (i.spec.flows){
+            const f:FilterDefinition = (i.spec.flows[0] as 
RouteDefinition).from.steps[1];
+            const t:ToDefinition = <ToDefinition> (f.steps ? f.steps[0] : 
undefined);
+            expect(t.uri).to.equal("log");
+            expect(t.parameters.level).to.equal("OFF");
+        }
+        console.log(CamelDefinitionYaml.integrationToYaml(i))
+    });
+
+    it('YAML <-> Object 2', () => {
+        const yaml = 
fs.readFileSync('test/integration2.yaml',{encoding:'utf8', flag:'r'});
+        const i = CamelDefinitionYaml.yamlToIntegration("test1.yaml", yaml);
+        expect(i.metadata.name).to.equal('test1.yaml');
+        expect(i.kind).to.equal('Integration');
+        expect(i.spec.flows?.length).to.equal(1);
+        expect(i.type).to.equal('crd');
+
+        if (i.spec.flows){
+            const f:FilterDefinition = (i.spec.flows[0] as 
RouteDefinition).from.steps[1];
+            const t:ToDefinition = <ToDefinition> (f.steps ? f.steps[0] : 
undefined);
+            expect(t.uri).to.equal("log");
+            expect(t.parameters.level).to.equal("OFF");
+        }
+    });
+
+});
\ No newline at end of file

Reply via email to