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 2023/10/26 00:05:06 UTC
[camel-karavan] 02/07: Kamelet Source in Sink Kamelet for #315
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 2d8216b482315e970141e1ff6398b4f310c55178
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Mon Oct 23 17:58:18 2023 -0400
Kamelet Source in Sink Kamelet for #315
---
karavan-core/src/core/model/KameletModels.ts | 2 +-
.../example/aws-cloudwatch-sink.kamelet.yaml | 185 +++++++++++++++++++++
karavan-designer/src/App.tsx | 3 +-
.../src/designer/route/DslConnections.tsx | 1 +
karavan-designer/src/designer/route/DslElement.tsx | 4 +-
.../src/designer/route/RouteDesigner.tsx | 53 +++---
.../src/designer/route/useRouteDesignerHook.tsx | 31 +++-
7 files changed, 254 insertions(+), 25 deletions(-)
diff --git a/karavan-core/src/core/model/KameletModels.ts b/karavan-core/src/core/model/KameletModels.ts
index e5c9855e..342d8a35 100644
--- a/karavan-core/src/core/model/KameletModels.ts
+++ b/karavan-core/src/core/model/KameletModels.ts
@@ -49,7 +49,7 @@ export class KameletSpec {
}
export class Labels {
- 'camel.apache.org/kamelet.type': string | any = '';
+ 'camel.apache.org/kamelet.type': "sink" | "source" | "action" = 'source';
public constructor(init?: Partial<Labels>) {
Object.assign(this, init);
diff --git a/karavan-designer/public/example/aws-cloudwatch-sink.kamelet.yaml b/karavan-designer/public/example/aws-cloudwatch-sink.kamelet.yaml
new file mode 100644
index 00000000..d22ca1fc
--- /dev/null
+++ b/karavan-designer/public/example/aws-cloudwatch-sink.kamelet.yaml
@@ -0,0 +1,185 @@
+# ---------------------------------------------------------------------------
+# 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: aws-cloudwatch-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.0.1"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIwNyIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI5MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTI1NiAxOTkuMzA1bC0xMjcuOTU3LTE4Ljc5N0wwIDE5OS4zMjlsMTI4LjAxIDQ3LjQzOUwyNTYgMTk5LjMwNSIgZmlsbD0iI0I3Q0E5RCIvPjxwYXRoIGQ9Ik0yNS42MjEgMTk3LjExM2wyMS42MyA2Ljc2MSAxLjk3MS0yLjIzOFY1MC4yODRsLTEuOTcxLTIuNTg1LTIxLjYzIDguMjc0djE0MS4xNCIgZmlsbD0iIzRCNjEyQyIvPjxwYXRoIG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Cloudwatch"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS CloudWatch Metrics Sink"
+ description: |-
+ Send data to Amazon CloudWatch metrics.
+
+ The basic authentication method for the AWS CloudWatch metrics service is to specify an access key and a secret key. These parameters are optional because the Kamelet provides a default credentials provider.
+
+ If you use the default credentials provider, the CloudWatch client loads the credentials through this provider and doesn't use the basic authentication method.
+
+ You can set the following properties in the header:
+
+ `metric-name` / `ce-metricname` for the metric name.
+ `metric-value` / `ce-metricvalue` for the metric value.
+ `metric-unit` / `ce-metricunit` for the metric unit.
+ `metric-timestamp` / `ce-metrictimestamp` for the metric timestamp.
+ `metric-dimension-name` / `ce-metricdimensionname` for the dimension name.
+ `metric-dimension-value` / `ce-metricdimensionvalue` for the dimension value.
+ required:
+ - cwNamespace
+ - region
+ type: object
+ properties:
+ cwNamespace:
+ title: Cloud Watch Namespace
+ description: The CloudWatch metric namespace.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:password
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:password
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the CloudWatch client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ x-descriptors:
+ - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+ default: false
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ x-descriptors:
+ - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-cw"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[metric-name]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricName
+ simple: "${header[metric-name]}"
+ - simple: "${header[ce-metricname]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricName
+ simple: "${header[ce-metricname]}"
+ - choice:
+ when:
+ - simple: "${header[metric-value]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricValue
+ simple: "${header[metric-value]}"
+ - simple: "${header[ce-metricvalue]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricValue
+ simple: "${header[ce-metricvalue]}"
+ - choice:
+ when:
+ - simple: "${header[metric-unit]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricUnit
+ simple: "${header[metric-unit]}"
+ - simple: "${header[ce-metricunit]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricUnit
+ simple: "${header[ce-metricunit]}"
+ - choice:
+ when:
+ - simple: "${header[metric-timestamp]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricTimestamp
+ simple: "${header[metric-timestamp]}"
+ - simple: "${header[ce-metrictimestamp]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricTimestamp
+ simple: "${header[ce-metrictimestamp]}"
+ - choice:
+ when:
+ - simple: "${header[metric-dimension-name]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricDimensionName
+ simple: "${header[metric-dimension-name]}"
+ - simple: "${header[ce-metricdimensionname]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricDimensionName
+ simple: "${header[ce-metricdimensionname]}"
+ - choice:
+ when:
+ - simple: "${header[metric-dimension-value]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricDimensionValue
+ simple: "${header[metric-dimension-value]}"
+ - simple: "${header[ce-metricdimensionvalue]}"
+ steps:
+ - set-header:
+ name: CamelAwsCwMetricDimensionValue
+ simple: "${header[ce-metricdimensionvalue]}"
+ - to:
+ uri: "aws2-cw:{{cwNamespace}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
\ No newline at end of file
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 30196dab..af23ed39 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -82,7 +82,8 @@ class App extends React.Component<Props, State> {
fetch("snippets/org.apache.camel.AggregationStrategy"),
fetch("snippets/org.apache.camel.Processor"),
// fetch("example/demo.camel.yaml")
- fetch("example/aws-s3-cdc-source.kamelet.yaml")
+ fetch("example/aws-cloudwatch-sink.kamelet.yaml")
+ // fetch("example/aws-s3-cdc-source.kamelet.yaml")
// fetch("components/supported-components.json"),
]).then(responses =>
Promise.all(responses.map(response => response.text()))
diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx
index 10338ae9..a636339e 100644
--- a/karavan-designer/src/designer/route/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -63,6 +63,7 @@ export function DslConnections() {
.filter(pos => ["FromDefinition"].includes(pos.step.dslName))
.filter(pos => !TopologyUtils.isElementInternalComponent(pos.step))
.filter(pos => !(pos.step.dslName === 'FromDefinition' && TopologyUtils.hasInternalUri(pos.step)))
+ .filter(pos => !(pos.step.dslName === 'FromDefinition' && (pos.step as any).uri === 'kamelet:source'))
.sort((pos1: DslPosition, pos2: DslPosition) => {
const y1 = pos1.headerRect.y + pos1.headerRect.height / 2;
const y2 = pos2.headerRect.y + pos2.headerRect.height / 2;
diff --git a/karavan-designer/src/designer/route/DslElement.tsx b/karavan-designer/src/designer/route/DslElement.tsx
index c45dcbe4..9e4a8c70 100644
--- a/karavan-designer/src/designer/route/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -42,7 +42,7 @@ interface Props {
export function DslElement(props: Props) {
const headerRef = React.useRef<HTMLDivElement>(null);
- const {selectElement, moveElement, onShowDeleteConfirmation, openSelector, isKamelet} = useRouteDesignerHook();
+ const {selectElement, moveElement, onShowDeleteConfirmation, openSelector, isKamelet, isSourceKamelet, isActionKamelet} = useRouteDesignerHook();
const [integration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
@@ -244,6 +244,8 @@ export function DslElement(props: Props) {
function getHeaderText(step: CamelElement): string {
if (isKamelet() && step.dslName === 'ToDefinition' && (step as any).uri === 'kamelet:sink') {
return "Sink";
+ } else if (isKamelet() && step.dslName === 'FromDefinition' && (step as any).uri === 'kamelet:source') {
+ return "Source";
} else {
return (step as any).description ? (step as any).description : CamelUi.getElementTitle(props.step);
}
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx b/karavan-designer/src/designer/route/RouteDesigner.tsx
index 215f334b..c57260db 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -40,7 +40,8 @@ import {DslElementMoveModal} from "./DslElementMoveModal";
export function RouteDesigner() {
- const {openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement} = useRouteDesignerHook();
+ const {openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement, onDslSelect,
+ isSourceKamelet, isActionKamelet, isKamelet, isSinkKamelet} = useRouteDesignerHook();
const [integration] = useIntegrationStore((state) => [state.integration], shallow)
const [showDeleteConfirmation, setPosition, width, height, top, left, hideLogDSL, showMoveConfirmation, setShowMoveConfirmation] =
@@ -104,6 +105,37 @@ export function RouteDesigner() {
)
}
+ function getGraphButtons() {
+ const routes = CamelUi.getRoutes(integration);
+ const showNewRoute = (isKamelet() && routes.length === 0) || !isKamelet();
+ const showNewRouteConfiguration = !isKamelet();
+ return (
+ <div className="add-flow">
+ {showNewRoute && <Button
+ variant={routes.length === 0 ? "primary" : "secondary"}
+ icon={<PlusIcon/>}
+ onClick={e => {
+ if (isSinkKamelet() || isActionKamelet()) {
+ const dsl = CamelUi.getDslMetaModel('FromDefinition');
+ dsl.uri = 'kamelet:source';
+ onDslSelect(dsl, '', undefined);
+ } else {
+ openSelector(undefined, undefined)
+ }
+ }}
+ >
+ Create route
+ </Button>}
+ {showNewRouteConfiguration && <Button
+ variant="secondary"
+ icon={<PlusIcon/>}
+ onClick={e => createRouteConfiguration()}
+ >
+ Create configuration
+ </Button>}
+ </div>
+ )
+ }
function getGraph() {
const routes = CamelUi.getRoutes(integration);
const routeConfigurations = CamelUi.getRouteConfigurations(integration);
@@ -129,24 +161,7 @@ export function RouteDesigner() {
step={route}
parent={undefined}/>
))}
- <div className="add-flow">
- <Button
- variant={routes.length === 0 ? "primary" : "secondary"}
- icon={<PlusIcon/>}
- onClick={e => {
- openSelector(undefined, undefined)
- }}
- >
- Create route
- </Button>
- <Button
- variant="secondary"
- icon={<PlusIcon/>}
- onClick={e => createRouteConfiguration()}
- >
- Create configuration
- </Button>
- </div>
+ {getGraphButtons()}
</div>
</div>)
}
diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
index 5848acc9..0d97214d 100644
--- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
@@ -19,7 +19,7 @@ import '../karavan.css';
import {DslMetaModel} from "../utils/DslMetaModel";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {ChoiceDefinition, FromDefinition, LogDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
-import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement, MetadataLabels} from "karavan-core/lib/model/IntegrationDefinition";
import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {Command, EventBus} from "../utils/EventBus";
@@ -50,6 +50,30 @@ export function useRouteDesignerHook () {
return integration.type === 'kamelet';
}
+ function isSourceKamelet(): boolean {
+ if (isKamelet()){
+ const m: MetadataLabels | undefined = integration.metadata.labels;
+ return m !== undefined && m["camel.apache.org/kamelet.type"] === 'source';
+ }
+ return false;
+ }
+
+ function isSinkKamelet(): boolean {
+ if (isKamelet()){
+ const m: MetadataLabels | undefined = integration.metadata.labels;
+ return m !== undefined && m["camel.apache.org/kamelet.type"] === 'sink';
+ }
+ return false;
+ }
+
+ function isActionKamelet(): boolean {
+ if (isKamelet()){
+ const m: MetadataLabels | undefined = integration.metadata.labels;
+ return m !== undefined && m["camel.apache.org/kamelet.type"] === 'action';
+ }
+ return false;
+ }
+
const onShowDeleteConfirmation = (id: string) => {
let message: string;
const uuidsToDelete:string [] = [id];
@@ -197,7 +221,7 @@ export function useRouteDesignerHook () {
setSelectorTabIndex((parentId === undefined && parentDsl === undefined) ? 'kamelet' : 'eip');
}
- const onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
+ function onDslSelect (dsl: DslMetaModel, parentId: string, position?: number | undefined) {
switch (dsl.dsl) {
case 'FromDefinition' :
const route = CamelDefinitionApi.createRouteDefinition({from: new FromDefinition({uri: dsl.uri})});
@@ -298,5 +322,6 @@ export function useRouteDesignerHook () {
}
return { deleteElement, selectElement, moveElement, onShowDeleteConfirmation, onDslSelect, openSelector,
- createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement, isKamelet}
+ createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement, isKamelet, isSourceKamelet,
+ isActionKamelet, isSinkKamelet}
}
\ No newline at end of file