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 b1bf31b Beans config (#181)
b1bf31b is described below
commit b1bf31b5888b667dc0bb49b9c1855a8822d96536
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Thu Feb 10 16:21:48 2022 -0500
Beans config (#181)
* Support bean in Core
* Beans gallery
* Beans editor
* Bean config UI
* Bump version to 0.0.12
---
karavan-app/pom.xml | 2 +-
karavan-app/src/main/webapp/package.json | 2 +-
.../webapp/src/integrations/IntegrationCard.tsx | 2 +-
.../webapp/src/integrations/IntegrationPage.tsx | 2 +-
.../src/main/webapp/src/kamelets/KameletCard.tsx | 2 +-
karavan-core/src/core/api/CamelDefinitionApiExt.ts | 67 ++++-
karavan-core/src/core/api/CamelDefinitionYaml.ts | 46 ++-
karavan-core/src/core/api/CamelUtil.ts | 21 +-
karavan-core/src/core/model/CamelDefinition.ts | 20 ++
karavan-core/test/addStep.spec.ts | 1 -
karavan-core/test/beans.spec.ts | 56 ++++
karavan-core/test/beans1.yaml | 36 +++
karavan-core/test/beans2.yaml | 42 +++
karavan-demo/http-to-kafka.yaml | 35 +++
karavan-designer/package-lock.json | 4 +-
karavan-designer/package.json | 2 +-
karavan-designer/src/App.tsx | 62 ++--
karavan-designer/src/designer/KaravanDesigner.tsx | 314 +++++----------------
.../src/designer/beans/BeanProperties.tsx | 157 +++++++++++
.../src/designer/beans/BeansDesigner.tsx | 183 ++++++++++++
.../src/designer/error/ErrorDesigner.tsx | 74 +++++
.../src/designer/exception/ExceptionDesigner.tsx | 74 +++++
.../src/designer/field/DataFormatField.tsx | 1 -
.../src/designer/field/DslPropertyField.tsx | 2 +-
.../src/designer/field/ExpressionField.tsx | 2 +-
karavan-designer/src/designer/karavan.css | 251 ++++++++++++----
.../src/designer/rest/RestDesigner.tsx | 74 +++++
.../src/designer/{ => route}/DslConnections.tsx | 6 +-
.../src/designer/{ => route}/DslElement.tsx | 6 +-
.../src/designer/{ => route}/DslProperties.tsx | 31 +-
.../src/designer/{ => route}/DslSelector.tsx | 6 +-
.../RouteDesigner.tsx} | 129 ++-------
.../src/designer/templates/TemplatesDesigner.tsx | 74 +++++
.../src/designer/{ => utils}/CamelUi.ts | 36 ++-
.../src/designer/utils}/DslMetaModel.ts | 0
.../src/designer/{ => utils}/EventBus.ts | 0
.../src/designer/utils/KaravanComponents.tsx | 45 +++
.../src/designer/utils/KaravanIcons.tsx | 51 ++++
karavan-generator/pom.xml | 2 +-
.../src/main/resources/CamelDefinition.header.ts | 21 +-
karavan-vscode/package.json | 12 +-
karavan-vscode/webview/App.tsx | 2 +-
karavan-vscode/webview/index.css | 79 +++++-
43 files changed, 1504 insertions(+), 530 deletions(-)
diff --git a/karavan-app/pom.xml b/karavan-app/pom.xml
index d305aa8..63c03e8 100644
--- a/karavan-app/pom.xml
+++ b/karavan-app/pom.xml
@@ -18,7 +18,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.camel.karavan</groupId>
- <version>0.0.11</version>
+ <version>0.0.12</version>
<artifactId>karavan</artifactId>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
diff --git a/karavan-app/src/main/webapp/package.json
b/karavan-app/src/main/webapp/package.json
index 98bcc76..5f5ecef 100644
--- a/karavan-app/src/main/webapp/package.json
+++ b/karavan-app/src/main/webapp/package.json
@@ -1,6 +1,6 @@
{
"name": "karavan",
- "version": "0.0.11",
+ "version": "0.0.12",
"private": true,
"dependencies": {
"@patternfly/patternfly": "^4.171.1",
diff --git a/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
b/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
index db25be9..7402caf 100644
--- a/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
+++ b/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
@@ -4,7 +4,7 @@ import {
} from '@patternfly/react-core';
import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
import '../designer/karavan.css';
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
interface Props {
name: string,
diff --git a/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
b/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
index 328c6ae..d9b62a6 100644
--- a/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
+++ b/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
@@ -16,7 +16,7 @@ import {MainToolbar} from "../MainToolbar";
import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
import {Integration} from "karavan-core/lib/model/CamelDefinition";
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
interface Props {
integrations: Map<string,string>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
index 80e56a4..8a9cd75 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
@@ -4,7 +4,7 @@ import {
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
interface Props {
kamelet: KameletModel,
diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 02b03c5..1197f73 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -18,6 +18,7 @@ import {CamelMetadataApi, ElementMeta, Languages,
PropertyMeta} from "../model/C
import {ComponentApi} from "./ComponentApi";
import {CamelUtil} from "./CamelUtil";
import {
+ Bean, Beans,
CamelElement, CamelElementMeta,
ExpressionDefinition,
Integration, RouteDefinition
@@ -54,8 +55,8 @@ export class CamelDefinitionApiExt {
let added = false;
// Check all fields except steps
children.filter(child => child.name !== 'steps').forEach(child => {
- if (result.uuid === parentId){
- if (child.className === stepAdded.dslName){
+ if (result.uuid === parentId) {
+ if (child.className === stepAdded.dslName) {
added = true;
if (child.multiple) (result as
any)[child.name].push(stepAdded)
else (result as any)[child.name] = stepAdded;
@@ -68,7 +69,7 @@ export class CamelDefinitionApiExt {
});
// Then steps
const steps = children.filter(child => child.name === 'steps');
- if (!added && steps && result.uuid === parentId){
+ if (!added && steps && result.uuid === parentId) {
(result as any).steps.push(stepAdded);
} else if (!added && steps && (result as any).steps) {
(result as any).steps =
CamelDefinitionApiExt.addStepToSteps((result as any).steps, stepAdded,
parentId, position);
@@ -92,7 +93,7 @@ export class CamelDefinitionApiExt {
static findStep = (steps: CamelElement[] | undefined, uuid: string,
result: CamelElementMeta = new CamelElementMeta(undefined, undefined,
undefined, []), parentUuid?: string): CamelElementMeta => {
if (result?.step !== undefined) return result;
- if (steps !== undefined){
+ if (steps !== undefined) {
for (let index = 0, step: CamelElement; step = steps[index];
index++) {
if (step.uuid === uuid) {
const p = [...result.pathUuids];
@@ -141,8 +142,11 @@ export class CamelDefinitionApiExt {
}
static deleteStepFromIntegration = (integration: Integration,
uuidToDelete: string): Integration => {
- const flows =
CamelDefinitionApiExt.deleteStepFromSteps(integration.spec.flows, uuidToDelete);
- integration.spec.flows = flows as RouteDefinition[];
+ const flows: any[] = [];
+ integration.spec.flows?.filter(flow => flow.dslName ===
'Beans').forEach(bean => flows.push(bean));
+ const routes =
CamelDefinitionApiExt.deleteStepFromSteps(integration.spec.flows?.filter(flow
=> flow.dslName === 'RouteDefinition'), uuidToDelete);
+ flows.push(...routes);
+ integration.spec.flows = flows;
return integration;
}
@@ -151,7 +155,7 @@ export class CamelDefinitionApiExt {
const ce =
CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName);
ce.forEach(e => {
const cel = CamelDefinitionApiExt.getElementChildren(step, e);
- if (e.multiple){
+ if (e.multiple) {
(result as any)[e.name] =
CamelDefinitionApiExt.deleteStepFromSteps((result as any)[e.name],
uuidToDelete);
} else {
const prop = (result as any)[e.name];
@@ -169,7 +173,7 @@ export class CamelDefinitionApiExt {
static deleteStepFromSteps = (steps: CamelElement[] | undefined,
uuidToDelete: string): CamelElement[] => {
const result: CamelElement[] = []
- if (steps !== undefined){
+ if (steps !== undefined) {
steps.forEach(step => {
if (step.uuid !== uuidToDelete) {
step = CamelDefinitionApiExt.deleteStepFromStep(step,
uuidToDelete);
@@ -180,6 +184,47 @@ export class CamelDefinitionApiExt {
return result
}
+ static addBeanToIntegration = (integration: Integration, bean: Bean):
Integration => {
+ const flows: any[] = [];
+ if (integration.spec.flows?.filter(flow => flow.dslName ===
'Beans').length === 0) {
+ flows.push(...integration.spec.flows);
+ flows.push(new Beans({beans: [bean]}))
+ } else {
+ flows.push(...integration.spec.flows?.filter(flow => flow.dslName
!== 'Beans') || []);
+ integration.spec.flows?.filter(flow => flow.dslName ===
'Beans').forEach(flow => {
+ const beans: Bean[] = [];
+ if ((flow as Beans).beans.filter(b => b.uuid ===
bean.uuid).length === 0){
+ beans.push(...(flow as Beans).beans.filter(b => b.uuid !==
bean.uuid));
+ beans.push(bean);
+ } else {
+ (flow as Beans).beans.forEach(b => {
+ if (b.uuid === bean.uuid) beans.push(bean)
+ else beans.push(b);
+ })
+ }
+ const newBeans = new Beans({beans: beans});
+ flows.push(newBeans);
+ })
+ }
+ integration.spec.flows = flows;
+ return integration;
+ }
+
+ static deleteBeanFromIntegration = (integration: Integration, bean?:
Bean): Integration => {
+ const flows: any[] = [];
+ integration.spec.flows?.forEach(flow => {
+ if (flow.dslName === 'Beans') {
+ const beans = (flow as Beans).beans.filter(b => !(b.uuid ===
bean?.uuid && b.type === bean?.type));
+ const newBeans = new Beans({beans: beans});
+ flows.push(newBeans);
+ } else {
+ flows.push(flow);
+ }
+ })
+ integration.spec.flows = flows;
+ return integration;
+ }
+
static getExpressionLanguageName = (expression: ExpressionDefinition |
undefined): string | undefined => {
let result: string | undefined = undefined;
if (expression) {
@@ -304,15 +349,15 @@ export class CamelDefinitionApiExt {
static getElementPropertiesByName = (name: string): PropertyMeta[] => {
const model = CamelMetadataApi.getCamelModelMetadataByName(name);
- if (model){
+ if (model) {
return this.getElementProperties(model.className);
}
const language = CamelMetadataApi.getCamelLanguageMetadataByName(name);
- if (language){
+ if (language) {
return this.getElementProperties(language.className);
}
const dataFormat =
CamelMetadataApi.getCamelDataFormatMetadataByName(name);
- if (dataFormat){
+ if (dataFormat) {
return this.getElementProperties(dataFormat.className);
}
return [];
diff --git a/karavan-core/src/core/api/CamelDefinitionYaml.ts
b/karavan-core/src/core/api/CamelDefinitionYaml.ts
index 3e022c5..0587dc0 100644
--- a/karavan-core/src/core/api/CamelDefinitionYaml.ts
+++ b/karavan-core/src/core/api/CamelDefinitionYaml.ts
@@ -17,7 +17,7 @@
import * as yaml from 'js-yaml';
import {
Integration,
- CamelElement, RouteDefinition,
+ CamelElement, RouteDefinition, Bean, Beans,
} from "../model/CamelDefinition";
import {CamelUtil} from "./CamelUtil";
import {CamelDefinitionYamlStep} from "./CamelDefinitionYamlStep";
@@ -27,7 +27,7 @@ export class CamelDefinitionYaml {
static integrationToYaml = (integration: Integration): string => {
const clone: any = Object.assign({}, integration);
const flows = integration.spec.flows
- clone.spec.flows = flows?.map((f: any) =>
CamelDefinitionYaml.cleanupElement(f));
+ clone.spec.flows = flows?.map((f: any) =>
CamelDefinitionYaml.cleanupElement(f)).filter(x => Object.keys(x).length !== 0);
if (integration.crd) {
delete clone.crd
const i = JSON.parse(JSON.stringify(clone, null, 3)); // fix
undefined in string attributes
@@ -48,6 +48,8 @@ export class CamelDefinitionYaml {
delete object.expressionName;
} else if (object.dslName.endsWith('DataFormat')) {
delete object.dataFormatName;
+ } else if (object.dslName = 'Bean') {
+ if (object.properties && Object.keys(object.properties).length ===
0) delete object.properties;
}
delete object.uuid;
delete object.dslName;
@@ -122,14 +124,50 @@ export class CamelDefinitionYaml {
return i;
}
- static flowsToCamelElements = (flows: any[]): CamelElement[] => {
- const result:CamelElement[] = [];
+ static flowsToCamelElements = (flows: any[]): any[] => {
+ const result: any[] = [];
flows.filter((e: any) => e.hasOwnProperty('route'))
.forEach((f: any) =>
result.push(CamelDefinitionYamlStep.readRouteDefinition(f.route)));
flows.filter((e: any) => e.hasOwnProperty('from'))
.forEach((f: any) =>
result.push(CamelDefinitionYamlStep.readRouteDefinition(new
RouteDefinition({from: f.from}))));
+ flows.filter((e: any) => e.hasOwnProperty('beans'))
+ .forEach((b: any) =>
result.push(CamelDefinitionYaml.readBeanDefinition(b)));
return result;
}
+
+ static readBeanDefinition = (beans: any): Beans => {
+ const result: Beans = new Beans();
+ beans.beans.forEach((b: any) => {
+ const props: any = {}
+ if (b && b.properties){
+ // convert map style to properties if requires
+ Object.keys(b.properties).forEach( key => {
+ const value = b.properties[key];
+ CamelDefinitionYaml.flatMapProperty(key, value, new
Map<string, any>())
+ .forEach((v, k) => props[k] = v);
+ })
+ }
+ b.properties = props;
+ result.beans.push(new Bean(b))
+ })
+ return result;
+ }
+
+ // convert map style to properties if requires
+ static flatMapProperty = (key: string, value: any, properties: Map<string,
any>): Map<string, any> => {
+ if (value === undefined) {
+ } else if (typeof value === 'object') {
+ Object.keys(value).forEach(k => {
+ const key2 = key + "." + k;
+ const value2: any = value[k];
+ CamelDefinitionYaml.flatMapProperty(key2, value2, new
Map<string, any>())
+ .forEach((value1, key1) => properties.set(key1, value1));
+ })
+ } else {
+ properties.set(key, value);
+ }
+ return properties;
+ }
}
diff --git a/karavan-core/src/core/api/CamelUtil.ts
b/karavan-core/src/core/api/CamelUtil.ts
index 3beec6f..484c7fb 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -16,7 +16,7 @@
*/
import {
Integration,
- CamelElement,
+ CamelElement, Bean, Beans,
} from "../model/CamelDefinition";
import {CamelDefinitionApi} from "./CamelDefinitionApi";
@@ -25,7 +25,15 @@ export class CamelUtil {
static cloneIntegration = (integration: Integration): Integration => {
const clone = JSON.parse(JSON.stringify(integration));
const int: Integration = new Integration({...clone});
- const flows = int.spec.flows?.map(f =>
CamelDefinitionApi.createStep(f.dslName, f));
+ const flows: any[] = [];
+ int.spec.flows?.filter((e: any) => e.dslName === 'RouteDefinition')
+ .forEach(f => flows.push(CamelDefinitionApi.createStep(f.dslName,
f)));
+ int.spec.flows?.filter((e: any) => e.dslName === 'Beans')
+ .forEach(beans => {
+ const newBeans = new Beans();
+ (beans as Beans).beans.forEach(b =>
newBeans.beans.push(CamelUtil.cloneBean(b)));
+ flows.push(newBeans);
+ });
int.spec.flows = flows;
return int;
}
@@ -35,7 +43,14 @@ export class CamelUtil {
return CamelDefinitionApi.createStep(step.dslName, clone, true);
}
- static replacer = (key:string, value:any): any=> {
+ static cloneBean = (bean: Bean): Bean => {
+ const clone = JSON.parse(JSON.stringify(bean));
+ const newBean = new Bean(clone);
+ newBean.uuid = bean.uuid;
+ return newBean;
+ }
+
+ static replacer = (key:string, value:any): any => {
if (typeof value == 'object' && (value.hasOwnProperty('stepName') ||
value.hasOwnProperty('step-name'))) {
const stepNameField = value.hasOwnProperty('stepName') ?
'stepName' : 'step-name';
const stepName = value[stepNameField];
diff --git a/karavan-core/src/core/model/CamelDefinition.ts
b/karavan-core/src/core/model/CamelDefinition.ts
index 107c9f5..6e22563 100644
--- a/karavan-core/src/core/model/CamelDefinition.ts
+++ b/karavan-core/src/core/model/CamelDefinition.ts
@@ -53,6 +53,26 @@ export class CamelElement {
}
}
+export class Beans extends CamelElement {
+ beans: Bean[] = []
+
+ public constructor(init?: Partial<Beans>) {
+ super("Beans")
+ Object.assign(this, init);
+ }
+}
+
+export class Bean extends CamelElement {
+ name: string = ''
+ type: string = ''
+ properties: any
+
+ public constructor(init?: Partial<Bean>) {
+ super("Bean")
+ Object.assign(this, init);
+ }
+}
+
export class CamelElementMeta {
step?: CamelElement
parentUuid?: string
diff --git a/karavan-core/test/addStep.spec.ts
b/karavan-core/test/addStep.spec.ts
index d59a5da..e8c4552 100644
--- a/karavan-core/test/addStep.spec.ts
+++ b/karavan-core/test/addStep.spec.ts
@@ -92,7 +92,6 @@ describe('Add Step', () => {
const i2 = CamelDefinitionApiExt.addStepToIntegration(i1, w,
parentUuid);
if (i2.spec.flows) {
- console.log(CamelDefinitionYaml.integrationToYaml(i2));
expect(i2.spec.flows[0].from.steps[0].doCatch[0].onWhen.expression.simple.expression).to.equal("${body}
!= null");
}
}
diff --git a/karavan-core/test/beans.spec.ts b/karavan-core/test/beans.spec.ts
new file mode 100644
index 0000000..42f593d
--- /dev/null
+++ b/karavan-core/test/beans.spec.ts
@@ -0,0 +1,56 @@
+/*
+ * 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 {CamelDefinitionYamlStep} from
"../src/core/api/CamelDefinitionYamlStep";
+import {RouteDefinition} from "../src/core/model/CamelDefinition";
+
+describe('bean configuration', () => {
+
+ it('Read beans from plain YAML', () => {
+ const yaml = fs.readFileSync('test/beans1.yaml',{encoding:'utf8',
flag:'r'});
+ const i = CamelDefinitionYaml.yamlToIntegration("beans.yaml", yaml);
+ expect(i.metadata.name).to.equal('beans.yaml');
+ expect(i.kind).to.equal('Integration');
+ expect(i.spec.flows?.length).to.equal(3);
+ expect(i.crd).to.equal(false);
+ if (i.spec.flows) {
+ expect(i.spec.flows[2].beans[0].name).to.equal('myNested');
+
expect(i.spec.flows[2].beans[0].type).to.equal('${MyBean.class.name}');
+
expect(i.spec.flows[2].beans[0].properties['nested.foo']).to.equal('valueFoo');
+ expect(i.spec.flows[2].beans[1].name).to.equal('myProps');
+ }
+ });
+
+ it('Read beans from Integration', () => {
+ const yaml = fs.readFileSync('test/beans2.yaml',{encoding:'utf8',
flag:'r'});
+ const i = CamelDefinitionYaml.yamlToIntegration("beans.yaml", yaml);
+ expect(i.metadata.name).to.equal('beans.yaml');
+ expect(i.kind).to.equal('Integration');
+ expect(i.spec.flows?.length).to.equal(3);
+ expect(i.crd).to.equal(true);
+ if (i.spec.flows) {
+ expect(i.spec.flows[2].beans[0].name).to.equal('myNested');
+
expect(i.spec.flows[2].beans[0].type).to.equal('${MyBean.class.name}');
+
expect(i.spec.flows[2].beans[0].properties['nested.foo']).to.equal('valueFoo');
+ expect(i.spec.flows[2].beans[1].name).to.equal('myProps');
+ }
+ });
+
+});
diff --git a/karavan-core/test/beans1.yaml b/karavan-core/test/beans1.yaml
new file mode 100644
index 0000000..fbe81fc
--- /dev/null
+++ b/karavan-core/test/beans1.yaml
@@ -0,0 +1,36 @@
+- beans:
+ - name: myNested
+ type: ${MyBean.class.name}
+ properties:
+ field1: 'value1'
+ field2: 'value2'
+ nested:
+ foo: 'valueFoo'
+ bar: 'valueBar'
+ - name: myProps
+ type: ${MyBean.class.name}
+ properties:
+ field1: 'f1_p'
+ field2: 'f2_p'
+ nested.foo: 'nf1_p'
+ nested.bar: 'nf2_p'
+- from:
+ uri: "direct:route"
+ steps:
+ - aggregate:
+ strategy-ref: "myAggregatorStrategy"
+ completion-size: 2
+ correlation-expression:
+ simple: "${header.StockSymbol}"
+ steps:
+ - to: "mock:route"
+- from:
+ uri: "direct:route"
+ steps:
+ - aggregate:
+ strategy-ref: "myAggregatorStrategy"
+ completion-size: 2
+ correlation-expression:
+ simple: "${header.StockSymbol}"
+ steps:
+ - to: "mock:route"
\ No newline at end of file
diff --git a/karavan-core/test/beans2.yaml b/karavan-core/test/beans2.yaml
new file mode 100644
index 0000000..4bf83d1
--- /dev/null
+++ b/karavan-core/test/beans2.yaml
@@ -0,0 +1,42 @@
+apiVersion: camel.apache.org/v1
+kind: Integration
+metadata:
+ name: test1.yaml
+spec:
+ flows:
+ - beans:
+ - name: myNested
+ type: ${MyBean.class.name}
+ properties:
+ field1: 'value1'
+ field2: 'value2'
+ nested:
+ foo: 'valueFoo'
+ bar: 'valueBar'
+ - name: myProps
+ type: ${MyBean.class.name}
+ properties:
+ field1: 'f1_p'
+ field2: 'f2_p'
+ nested.foo: 'nf1_p'
+ nested.bar: 'nf2_p'
+ - from:
+ uri: "direct:route"
+ steps:
+ - aggregate:
+ strategy-ref: "myAggregatorStrategy"
+ completion-size: 2
+ correlation-expression:
+ simple: "${header.StockSymbol}"
+ steps:
+ - to: "mock:route"
+ - from:
+ uri: "direct:route"
+ steps:
+ - aggregate:
+ strategy-ref: "myAggregatorStrategy"
+ completion-size: 2
+ correlation-expression:
+ simple: "${header.StockSymbol}"
+ steps:
+ - to: "mock:route"
\ No newline at end of file
diff --git a/karavan-demo/http-to-kafka.yaml b/karavan-demo/http-to-kafka.yaml
new file mode 100644
index 0000000..298967a
--- /dev/null
+++ b/karavan-demo/http-to-kafka.yaml
@@ -0,0 +1,35 @@
+- route:
+ from:
+ uri: platform-http:/demo
+ steps:
+ - unmarshal:
+ json:
+ library: jackson
+ - choice:
+ when:
+ - expression:
+ simple:
+ expression: ${body[amount]} > 1000
+ steps:
+ - marshal:
+ json:
+ library: jackson
+ - kamelet:
+ name: kafka-not-secured-sink
+ parameters:
+ topic: topic-demo
+ bootstrapServers: localhost:9092
+ otherwise:
+ steps:
+ - log:
+ message: Amount is too small
+ loggingLevel: INFO
+ logName: demo
+ - setBody:
+ expression:
+ constant:
+ expression: '{"result":"OK"}'
+ - circuitBreaker: {}
+ parameters:
+ httpMethodRestrict: POST
+ produces: application/json
diff --git a/karavan-designer/package-lock.json
b/karavan-designer/package-lock.json
index 409e45c..1795c1d 100644
--- a/karavan-designer/package-lock.json
+++ b/karavan-designer/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "karavan-designer",
- "version": "0.0.10",
+ "version": "0.0.11",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "karavan-designer",
- "version": "0.0.10",
+ "version": "0.0.11",
"license": "Apache-2.0",
"dependencies": {
"@patternfly/patternfly": "4.171.1",
diff --git a/karavan-designer/package.json b/karavan-designer/package.json
index 1c331d0..50b555a 100644
--- a/karavan-designer/package.json
+++ b/karavan-designer/package.json
@@ -1,6 +1,6 @@
{
"name": "karavan-designer",
- "version": "0.0.11",
+ "version": "0.0.12",
"license": "Apache-2.0",
"scripts": {
"start": "react-scripts start",
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 3d29a5e..c504245 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -34,11 +34,11 @@ interface State {
class App extends React.Component<Props, State> {
public state: State = {
- name: '',
+ name: 'demo.yaml',
yaml: 'apiVersion: camel.apache.org/v1\n' +
'kind: Integration\n' +
'metadata:\n' +
- ' name: \'\'\n' +
+ ' name: demo.yaml\'\'\n' +
'spec:\n' +
' flows:\n' +
' - route:\n' +
@@ -53,26 +53,26 @@ class App extends React.Component<Props, State> {
// ' - option-name: o2\n' +
// ' expression:\n' +
// ' simple: "${body}" \n' +
- ' - do-try:\n' +
- ' steps:\n' +
- ' - to: "direct:direct1"\n' +
- ' - to: "direct:direct2"\n' +
- ' - log: "log1"\n' +
- ' do-catch:\n' +
- ' - exception:\n' +
- ' - "java.io.FileNotFoundException"\n' +
- ' - "java.io.IOException"\n' +
- ' steps:\n' +
- ' - log: "log1"\n' +
- ' - kamelet: \n' +
- ' name: kafka-sink \n' +
- ' - exception:\n' +
- ' - "java.io.FileNotFoundException"\n' +
- ' - "java.io.IOException"\n' +
- ' steps:\n' +
- ' - log: "log1"\n' +
- ' - kamelet: \n' +
- ' name: http-sink \n' +
+ // ' - do-try:\n' +
+ // ' steps:\n' +
+ // ' - to: "direct:direct1"\n' +
+ // ' - to: "direct:direct2"\n' +
+ // ' - log: "log1"\n' +
+ // ' do-catch:\n' +
+ // ' - exception:\n' +
+ // ' - "java.io.FileNotFoundException"\n' +
+ // ' - "java.io.IOException"\n' +
+ // ' steps:\n' +
+ // ' - log: "log1"\n' +
+ // ' - kamelet: \n' +
+ // ' name: kafka-sink \n' +
+ // ' - exception:\n' +
+ // ' - "java.io.FileNotFoundException"\n' +
+ // ' - "java.io.IOException"\n' +
+ // ' steps:\n' +
+ // ' - log: "log1"\n' +
+ // ' - kamelet: \n' +
+ // ' name: http-sink \n' +
' - choice:\n' +
' when:\n' +
' - simple: "hello world"\n' +
@@ -81,6 +81,24 @@ class App extends React.Component<Props, State> {
' message: hello22s\n' +
' logName: log22\n' +
' otherwise: {}\n'+
+ ' - beans:\n' +
+ ' - name: myNested\n' +
+ ' type: ${MyBean.class.name}\n' +
+ ' properties:\n' +
+ ' field1: \'value1\'\n' +
+ ' field2: \'value2\'\n' +
+ ' nested:\n' +
+ ' foo: \'valueFoo\'\n' +
+ ' bar: \'valueBar\'\n' +
+ ' - name: myProps\n' +
+ ' type: ${MyBean.class.name}\n' +
+ ' properties:\n' +
+ ' field1: \'f1_p\'\n' +
+ ' field2: \'f2_p\'\n' +
+ ' nested.foo: \'nf1_p\'\n' +
+ ' nested.bar: \'nf2_p\'\n'+
+ ' - name: myAggregatorStrategy \n' +
+ ' type:
org.apache.camel.processor.aggregate.UseLatestAggregationStrategy\n' +
'',
key: ''
};
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx
b/karavan-designer/src/designer/KaravanDesigner.tsx
index d132ba2..7a3e423 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/KaravanDesigner.tsx
@@ -16,22 +16,20 @@
*/
import React from 'react';
import {
- Button, Modal,
+ Badge,
PageSection, Tab, Tabs, TabTitleIcon, TabTitleText, Tooltip,
} from '@patternfly/react-core';
import './karavan.css';
-import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
-import {DslProperties} from "./DslProperties";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {CamelElement, FromDefinition, Integration} from
"karavan-core/lib/model/CamelDefinition";
+import {RouteDesigner} from "./route/RouteDesigner";
import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
-import {DslConnections} from "./DslConnections";
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {DslElement} from "./DslElement";
-import {EventBus} from "./EventBus";
+import {Integration} from "karavan-core/lib/model/CamelDefinition";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {CamelUi} from "./utils/CamelUi";
+import {BeansDesigner} from "./beans/BeansDesigner";
+import {RestDesigner} from "./rest/RestDesigner";
+import {ErrorDesigner} from "./error/ErrorDesigner";
+import {TemplatesDesigner} from "./templates/TemplatesDesigner";
+import {ExceptionDesigner} from "./exception/ExceptionDesigner";
interface Props {
onSave?: (filename: string, yaml: string) => void
@@ -43,241 +41,45 @@ interface Props {
}
interface State {
- integration: Integration
- selectedStep?: CamelElement
- showSelector: boolean
- showDeleteConfirmation: boolean
- parentId: string
- parentDsl?: string
- showSteps: boolean
- selectedUuid: string
- key: string
- width: number
- height: number
- top: number
+ tab: string,
+ integration: Integration,
+ key: string,
}
export class KaravanDesigner extends React.Component<Props, State> {
public state: State = {
+ tab: 'routes',
integration: this.props.yaml
? CamelDefinitionYaml.yamlToIntegration(this.props.filename,
this.props.yaml)
: Integration.createNew(this.props.filename),
- showSelector: false,
- showDeleteConfirmation: false,
- parentId: '',
- showSteps: true,
- selectedUuid: '',
key: "",
- width: 1000,
- height: 1000,
- top: 0,
};
- componentDidMount() {
- window.addEventListener('resize', this.handleResize);
- }
-
- componentWillUnmount() {
- window.removeEventListener('resize', this.handleResize);
- }
-
- handleResize = () => {
- this.setState({key: Math.random().toString()});
- }
-
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
if (prevState.key !== this.state.key) {
this.props.onSave?.call(this,
this.state.integration.metadata.name, this.getCode(this.state.integration));
}
}
- unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
- if ((evt.target as any).dataset.click === 'FLOWS') {
- evt.stopPropagation()
- this.setState({selectedStep: undefined, selectedUuid: '',
showSelector: false})
- }
- };
+ save = (integration: Integration): void => {
+ this.setState({key: Math.random().toString(), integration:
integration});
+ }
getCode = (integration: Integration): string => {
const clone = CamelUtil.cloneIntegration(integration);
return CamelDefinitionYaml.integrationToYaml(clone);
}
- onPropertyUpdate = (element: CamelElement, updatedUuid: string) => {
- const clone = CamelUtil.cloneIntegration(this.state.integration);
- const i = CamelDefinitionApiExt.updateIntegration(clone, element,
updatedUuid);
- this.setState({integration: i, key: Math.random().toString()});
- }
-
- showDeleteConfirmation = (id: string) => {
- this.setState({selectedUuid: id, showSelector: false,
showDeleteConfirmation: true});
- }
-
- deleteElement = () => {
- const id = this.state.selectedUuid;
- const i =
CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id);
- this.setState({
- integration: i,
- showSelector: false,
- showDeleteConfirmation: false,
- key: Math.random().toString(),
- selectedStep: undefined,
- selectedUuid: ''
- });
- const el = new CamelElement("");
- el.uuid = id;
- EventBus.sendPosition("delete", el, undefined, new DOMRect(), new
DOMRect(), 0);
- }
-
- selectElement = (element: CamelElement) => {
- this.setState({selectedStep: element, selectedUuid: element.uuid,
showSelector: false})
- }
-
- openSelector = (parentId: string | undefined, parentDsl: string |
undefined, showSteps: boolean = true) => {
- this.setState({showSelector: true, parentId: parentId || '',
parentDsl: parentDsl, showSteps: showSteps})
- }
-
- closeDslSelector = () => {
- this.setState({showSelector: false})
- }
-
- onDslSelect = (dsl: DslMetaModel, parentId: string) => {
- switch (dsl.dsl) {
- case 'FromDefinition' :
- const from = CamelDefinitionApi.createRouteDefinition({from:
new FromDefinition({uri: dsl.uri})});
- this.addStep(from, parentId)
- break;
- case 'ToDefinition' :
- const to = CamelDefinitionApi.createStep(dsl.dsl, {uri:
dsl.uri});
- this.addStep(to, parentId)
- break;
- case 'ToDynamicDefinition' :
- const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri:
dsl.uri});
- this.addStep(toD, parentId)
- break;
- case 'KameletDefinition' :
- const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name:
dsl.name});
- this.addStep(kamelet, parentId)
- break;
- default:
- const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
- this.addStep(step, parentId)
- break;
- }
- }
-
- addStep = (step: CamelElement, parentId: string) => {
- const i =
CamelDefinitionApiExt.addStepToIntegration(this.state.integration, step,
parentId);
- const clone = CamelUtil.cloneIntegration(i);
- this.setState({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: step,
- selectedUuid: step.uuid
- });
- }
-
- onIntegrationUpdate = (i: Integration) => {
- this.setState({integration: i, showSelector: false, key:
Math.random().toString()});
- }
-
- moveElement = (source: string, target: string) => {
- const i = CamelDefinitionApiExt.moveElement(this.state.integration,
source, target);
- const clone = CamelUtil.cloneIntegration(i);
- const selectedStep =
CamelDefinitionApiExt.findElementInIntegration(clone, source);
- this.setState({
- integration: clone,
- key: Math.random().toString(),
- showSelector: false,
- selectedStep: selectedStep,
- selectedUuid: source
- });
- }
-
- onResizePage(el: HTMLDivElement | null) {
- const rect = el?.getBoundingClientRect();
- if (el && rect && (rect?.width !== this.state.width || rect.height !==
this.state.height || rect.top !== this.state.top)) {
- this.setState({width: rect.width, height: rect.height, top:
rect.top});
- }
- }
-
- getSelectorModal() {
- return (
- <Modal
- title={this.state.parentDsl === undefined ? "Select
source/from" : "Select step"}
- width={'90%'}
- className='dsl-modal'
- isOpen={this.state.showSelector}
- onClose={() => this.closeDslSelector()}
- actions={{}}>
- <DslSelector
- dark={this.props.dark}
- parentId={this.state.parentId}
- parentDsl={this.state.parentDsl}
- showSteps={this.state.showSteps}
- onDslSelect={this.onDslSelect}/>
- </Modal>)
- }
-
- getDeleteConfirmation() {
- return (<Modal
- className="modal-delete"
- title="Confirmation"
- isOpen={this.state.showDeleteConfirmation}
- onClose={() => this.setState({showDeleteConfirmation: false})}
- actions={[
- <Button key="confirm" variant="primary" onClick={e =>
this.deleteElement()}>Delete</Button>,
- <Button key="cancel" variant="link"
- onClick={e => this.setState({showDeleteConfirmation:
false})}>Cancel</Button>
- ]}
- onEscapePress={e => this.setState({showDeleteConfirmation:
false})}>
- <div>
- Delete element from integration?
- </div>
- </Modal>)
- }
-
- getGraph() {
- return (
- <div className="graph">
- <DslConnections height={this.state.height}
width={this.state.width} top={this.state.top}
integration={this.state.integration}/>
- <div className="flows" data-click="FLOWS" onClick={event =>
this.unselectElement(event)}
- ref={el => this.onResizePage(el)}>
- {this.state.integration.spec.flows?.map((from: any, index:
number) => (
- <DslElement key={from.uuid + this.state.key}
- openSelector={this.openSelector}
- deleteElement={this.showDeleteConfirmation}
- selectElement={this.selectElement}
- moveElement={this.moveElement}
- selectedUuid={this.state.selectedUuid}
- borderColor={this.props.borderColor}
-
borderColorSelected={this.props.borderColorSelected}
- inSteps={false}
- position={index}
- step={from}
- parent={undefined}/>
- ))}
- <div className="add-flow">
- <Button
- variant={this.state.integration.spec.flows?.length
=== 0 ? "primary" : "secondary"}
- data-click="ADD_ROUTE"
- icon={<PlusIcon/>}
- onClick={e => this.openSelector(undefined,
undefined)}>Add new route
- </Button>
- </div>
- </div>
- </div>)
- }
-
getTab(title: string, tooltip: string, icon: string) {
+ const counts = CamelUi.getFlowCounts(this.state.integration);
return (
<Tooltip position={"bottom"}
content={<div>{tooltip}</div>}>
<div className="top-menu-item">
<TabTitleIcon>{this.getIcon(icon)}</TabTitleIcon>
<TabTitleText>{title}</TabTitleText>
+ {counts.has(icon) && <Badge isRead
className="count">{counts.get(icon)}</Badge>}
</div>
</Tooltip>
@@ -310,14 +112,13 @@ export class KaravanDesigner extends
React.Component<Props, State> {
</svg>
)
if (icon === 'beans') return (
- <svg className="top-icon" viewBox="0 0 536.243 536.242" >
- <g>
- <path
d="M471.053,197.07c-94.2-101.601-284-183.601-423.5-154.2c-9.2,1.8-12.9,9.2-12.2,16.5c-86.9,47.7,9.2,213,45.9,261.3
-
c72.2,96.1,200.701,203.2,329.901,173.8c60-13.5,103.399-69.8,120-126.1C550.053,304.77,513.253,242.37,471.053,197.07z
-
M393.353,465.17c-102.199,23.3-210.5-75.9-271.7-145c-61.2-70.4-108.3-155.4-71-243c83.8,151.8,253.4,269.3,414.9,321.899
-
c19.601,6.101,28.2-24.5,8.601-31.199C318.753,315.27,166.353,209.97,73.953,72.27c111.4-13.5,238.701,45.9,326.201,107.101
-
c50.199,35.5,98.5,87.5,102.8,151.8C505.954,394.17,451.454,451.67,393.353,465.17z"/>
- </g>
+ <svg className="top-icon" width="32px" height="32px" viewBox="0 0
32 32">
+ <defs>
+ <style>{".cls-1 {fill: none;}"}</style>
+ </defs>
+ <path
+
d="M28.5039,8.1362l-12-7a1,1,0,0,0-1.0078,0l-12,7A1,1,0,0,0,3,9V23a1,1,0,0,0,.4961.8638l12,7a1,1,0,0,0,1.0078,0l12-7A1,1,0,0,0,29,23V9A1,1,0,0,0,28.5039,8.1362ZM16,3.1577,26.0156,9,16,14.8423,5.9844,9ZM5,10.7412l10,5.833V28.2588L5,22.4258ZM17,28.2588V16.5742l10-5.833V22.4258Z"/>
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32"/>
</svg>
)
if (icon === 'error') return (
@@ -351,30 +152,47 @@ export class KaravanDesigner extends
React.Component<Props, State> {
}
render() {
+ const tab = this.state.tab;
return (
- <PageSection className="dsl-page" isFilled padding={{default:
'noPadding'}}>
- <div className="dsl-page-columns">
- <div style={{width: "100%"}}>
- <Tabs isFilled className="main-tabs" activeKey={0}
onSelect={event => {
- }} style={{width: "100%"}}>
- <Tab eventKey={0} title={this.getTab("Routes",
"Integration flows", "routes")}></Tab>
- <Tab eventKey={1} title={this.getTab("REST", "REST
services","rest")}></Tab>
- <Tab eventKey={2} title={this.getTab("Beans",
"Beans Configuration","beans")}></Tab>
- <Tab eventKey={3}
title={this.getTab("Error","Error Handler configuration", "error")}></Tab>
- <Tab eventKey={4}
title={this.getTab("Exceptions","Exception Clauses per type",
"exception")}></Tab>
- <Tab eventKey={5} title={this.getTab("Templates",
"Route Templates","template")}></Tab>
- </Tabs>
- {this.getGraph()}
- </div>
- <DslProperties
- integration={this.state.integration}
- step={this.state.selectedStep}
- onIntegrationUpdate={this.onIntegrationUpdate}
- onPropertyUpdate={this.onPropertyUpdate}
- />
- </div>
- {this.getSelectorModal()}
- {this.getDeleteConfirmation()}
+ <PageSection className="page" isFilled padding={{default:
'noPadding'}}>
+ <Tabs className="main-tabs" activeKey={tab} onSelect={(event,
tabIndex) => this.setState({tab: tabIndex.toString()})} style={{width: "100%"}}>
+ <Tab eventKey='routes' title={this.getTab("Routes",
"Integration flows", "routes")}></Tab>
+ <Tab eventKey='rest' title={this.getTab("REST", "REST
services", "rest")}></Tab>
+ <Tab eventKey='beans' title={this.getTab("Beans", "Beans
Configuration", "beans")}></Tab>
+ <Tab eventKey='error' title={this.getTab("Error", "Error
Handler configuration", "error")}></Tab>
+ <Tab eventKey='exception' title={this.getTab("Exceptions",
"Exception Clauses per type", "exception")}></Tab>
+ <Tab eventKey='templates' title={this.getTab("Templates",
"Route Templates", "template")}></Tab>
+ </Tabs>
+ {tab === 'routes' && <RouteDesigner
integration={this.state.integration}
+ onSave={(integration) =>
this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+ dark={this.props.dark}/>}
+ {tab === 'rest' && <RestDesigner
integration={this.state.integration}
+ onSave={(integration) =>
this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+ dark={this.props.dark}/>}
+ {tab === 'beans' && <BeansDesigner
integration={this.state.integration}
+ onSave={(integration) =>
this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+ dark={this.props.dark}/>}
+ {tab === 'error' && <ErrorDesigner
integration={this.state.integration}
+ onSave={(integration) =>
this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+ dark={this.props.dark}/>}
+ {tab === 'exception' && <ExceptionDesigner
integration={this.state.integration}
+
onSave={(integration) => this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+
dark={this.props.dark}/>}
+ {tab === 'templates' && <TemplatesDesigner
integration={this.state.integration}
+
onSave={(integration) => this.save(integration)}
+
borderColor={this.props.borderColor}
+
borderColorSelected={this.props.borderColorSelected}
+
dark={this.props.dark}/>}
</PageSection>
);
}
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx
b/karavan-designer/src/designer/beans/BeanProperties.tsx
new file mode 100644
index 0000000..ad6b578
--- /dev/null
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -0,0 +1,157 @@
+/*
+ * 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 React from 'react';
+import {
+ Form,
+ FormGroup,
+ TextInput,
+ Text,
+ Title,
+ TextVariants, Button,
+} from '@patternfly/react-core';
+import '../karavan.css';
+import "@patternfly/patternfly/patternfly.css";
+import {DataFormatField} from "../field/DataFormatField";
+import {DslPropertyField} from "../field/DslPropertyField";
+import {
+ CamelElement,
+ Integration,
+ ExpressionDefinition,
+ DataFormatDefinition, Bean
+} from "karavan-core/lib/model/CamelDefinition";
+import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {CamelUi} from "../utils/CamelUi";
+import {CamelMetadataApi, PropertyMeta} from
"karavan-core/lib/model/CamelMetadata";
+import {v4 as uuidv4} from "uuid";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
+import {IntegrationHeader} from "../utils/KaravanComponents";
+
+interface Props {
+ integration: Integration
+ bean?: Bean
+ dark: boolean
+ onChange: (bean: Bean) => void
+}
+
+interface State {
+ bean?: Bean
+ properties: Map<string, [string, string]>
+ key: string
+}
+
+export class BeanProperties extends React.Component<Props, State> {
+
+ preparePropertiesMap = (properties: any): Map<string, [string, string]> =>
{
+ const result = new Map<string, [string, string]>();
+ Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k,
properties[k]]));
+ return result;
+ }
+
+ public state: State = {
+ bean: this.props.bean,
+ key: '',
+ properties: this.props.bean?.properties ?
this.preparePropertiesMap(this.props.bean?.properties) : new Map<string,
[string, string]>()
+ };
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevProps.bean?.uuid !== this.props.bean?.uuid) {
+ this.setBean(this.props.bean);
+ }
+ if (prevState.key !== this.state.key && this.state.bean) {
+ const bean = CamelUtil.cloneBean(this.state.bean);
+ const properties: any = {};
+ this.state.properties.forEach(p => properties[p[0]] = p[1]);
+ bean.properties = properties;
+ this.setState({bean: bean});
+ this.props.onChange?.call(this, bean);
+ }
+ }
+
+ setBean = (bean?: Bean) => {
+ this.setState({
+ bean: bean,
+ properties: bean?.properties ?
this.preparePropertiesMap(bean.properties) : new Map<string, [string, string]>()
+ });
+ }
+
+ beanChanged = (fieldId: string, value: string) => {
+ if (this.state.bean) {
+ const bean = CamelUtil.cloneBean(this.state.bean);
+ (bean as any)[fieldId] = value;
+ this.setState({bean: bean});
+ this.props.onChange?.call(this, bean);
+ }
+ }
+
+ propertyChanged = (uuid: string, key: string, value: string) => {
+ this.setState(state => {
+ state.properties.set(uuid, [key, value]);
+ return {properties: state.properties, key:
Math.random().toString()};
+ })
+ }
+
+ propertyDeleted = (uuid: string) => {
+ this.setState(state => {
+ state.properties.delete(uuid);
+ return {properties: state.properties, key:
Math.random().toString()};
+ })
+ }
+
+ getBeanForm() {
+ const bean = this.state.bean;
+ return (
+ <>
+ <FormGroup label="Name" fieldId="name" isRequired>
+ <TextInput className="text-field" isRequired type="text"
id="name" name="name" value={bean?.name}
+ onChange={e => this.beanChanged("name", e)}/>
+ </FormGroup>
+ <FormGroup label="Type" fieldId="type" isRequired>
+ <TextInput className="text-field" isRequired type="text"
id="type" name="type" value={bean?.type} onChange={e =>
this.beanChanged("type", e)}/>
+ </FormGroup>
+ <FormGroup label="Properties" fieldId="properties"
className="bean-properties">
+ {Array.from(this.state.properties.entries()).map((v,
index, array) => {
+ const i = v[0];
+ const key = v[1][0];
+ const value = v[1][1];
+ return (
+ <div key={"key-" + i} className="bean-property">
+ <TextInput className="text-field" isRequired
type="text" id="key" name="key" value={key} onChange={e =>
this.propertyChanged(i, e, value)}/>
+ <TextInput className="text-field" isRequired
type="text" id="value" name="value" value={value} onChange={e =>
this.propertyChanged(i, key, e)}/>
+ <Button variant="link"
className="delete-button" onClick={e =>
this.propertyDeleted(i)}><DeleteIcon/></Button>
+ </div>
+ )
+ })}
+ <Button variant="link" className="add-button" onClick={e
=> this.propertyChanged(uuidv4(), '', '')}><AddIcon/>Add property</Button>
+ </FormGroup>
+ </>
+ )
+ }
+
+ render() {
+ return (
+ <div className='properties' key={this.state.bean ?
this.state.bean.uuid : 'integration'}>
+ <Form autoComplete="off" onSubmit={event =>
event.preventDefault()}>
+ {this.state.bean === undefined && <IntegrationHeader
integration={this.props.integration}/>}
+ {this.state.bean !== undefined && this.getBeanForm()}
+ </Form>
+ </div>
+ )
+ }
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/beans/BeansDesigner.tsx
b/karavan-designer/src/designer/beans/BeansDesigner.tsx
new file mode 100644
index 0000000..2416964
--- /dev/null
+++ b/karavan-designer/src/designer/beans/BeansDesigner.tsx
@@ -0,0 +1,183 @@
+/*
+ * 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 React from 'react';
+import {
+ Button, Card, CardActions, CardBody, CardFooter, CardHeader, CardTitle,
Gallery, Modal, PageSection
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {Bean, Integration} from "karavan-core/lib/model/CamelDefinition";
+import {CamelUi} from "../utils/CamelUi";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
+import DeleteIcon from
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import {BeanIcon} from "../utils/KaravanIcons";
+import {BeanProperties} from "./BeanProperties";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+
+interface Props {
+ onSave?: (integration: Integration) => void
+ integration: Integration
+ borderColor: string
+ borderColorSelected: string
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ showDeleteConfirmation: boolean
+ selectedBean?: Bean
+ key: string
+ showBeanEditor: boolean
+}
+
+export class BeansDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ showDeleteConfirmation: false,
+ key: "",
+ showBeanEditor: false,
+ };
+
+ componentDidMount() {
+ window.addEventListener('resize', this.handleResize);
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.handleResize);
+ }
+
+ handleResize = () => {
+ this.setState({key: Math.random().toString()});
+ }
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration);
+ }
+ }
+
+ showDeleteConfirmation = (e: React.MouseEvent, bean: Bean) => {
+ e.stopPropagation();
+ this.setState({selectedBean: bean, showDeleteConfirmation: true});
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, showDeleteConfirmation: false, key:
Math.random().toString()});
+ }
+
+ deleteBean = () => {
+ const i =
CamelDefinitionApiExt.deleteBeanFromIntegration(this.state.integration,
this.state.selectedBean);
+ this.setState({
+ integration: i,
+ showDeleteConfirmation: false,
+ key: Math.random().toString(),
+ selectedBean: new Bean()
+ });
+ }
+
+ changeBean = (bean: Bean) => {
+ const clone = CamelUtil.cloneIntegration(this.state.integration);
+ const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
+ this.setState({integration: i, key: Math.random().toString(),
selectedBean: bean});
+ }
+
+ getDeleteConfirmation() {
+ return (<Modal
+ className="modal-delete"
+ title="Confirmation"
+ isOpen={this.state.showDeleteConfirmation}
+ onClose={() => this.setState({showDeleteConfirmation: false})}
+ actions={[
+ <Button key="confirm" variant="primary" onClick={e =>
this.deleteBean()}>Delete</Button>,
+ <Button key="cancel" variant="link"
+ onClick={e => this.setState({showDeleteConfirmation:
false})}>Cancel</Button>
+ ]}
+ onEscapePress={e => this.setState({showDeleteConfirmation:
false})}>
+ <div>
+ Delete bean from integration?
+ </div>
+ </Modal>)
+ }
+
+ closeBeanEditor = () => {
+ this.setState({showBeanEditor: false})
+ }
+
+ openBeanEditor = () => {
+ this.setState({showBeanEditor: true})
+ }
+
+ selectBean = (bean?: Bean) => {
+ this.setState({selectedBean: bean})
+ }
+
+ unselectBean = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
+ if ((evt.target as any).dataset.click === 'BEANS') {
+ evt.stopPropagation()
+ this.setState({selectedBean: undefined})
+ }
+ };
+
+ createBean = () => {
+ this.changeBean(new Bean());
+ }
+
+ getCard(bean: Bean, index: number) {
+ return (
+ <Card key={bean.dslName + index} isHoverable isCompact
+ className={this.state.selectedBean?.uuid === bean.uuid ?
"bean-card bean-card-selected" : "bean-card bean-card-unselected"}
+ onClick={e => this.selectBean(bean)}>
+ <CardHeader>
+ <BeanIcon/>
+ <CardActions>
+ <Button variant="link" className="delete-button"
onClick={e => this.showDeleteConfirmation(e, bean)}><DeleteIcon/></Button>
+ </CardActions>
+ </CardHeader>
+ <CardTitle>{bean.name}</CardTitle>
+ <CardBody>{bean.type}</CardBody>
+ <CardFooter className="">
+ </CardFooter>
+ </Card>
+ )
+ }
+
+ render() {
+ const beans = CamelUi.getBeans(this.state.integration);
+ return (
+ <PageSection className="beans-page" isFilled padding={{default:
'noPadding'}}>
+ <div className="beans-page-columns" data-click="BEANS"
onClick={event => this.unselectBean(event)}>
+ <div className="beans-panel">
+ <Gallery hasGutter className="beans-gallery"
data-click="BEANS" onClick={event => this.unselectBean(event)}>
+ {beans.map((bean: Bean, index: number) =>
this.getCard(bean, index))}
+ </Gallery>
+ <div className="add-button-div" data-click="BEANS"
onClick={event => this.unselectBean(event)}>
+ <Button icon={<PlusIcon/>} variant={beans.length
=== 0 ? "primary" : "secondary"} onClick={e => this.createBean()}
className="add-bean-button">
+ Add new bean
+ </Button>
+ </div>
+ </div>
+ <BeanProperties integration={this.props.integration}
+ bean={this.state.selectedBean}
+ dark={this.props.dark}
+ onChange={this.changeBean}/>
+ </div>
+ {this.getDeleteConfirmation()}
+ </PageSection>
+ );
+ }
+}
diff --git a/karavan-designer/src/designer/error/ErrorDesigner.tsx
b/karavan-designer/src/designer/error/ErrorDesigner.tsx
new file mode 100644
index 0000000..39336a3
--- /dev/null
+++ b/karavan-designer/src/designer/error/ErrorDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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 React from 'react';
+import {
+ Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+ PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+ onSave?: (integration: Integration) => void
+ integration: Integration
+ borderColor: string
+ borderColorSelected: string
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ selectedStep?: CamelElement
+ key: string
+}
+
+export class ErrorDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ key: "",
+ };
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration);
+ }
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, key: Math.random().toString()});
+ }
+
+ render() {
+ return (
+ <PageSection className="error-page" isFilled padding={{default:
'noPadding'}}>
+ <div className="error-page-columns">
+ <EmptyState>
+ <EmptyStateIcon icon={CubesIcon} />
+ <Title headingLevel="h4" size="lg">
+ Error handler
+ </Title>
+ <EmptyStateBody>
+ Error handler not implemented yet
+ </EmptyStateBody>
+ </EmptyState>
+ </div>
+ </PageSection>
+ );
+ }
+}
diff --git a/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
b/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
new file mode 100644
index 0000000..a340fd8
--- /dev/null
+++ b/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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 React from 'react';
+import {
+ Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+ PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+ onSave?: (integration: Integration) => void
+ integration: Integration
+ borderColor: string
+ borderColorSelected: string
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ selectedStep?: CamelElement
+ key: string
+}
+
+export class ExceptionDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ key: "",
+ };
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration);
+ }
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, key: Math.random().toString()});
+ }
+
+ render() {
+ return (
+ <PageSection className="exception-page" isFilled
padding={{default: 'noPadding'}}>
+ <div className="exception-page-columns">
+ <EmptyState>
+ <EmptyStateIcon icon={CubesIcon} />
+ <Title headingLevel="h4" size="lg">
+ Exception Clauses
+ </Title>
+ <EmptyStateBody>
+ Exception Clauses not implemented yet
+ </EmptyStateBody>
+ </EmptyState>
+ </div>
+ </PageSection>
+ );
+ }
+}
diff --git a/karavan-designer/src/designer/field/DataFormatField.tsx
b/karavan-designer/src/designer/field/DataFormatField.tsx
index 0250ed2..78d4487 100644
--- a/karavan-designer/src/designer/field/DataFormatField.tsx
+++ b/karavan-designer/src/designer/field/DataFormatField.tsx
@@ -99,7 +99,6 @@ export class DataFormatField extends React.Component<Props,
State> {
const s = <SelectOption key={lang[0]} value={lang[0]}
description={lang[2]}/>;
selectOptions.push(s);
})
- console.log(properties)
return (
<div>
<FormGroup label={"Data Format"} key={"dataFormat"}
fieldId={"dataFormat"}>
diff --git a/karavan-designer/src/designer/field/DslPropertyField.tsx
b/karavan-designer/src/designer/field/DslPropertyField.tsx
index fa79cc4..820d2b2 100644
--- a/karavan-designer/src/designer/field/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/field/DslPropertyField.tsx
@@ -33,7 +33,7 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import { PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import {ExpressionField} from "./ExpressionField";
-import {CamelUi} from "../CamelUi";
+import {CamelUi} from "../utils/CamelUi";
import {ComponentParameterField} from "./ComponentParameterField";
import {CamelElement, DataFormatDefinition} from
"karavan-core/lib/model/CamelDefinition";
import {KameletPropertyField} from "./KameletPropertyField";
diff --git a/karavan-designer/src/designer/field/ExpressionField.tsx
b/karavan-designer/src/designer/field/ExpressionField.tsx
index c90f1e7..1b23db8 100644
--- a/karavan-designer/src/designer/field/ExpressionField.tsx
+++ b/karavan-designer/src/designer/field/ExpressionField.tsx
@@ -31,7 +31,7 @@ import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt"
import {CamelElement, ExpressionDefinition} from
"karavan-core/lib/model/CamelDefinition";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {DslPropertyField} from "./DslPropertyField";
-import {CamelUi} from "../CamelUi";
+import {CamelUi} from "../utils/CamelUi";
interface Props {
property: PropertyMeta,
diff --git a/karavan-designer/src/designer/karavan.css
b/karavan-designer/src/designer/karavan.css
index 578ccc5..4a20c73 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -171,10 +171,18 @@
user-select: none;
}
-/*DSL*/
-.karavan .dsl-page {
+.karavan .page {
height: 100%;
+ width: 100%;
overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+/*DSL*/
+.karavan .dsl-page {
+ flex: 1;
+ overflow: auto;
}
.karavan .dsl-page .dsl-page-columns {
@@ -193,14 +201,25 @@
flex-direction: row;
}
+.karavan .main-tabs .top-menu-item .count {
+ background: var(--pf-global--active-color--100);
+ /*color: white;*/
+ height: fit-content;
+ margin-top: auto;
+ margin-bottom: auto;
+}
+
.karavan .main-tabs .pf-c-tabs__link .pf-c-tabs__item-icon {
height: 24px;
- margin-right: 10px
+ margin-right: 0;
}
.karavan .main-tabs .pf-c-tabs__item-text {
font-size: 14px;
font-weight: bold;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-right: 6px;
}
.karavan .main-tabs .pf-c-tabs__item.pf-m-current {
@@ -208,7 +227,7 @@
}
/*Properties*/
-.karavan .dsl-page .properties {
+.karavan .properties {
border: 1px solid #eee;
padding: 10px 10px 10px 10px;
font-size: 13px;
@@ -221,87 +240,87 @@
justify-content: space-between;
}
-.karavan .dsl-page .properties .headers {
+.karavan .properties .headers {
grid-row-gap: 10px;
row-gap: 10px;
display: contents;
}
-.karavan .dsl-page .properties .footer {
+.karavan .properties .footer {
height: 100%;
display: contents;
}
-.karavan .dsl-page .properties .pf-c-form {
+.karavan .properties .pf-c-form {
row-gap: 10px;
}
-.karavan .dsl-page .properties .pf-c-form__group-label {
+.karavan .properties .pf-c-form__group-label {
padding-bottom: 3px;
display: flex;
justify-content: space-between;
}
-.karavan .dsl-page .properties .pf-c-form__label {
+.karavan .properties .pf-c-form__label {
font-size: 13px;
}
-.karavan .dsl-page .properties .text-field {
+.karavan .properties .text-field {
font-size: 13px;
height: auto;
}
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__text {
+.karavan .properties .input-group .pf-c-text-input-group__text {
width: 100%;
}
-.karavan .dsl-page .properties .input-group .pf-c-chip-group,
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__main,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group
.pf-c-chip-group__list,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group
.pf-c-chip-group__list .pf-c-chip-group__list-item,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group
.pf-c-chip-group__main {
+.karavan .properties .input-group .pf-c-chip-group,
+.karavan .properties .input-group .pf-c-text-input-group__main,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__list,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__list
.pf-c-chip-group__list-item,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__main {
display:block;
}
-.karavan .dsl-page .properties .input-group .pf-c-chip-group {
+.karavan .properties .input-group .pf-c-chip-group {
margin-left: 0;
}
-.karavan .dsl-page .properties .input-group .pf-c-chip-group .pf-c-chip
.pf-c-chip__text{
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip .pf-c-chip__text{
max-width: inherit;
}
-.karavan .dsl-page .properties .input-group .pf-c-chip-group .pf-c-chip {
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip {
width: 100%;
}
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__utilities {
+.karavan .properties .input-group .pf-c-text-input-group__utilities {
align-items: end;
}
-.karavan .dsl-page .properties .chip .pf-c-button{
+.karavan .properties .chip .pf-c-button{
position:absolute;
right: 0;
}
-.karavan .dsl-page .properties .expression-title {
+.karavan .properties .expression-title {
font-size: 17px;
font-weught: bold;
}
-.karavan .dsl-page .properties .text-area {
+.karavan .properties .text-area {
font-size: 13px;
}
-.karavan .dsl-page .properties .pf-c-select__menu-search {
+.karavan .properties .pf-c-select__menu-search {
padding: 0px 6px 6px 6px;
}
-.karavan .dsl-page .properties .pf-c-select__toggle-typeahead {
+.karavan .properties .pf-c-select__toggle-typeahead {
font-size: 13px;
height: auto;
}
-.karavan .dsl-page .properties .pf-c-select__menu-item {
+.karavan .properties .pf-c-select__menu-item {
width: 280px;
font-size: 15px;
/*white-space: nowrap;*/
@@ -310,16 +329,16 @@
/*line-height: 12px;*/
}
-.karavan .dsl-page .properties .number {
+.karavan .properties .number {
display: flex;
justify-content: space-between;
}
-.karavan .dsl-page .properties .number .number-property {
+.karavan .properties .number .number-property {
width: 100%;
}
-.karavan .dsl-page .properties .number .clear-button {
+.karavan .properties .number .clear-button {
color: #b1b1b7;
--pf-c-button--BorderRadius: var(--pf-c-button--m-control--BorderRadius);
--pf-c-button--disabled--BackgroundColor:
var(--pf-c-button--m-control--disabled--BackgroundColor);
@@ -331,11 +350,11 @@
padding-right: 5px;
}
-.karavan .dsl-page .properties .help-button {
+.karavan .properties .help-button {
font-size: 12px;
}
-.karavan .dsl-page .properties .component-selector {
+.karavan .properties .component-selector {
border-width: var(--pf-global--BorderWidth--sm);
border-top-color: var(--pf-global--BorderColor--300);
border-right-color: var(--pf-global--BorderColor--300);
@@ -344,38 +363,38 @@
border-style: solid;
}
-.karavan .dsl-page .properties .expression,
-.karavan .dsl-page .properties .object,
-.karavan .dsl-page .properties .dataformat,
-.karavan .dsl-page .properties .parameters {
+.karavan .properties .expression,
+.karavan .properties .object,
+.karavan .properties .dataformat,
+.karavan .properties .parameters {
padding-top: 6px;
padding-left: 16px;
row-gap: 6px;
display: grid;
}
-.karavan .dsl-page .properties .expression .pf-c-form__group-label,
-.karavan .dsl-page .properties .object .pf-c-form__group-label,
-.karavan .dsl-page .properties .dataformat .pf-c-form__group-label,
-.karavan .dsl-page .properties .parameters .pf-c-form__group-label {
+.karavan .properties .expression .pf-c-form__group-label,
+.karavan .properties .object .pf-c-form__group-label,
+.karavan .properties .dataformat .pf-c-form__group-label,
+.karavan .properties .parameters .pf-c-form__group-label {
font-weight: 100;
}
-.karavan .dsl-page .properties .expression .pf-c-form__group,
-.karavan .dsl-page .properties .object .pf-c-form__group,
-.karavan .dsl-page .properties .dataformat .pf-c-form__group,
-.karavan .dsl-page .properties .parameters .pf-c-form__group {
+.karavan .properties .expression .pf-c-form__group,
+.karavan .properties .object .pf-c-form__group,
+.karavan .properties .dataformat .pf-c-form__group,
+.karavan .properties .parameters .pf-c-form__group {
margin-bottom: 10px;
}
-.karavan .dsl-page .properties .expression .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .object .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .dataformat .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .parameters .pf-c-select__menu-wrapper{
+.karavan .properties .expression .pf-c-select__menu-wrapper,
+.karavan .properties .object .pf-c-select__menu-wrapper,
+.karavan .properties .dataformat .pf-c-select__menu-wrapper,
+.karavan .properties .parameters .pf-c-select__menu-wrapper{
width: 350px;
}
-.karavan .dsl-page .properties .add-button {
+.karavan .properties .add-button {
font-size: 15px;
height: 15px;
line-height: 1;
@@ -386,6 +405,10 @@
color: #fb8824;
}
+.karavan .properties .add-button svg {
+ margin-right: 6px;
+}
+
/*Graph*/
.karavan .dsl-page .graph {
@@ -500,13 +523,13 @@
position: absolute;
top: 4px;
right: 4px;
- font-size: 13px;
+ font-size: 14px;
line-height: 1;
border: 0;
padding: 0;
margin: 0;
background: transparent;
- color: #b1b1b7;
+ color: #909090;
visibility: hidden;
}
@@ -514,13 +537,13 @@
.element-builder .header .delete-button {
position: absolute;
top: 0px;
- font-size: 13px;
+ font-size: 14px;
line-height: 1;
border: 0;
padding: 0;
margin: 0 0 0 10px;
background: transparent;
- color: #b1b1b7;
+ color: #909090;
visibility: hidden;
}
@@ -531,7 +554,7 @@
}
.modal-delete {
- width: 350px;
+ width: 350px !important;
}
.step-element .header {
@@ -775,4 +798,126 @@
.karavan .pf-c-select__menu-wrapper:hover, .karavan
.pf-c-select__menu-item:hover {
background-color: #fca338;
+}
+
+/*Beans*/
+.karavan .beans-page {
+ flex: 1 1;
+ overflow: auto;
+}
+.karavan .beans-page-columns {
+ height: 100%;
+ background: #fafafa;
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .beans-panel {
+ padding: 16px;
+ display: block;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+ position: relative;
+ overflow-y: auto;
+}
+.karavan .beans-page .add-button-div {
+ width: 100%;
+ margin-top: 16px;
+ display: flex;
+}
+
+.karavan .beans-page .add-bean-button {
+ margin: auto;
+}
+
+.karavan .beans-page .bean-card-selected {
+ border-color: rgb(48, 50, 132);
+ background-color: rgb(171, 172, 224, 0.1);
+}
+
+.karavan .beans-page .bean-card-unselected {
+ border-color: #fb8824;
+ background-color: transparent;
+}
+
+.karavan .beans-page .bean-card,
+.karavan .beans-page .bean-card:hover {
+ border-radius: 20px;
+ border-width: 1px;
+ border-style: dotted;
+ box-shadow: none;
+}
+
+.karavan .beans-page .bean-card .pf-c-card__header {
+ padding-right: 6px;
+ word-wrap:anywhere;
+}
+
+.karavan .beans-page .bean-card .pf-c-card__body {
+ word-wrap:anywhere;
+}
+
+.karavan .beans-page .bean-card .icon {
+ height: 24px;
+}
+
+.karavan .beans-page .bean-card .delete-button {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ font-size: 14px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ background: transparent;
+ color: #909090;
+ visibility: hidden;
+}
+
+.karavan .beans-page .bean-card:hover .delete-button {
+ visibility: visible;
+}
+
+.karavan .beans-page .properties .bean-properties .pf-c-form__group-control {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.karavan .beans-page .properties .bean-property {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+}
+
+.karavan .beans-page .properties .bean-property .delete-button {
+ padding: 3px;
+ color: #b1b1b7;
+ font-size: 13px;
+}
+
+.karavan .templates-page,
+.karavan .exception-page,
+.karavan .error-page,
+.karavan .rest-page {
+ flex: 1;
+ overflow: auto;
+}
+
+.karavan .templates-page-columns,
+.karavan .exception-page-columns,
+.karavan .error-page-columns,
+.karavan .rest-page-columns {
+ height: 100%;
+ background: #fafafa;
+}
+
+.karavan .templates-page-columns .pf-c-empty-state,
+.karavan .exception-page-columns .pf-c-empty-state,
+.karavan .error-page-columns .pf-c-empty-state,
+.karavan .rest-page-columns .pf-c-empty-state {
+ margin: auto;
+ height: 100%;
}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx
b/karavan-designer/src/designer/rest/RestDesigner.tsx
new file mode 100644
index 0000000..036b3e7
--- /dev/null
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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 React from 'react';
+import {
+ Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+ PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+ onSave?: (integration: Integration) => void
+ integration: Integration
+ borderColor: string
+ borderColorSelected: string
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ selectedStep?: CamelElement
+ key: string
+}
+
+export class RestDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ key: "",
+ };
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration);
+ }
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, key: Math.random().toString()});
+ }
+
+ render() {
+ return (
+ <PageSection className="rest-page" isFilled padding={{default:
'noPadding'}}>
+ <div className="rest-page-columns">
+ <EmptyState>
+ <EmptyStateIcon icon={CubesIcon} />
+ <Title headingLevel="h4" size="lg">
+ REST
+ </Title>
+ <EmptyStateBody>
+ Rest DSL not implemented yet
+ </EmptyStateBody>
+ </EmptyState>
+ </div>
+ </PageSection>
+ );
+ }
+}
diff --git a/karavan-designer/src/designer/DslConnections.tsx
b/karavan-designer/src/designer/route/DslConnections.tsx
similarity index 98%
rename from karavan-designer/src/designer/DslConnections.tsx
rename to karavan-designer/src/designer/route/DslConnections.tsx
index c5dd52b..db82cc3 100644
--- a/karavan-designer/src/designer/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -15,10 +15,10 @@
* limitations under the License.
*/
import React from 'react';
-import './karavan.css';
+import '../karavan.css';
import {CamelElement, Integration} from
"karavan-core/lib/model/CamelDefinition";
-import {DslPosition, EventBus} from "./EventBus";
-import {CamelUi} from "./CamelUi";
+import {DslPosition, EventBus} from "../utils/EventBus";
+import {CamelUi} from "../utils/CamelUi";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {Subscription} from "rxjs";
diff --git a/karavan-designer/src/designer/DslElement.tsx
b/karavan-designer/src/designer/route/DslElement.tsx
similarity index 99%
rename from karavan-designer/src/designer/DslElement.tsx
rename to karavan-designer/src/designer/route/DslElement.tsx
index cda6016..f214a24 100644
--- a/karavan-designer/src/designer/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -18,12 +18,12 @@ import React, {CSSProperties} from 'react';
import {
Text, Tooltip,
} from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
import DeleteIcon from
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
import {CamelElement} from "karavan-core/lib/model/CamelDefinition";
-import {CamelUi} from "./CamelUi";
-import {EventBus} from "./EventBus";
+import {CamelUi} from "../utils/CamelUi";
+import {EventBus} from "../utils/EventBus";
import {ChildElement, CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import ReactDOM from "react-dom";
diff --git a/karavan-designer/src/designer/DslProperties.tsx
b/karavan-designer/src/designer/route/DslProperties.tsx
similarity index 84%
rename from karavan-designer/src/designer/DslProperties.tsx
rename to karavan-designer/src/designer/route/DslProperties.tsx
index e67305a..86f4a1e 100644
--- a/karavan-designer/src/designer/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -23,10 +23,10 @@ import {
Title,
TextVariants,
} from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
import "@patternfly/patternfly/patternfly.css";
-import {DataFormatField} from "./field/DataFormatField";
-import {DslPropertyField} from "./field/DslPropertyField";
+import {DataFormatField} from "../field/DataFormatField";
+import {DslPropertyField} from "../field/DslPropertyField";
import {
CamelElement,
Integration,
@@ -36,8 +36,9 @@ import {
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {CamelUi} from "./CamelUi";
+import {CamelUi} from "../utils/CamelUi";
import {CamelMetadataApi, PropertyMeta} from
"karavan-core/lib/model/CamelMetadata";
+import {IntegrationHeader} from "../utils/KaravanComponents";
interface Props {
integration: Integration,
@@ -47,7 +48,6 @@ interface Props {
}
interface State {
- integration: Integration,
step?: CamelElement,
selectStatus: Map<string, boolean>
}
@@ -56,7 +56,6 @@ export class DslProperties extends React.Component<Props,
State> {
public state: State = {
step: this.props.step,
- integration: this.props.integration,
selectStatus: new Map<string, boolean>(),
};
@@ -113,24 +112,6 @@ export class DslProperties extends React.Component<Props,
State> {
});
}
- getIntegrationHeader = (): JSX.Element => {
- return (
- <div className="headers">
- <Title headingLevel="h1" size="md">Integration</Title>
- <FormGroup label="Title" fieldId="title" isRequired>
- <TextInput className="text-field" type="text" id="title"
name="title" isReadOnly
- value={
-
CamelUi.titleFromName(this.state.integration.metadata.name)
- }/>
- </FormGroup>
- <FormGroup label="Name" fieldId="name" isRequired>
- <TextInput className="text-field" type="text" id="name"
name="name" isReadOnly
- value={this.state.integration.metadata.name}/>
- </FormGroup>
- </div>
- )
- }
-
getComponentHeader = (): JSX.Element => {
const title = this.state.step && CamelUi.getTitle(this.state.step)
const kamelet = this.state.step && CamelUi.getKamelet(this.state.step)
@@ -155,7 +136,7 @@ export class DslProperties extends React.Component<Props,
State> {
return (
<div key={this.state.step ? this.state.step.uuid : 'integration'}
className='properties'>
<Form autoComplete="off" onSubmit={event =>
event.preventDefault()}>
- {this.state.step === undefined &&
this.getIntegrationHeader()}
+ {this.state.step === undefined && <IntegrationHeader
integration={this.props.integration}/>}
{this.state.step && this.getComponentHeader()}
{this.state.step && !['MarshalDefinition',
'UnmarshalDefinition'].includes(this.state.step.dslName) &&
this.getProps().map((property: PropertyMeta) =>
<DslPropertyField key={property.name}
diff --git a/karavan-designer/src/designer/DslSelector.tsx
b/karavan-designer/src/designer/route/DslSelector.tsx
similarity index 97%
rename from karavan-designer/src/designer/DslSelector.tsx
rename to karavan-designer/src/designer/route/DslSelector.tsx
index 7636240..04c9e3e 100644
--- a/karavan-designer/src/designer/DslSelector.tsx
+++ b/karavan-designer/src/designer/route/DslSelector.tsx
@@ -21,9 +21,9 @@ import {
Tab, Tabs, TabTitleText,
Text, TextInput,
} from '@patternfly/react-core';
-import './karavan.css';
-import {CamelUi} from "./CamelUi";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import '../karavan.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
interface Props {
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx
b/karavan-designer/src/designer/route/RouteDesigner.tsx
similarity index 56%
copy from karavan-designer/src/designer/KaravanDesigner.tsx
copy to karavan-designer/src/designer/route/RouteDesigner.tsx
index d132ba2..0f16413 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -17,26 +17,25 @@
import React from 'react';
import {
Button, Modal,
- PageSection, Tab, Tabs, TabTitleIcon, TabTitleText, Tooltip,
+ PageSection
} from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import {DslMetaModel} from "../utils/DslMetaModel";
import {DslProperties} from "./DslProperties";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {CamelElement, FromDefinition, Integration} from
"karavan-core/lib/model/CamelDefinition";
-import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
import {DslConnections} from "./DslConnections";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {DslElement} from "./DslElement";
-import {EventBus} from "./EventBus";
+import {EventBus} from "../utils/EventBus";
+import {CamelUi} from "../utils/CamelUi";
interface Props {
- onSave?: (filename: string, yaml: string) => void
- filename: string
- yaml: string
+ onSave?: (integration: Integration) => void
+ integration: Integration
borderColor: string
borderColorSelected: string
dark: boolean
@@ -57,12 +56,10 @@ interface State {
top: number
}
-export class KaravanDesigner extends React.Component<Props, State> {
+export class RouteDesigner extends React.Component<Props, State> {
public state: State = {
- integration: this.props.yaml
- ? CamelDefinitionYaml.yamlToIntegration(this.props.filename,
this.props.yaml)
- : Integration.createNew(this.props.filename),
+ integration: this.props.integration,
showSelector: false,
showDeleteConfirmation: false,
parentId: '',
@@ -88,7 +85,7 @@ export class KaravanDesigner extends React.Component<Props,
State> {
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
if (prevState.key !== this.state.key) {
- this.props.onSave?.call(this,
this.state.integration.metadata.name, this.getCode(this.state.integration));
+ this.props.onSave?.call(this, this.state.integration);
}
}
@@ -99,11 +96,6 @@ export class KaravanDesigner extends React.Component<Props,
State> {
}
};
- getCode = (integration: Integration): string => {
- const clone = CamelUtil.cloneIntegration(integration);
- return CamelDefinitionYaml.integrationToYaml(clone);
- }
-
onPropertyUpdate = (element: CamelElement, updatedUuid: string) => {
const clone = CamelUtil.cloneIntegration(this.state.integration);
const i = CamelDefinitionApiExt.updateIntegration(clone, element,
updatedUuid);
@@ -240,13 +232,14 @@ export class KaravanDesigner extends
React.Component<Props, State> {
}
getGraph() {
+ const integrations = CamelUi.getRoutes(this.state.integration);
return (
<div className="graph">
<DslConnections height={this.state.height}
width={this.state.width} top={this.state.top}
integration={this.state.integration}/>
<div className="flows" data-click="FLOWS" onClick={event =>
this.unselectElement(event)}
ref={el => this.onResizePage(el)}>
- {this.state.integration.spec.flows?.map((from: any, index:
number) => (
- <DslElement key={from.uuid + this.state.key}
+ {integrations?.map((route: any, index: number) => (
+ <DslElement key={route.uuid + this.state.key}
openSelector={this.openSelector}
deleteElement={this.showDeleteConfirmation}
selectElement={this.selectElement}
@@ -256,12 +249,12 @@ export class KaravanDesigner extends
React.Component<Props, State> {
borderColorSelected={this.props.borderColorSelected}
inSteps={false}
position={index}
- step={from}
+ step={route}
parent={undefined}/>
))}
<div className="add-flow">
<Button
- variant={this.state.integration.spec.flows?.length
=== 0 ? "primary" : "secondary"}
+ variant={integrations.length === 0 ? "primary" :
"secondary"}
data-click="ADD_ROUTE"
icon={<PlusIcon/>}
onClick={e => this.openSelector(undefined,
undefined)}>Add new route
@@ -271,101 +264,11 @@ export class KaravanDesigner extends
React.Component<Props, State> {
</div>)
}
- getTab(title: string, tooltip: string, icon: string) {
- return (
- <Tooltip position={"bottom"}
- content={<div>{tooltip}</div>}>
- <div className="top-menu-item">
- <TabTitleIcon>{this.getIcon(icon)}</TabTitleIcon>
- <TabTitleText>{title}</TabTitleText>
- </div>
- </Tooltip>
-
- )
- }
-
- getIcon(icon: string) {
- if (icon === 'routes') return (
- <svg className="top-icon" width="32px" height="32px" viewBox="0 0
32 32" id="icon">
- <defs>
- <style>{".cls-1{fill:none;}"}</style>
- </defs>
- <path
d="M29,10H24v2h5v6H22v2h3v2.142a4,4,0,1,0,2,0V20h2a2.0027,2.0027,0,0,0,2-2V12A2.0023,2.0023,0,0,0,29,10ZM28,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,28,26Z"/>
- <path
d="M19,6H14V8h5v6H12v2h3v6.142a4,4,0,1,0,2,0V16h2a2.0023,2.0023,0,0,0,2-2V8A2.0023,2.0023,0,0,0,19,6ZM18,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,18,26Z"/>
- <path
-
d="M9,2H3A2.002,2.002,0,0,0,1,4v6a2.002,2.002,0,0,0,2,2H5V22.142a4,4,0,1,0,2,0V12H9a2.002,2.002,0,0,0,2-2V4A2.002,2.002,0,0,0,9,2ZM8,26a2,2,0,1,1-2-2A2.0023,2.0023,0,0,1,8,26ZM3,10V4H9l.0015,6Z"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32"/>
- </svg>)
- if (icon === 'rest') return (
- <svg className="top-icon" viewBox="0 0 32 32">
- <g className="layer">
- <title>Layer 1</title>
- <path
- d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0
0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0
-13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0
0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0
0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
- id="svg_1"/>
- <path
- d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0
0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0
-1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0
-1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0
-0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0
0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0
1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0
1.7529,-0.7319l1.49,1.49l1.414,-1 [...]
- id="svg_2" transform="rotate(25 15.9724 21.2664)"
xmlns="http://www.w3.org/2000/svg"/>
- </g>
- </svg>
- )
- if (icon === 'beans') return (
- <svg className="top-icon" viewBox="0 0 536.243 536.242" >
- <g>
- <path
d="M471.053,197.07c-94.2-101.601-284-183.601-423.5-154.2c-9.2,1.8-12.9,9.2-12.2,16.5c-86.9,47.7,9.2,213,45.9,261.3
-
c72.2,96.1,200.701,203.2,329.901,173.8c60-13.5,103.399-69.8,120-126.1C550.053,304.77,513.253,242.37,471.053,197.07z
-
M393.353,465.17c-102.199,23.3-210.5-75.9-271.7-145c-61.2-70.4-108.3-155.4-71-243c83.8,151.8,253.4,269.3,414.9,321.899
-
c19.601,6.101,28.2-24.5,8.601-31.199C318.753,315.27,166.353,209.97,73.953,72.27c111.4-13.5,238.701,45.9,326.201,107.101
-
c50.199,35.5,98.5,87.5,102.8,151.8C505.954,394.17,451.454,451.67,393.353,465.17z"/>
- </g>
- </svg>
- )
- if (icon === 'error') return (
- <svg className="top-icon" width="36px" height="36px" viewBox="0 0
36 36" version="1.1" preserveAspectRatio="xMidYMid meet">
- <circle className="clr-i-outline clr-i-outline-path-1" cx="18"
cy="26.06" r="1.33"/>
- <path className="clr-i-outline clr-i-outline-path-2"
d="M18,22.61a1,1,0,0,1-1-1v-12a1,1,0,1,1,2,0v12A1,1,0,0,1,18,22.61Z"/>
- <path className="clr-i-outline clr-i-outline-path-3"
d="M18,34A16,16,0,1,1,34,18,16,16,0,0,1,18,34ZM18,4A14,14,0,1,0,32,18,14,14,0,0,0,18,4Z"/>
- <rect x="0" y="0" width="36" height="36" fillOpacity="0"/>
- </svg>)
- if (icon === 'exception') return (
- <svg className="top-icon" width="32px" height="32px" viewBox="0 0
32 32" id="icon">
- <defs>
- <style>{".cls-1{fill:none;}"}</style>
- </defs>
- <title>misuse--alt</title>
- <polygon points="21.41 23 16 17.591 10.59 23 9 21.41 14.409 16
9 10.591 10.591 9 16 14.409 21.409 9 23 10.591 17.591 16 23 21.41 21.41 23"/>
- <path
d="M16,4A12,12,0,1,1,4,16,12.0136,12.0136,0,0,1,16,4m0-2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Z"
transform="translate(0)"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32"/>
- </svg>)
- if (icon === 'template') return (
- <svg className="top-icon" width="32px" height="32px" viewBox="0 0
32 32" id="icon" xmlns="http://www.w3.org/2000/svg">
- <defs>
- <style>{".cls-1{fill:none;}"}</style>
- </defs>
- <title>code</title>
- <polygon points="31 16 24 23 22.59 21.59 28.17 16 22.59 10.41
24 9 31 16"/>
- <polygon points="1 16 8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1
16"/>
- <rect x="5.91" y="15" width="20.17" height="2"
transform="translate(-3.6 27.31) rotate(-75)"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32" transform="translate(0
32) rotate(-90)"/>
- </svg>)
- }
-
render() {
return (
<PageSection className="dsl-page" isFilled padding={{default:
'noPadding'}}>
<div className="dsl-page-columns">
- <div style={{width: "100%"}}>
- <Tabs isFilled className="main-tabs" activeKey={0}
onSelect={event => {
- }} style={{width: "100%"}}>
- <Tab eventKey={0} title={this.getTab("Routes",
"Integration flows", "routes")}></Tab>
- <Tab eventKey={1} title={this.getTab("REST", "REST
services","rest")}></Tab>
- <Tab eventKey={2} title={this.getTab("Beans",
"Beans Configuration","beans")}></Tab>
- <Tab eventKey={3}
title={this.getTab("Error","Error Handler configuration", "error")}></Tab>
- <Tab eventKey={4}
title={this.getTab("Exceptions","Exception Clauses per type",
"exception")}></Tab>
- <Tab eventKey={5} title={this.getTab("Templates",
"Route Templates","template")}></Tab>
- </Tabs>
- {this.getGraph()}
- </div>
+ {this.getGraph()}
<DslProperties
integration={this.state.integration}
step={this.state.selectedStep}
diff --git a/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
b/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
new file mode 100644
index 0000000..c49ed10
--- /dev/null
+++ b/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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 React from 'react';
+import {
+ Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+ PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+ onSave?: (integration: Integration) => void
+ integration: Integration
+ borderColor: string
+ borderColorSelected: string
+ dark: boolean
+}
+
+interface State {
+ integration: Integration
+ selectedStep?: CamelElement
+ key: string
+}
+
+export class TemplatesDesigner extends React.Component<Props, State> {
+
+ public state: State = {
+ integration: this.props.integration,
+ key: "",
+ };
+
+ componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
+ if (prevState.key !== this.state.key) {
+ this.props.onSave?.call(this, this.state.integration);
+ }
+ }
+
+ onIntegrationUpdate = (i: Integration) => {
+ this.setState({integration: i, key: Math.random().toString()});
+ }
+
+ render() {
+ return (
+ <PageSection className="templates-page" isFilled
padding={{default: 'noPadding'}}>
+ <div className="templates-page-columns">
+ <EmptyState>
+ <EmptyStateIcon icon={CubesIcon} />
+ <Title headingLevel="h4" size="lg">
+ Templates
+ </Title>
+ <EmptyStateBody>
+ Templates not implemented yet
+ </EmptyStateBody>
+ </EmptyState>
+ </div>
+ </PageSection>
+ );
+ }
+}
diff --git a/karavan-designer/src/designer/CamelUi.ts
b/karavan-designer/src/designer/utils/CamelUi.ts
similarity index 75%
rename from karavan-designer/src/designer/CamelUi.ts
rename to karavan-designer/src/designer/utils/CamelUi.ts
index de294da..5fdbd6d 100644
--- a/karavan-designer/src/designer/CamelUi.ts
+++ b/karavan-designer/src/designer/utils/CamelUi.ts
@@ -16,13 +16,14 @@
*/
import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import {DslMetaModel} from "./DslMetaModel";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
import {CamelMetadataApi} from "karavan-core/lib/model/CamelMetadata";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
import {CamelDefinitionApiExt} from
"karavan-core/lib/api/CamelDefinitionApiExt";
import {CamelElement, KameletDefinition, RouteDefinition} from
"karavan-core/lib/model/CamelDefinition";
+import {Bean, Beans, Integration} from
"karavan-core/src/core/model/CamelDefinition";
const StepElements: string[] = [
"AggregateDefinition",
@@ -269,9 +270,9 @@ export class CamelUi {
case "WhenDefinition":
return "data:image/svg+xml,%0A%3Csvg width='32px'
height='32px' viewBox='0 0 32 32' id='icon'
xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:none;%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Eidea%3C/title%3E%3Crect
x='11' y='24' width='10' height='2'/%3E%3Crect x='13' y='28' width='6'
height='2'/%3E%3Cpath
d='M16,2A10,10,0,0,0,6,12a9.19,9.19,0,0,0,3.46,7.62c1,.93,1.54,1.46,1.54,2.38h2c0-1.84-1.11-2.87-2.19-3.86A7.2,7.2,0,0,1,8,12a8,8,0,0,1,16,0,7.2,7.2,0,
[...]
case "AggregateDefinition":
- return "data:image/svg+xml,%3Csvg version='1.1' id='Layer_1'
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'
x='0px' y='0px' width='512px' height='640px' viewBox='0 0 512 640'
enable-background='new 0 0 512 640' xml:space='preserve'%3E%3Cimage id='image0'
width='512' height='640' x='0' y='0'
href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKACAAAAADPo5/+AAAABGdBTUEAALGPC/xhBQAAACBjSFJN%0AAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3Ccul
[...]
+ return "data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'
version='1.1' id='icon' x='0px' y='0px' width='32px' height='32px' viewBox='0 0
32 32' style='enable-background:new 0 0 32 32;' xml:space='preserve'%3E%3Cstyle
type='text/css'%3E .st0%7Bfill:none;%7D%0A%3C/style%3E%3Cpath
d='M16,4c6.6,0,12,5.4,12,12s-5.4,12-12,12S4,22.6,4,16S9.4,4,16,4
M16,2C8.3,2,2,8.3,2,16s6.3,14,14,14s14-6.3,14-14 S23.7,2,16,2z'/%3E%3Cpolygon
[...]
case "SplitDefinition":
- return "data:image/svg+xml,%3Csvg version='1.1' id='Layer_1'
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'
x='0px' y='0px' width='512px' height='640px' viewBox='0 0 512 640'
enable-background='new 0 0 512 640' xml:space='preserve'%3E%3Cimage id='image0'
width='512' height='640' x='0' y='0'
href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKACAAAAADPo5/+AAAABGdBTUEAALGPC/xhBQAAACBjSFJN%0AAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3Ccul
[...]
+ return "data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg' width='32px' height='32px' viewBox='0 0 32
32' id='icon'%3E%3Cdefs%3E%3Cstyle%3E .cls-1 %7B fill: none; %7D
%3C/style%3E%3C/defs%3E%3Ctitle%3Esplit%3C/title%3E%3Crect x='15' y='20'
width='2' height='4'/%3E%3Crect x='15' y='14' width='2' height='4'/%3E%3Crect
x='15' y='8' width='2' height='4'/%3E%3Cpath
d='M28,16A12.01,12.01,0,0,0,17,4.0508V2H15V4.0508a11.99,11.99,0,0,0,0,23.8984V30h2V27.9492A12.01,12.01,
[...]
case "SortDefinition":
return "data:image/svg+xml,%0A%3Csvg aria-hidden='true'
focusable='false' data-prefix='fas' data-icon='sort-amount-down'
class='svg-inline--fa fa-sort-amount-down fa-w-16' role='img'
xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath
fill='currentColor' d='M304 416h-64a16 16 0 0 0-16 16v32a16 16 0 0 0 16
16h64a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm-128-64h-48V48a16 16 0 0
0-16-16H80a16 16 0 0 0-16 16v304H16c-14.19 0-21.37 17.24-11.29 27.31l80 96a16
16 0 [...]
case "ResequenceDefinition":
@@ -352,13 +353,30 @@ export class CamelUi {
}
}
- static getIconForComponentLabel = (dslName: string): string => {
- switch (dslName) {
- case "messaging":
- return "data:image/svg+xml,%3Csvg aria-hidden='true'
focusable='false' data-prefix='fas' data-icon='filter' class='svg-inline--fa
fa-filter fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0
512 512'%3E%3Cpath fill='currentColor' d='M487.976 0H24.028C2.71 0-8.047 25.866
7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02
518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0
487.976 0z'%3E%3C/path%3E%3C/svg%3E";
- default:
- return defaultIcon;
+ static getFlowCounts = (i: Integration): Map<string, number> => {
+ const result = new Map<string, number>();
+ result.set('routes', i.spec.flows?.filter((e: any) => e.dslName ===
'RouteDefinition').length || 0);
+ const beans = i.spec.flows?.filter((e: any) => e.dslName === 'Beans');
+ if (beans && beans.length > 0 && beans[0].beans){
+ result.set('beans', Array.from(beans[0].beans).length);
+ }
+ return result;
+ }
+
+ static getRoutes = (integration: Integration): CamelElement[] => {
+ const result: CamelElement[] = [];
+ integration.spec.flows?.filter((e: any) => e.dslName ===
'RouteDefinition')
+ .forEach((f: any) => result.push(f));
+ return result;
+ }
+
+ static getBeans = (integration: Integration): Bean[] => {
+ const result: Bean[] = [];
+ const beans = integration.spec.flows?.filter((e: any) => e.dslName ===
'Beans');
+ if (beans && beans.length > 0 && beans[0].beans) {
+ result.push(...beans[0].beans);
}
+ return result;
}
}
diff --git a/karavan-core/src/core/model/DslMetaModel.ts
b/karavan-designer/src/designer/utils/DslMetaModel.ts
similarity index 100%
rename from karavan-core/src/core/model/DslMetaModel.ts
rename to karavan-designer/src/designer/utils/DslMetaModel.ts
diff --git a/karavan-designer/src/designer/EventBus.ts
b/karavan-designer/src/designer/utils/EventBus.ts
similarity index 100%
rename from karavan-designer/src/designer/EventBus.ts
rename to karavan-designer/src/designer/utils/EventBus.ts
diff --git a/karavan-designer/src/designer/utils/KaravanComponents.tsx
b/karavan-designer/src/designer/utils/KaravanComponents.tsx
new file mode 100644
index 0000000..c8ad23b
--- /dev/null
+++ b/karavan-designer/src/designer/utils/KaravanComponents.tsx
@@ -0,0 +1,45 @@
+/*
+ * 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 React from 'react';
+import {FormGroup, TextInput, Title} from "@patternfly/react-core";
+import {CamelUi} from "./CamelUi";
+import {Integration} from "karavan-core/lib/model/CamelDefinition";
+
+interface Props {
+ integration: Integration,
+}
+
+export class IntegrationHeader extends React.Component<Props> {
+
+ render() {
+ return (
+ <div className="headers">
+ <Title headingLevel="h1" size="md">Integration</Title>
+ <FormGroup label="Title" fieldId="title" isRequired>
+ <TextInput className="text-field" type="text" id="title"
name="title" isReadOnly
+ value={
+
CamelUi.titleFromName(this.props.integration.metadata.name)
+ }/>
+ </FormGroup>
+ <FormGroup label="Name" fieldId="name" isRequired>
+ <TextInput className="text-field" type="text" id="name"
name="name" isReadOnly
+ value={this.props.integration.metadata.name}/>
+ </FormGroup>
+ </div>
+ )
+ }
+}
diff --git a/karavan-designer/src/designer/utils/KaravanIcons.tsx
b/karavan-designer/src/designer/utils/KaravanIcons.tsx
new file mode 100644
index 0000000..f2866a1
--- /dev/null
+++ b/karavan-designer/src/designer/utils/KaravanIcons.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 React from 'react';
+
+
+export class BeanIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32
32">
+ <defs>
+ <style>{".cls-1 {fill: none;}"}</style>
+ </defs>
+ <path
+
d="M28.5039,8.1362l-12-7a1,1,0,0,0-1.0078,0l-12,7A1,1,0,0,0,3,9V23a1,1,0,0,0,.4961.8638l12,7a1,1,0,0,0,1.0078,0l12-7A1,1,0,0,0,29,23V9A1,1,0,0,0,28.5039,8.1362ZM16,3.1577,26.0156,9,16,14.8423,5.9844,9ZM5,10.7412l10,5.833V28.2588L5,22.4258ZM17,28.2588V16.5742l10-5.833V22.4258Z"/>
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32"/>
+ </svg>
+ )
+ }
+}
+
+export class ConceptIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32
32" >
+ <defs>
+ <style>{".cls-1 {fill: none;}"}</style>
+ </defs>
+ <title>concept</title>
+ <path
+
d="M20.8851,19.4711a5.9609,5.9609,0,0,0,0-6.9422L23,10.4141l1.293,1.2929a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414l-4-4a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414L21.5859,9l-2.1148,2.1149a5.9609,5.9609,0,0,0-6.9422,0L10,8.5859V2H2v8H8.5859l2.529,2.5289a5.9609,5.9609,0,0,0,0,6.9422L9,21.5859,7.707,20.293a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414l4,4a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414L10.4141,23l2.1148-2.1149a5.960
[...]
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent
Rectangle>" className="cls-1" width="32" height="32"/>
+ </svg>
+ )
+ }
+}
\ No newline at end of file
diff --git a/karavan-generator/pom.xml b/karavan-generator/pom.xml
index f286a49..8457c9a 100644
--- a/karavan-generator/pom.xml
+++ b/karavan-generator/pom.xml
@@ -19,7 +19,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.camel.karavan</groupId>
<artifactId>karavan-generator</artifactId>
- <version>0.0.11</version>
+ <version>0.0.12</version>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
diff --git a/karavan-generator/src/main/resources/CamelDefinition.header.ts
b/karavan-generator/src/main/resources/CamelDefinition.header.ts
index f43e85f..ebda5ea 100644
--- a/karavan-generator/src/main/resources/CamelDefinition.header.ts
+++ b/karavan-generator/src/main/resources/CamelDefinition.header.ts
@@ -53,13 +53,32 @@ export class CamelElement {
}
}
+export class Beans extends CamelElement {
+ beans: Bean[] = []
+
+ public constructor(init?: Partial<Beans>) {
+ super("Beans")
+ Object.assign(this, init);
+ }
+}
+
+export class Bean extends CamelElement {
+ name: string = ''
+ type: string = ''
+ properties: any
+
+ public constructor(init?: Partial<Bean>) {
+ super("Bean")
+ Object.assign(this, init);
+ }
+}
+
export class CamelElementMeta {
step?: CamelElement
parentUuid?: string
position: number = 0;
pathUuids: string [] = [];
-
constructor(step?: CamelElement, parentUuid?: string, position?: number,
pathUuids?: string []) {
this.step = step;
this.parentUuid = parentUuid;
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 660c0a3..6358f23 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -4,7 +4,7 @@
"displayName": "Camel Karavan Designer",
"icon": "icons/icon.png",
"description": "Integration Designer for Apache Camel",
- "version": "0.0.11",
+ "version": "0.0.12",
"license": "Apache-2.0",
"preview": true,
"bugs": {
@@ -151,13 +151,13 @@
}
},
"scripts": {
- "vscode:prepublish": "cp -r ../karavan-designer/src/designer . && yarn run
package",
- "compile": "cp -r ../karavan-designer/src/designer . && cross-env
NODE_ENV=development webpack --progress",
- "watch": "cp -r ../karavan-designer/src/designer . && cross-env
NODE_ENV=development webpack --progress --watch",
- "package": "cp -r ../karavan-designer/src/designer . && cross-env
NODE_ENV=production webpack --progress",
+ "vscode:prepublish": "cp -r ../karavan-designer/src/designer webview &&
yarn run package",
+ "compile": "cp -r ../karavan-designer/src/designer webview && cross-env
NODE_ENV=development webpack --progress",
+ "watch": "cp -r ../karavan-designer/src/designer webview && cross-env
NODE_ENV=development webpack --progress --watch",
+ "package": "cp -r ../karavan-designer/src/designer webview && cross-env
NODE_ENV=production webpack --progress",
"test-compile": "tsc -p ./",
"test-watch": "tsc -watch -p ./",
- "pretest": "cp -r ../karavan-designer/src/designer . && yarn run
test-compile && yarn run lint",
+ "pretest": "cp -r ../karavan-designer/src/designer webview && yarn run
test-compile && yarn run lint",
"lint": "eslint src webview --ext .ts,.tsx",
"lint:fix": "eslint --fix src webview --ext .ts,.tsx",
"test": "node ./out/test/runTest.js"
diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx
index 11d27c2..c833189 100644
--- a/karavan-vscode/webview/App.tsx
+++ b/karavan-vscode/webview/App.tsx
@@ -18,7 +18,7 @@ import * as React from "react";
import {
Page,
} from "@patternfly/react-core";
-import {KaravanDesigner} from "../designer/KaravanDesigner";
+import {KaravanDesigner} from "./designer/KaravanDesigner";
import vscode from "./vscode";
import {KameletApi} from "karavan-core/lib/api/KameletApi";
import { ComponentApi } from "karavan-core/lib/api/ComponentApi";
diff --git a/karavan-vscode/webview/index.css b/karavan-vscode/webview/index.css
index a062dba..689c7a2 100644
--- a/karavan-vscode/webview/index.css
+++ b/karavan-vscode/webview/index.css
@@ -17,6 +17,8 @@ body,
--pf-global--link--Color--light--hover: rgb(239, 166, 79) !important;
--pf-global--link--Color--dark: rgb(239, 166, 79) !important;
--pf-global--link--Color--dark--hover: rgb(235, 146, 40) !important;
+
+ --pf-global--active-color--100: rgb(247, 205, 159) !important;
}
.vscode-dark .karavan {
@@ -27,15 +29,28 @@ body,
fill: rgb(255, 255, 255);
}
+.vscode-dark .karavan .main-tabs {
+ background-color: rgb(37, 37, 38);
+}
+
.vscode-dark .karavan .main-tabs .pf-c-tabs__list {
background-color: rgb(37, 37, 38);
}
+.vscode-dark .karavan .main-tabs::before {
+ border-color: rgb(37, 37, 38);
+}
+
.vscode-dark .karavan .main-tabs .pf-c-tabs__item.pf-m-current {
background-color: rgb(30, 30, 30);
}
-.vscode-dark .karavan .dsl-page .dsl-page-columns {
+.vscode-dark .karavan .dsl-page .dsl-page-columns,
+.vscode-dark .karavan .rest-page .rest-page-columns,
+.vscode-dark .karavan .beans-page .beans-page-columns,
+.vscode-dark .karavan .error-page .error-page-columns,
+.vscode-dark .karavan .exception-page .exception-page-columns,
+.vscode-dark .karavan .templates-page .templates-page-columns {
background-color: rgb(50, 50, 50);
}
@@ -76,17 +91,21 @@ body,
background-color: rgb(50, 50, 50, 0.5);
}
-.vscode-dark .karavan .dsl-page .properties {
+.vscode-dark .karavan .properties {
border: none;
background: rgb(37, 37, 38);
}
-.vscode-dark .karavan .dsl-page .properties .text-field {
+.vscode-dark .karavan .properties .text-field {
background-color: rgb(50, 50, 50);
border-color: rgb(50, 50, 50);
color: rgb(255, 255, 255);
}
+.vscode-dark .karavan .properties .add-button {
+ color: var(--pf-global--active-color--100);
+}
+
.vscode-dark .pf-c-select {
--pf-c-select__toggle--BackgroundColor: #3B3B3B;
--pf-c-select__toggle--before--BorderTopColor: #3B3B3B;
@@ -101,15 +120,15 @@ body,
box-shadow: var(--pf-c-select__menu--BoxShadow);
}
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__menu-item {
+.vscode-dark .karavan .properties .pf-c-select__menu-item {
color: rgb(255, 255, 255);
}
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__menu-item:hover {
+.vscode-dark .karavan .properties .pf-c-select__menu-item:hover {
color: black;
}
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__toggle-typeahead {
+.vscode-dark .karavan .properties .pf-c-select__toggle-typeahead {
color: rgb(255, 255, 255);
}
@@ -186,7 +205,7 @@ body,
color: rgb(255, 255, 255);
}
-.vscode-dark .karavan .dsl-page .properties .pf-c-text-input-group {
+.vscode-dark .karavan .properties .pf-c-text-input-group {
background-color: rgb(50, 50, 50);
border-color: #3B3B3B;
color: rgb(255, 255, 255);
@@ -194,7 +213,7 @@ body,
--pf-c-text-input-group__text--after--BorderBottomColor: transparent;
}
-.vscode-dark .karavan .dsl-page .properties .input-group .pf-c-chip-group
.pf-c-chip {
+.vscode-dark .karavan .properties .input-group .pf-c-chip-group .pf-c-chip {
--pf-c-chip--BackgroundColor: transparent;
--pf-c-chip__text--Color: white;
--pf-c-chip--before--BorderColor: grey;
@@ -211,13 +230,49 @@ body,
color: rgb(239, 166, 79);
}
-.vscode-dark .karavan .dsl-page .properties .expression,
-.vscode-dark .karavan .dsl-page .properties .object,
-.vscode-dark .karavan .dsl-page .properties .dataformat,
-.vscode-dark .karavan .dsl-page .properties .parameters {
+.vscode-dark .karavan .properties .expression,
+.vscode-dark .karavan .properties .object,
+.vscode-dark .karavan .properties .dataformat,
+.vscode-dark .karavan .properties .parameters {
border-style: none;
}
.vscode-dark .modal-delete {
width: 350px;
+ --pf-c-modal-box--BackgroundColor: #505050;
}
+
+/* Bean */
+.vscode-dark .karavan .beans-page {
+ --pf-c-page__main-section--BackgroundColor:
var(--pf-c-page__main-section--m-dark-100--BackgroundColor);
+}
+
+.vscode-dark .karavan .beans-page .add-bean-button {
+ color: rgb(239, 166, 79);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-unselected {
+ border-color: rgb(239, 166, 79);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected {
+ color: rgb(171, 172, 224);
+ border-color: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected {
+ background-color: rgb(37, 37, 38, 0.7);
+ color: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected .icon {
+ fill: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card:hover {
+ box-shadow: 0 0.01rem 0.001rem 0rem rgb(247 205 159 / 13%), 0 0.1rem 0.5rem
0.1rem rgb(247 205 159 / 12%);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-unselected .icon {
+ fill: white;
+}
\ No newline at end of file