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 2024/04/19 19:40:56 UTC
(camel-karavan) 06/06: Kamelet for project
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 <ma...@talismancloud.io>
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