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 7ae5077  Preparations for Traits (#265)
7ae5077 is described below

commit 7ae5077cfdc70f632e7d7991c072d2479540d478
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Thu Mar 31 13:23:37 2022 -0400

    Preparations for Traits (#265)
---
 karavan-core/src/core/model/TraitDefinition.ts     | 105 ++++++++++++++++++++
 karavan-designer/src/App.tsx                       |  25 ++++-
 .../src/designer/beans/BeansDesigner.tsx           |   2 -
 karavan-designer/src/designer/traits/TraitCard.tsx |  40 +++++---
 .../src/designer/traits/TraitProperties.tsx        | 108 ++++++++++-----------
 .../src/designer/traits/TraitsDesigner.tsx         | 100 +++++++++++--------
 karavan-designer/src/designer/utils/CamelUi.ts     |   7 ++
 .../generator/TraitDefinitionGenerator.java        |  10 ++
 .../src/main/resources/TraitDefinition.header.ts   |  29 ++++++
 9 files changed, 313 insertions(+), 113 deletions(-)

diff --git a/karavan-core/src/core/model/TraitDefinition.ts 
b/karavan-core/src/core/model/TraitDefinition.ts
index 906fbb6..73a39db 100644
--- a/karavan-core/src/core/model/TraitDefinition.ts
+++ b/karavan-core/src/core/model/TraitDefinition.ts
@@ -3,6 +3,35 @@
  */
 import {CamelElement} from "./IntegrationDefinition";
 
+export class TraitPropertyMeta {
+    name: string
+    type: string
+    description: string
+
+    constructor(name: string, type: string, description: string) {
+        this.name = name;
+        this.type = type;
+        this.description = description;
+    }
+}
+
+export class TraitMeta {
+    name: string
+    platform: boolean
+    profiles: string
+    description: string
+    properties: TraitPropertyMeta[]
+
+
+    constructor(name: string, platform:boolean, profiles: string, description: 
string, properties: TraitPropertyMeta[]) {
+        this.name = name;
+        this.platform = platform;
+        this.profiles = profiles;
+        this.description = description;
+        this.properties = properties;
+    }
+}
+
 export class Trait extends CamelElement {
     affinity?: AffinityTrait;
     builder?: BuilderTrait;
@@ -596,3 +625,79 @@ export class TraitApi {
     }
 }
 
+export const CamelTraitMetadata: TraitMeta[] = [    new TraitMeta("affinity", 
false, "Kubernetes, Knative, OpenShift", "Allows constraining which nodes the 
integration pod(s) are eligible to be scheduled on, based on labels on the 
node, or with inter-pod affinity and anti-affinity, based on labels on pods 
that are already running on the nodes. It's disabled by default.", [
+    ]),
+    new TraitMeta("builder", false, "Kubernetes, Knative, OpenShift", "The 
builder trait is internally used to determine the best strategy to build and 
configure IntegrationKits.", [
+    ]),
+    new TraitMeta("camel", false, "Kubernetes, Knative, OpenShift", "The Camel 
trait can be used to configure versions of Apache Camel K runtime and related 
libraries, it cannot be disabled.", [
+    ]),
+    new TraitMeta("container", false, "Kubernetes, Knative, OpenShift", "The 
Container trait can be used to configure properties of the container where the 
integration will run. It also provides configuration for Services associated to 
the container.", [
+    ]),
+    new TraitMeta("cron", false, "Kubernetes, Knative, OpenShift", "The Cron 
trait can be used to customize the behaviour of periodic timer/cron based 
integrations. While normally an integration requires a pod to be always up and 
running, some periodic tasks, such as batch jobs, require to be activated at 
specific hours of the day or with a periodic delay of minutes. For such tasks, 
the cron trait can materialize the integration as a Kubernetes CronJob instead 
of a standard deployment, i [...]
+    ]),
+    new TraitMeta("dependencies", false, "Kubernetes, Knative, OpenShift", 
"The Dependencies trait is internally used to automatically add runtime 
dependencies based on the integration that the user wants to run.", [
+    ]),
+    new TraitMeta("deployer", false, "Kubernetes, Knative, OpenShift", "The 
deployer trait is responsible for deploying the resources owned by the 
integration, and can be used to explicitly select the underlying controller 
that will manage the integration pods.", [
+    ]),
+    new TraitMeta("deployment", false, "Kubernetes, Knative, OpenShift", "The 
Deployment trait is responsible for generating the Kubernetes deployment that 
will make sure the integration will run in the cluster.", [
+    ]),
+    new TraitMeta("environment", false, "Kubernetes, Knative, OpenShift", "The 
environment trait is used internally to inject standard environment variables 
in the integration container, such as `NAMESPACE`, `POD_NAME` and others.", [
+    ]),
+    new TraitMeta("error-handler", false, "Kubernetes, Knative, OpenShift", 
"The error-handler is a platform trait used to inject Error Handler source into 
the integration runtime.", [
+    ]),
+    new TraitMeta("gc", false, "Kubernetes, Knative, OpenShift", "The GC Trait 
garbage-collects all resources that are no longer necessary upon integration 
updates.", [
+    ]),
+    new TraitMeta("health", false, "Kubernetes, Knative, OpenShift", "The 
health trait is responsible for configuring the health probes on the 
integration container. It's disabled by default.", [
+    ]),
+    new TraitMeta("ingress", false, "Kubernetes", "The Ingress trait can be 
used to expose the service associated with the integration to the outside world 
with a Kubernetes Ingress. It's enabled by default whenever a Service is added 
to the integration (through the `service` trait).", [
+    ]),
+    new TraitMeta("istio", false, "Kubernetes, Knative, OpenShift", "The Istio 
trait allows configuring properties related to the Istio service mesh, such as 
sidecar injection and outbound IP ranges.", [
+    ]),
+    new TraitMeta("jolokia", false, "Kubernetes, Knative, OpenShift", "The 
Jolokia trait activates and configures the Jolokia Java agent. See 
https://jolokia.org/reference/html/agents.html";, [
+    ]),
+    new TraitMeta("jvm", false, "Kubernetes, Knative, OpenShift", "The JVM 
trait is used to configure the JVM that runs the integration.", [
+    ]),
+    new TraitMeta("kamelets", false, "Kubernetes, Knative, OpenShift", "The 
kamelets trait is a platform trait used to inject Kamelets into the integration 
runtime.", [
+    ]),
+    new TraitMeta("keda", false, "Kubernetes, Knative, OpenShift", "The KEDA 
trait can be used for automatic integration with KEDA autoscalers. The trait 
can be either manually configured using the `triggers` option or automatically 
configured via markers in the Kamelets. For information on how to use KEDA 
enabled Kamelets with the KEDA trait, refer to 
xref:ROOT:kamelets/kamelets-user.adoc#kamelet-keda-user[the KEDA section in the 
Kamelets user guide]. If you want to create Kamelets that [...]
+    ]),
+    new TraitMeta("knative-service", false, "Knative", "The Knative Service 
trait allows configuring options when running the Integration as a Knative 
service, instead of a standard Kubernetes Deployment. Running an Integration as 
a Knative Service enables auto-scaling (and scaling-to-zero), but those 
features are only relevant when the Camel route(s) use(s) an HTTP endpoint 
consumer.", [
+    ]),
+    new TraitMeta("knative", false, "Knative", "The Knative trait 
automatically discovers addresses of Knative resources and inject them into the 
running integration. The full Knative configuration is injected in the 
CAMEL_KNATIVE_CONFIGURATION in JSON format. The Camel Knative component will 
then use the full configuration to configure the routes. The trait is enabled 
by default when the Knative profile is active.", [
+    ]),
+    new TraitMeta("logging", false, "Kubernetes, Knative, OpenShift", "The 
Logging trait is used to configure Integration runtime logging options (such as 
color and format). The logging backend is provided by Quarkus, whose 
configuration is documented at https://quarkus.io/guides/logging.";, [
+    ]),
+    new TraitMeta("master", false, "Kubernetes, Knative, OpenShift", "The 
Master trait allows to configure the integration to automatically leverage 
Kubernetes resources for doing leader election and starting *master* routes 
only on certain instances. It's activated automatically when using the master 
endpoint in a route, e.g. `from(\"master:lockname:telegram:bots\")...`. NOTE: 
this trait adds special permissions to the integration service account in order 
to read/write configmaps and re [...]
+    ]),
+    new TraitMeta("mount", false, "Kubernetes, Knative, OpenShift", "The Mount 
trait can be used to configure volumes mounted on the Integration Pods.", [
+    ]),
+    new TraitMeta("openapi", false, "Kubernetes, Knative, OpenShift", "The 
OpenAPI DSL trait is internally used to allow creating integrations from a 
OpenAPI specs.", [
+    ]),
+    new TraitMeta("owner", false, "Kubernetes, Knative, OpenShift", "The Owner 
trait ensures that all created resources belong to the integration being 
created and transfers annotations and labels on the integration onto these 
owned resources.", [
+    ]),
+    new TraitMeta("pdb", false, "Kubernetes, Knative, OpenShift", "The PDB 
trait allows to configure the PodDisruptionBudget resource for the Integration 
pods.", [
+    ]),
+    new TraitMeta("platform", false, "Kubernetes, Knative, OpenShift", "The 
platform trait is a base trait that is used to assign an integration platform 
to an integration. In case the platform is missing, the trait is allowed to 
create a default platform. This feature is especially useful in contexts where 
there's no need to provide a custom configuration for the platform (e.g. on 
OpenShift the default settings work, since there's an embedded container image 
registry).", [
+    ]),
+    new TraitMeta("pod", false, "Kubernetes, Knative, OpenShift", "The pod 
trait allows the customization of the Integration pods. It applies the 
`PodSpecTemplate` struct contained in the Integration `.spec.podTemplate` 
field, into the Integration deployment Pods template, using strategic merge 
patch. This can be used to customize the container where Camel routes execute, 
by using the `integration` container name.", [
+    ]),
+    new TraitMeta("prometheus", false, "Kubernetes, Knative, OpenShift", "The 
Prometheus trait configures a Prometheus-compatible endpoint. It also creates a 
`PodMonitor` resource, so that the endpoint can be scraped automatically, when 
using the Prometheus operator. The metrics are exposed using MicroProfile 
Metrics. WARNING: The creation of the `PodMonitor` resource requires the 
https://github.com/coreos/prometheus-operator[Prometheus Operator] custom 
resource definition to be installe [...]
+    ]),
+    new TraitMeta("pull-secret", false, "Kubernetes, Knative, OpenShift", "The 
Pull Secret trait sets a pull secret on the pod, to allow Kubernetes to 
retrieve the container image from an external registry. The pull secret can be 
specified manually or, in case you've configured authentication for an external 
container registry on the `IntegrationPlatform`, the same secret is used to 
pull images. It's enabled by default whenever you configure authentication for 
an external container regis [...]
+    ]),
+    new TraitMeta("quarkus", false, "Kubernetes, Knative, OpenShift", "The 
Quarkus trait configures the Quarkus runtime. It's enabled by default. NOTE: 
Compiling to a native executable, i.e. when using `package-type=native`, is 
only supported for kamelets, as well as YAML and XML integrations. It also 
requires at least 4GiB of memory, so the Pod running the native build, that is 
either the operator Pod, or the build Pod (depending on the build strategy 
configured for the platform), must  [...]
+    ]),
+    new TraitMeta("route", false, "OpenShift", "The Route trait can be used to 
configure the creation of OpenShift routes for the integration. The certificate 
and key contents may be sourced either from the local filesystem or in a 
Openshift `secret` object. The user may use the parameters ending in `-secret` 
(example: `tls-certificate-secret`) to reference a certificate stored in a 
`secret`. Parameters ending in `-secret` have higher priorities and in case the 
same route parameter is se [...]
+    ]),
+    new TraitMeta("service-binding", false, "Kubernetes, Knative, OpenShift", 
"The Service Binding trait allows users to connect to Services in Kubernetes: 
https://github.com/k8s-service-bindings/spec#service-binding As the 
specification is still evolving this is subject to change", [
+    ]),
+    new TraitMeta("service", false, "Kubernetes, OpenShift", "The Service 
trait exposes the integration with a Service resource so that it can be 
accessed by other applications (or integrations) in the same namespace. It's 
enabled by default if the integration depends on a Camel component that can 
expose a HTTP endpoint.", [
+    ]),
+    new TraitMeta("3scale", false, "Kubernetes, Knative, OpenShift", "The 
3scale trait can be used to automatically create annotations that allow 3scale 
to discover the generated service and make it available for API management. The 
3scale trait is disabled by default.", [
+    ]),
+    new TraitMeta("toleration", false, "Kubernetes, Knative, OpenShift", "This 
trait sets Tolerations over Integration pods. Tolerations allow (but do not 
require) the pods to schedule onto nodes with matching taints. See 
https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ 
for more details. The toleration should be expressed in a similar manner that 
of taints, i.e., `Key[=Value]:Effect[:Seconds]`, where values in square 
brackets are optional. For examples: - `no [...]
+    ]),
+    new TraitMeta("tracing", false, "Kubernetes, Knative, OpenShift", "The 
Tracing trait can be used to automatically publish tracing information to an 
OpenTracing compatible collector. The trait is able to automatically discover 
the tracing endpoint available in the namespace (supports **Jaeger**). The 
Tracing trait is disabled by default.", [
+    ]),
+] 
+
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 35f5a3a..ab3b931 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -53,7 +53,30 @@ class App extends React.Component<Props, State> {
             '                parameters:\n' +
             '                  topic: topic1\n' +
             '        id: post\n' +
-            ''
+            '  traits:\n' +
+            '    camel:\n' +
+            '      configuration:\n' +
+            '        runtimeVersion: 3.16.0\n' +
+            '        properties:\n' +
+            '          - camel.component.seda.queueSize = 10\n' +
+            '          - camel.component.seda.enabled = false\n' +
+            '    jvm:\n' +
+            '      configuration:\n' +
+            '        debug: true\n' +
+            '        options:\n' +
+            '          - option1\n' +
+            '          - option2\n' +
+            '        classpath: 
/path/to/my-dependency.jar:/path/to/another-dependency.jar\n' +
+            '    threeScale:\n' +
+            '      configuration:\n' +
+            '        enabled: true\n' +
+            '        auto: true\n' +
+            '        path: /\n' +
+            '    3scale:\n' +
+            '      configuration:\n' +
+            '        enabled: true\n' +
+            '        auto: true\n' +
+            '        path: / \n'
     };
 
     componentDidMount() {
diff --git a/karavan-designer/src/designer/beans/BeansDesigner.tsx 
b/karavan-designer/src/designer/beans/BeansDesigner.tsx
index b61e8f6..d48ea68 100644
--- a/karavan-designer/src/designer/beans/BeansDesigner.tsx
+++ b/karavan-designer/src/designer/beans/BeansDesigner.tsx
@@ -39,7 +39,6 @@ interface State {
     showDeleteConfirmation: boolean
     selectedBean?: NamedBeanDefinition
     key: string
-    showBeanEditor: boolean
     propertyOnly: boolean
 }
 
@@ -49,7 +48,6 @@ export class BeansDesigner extends React.Component<Props, 
State> {
         integration: this.props.integration,
         showDeleteConfirmation: false,
         key: "",
-        showBeanEditor: false,
         propertyOnly: false
     };
 
diff --git a/karavan-designer/src/designer/traits/TraitCard.tsx 
b/karavan-designer/src/designer/traits/TraitCard.tsx
index 3ba38a8..20e3a47 100644
--- a/karavan-designer/src/designer/traits/TraitCard.tsx
+++ b/karavan-designer/src/designer/traits/TraitCard.tsx
@@ -19,45 +19,55 @@ import {
     Button
 } from '@patternfly/react-core';
 import '../karavan.css';
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {NamedBeanDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {CamelElement, Integration} from 
"karavan-core/lib/model/IntegrationDefinition";
 import DeleteIcon from 
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
 
 interface Props {
-    bean: NamedBeanDefinition
-    selectedStep?: NamedBeanDefinition
+    trait: CamelElement
+    selectedTrait?: CamelElement
     integration: Integration
-    selectElement: (element: NamedBeanDefinition) => void
-    deleteElement: (element: NamedBeanDefinition) => void
+    // selectMethod: (element: CamelElement) => void
+    // selectElement: (element: CamelElement) => void
+    // deleteElement: (element: CamelElement) => void
 }
 
 export class TraitCard extends React.Component<Props, any> {
 
     selectElement = (evt: React.MouseEvent) => {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.props.bean);
+        // this.props.selectElement.call(this, this.props.rest);
+    }
+
+    selectMethod = (evt: React.MouseEvent) => {
+        evt.stopPropagation();
+        // this.props.selectMethod.call(this, this.props.rest);
     }
 
     delete = (evt: React.MouseEvent) => {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.bean);
+        // this.props.deleteElement.call(this, this.props.rest);
     }
 
     render() {
-        const bean = this.props.bean;
+        const trait = this.props.trait;
         return (
-            <div className={this.props.selectedStep?.uuid === bean.uuid ? 
"rest-card rest-card-selected" : "rest-card rest-card-unselected"} onClick={e 
=> this.selectElement(e)}>
+            <div className={this.props.selectedTrait?.uuid === trait.uuid ? 
"rest-card rest-card-selected" : "rest-card rest-card-unselected"} onClick={e 
=> this.selectElement(e)}>
                 <div className="header">
-                    <div className="title">BEAN</div>
-                    <div className="title">{bean.name}</div>
-                    <div className="description">{bean.type}</div>
+                    <div className="title">Trait</div>
+                    <div className="title">{trait.dslName.replace("Trait", 
"")}</div>
+                    {/*<div 
className="description">{trait.description}</div>*/}
                     {/*<Tooltip position={"bottom"} content={<div>Add REST 
method</div>}>*/}
-                        {/*<Button variant={"link"} icon={<AddIcon/>} 
aria-label="Add" onClick={e => this.selectMethod(e)} className="add-button">Add 
method</Button>*/}
+                    {/*    <Button variant={"link"} icon={<AddIcon/>} 
aria-label="Add" onClick={e => this.selectMethod(e)} className="add-button">Add 
method</Button>*/}
                     {/*</Tooltip>*/}
                     <Button variant="link" className="delete-button" 
onClick={e => this.delete(e)}><DeleteIcon/></Button>
                 </div>
                 <div className="rest-content" key={Math.random().toString()}>
-
+                    {/*{trait.get?.map(get => <RestMethodCard key={get.uuid} 
method={get} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
+                    {/*{trait.post?.map(post => <RestMethodCard 
key={post.uuid} method={post} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
+                    {/*{trait.put?.map(put => <RestMethodCard key={put.uuid} 
method={put} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
+                    {/*{trait.patch?.map(patch => <RestMethodCard 
key={patch.uuid} method={patch} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
+                    {/*{trait.delete?.map(del => <RestMethodCard 
key={del.uuid} method={del} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
+                    {/*{trait.head?.map(head => <RestMethodCard 
key={head.uuid} method={head} selectedStep={this.props.selectedStep} 
integration={this.props.integration} selectElement={this.props.selectElement} 
deleteElement={this.props.deleteElement}/>)}*/}
                 </div>
             </div>
         );
diff --git a/karavan-designer/src/designer/traits/TraitProperties.tsx 
b/karavan-designer/src/designer/traits/TraitProperties.tsx
index 9852744..dc3effd 100644
--- a/karavan-designer/src/designer/traits/TraitProperties.tsx
+++ b/karavan-designer/src/designer/traits/TraitProperties.tsx
@@ -25,7 +25,7 @@ import "@patternfly/patternfly/patternfly.css";
 import {
     NamedBeanDefinition,
 } from "karavan-core/lib/model/CamelDefinition";
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement, Integration} from 
"karavan-core/lib/model/IntegrationDefinition";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {v4 as uuidv4} from "uuid";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
@@ -34,14 +34,14 @@ import {IntegrationHeader} from 
"../utils/KaravanComponents";
 
 interface Props {
     integration: Integration
-    bean?: NamedBeanDefinition
+    trait?: CamelElement
     dark: boolean
-    onChange: (bean: NamedBeanDefinition) => void
+    onChange: (trait: CamelElement) => void
 }
 
 interface State {
-    bean?: NamedBeanDefinition
-    properties: Map<string, [string, string]>
+    trait?: CamelElement
+    // properties: Map<string, [string, string]>
     key: string
 }
 
@@ -54,91 +54,91 @@ export class TraitProperties extends React.Component<Props, 
State> {
     }
 
     public state: State = {
-        bean: this.props.bean,
+        trait: this.props.trait,
         key: '',
-        properties: this.props.bean?.properties ? 
this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, 
[string, string]>()
+        // properties: this.props.trait?.properties ? 
this.preparePropertiesMap(this.props.trait?.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);
+        if (prevProps.trait?.uuid !== this.props.trait?.uuid) {
+            // this.setBean(this.props.trait);
         }
+        // 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?: NamedBeanDefinition) => {
+    setBean = (trait?: CamelElement) => {
         this.setState({
-            bean: bean,
-            properties: bean?.properties ? 
this.preparePropertiesMap(bean.properties) : new Map<string, [string, string]>()
+            trait: trait,
+            // 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);
-        }
+        // 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()};
-        })
+        // 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()};
+            // state.properties.delete(uuid);
+            // return {properties: state.properties, key: 
Math.random().toString()};
         })
     }
 
     getBeanForm() {
-        const bean = this.state.bean;
+        const trait = this.state.trait;
         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)}/>
+                    {/*<TextInput className="text-field" isRequired 
type="text" id="name" name="name" value={trait?.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>
+                    {/*<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'}>
+            <div className='properties' key={this.state.trait ? 
this.state.trait.uuid : 'integration'}>
                 <Form autoComplete="off" onSubmit={event => 
event.preventDefault()}>
-                    {this.state.bean === undefined && <IntegrationHeader 
integration={this.props.integration}/>}
-                    {this.state.bean !== undefined && this.getBeanForm()}
+                    {this.state.trait === undefined && <IntegrationHeader 
integration={this.props.integration}/>}
+                    {this.state.trait !== undefined && this.getBeanForm()}
                 </Form>
             </div>
         )
diff --git a/karavan-designer/src/designer/traits/TraitsDesigner.tsx 
b/karavan-designer/src/designer/traits/TraitsDesigner.tsx
index 056da09..f06df3a 100644
--- a/karavan-designer/src/designer/traits/TraitsDesigner.tsx
+++ b/karavan-designer/src/designer/traits/TraitsDesigner.tsx
@@ -16,7 +16,7 @@
  */
 import React from 'react';
 import {
-    Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal, PageSection, 
Title
+    Button, Drawer, DrawerContent, DrawerContentBody, DrawerPanelContent, 
EmptyState, EmptyStateBody, EmptyStateIcon, Modal, PageSection, Title
 } from '@patternfly/react-core';
 import '../karavan.css';
 import {NamedBeanDefinition} from "karavan-core/lib/model/CamelDefinition";
@@ -28,6 +28,8 @@ import {TraitProperties} from "./TraitProperties";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {TraitCard} from "./TraitCard";
 import CubesIcon from "@patternfly/react-icons/dist/esm/icons/cubes-icon";
+import {CamelElement} from 
"../../../../karavan-core/src/core/model/IntegrationDefinition";
+import {DslProperties} from "../route/DslProperties";
 
 interface Props {
     onSave?: (integration: Integration, propertyOnly: boolean) => void
@@ -38,7 +40,7 @@ interface Props {
 interface State {
     integration: Integration
     showDeleteConfirmation: boolean
-    selectedBean?: NamedBeanDefinition
+    selectedTrait?: CamelElement
     key: string
     showBeanEditor: boolean
     propertyOnly: boolean
@@ -60,8 +62,8 @@ export class TraitsDesigner extends React.Component<Props, 
State> {
         }
     }
 
-    showDeleteConfirmation = (bean: NamedBeanDefinition) => {
-        this.setState({selectedBean: bean, showDeleteConfirmation: true});
+    showDeleteConfirmation = (trait: CamelElement) => {
+        this.setState({selectedTrait: trait, showDeleteConfirmation: true});
     }
 
     onIntegrationUpdate = (i: Integration) => {
@@ -69,19 +71,19 @@ export class TraitsDesigner extends React.Component<Props, 
State> {
     }
 
     deleteBean = () => {
-        const i = 
CamelDefinitionApiExt.deleteBeanFromIntegration(this.state.integration, 
this.state.selectedBean);
-        this.setState({
-            integration: i,
-            showDeleteConfirmation: false,
-            key: Math.random().toString(),
-            selectedBean: new NamedBeanDefinition()
-        });
+        // const i = 
CamelDefinitionApiExt.deleteTraitFromIntegration(this.state.integration, 
this.state.selectedTrait);
+        // this.setState({
+        //     integration: i,
+        //     showDeleteConfirmation: false,
+        //     key: Math.random().toString(),
+        //     selectedBean: new NamedBeanDefinition()
+        // });
     }
 
-    changeBean = (bean: NamedBeanDefinition) => {
-        const clone = CamelUtil.cloneIntegration(this.state.integration);
-        const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
-        this.setState({integration: i, key: Math.random().toString(), 
selectedBean: bean});
+    changeTrait = (trait: CamelElement) => {
+        // const clone = CamelUtil.cloneIntegration(this.state.integration);
+        // const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
+        // this.setState({integration: i, key: Math.random().toString(), 
selectedBean: bean});
     }
 
     getDeleteConfirmation() {
@@ -103,25 +105,38 @@ export class TraitsDesigner extends 
React.Component<Props, State> {
     }
 
     selectBean = (bean?: NamedBeanDefinition) => {
-        this.setState({selectedBean: 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})
+            // this.setState({selectedBean: undefined})
         }
     };
 
     createBean = () => {
-        this.changeBean(new NamedBeanDefinition());
+        this.changeTrait(new NamedBeanDefinition());
+    }
+
+    getPropertiesPanel() {
+        return (
+            <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'} 
maxSize={'800px'} minSize={'300px'}>
+                <TraitProperties integration={this.props.integration}
+                                 trait={this.state.selectedTrait}
+                                 dark={this.props.dark}
+                                 onChange={this.changeTrait}/>
+            </DrawerPanelContent>
+        )
     }
 
     render() {
-        const beans = CamelUi.getBeans(this.state.integration);
+        const traits = CamelUi.getBeans(this.state.integration);
         return (
             <PageSection className="exception-page" isFilled 
padding={{default: 'noPadding'}}>
                 <div className="exception-page-columns">
+            {/*<PageSection className="rest-page" isFilled padding={{default: 
'noPadding'}}>*/}
+            {/*    <div className="rest-page-columns">*/}
                     <EmptyState>
                         <EmptyStateIcon icon={CubesIcon} />
                         <Title headingLevel="h4" size="lg">
@@ -131,28 +146,31 @@ export class TraitsDesigner extends 
React.Component<Props, State> {
                             Traits not implemented yet
                         </EmptyStateBody>
                     </EmptyState>
-                    {/*<div className="graph" data-click="REST"  
onClick={event => this.unselectBean(event)}>*/}
-                    {/*    <div className="flows">*/}
-                    {/*        {beans?.map(bean => <TraitCard key={bean.uuid + 
this.state.key}*/}
-                    {/*                                       
selectedStep={this.state.selectedBean}*/}
-                    {/*                                       bean={bean}*/}
-                    {/*                                       
integration={this.props.integration}*/}
-                    {/*                                       
selectElement={this.selectBean}*/}
-                    {/*                                       
deleteElement={this.showDeleteConfirmation}/>)}*/}
-                    {/*        <div className="add-rest">*/}
-                    {/*            <Button*/}
-                    {/*                variant={beans?.length === 0 ? 
"primary" : "secondary"}*/}
-                    {/*                data-click="ADD_TRAIT"*/}
-                    {/*                icon={<PlusIcon/>}*/}
-                    {/*                onClick={e => this.createBean()}>Create 
new bean*/}
-                    {/*            </Button>*/}
-                    {/*        </div>*/}
-                    {/*    </div>*/}
-                    {/*</div>*/}
-                    {/*<TraitProperties integration={this.props.integration}*/}
-                    {/*                 bean={this.state.selectedBean}*/}
-                    {/*                 dark={this.props.dark}*/}
-                    {/*                 onChange={this.changeBean}/>*/}
+                    {/*<Drawer isExpanded isInline>*/}
+                    {/*    <DrawerContent 
panelContent={this.getPropertiesPanel()}>*/}
+                    {/*        <DrawerContentBody>*/}
+                    {/*            <div className="graph" data-click="REST"  
onClick={event => this.unselectBean(event)}>*/}
+                    {/*                <div className="flows">*/}
+                    {/*                    {traits?.map(trait => <TraitCard 
key={trait.uuid + this.state.key}*/}
+                    {/*                                                     
selectedTrait={this.state.selectedTrait}*/}
+                    {/*                                                     
integration={this.props.integration}*/}
+                    {/*                                                     
trait={trait}*/}
+                    {/*                        // 
selectElement={this.selectBean}*/}
+                    {/*                        // 
deleteElement={this.showDeleteConfirmation}*/}
+                    {/*                    />)}*/}
+                    {/*                    <div className="add-rest">*/}
+                    {/*                        <Button*/}
+                    {/*                            variant={traits?.length === 
0 ? "primary" : "secondary"}*/}
+                    {/*                            data-click="ADD_TRAIT"*/}
+                    {/*                            icon={<PlusIcon/>}*/}
+                    {/*                            onClick={e => 
this.createBean()}>Create new trait*/}
+                    {/*                        </Button>*/}
+                    {/*                    </div>*/}
+                    {/*                </div>*/}
+                    {/*            </div>*/}
+                    {/*        </DrawerContentBody>*/}
+                    {/*    </DrawerContent>*/}
+                    {/*</Drawer>*/}
                 </div>
                 {this.getDeleteConfirmation()}
             </PageSection>
diff --git a/karavan-designer/src/designer/utils/CamelUi.ts 
b/karavan-designer/src/designer/utils/CamelUi.ts
index 7d919df..04c20ce 100644
--- a/karavan-designer/src/designer/utils/CamelUi.ts
+++ b/karavan-designer/src/designer/utils/CamelUi.ts
@@ -24,6 +24,7 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {KameletDefinition, NamedBeanDefinition, RouteDefinition, 
SagaDefinition, ToDefinition} from "karavan-core/lib/model/CamelDefinition";
 import {CamelElement, Dependency, Integration} from 
"karavan-core/lib/model/IntegrationDefinition";
+import {Trait} from "../../../../karavan-core/src/core/model/TraitDefinition";
 
 const StepElements: string[] = [
     "AggregateDefinition",
@@ -465,6 +466,7 @@ export class CamelUi {
         const result = new Map<string, number>();
         result.set('routes', i.spec.flows?.filter((e: any) => e.dslName === 
'RouteDefinition').length || 0);
         result.set('rest', i.spec.flows?.filter((e: any) => e.dslName === 
'RestDefinition').length || 0);
+        result.set('traits', this.getTraitCounts(i.spec.traits));
         const beans = i.spec.flows?.filter((e: any) => e.dslName === 'Beans');
         if (beans && beans.length > 0 && beans[0].beans && 
beans[0].beans.length > 0){
             result.set('beans', Array.from(beans[0].beans).length);
@@ -475,6 +477,11 @@ export class CamelUi {
         return result;
     }
 
+    static getTraitCounts = (t?: Trait): number => {
+        if (t) return Object.getOwnPropertyNames(t).filter(name => name !== 
'dslName' && name !== "uuid" && (t as any)[name]).length;
+        return 0;
+    }
+
     static getRoutes = (integration: Integration): CamelElement[] => {
         const result: CamelElement[] = [];
         integration.spec.flows?.filter((e: any) => e.dslName === 
'RouteDefinition')
diff --git 
a/karavan-generator/src/main/java/org/apache/camel/karavan/generator/TraitDefinitionGenerator.java
 
b/karavan-generator/src/main/java/org/apache/camel/karavan/generator/TraitDefinitionGenerator.java
index 5da1695..a9e0c6a 100644
--- 
a/karavan-generator/src/main/java/org/apache/camel/karavan/generator/TraitDefinitionGenerator.java
+++ 
b/karavan-generator/src/main/java/org/apache/camel/karavan/generator/TraitDefinitionGenerator.java
@@ -96,6 +96,16 @@ public final class TraitDefinitionGenerator extends 
AbstractGenerator {
                 "        return traits;\n" +
                 "    }\n" +
                 "}\n\n");
+
+        // Generate Metadata
+        camelModel.append("export const CamelTraitMetadata: TraitMeta[] = [");
+        getTraits().forEach(trait -> {
+
+            camelModel.append(String.format("    new TraitMeta(\"%s\", %s, 
\"%s\", \"%s\", [\n", trait.name, trait.platform, trait.profiles, 
trait.description.replace("\"", "\\\"")));
+            camelModel.append(String.format("    ]),\n"));
+        });
+        camelModel.append("] \n\n");
+
         writeFileText(targetModel, camelModel.toString());
     }
 
diff --git a/karavan-generator/src/main/resources/TraitDefinition.header.ts 
b/karavan-generator/src/main/resources/TraitDefinition.header.ts
index 3cb3775..c6470fb 100644
--- a/karavan-generator/src/main/resources/TraitDefinition.header.ts
+++ b/karavan-generator/src/main/resources/TraitDefinition.header.ts
@@ -3,3 +3,32 @@
  */
 import {CamelElement} from "./IntegrationDefinition";
 
+export class TraitPropertyMeta {
+    name: string
+    type: string
+    description: string
+
+    constructor(name: string, type: string, description: string) {
+        this.name = name;
+        this.type = type;
+        this.description = description;
+    }
+}
+
+export class TraitMeta {
+    name: string
+    platform: boolean
+    profiles: string
+    description: string
+    properties: TraitPropertyMeta[]
+
+
+    constructor(name: string, platform:boolean, profiles: string, description: 
string, properties: TraitPropertyMeta[]) {
+        this.name = name;
+        this.platform = platform;
+        this.profiles = profiles;
+        this.description = description;
+        this.properties = properties;
+    }
+}
+

Reply via email to