You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2022/04/12 14:45:26 UTC
[camel-karavan] branch main updated: EIP, Kamelet, Component catalogs (#303)
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 4056a54 EIP, Kamelet, Component catalogs (#303)
4056a54 is described below
commit 4056a5423542456465776e5393ab8fa25427f793
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Tue Apr 12 10:45:21 2022 -0400
EIP, Kamelet, Component catalogs (#303)
* Kamelet Catalog
* Kamelet Card Style
* Component Catalog VSCode
* EIP Calatog in VSCode
* Catalogs in Application
---
karavan-app/src/main/webapp/package.json | 7 +-
karavan-app/src/main/webapp/src/Main.tsx | 22 +++-
.../main/webapp/src/components/ComponentCard.tsx | 48 ++++++++
.../ComponentModal.tsx} | 67 ++++++-----
.../ComponentsPage.tsx} | 43 +++----
karavan-app/src/main/webapp/src/eip/EipCard.tsx | 46 ++++++++
.../KameletModal.tsx => eip/EipModal.tsx} | 60 +++++-----
.../{kamelets/KameletsPage.tsx => eip/EipPage.tsx} | 44 ++++---
.../src/main/webapp/src/kamelets/KameletCard.tsx | 17 +--
.../src/main/webapp/src/kamelets/KameletModal.tsx | 2 +-
.../src/main/webapp/src/kamelets/KameletsPage.tsx | 9 +-
karavan-core/package-lock.json | 4 +-
karavan-core/src/core/api/ComponentApi.ts | 4 +-
karavan-core/src/core/api/KameletApi.ts | 3 +-
karavan-designer/package-lock.json | 109 ++++++++++++++----
karavan-designer/package.json | 1 +
karavan-designer/src/App.tsx | 58 +++++-----
karavan-designer/src/components/ComponentCard.tsx | 48 ++++++++
.../src/components/ComponentModal.tsx | 67 ++++++-----
.../src/components/ComponentsPage.tsx | 43 +++----
karavan-designer/src/designer/karavan.css | 9 +-
karavan-designer/src/eip/EipCard.tsx | 46 ++++++++
.../src/eip/EipModal.tsx | 60 +++++-----
.../src/eip/EipPage.tsx | 44 ++++---
karavan-designer/src/index.tsx | 20 +++-
.../src/kamelets/KameletCard.tsx | 17 +--
.../src/kamelets/KameletModal.tsx | 2 +-
.../src/kamelets/KameletsPage.tsx | 9 +-
karavan-vscode/package-lock.json | 117 +++++++++++++++----
karavan-vscode/package.json | 80 +++++--------
karavan-vscode/src/componentView.ts | 70 ------------
karavan-vscode/src/designerView.ts | 2 +-
karavan-vscode/src/eipView.ts | 70 ------------
karavan-vscode/src/extension.ts | 24 ++--
karavan-vscode/src/helpView.ts | 126 +++++++++++++++++++++
karavan-vscode/src/kameletView.ts | 69 -----------
karavan-vscode/src/utils.ts | 3 -
karavan-vscode/webview/App.tsx | 28 ++++-
.../webview/components/ComponentCard.tsx | 48 ++++++++
.../webview/components/ComponentModal.tsx | 67 ++++++-----
.../webview/components/ComponentsPage.tsx | 43 +++----
karavan-vscode/webview/eip/EipCard.tsx | 46 ++++++++
.../webview/eip/EipModal.tsx | 60 +++++-----
.../webview/eip/EipPage.tsx | 44 ++++---
karavan-vscode/webview/index.css | 38 +++++++
.../webview}/kamelets/KameletCard.tsx | 17 +--
.../webview}/kamelets/KameletModal.tsx | 2 +-
.../webview}/kamelets/KameletsPage.tsx | 9 +-
48 files changed, 1160 insertions(+), 712 deletions(-)
diff --git a/karavan-app/src/main/webapp/package.json b/karavan-app/src/main/webapp/package.json
index 82e40cb..d7c065c 100644
--- a/karavan-app/src/main/webapp/package.json
+++ b/karavan-app/src/main/webapp/package.json
@@ -3,9 +3,10 @@
"version": "0.0.15",
"private": true,
"scripts": {
- "start": "cp -r ../../../../karavan-designer/src/designer src && react-scripts start",
- "build": "cp -r ../../../../karavan-designer/src/designer src && react-scripts build",
- "prod": "cp -r ../../../../karavan-designer/src/designer src && react-scripts build --dest && rsync -a build/* ../resources/META-INF/resources"
+ "copy-designer": "cp -r ../../../../karavan-designer/src/designer src && cp -r ../../../../karavan-designer/src/kamelets src && cp -r ../../../../karavan-designer/src/components src && cp -r ../../../../karavan-designer/src/eip src",
+ "start": "npm run copy-designer && react-scripts start",
+ "build": "npm run copy-designer && react-scripts build",
+ "prod": "npm run copy-designer && react-scripts build --dest && rsync -a build/* ../resources/META-INF/resources"
},
"proxy": "http://127.0.0.1:8080/",
"eslintConfig": {
diff --git a/karavan-app/src/main/webapp/src/Main.tsx b/karavan-app/src/main/webapp/src/Main.tsx
index b37d53b..aff65df 100644
--- a/karavan-app/src/main/webapp/src/Main.tsx
+++ b/karavan-app/src/main/webapp/src/Main.tsx
@@ -36,6 +36,8 @@ import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
import avatarImg from './avatarImg.svg';
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import Icon from "./Logo";
+import {ComponentsPage} from "./components/ComponentsPage";
+import {EipPage} from "./eip/EipPage";
class ToastMessage {
id: string = ''
@@ -58,7 +60,7 @@ interface State {
version: string,
mode: 'local' | 'gitops' | 'serverless',
isNavOpen: boolean,
- pageId: 'integrations' | 'configuration' | 'kamelets' | 'designer'
+ pageId: 'integrations' | 'configuration' | 'kamelets' | 'designer' | "components" | "eip"
integrations: Map<string,string>,
integration: Integration,
isModalOpen: boolean,
@@ -166,14 +168,22 @@ export class Main extends React.Component<Props, State> {
isActive={this.state.pageId === 'integrations'}>
Integrations
</NavItem>
+ <NavItem id="eip" to="#" itemId={"eip"}
+ isActive={this.state.pageId === 'eip'}>
+ Enterprise Integration Patterns
+ </NavItem>
<NavItem id="kamelets" to="#" itemId={"kamelets"}
isActive={this.state.pageId === 'kamelets'}>
Kamelets
</NavItem>
- <NavItem id="configuration" to="#" itemId={"configuration"}
- isActive={this.state.pageId === 'configuration'}>
- Configuration
+ <NavItem id="components" to="#" itemId={"components"}
+ isActive={this.state.pageId === 'components'}>
+ Components
</NavItem>
+ {/*<NavItem id="configuration" to="#" itemId={"configuration"}*/}
+ {/* isActive={this.state.pageId === 'configuration'}>*/}
+ {/* Configuration*/}
+ {/*</NavItem>*/}
</NavList>
</Nav>);
@@ -237,7 +247,9 @@ export class Main extends React.Component<Props, State> {
onDelete={this.onIntegrationDelete} onSelect={this.onIntegrationSelect}
onCreate={this.onIntegrationCreate}/>}
{this.state.pageId === 'configuration' && <ConfigurationPage/>}
- {this.state.pageId === 'kamelets' && <KameletsPage/>}
+ {this.state.pageId === 'kamelets' && <KameletsPage dark={false}/>}
+ {this.state.pageId === 'components' && <ComponentsPage dark={false}/>}
+ {this.state.pageId === 'eip' && <EipPage dark={false}/>}
{this.state.pageId === 'designer' &&
<DesignerPage mode={this.state.mode} integration={this.state.integration}/>}
<Modal
diff --git a/karavan-app/src/main/webapp/src/components/ComponentCard.tsx b/karavan-app/src/main/webapp/src/components/ComponentCard.tsx
new file mode 100644
index 0000000..e1adb01
--- /dev/null
+++ b/karavan-app/src/main/webapp/src/components/ComponentCard.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardActions, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+
+interface Props {
+ component: Component,
+ onClickCard: any
+}
+
+interface State {
+ component: Component,
+}
+
+export class ComponentCard extends React.Component<Props, State> {
+
+ public state: State = {
+ component: this.props.component
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.component);
+ }
+
+ render() {
+ const component = this.state.component;
+ return (
+ <Card isHoverable isCompact key={component.component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardBody>{component.component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.component.label}</Badge>
+ <Badge isRead className="version">{component.component.version}</Badge>
+ </CardFooter>
+ </Card>
+ );
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-app/src/main/webapp/src/components/ComponentModal.tsx
similarity index 51%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-app/src/main/webapp/src/components/ComponentModal.tsx
index 3213a87..25e72cc 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-app/src/main/webapp/src/components/ComponentModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,27 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {camelIcon} from "../designer/utils/CamelUi";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {ComponentProperty} from "karavan-core/src/core/model/ComponentModels";
interface Props {
- kamelet?: KameletModel,
+ component?: Component,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ component?: Component,
}
-export class KameletModal extends Component<Props, State> {
+export class ComponentModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ component: this.props.component,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +42,67 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.component;
+ const props = new Map<string, ComponentProperty>();
+ if (component){
+ ComponentApi.getComponentProperties(component?.component.name, "consumer").forEach(cp => props.set(cp.name, cp));
+ ComponentApi.getComponentProperties(component?.component.name, "producer").forEach(cp => props.set(cp.name, cp));
+ }
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.component.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.component.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.component.label}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.component.description}</Text>
+ {props.size !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {Array.from(props.values()).map((p: ComponentProperty, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +111,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-app/src/main/webapp/src/components/ComponentsPage.tsx
similarity index 54%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-app/src/main/webapp/src/components/ComponentsPage.tsx
index 6b2a251..203a789 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-app/src/main/webapp/src/components/ComponentsPage.tsx
@@ -8,59 +8,62 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {ComponentCard} from "./ComponentCard";
+import {ComponentModal} from "./ComponentModal";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ component?: Component;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ components: Component[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class ComponentsPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ components: [],
filter: ''
};
componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
+ this.setState({components: ComponentApi.getComponents()})
}
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (c: Component)=> {
+ this.setState({component: c, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ components: ComponentApi.getComponents().filter(c => c.component.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const component = this.state.component;
+ const components = this.state.components;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <ComponentModal key={component?.component.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} component={component}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Component Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +81,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {components.map(c => (
+ <ComponentCard key={c.component.name} component={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-app/src/main/webapp/src/eip/EipCard.tsx b/karavan-app/src/main/webapp/src/eip/EipCard.tsx
new file mode 100644
index 0000000..34d745e
--- /dev/null
+++ b/karavan-app/src/main/webapp/src/eip/EipCard.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
+
+interface Props {
+ element: ElementMeta,
+ onClickCard: any
+}
+
+interface State {
+ element: ElementMeta,
+}
+
+export class EipCard extends React.Component<Props, State> {
+
+ public state: State = {
+ element: this.props.element
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.element);
+ }
+
+ render() {
+ const component = this.state.element;
+ return (
+ <Card isHoverable isCompact key={component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={CamelUi.getIconForName(component.className)} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardBody>{component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.labels}</Badge>
+ </CardFooter>
+ </Card>
+ )
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-app/src/main/webapp/src/eip/EipModal.tsx
similarity index 57%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-app/src/main/webapp/src/eip/EipModal.tsx
index 3213a87..ea5e325 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-app/src/main/webapp/src/eip/EipModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,25 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
- kamelet?: KameletModel,
+ element?: ElementMeta,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ element?: ElementMeta,
}
-export class KameletModal extends Component<Props, State> {
+export class EipModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ element: this.props.element,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +40,62 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.element;
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={CamelUi.getIconForName(component?.name || '')} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.labels}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.description}</Text>
+ {component?.properties.length !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {component?.properties.map((p: PropertyMeta, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +104,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-app/src/main/webapp/src/eip/EipPage.tsx
similarity index 56%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-app/src/main/webapp/src/eip/EipPage.tsx
index 6b2a251..fe5fa2f 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-app/src/main/webapp/src/eip/EipPage.tsx
@@ -8,59 +8,57 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {EipCard} from "./EipCard";
+import {EipModal} from "./EipModal";
+import {CamelModelMetadata, ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ element?: ElementMeta;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ elements: ElementMeta[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class EipPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ elements: CamelModelMetadata.sort((a: ElementMeta,b: ElementMeta) => a.name > b.name ? 1 : -1),
filter: ''
};
- componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
- }
-
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (e: ElementMeta)=> {
+ this.setState({element: e, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ elements: CamelModelMetadata.filter(c => c.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const element = this.state.element;
+ const elements = this.state.elements;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <EipModal key={element?.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} element={element}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Enterprise Integration Patterns</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +76,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {elements.map(c => (
+ <EipCard key={c.name} element={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
index 8a9cd75..8e05901 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
@@ -27,20 +27,21 @@ export class KameletCard extends React.Component<Props, State> {
}
render() {
+ const kamelet = this.state.kamelet;
return (
- <Card isHoverable isCompact key={this.state.kamelet.metadata.name} className="kamelet-card"
+ <Card isHoverable isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false" src={this.state.kamelet.icon()} className="kamelet-icon" alt=""></img>
- <CardActions>
- <Badge className="badge" isRead> {this.state.kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- </CardActions>
+ <img draggable="false" src={kamelet.icon()} className="kamelet-icon" alt=""></img>
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(this.state.kamelet.metadata.name)}</CardTitle>
- <CardBody>{this.state.kamelet.spec.definition.description}</CardBody>
+ <CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
-
+ {/*<div style={{justifyContent: "space-between"}}>*/}
+ <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ {/*</div>*/}
</CardFooter>
</Card>
);
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
index 3213a87..738c68a 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
@@ -57,7 +57,7 @@ export class KameletModal extends Component<Props, State> {
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
index 6b2a251..a3e0cd4 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
@@ -14,6 +14,7 @@ import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
interface Props {
+ dark: boolean
}
interface State {
@@ -53,14 +54,14 @@ export class KameletsPage extends React.Component<Props, State> {
render() {
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
<KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Kamelet Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,7 +79,7 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{this.state.kamelets.map(k => (
<KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
diff --git a/karavan-core/package-lock.json b/karavan-core/package-lock.json
index 9da3e92..7d049f0 100644
--- a/karavan-core/package-lock.json
+++ b/karavan-core/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "karavan-core",
- "version": "0.0.14",
+ "version": "0.0.15",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "karavan-core",
- "version": "0.0.14",
+ "version": "0.0.15",
"license": "Apache-2.0",
"dependencies": {
"@types/js-yaml": "^4.0.5",
diff --git a/karavan-core/src/core/api/ComponentApi.ts b/karavan-core/src/core/api/ComponentApi.ts
index 8cc9e69..76c478d 100644
--- a/karavan-core/src/core/api/ComponentApi.ts
+++ b/karavan-core/src/core/api/ComponentApi.ts
@@ -16,6 +16,7 @@
*/
import {Component, ComponentProperty} from "../model/ComponentModels";
import {CamelMetadataApi} from "../model/CamelMetadata";
+import {Kamelets} from "./KameletApi";
export const Components: Component[] = [];
@@ -27,7 +28,8 @@ export const ComponentApi = {
return k;
},
- saveComponents: (jsons: string[]) => {
+ saveComponents: (jsons: string[], clean: boolean = false) => {
+ if (clean) Components.length = 0;
const components: Component[] = jsons.map(json => ComponentApi.jsonToComponent(json));
Components.push(...components);
},
diff --git a/karavan-core/src/core/api/KameletApi.ts b/karavan-core/src/core/api/KameletApi.ts
index 97fa38d..b60abe9 100644
--- a/karavan-core/src/core/api/KameletApi.ts
+++ b/karavan-core/src/core/api/KameletApi.ts
@@ -75,8 +75,9 @@ export const KameletApi = {
return KameletApi.jsonToKamelet(JSON.stringify(fromYaml));
},
- saveKamelets: (kameletYamls: string[]) => {
+ saveKamelets: (kameletYamls: string[], clean: boolean = false) => {
const kamelets:KameletModel[] = kameletYamls.map(text => KameletApi.yamlToKamelet(text));
+ if (clean) Kamelets.length = 0;
Kamelets.push(...kamelets.sort((a, b) => {
if (a.spec.definition.title.toLowerCase() < b.spec.definition.title.toLowerCase()) {
return -1;
diff --git a/karavan-designer/package-lock.json b/karavan-designer/package-lock.json
index 1a548f3..ce538b4 100644
--- a/karavan-designer/package-lock.json
+++ b/karavan-designer/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "karavan-designer",
- "version": "0.0.14",
+ "version": "0.0.15",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "karavan-designer",
- "version": "0.0.14",
+ "version": "0.0.15",
"license": "Apache-2.0",
"dependencies": {
"@patternfly/patternfly": "4.171.1",
"@patternfly/react-core": "4.192.7",
+ "@patternfly/react-table": "^4.71.16",
"@reactour/tour": "^2.10.2",
"@types/js-yaml": "^4.0.5",
"@types/uuid": "8.3.4",
@@ -33,7 +34,7 @@
}
},
"../karavan-core": {
- "version": "0.0.14",
+ "version": "0.0.15",
"license": "Apache-2.0",
"dependencies": {
"@types/js-yaml": "^4.0.5",
@@ -48,6 +49,7 @@
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.23",
"chai": "^4.3.4",
+ "cross-env": "^7.0.3",
"fs": "^0.0.1-security",
"mocha": "^9.2.0",
"ts-node": "^10.4.0"
@@ -2910,23 +2912,58 @@
}
},
"node_modules/@patternfly/react-icons": {
- "version": "4.49.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.49.5.tgz",
- "integrity": "sha512-pR04R32KZAd4uPWeFf/pYXp0uUTwDotsM1iPbjJ6Rpl1sELM4LuQV4gaG22dWLy24VCRizFoP6BSzDxmq+GY4g==",
+ "version": "4.53.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.53.16.tgz",
+ "integrity": "sha512-QQOZwl9MR71uNaKUPKJUm2qjvol28evN7GgyiqGn7fr0p4FnPopm9F5GsnKMsE/764/HGwGLjYHulUo3Eb06dQ==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
}
},
"node_modules/@patternfly/react-styles": {
- "version": "4.48.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.48.5.tgz",
- "integrity": "sha512-kXY2piAInTuv1PxuQbSuDYJ+ugIsEs9MnwWqZOMARGrcsElbRLn+vtSxShx7AQeJ9V9e0v64gdgP7pIJqisd1Q=="
+ "version": "4.52.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.52.16.tgz",
+ "integrity": "sha512-i/xj+r0qVlhSoxrFOePxXoC8BudDPsEma0qwP+3Ry4hSZhN6XhSRSqjA5xmaLkgbfWCAiT/+mR9ilCaguxoLTA=="
+ },
+ "node_modules/@patternfly/react-table": {
+ "version": "4.71.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.71.16.tgz",
+ "integrity": "sha512-HF//Sk1nnF7phAOjglC8zndRfJ3/3oe8Bkxbufhp3lSFdAyzjed6WBdV2dNIrsNj1UeO8MRSlYCbbDEZZlrO2A==",
+ "dependencies": {
+ "@patternfly/react-core": "^4.202.16",
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "lodash": "^4.17.19",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0"
+ }
+ },
+ "node_modules/@patternfly/react-table/node_modules/@patternfly/react-core": {
+ "version": "4.202.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.202.16.tgz",
+ "integrity": "sha512-yWDf0x+YFFVxm72RC/BUaSOn2UsIirT77qif6DfAWdSODhdxTfaLCeBZ08uWgxJ1YZNCrankj60va+G5L+LVrg==",
+ "dependencies": {
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "focus-trap": "6.2.2",
+ "react-dropzone": "9.0.0",
+ "tippy.js": "5.1.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0"
+ }
},
"node_modules/@patternfly/react-tokens": {
- "version": "4.50.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.50.5.tgz",
- "integrity": "sha512-u8+f4eevQdVC7w4jmy+ynIB9R7A9NlI2v5L8GMtkWLt3A0S4DBzNbU90MPSVwgfw0XHcvdFQjuK3OaS06M0bxw=="
+ "version": "4.54.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.54.16.tgz",
+ "integrity": "sha512-BBVg40L4gx0Gew2kDdGNxP+EtDwGeBuJwXewKrTjXlCa4uhOOj7TqJ5rxhS4GULfYiYbUGdYe7UMFVb+mKDVVg=="
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.4",
@@ -18254,20 +18291,49 @@
}
},
"@patternfly/react-icons": {
- "version": "4.49.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.49.5.tgz",
- "integrity": "sha512-pR04R32KZAd4uPWeFf/pYXp0uUTwDotsM1iPbjJ6Rpl1sELM4LuQV4gaG22dWLy24VCRizFoP6BSzDxmq+GY4g==",
+ "version": "4.53.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.53.16.tgz",
+ "integrity": "sha512-QQOZwl9MR71uNaKUPKJUm2qjvol28evN7GgyiqGn7fr0p4FnPopm9F5GsnKMsE/764/HGwGLjYHulUo3Eb06dQ==",
"requires": {}
},
"@patternfly/react-styles": {
- "version": "4.48.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.48.5.tgz",
- "integrity": "sha512-kXY2piAInTuv1PxuQbSuDYJ+ugIsEs9MnwWqZOMARGrcsElbRLn+vtSxShx7AQeJ9V9e0v64gdgP7pIJqisd1Q=="
+ "version": "4.52.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.52.16.tgz",
+ "integrity": "sha512-i/xj+r0qVlhSoxrFOePxXoC8BudDPsEma0qwP+3Ry4hSZhN6XhSRSqjA5xmaLkgbfWCAiT/+mR9ilCaguxoLTA=="
+ },
+ "@patternfly/react-table": {
+ "version": "4.71.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.71.16.tgz",
+ "integrity": "sha512-HF//Sk1nnF7phAOjglC8zndRfJ3/3oe8Bkxbufhp3lSFdAyzjed6WBdV2dNIrsNj1UeO8MRSlYCbbDEZZlrO2A==",
+ "requires": {
+ "@patternfly/react-core": "^4.202.16",
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "lodash": "^4.17.19",
+ "tslib": "^2.0.0"
+ },
+ "dependencies": {
+ "@patternfly/react-core": {
+ "version": "4.202.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.202.16.tgz",
+ "integrity": "sha512-yWDf0x+YFFVxm72RC/BUaSOn2UsIirT77qif6DfAWdSODhdxTfaLCeBZ08uWgxJ1YZNCrankj60va+G5L+LVrg==",
+ "requires": {
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "focus-trap": "6.2.2",
+ "react-dropzone": "9.0.0",
+ "tippy.js": "5.1.2",
+ "tslib": "^2.0.0"
+ }
+ }
+ }
},
"@patternfly/react-tokens": {
- "version": "4.50.5",
- "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.50.5.tgz",
- "integrity": "sha512-u8+f4eevQdVC7w4jmy+ynIB9R7A9NlI2v5L8GMtkWLt3A0S4DBzNbU90MPSVwgfw0XHcvdFQjuK3OaS06M0bxw=="
+ "version": "4.54.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.54.16.tgz",
+ "integrity": "sha512-BBVg40L4gx0Gew2kDdGNxP+EtDwGeBuJwXewKrTjXlCa4uhOOj7TqJ5rxhS4GULfYiYbUGdYe7UMFVb+mKDVVg=="
},
"@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.4",
@@ -24016,6 +24082,7 @@
"@types/node": "^17.0.23",
"@types/uuid": "^8.3.4",
"chai": "^4.3.4",
+ "cross-env": "^7.0.3",
"fs": "^0.0.1-security",
"mocha": "^9.2.0",
"ts-node": "^10.4.0",
diff --git a/karavan-designer/package.json b/karavan-designer/package.json
index 0f10956..4490c5f 100644
--- a/karavan-designer/package.json
+++ b/karavan-designer/package.json
@@ -28,6 +28,7 @@
"dependencies": {
"@patternfly/patternfly": "4.171.1",
"@patternfly/react-core": "4.192.7",
+ "@patternfly/react-table": "^4.71.16",
"@reactour/tour": "^2.10.2",
"@types/js-yaml": "^4.0.5",
"@types/uuid": "8.3.4",
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index e078a66..67426b7 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -21,9 +21,12 @@ import {
import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {KaravanDesigner} from "./designer/KaravanDesigner";
-import {TourProvider, useTour} from "@reactour/tour";
+import {KameletsPage} from "./kamelets/KameletsPage";
+import {ComponentsPage} from "./components/ComponentsPage";
+import {EipPage} from "./eip/EipPage";
interface Props {
+ page: "designer" | "kamelets" | "components" | "eip";
}
interface State {
@@ -38,27 +41,27 @@ class App extends React.Component<Props, State> {
name: 'demo.yaml',
key: '',
yaml:
- // 'apiVersion: camel.apache.org/v1\n' +
- // 'kind: Integration\n' +
- // 'metadata:\n' +
- // ' name: postman.yaml\n' +
- // 'spec:\n' +
- // ' flows:\n' +
- // ' - route:\n' +
- // ' from:\n' +
- // ' uri: direct:post\n' +
- // ' steps:\n' +
- // ' - log:\n' +
- // ' message: \'Received: ${body}\'\n' +
- // ' - log:\n' +
- // ' message: \'Received: ${body}\'\n' +
- // ' - log:\n' +
- // ' message: \'Received: ${body}\'\n' +
- // ' - to:\n' +
- // ' uri: kamelet:kafka-sink\n' +
- // ' parameters:\n' +
- // ' topic: topic1\n' +
- // ' id: post\n' +
+ // 'apiVersion: camel.apache.org/v1\n' +
+ // 'kind: Integration\n' +
+ // 'metadata:\n' +
+ // ' name: postman.yaml\n' +
+ // 'spec:\n' +
+ // ' flows:\n' +
+ // ' - route:\n' +
+ // ' from:\n' +
+ // ' uri: direct:post\n' +
+ // ' steps:\n' +
+ // ' - log:\n' +
+ // ' message: \'Received: ${body}\'\n' +
+ // ' - log:\n' +
+ // ' message: \'Received: ${body}\'\n' +
+ // ' - log:\n' +
+ // ' message: \'Received: ${body}\'\n' +
+ // ' - to:\n' +
+ // ' uri: kamelet:kafka-sink\n' +
+ // ' parameters:\n' +
+ // ' topic: topic1\n' +
+ // ' id: post\n' +
''
};
@@ -112,10 +115,13 @@ class App extends React.Component<Props, State> {
public render() {
return (
<Page className="karavan">
- <KaravanDesigner key={this.state.key} filename={this.state.name} yaml={this.state.yaml}
- onSave={(filename, yaml, propertyOnly) => this.save(filename, yaml, propertyOnly)}
- dark={document.body.className.includes('vscode-dark')}
- showStartHelp={true}/>
+ {this.props.page === "designer" && <KaravanDesigner key={this.state.key} filename={this.state.name} yaml={this.state.yaml}
+ onSave={(filename, yaml, propertyOnly) => this.save(filename, yaml, propertyOnly)}
+ dark={document.body.className.includes('vscode-dark')}
+ showStartHelp={true}/>}
+ {this.props.page === "kamelets" && <KameletsPage dark={document.body.className.includes('vscode-dark')} />}
+ {this.props.page === "components" && <ComponentsPage dark={document.body.className.includes('vscode-dark')} />}
+ {this.props.page === "eip" && <EipPage dark={document.body.className.includes('vscode-dark')} />}
</Page>
);
}
diff --git a/karavan-designer/src/components/ComponentCard.tsx b/karavan-designer/src/components/ComponentCard.tsx
new file mode 100644
index 0000000..e1adb01
--- /dev/null
+++ b/karavan-designer/src/components/ComponentCard.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardActions, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+
+interface Props {
+ component: Component,
+ onClickCard: any
+}
+
+interface State {
+ component: Component,
+}
+
+export class ComponentCard extends React.Component<Props, State> {
+
+ public state: State = {
+ component: this.props.component
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.component);
+ }
+
+ render() {
+ const component = this.state.component;
+ return (
+ <Card isHoverable isCompact key={component.component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardBody>{component.component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.component.label}</Badge>
+ <Badge isRead className="version">{component.component.version}</Badge>
+ </CardFooter>
+ </Card>
+ );
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-designer/src/components/ComponentModal.tsx
similarity index 51%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-designer/src/components/ComponentModal.tsx
index 3213a87..25e72cc 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-designer/src/components/ComponentModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,27 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {camelIcon} from "../designer/utils/CamelUi";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {ComponentProperty} from "karavan-core/src/core/model/ComponentModels";
interface Props {
- kamelet?: KameletModel,
+ component?: Component,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ component?: Component,
}
-export class KameletModal extends Component<Props, State> {
+export class ComponentModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ component: this.props.component,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +42,67 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.component;
+ const props = new Map<string, ComponentProperty>();
+ if (component){
+ ComponentApi.getComponentProperties(component?.component.name, "consumer").forEach(cp => props.set(cp.name, cp));
+ ComponentApi.getComponentProperties(component?.component.name, "producer").forEach(cp => props.set(cp.name, cp));
+ }
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.component.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.component.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.component.label}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.component.description}</Text>
+ {props.size !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {Array.from(props.values()).map((p: ComponentProperty, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +111,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-designer/src/components/ComponentsPage.tsx
similarity index 54%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-designer/src/components/ComponentsPage.tsx
index 6b2a251..203a789 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-designer/src/components/ComponentsPage.tsx
@@ -8,59 +8,62 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {ComponentCard} from "./ComponentCard";
+import {ComponentModal} from "./ComponentModal";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ component?: Component;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ components: Component[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class ComponentsPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ components: [],
filter: ''
};
componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
+ this.setState({components: ComponentApi.getComponents()})
}
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (c: Component)=> {
+ this.setState({component: c, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ components: ComponentApi.getComponents().filter(c => c.component.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const component = this.state.component;
+ const components = this.state.components;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <ComponentModal key={component?.component.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} component={component}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Component Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +81,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {components.map(c => (
+ <ComponentCard key={c.component.name} component={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index a5f2beb..88c7730 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -1081,4 +1081,11 @@ reactour-portal .reactour__popover button {
}
reactour-portal .reactour__popover button:focus-visible {
outline: none;
-}
\ No newline at end of file
+}
+
+/*Kamelets*/
+.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
diff --git a/karavan-designer/src/eip/EipCard.tsx b/karavan-designer/src/eip/EipCard.tsx
new file mode 100644
index 0000000..34d745e
--- /dev/null
+++ b/karavan-designer/src/eip/EipCard.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
+
+interface Props {
+ element: ElementMeta,
+ onClickCard: any
+}
+
+interface State {
+ element: ElementMeta,
+}
+
+export class EipCard extends React.Component<Props, State> {
+
+ public state: State = {
+ element: this.props.element
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.element);
+ }
+
+ render() {
+ const component = this.state.element;
+ return (
+ <Card isHoverable isCompact key={component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={CamelUi.getIconForName(component.className)} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardBody>{component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.labels}</Badge>
+ </CardFooter>
+ </Card>
+ )
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-designer/src/eip/EipModal.tsx
similarity index 57%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-designer/src/eip/EipModal.tsx
index 3213a87..ea5e325 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-designer/src/eip/EipModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,25 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
- kamelet?: KameletModel,
+ element?: ElementMeta,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ element?: ElementMeta,
}
-export class KameletModal extends Component<Props, State> {
+export class EipModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ element: this.props.element,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +40,62 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.element;
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={CamelUi.getIconForName(component?.name || '')} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.labels}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.description}</Text>
+ {component?.properties.length !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {component?.properties.map((p: PropertyMeta, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +104,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-designer/src/eip/EipPage.tsx
similarity index 56%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-designer/src/eip/EipPage.tsx
index 6b2a251..fe5fa2f 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-designer/src/eip/EipPage.tsx
@@ -8,59 +8,57 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {EipCard} from "./EipCard";
+import {EipModal} from "./EipModal";
+import {CamelModelMetadata, ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ element?: ElementMeta;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ elements: ElementMeta[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class EipPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ elements: CamelModelMetadata.sort((a: ElementMeta,b: ElementMeta) => a.name > b.name ? 1 : -1),
filter: ''
};
- componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
- }
-
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (e: ElementMeta)=> {
+ this.setState({element: e, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ elements: CamelModelMetadata.filter(c => c.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const element = this.state.element;
+ const elements = this.state.elements;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <EipModal key={element?.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} element={element}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Enterprise Integration Patterns</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +76,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {elements.map(c => (
+ <EipCard key={c.name} element={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-designer/src/index.tsx b/karavan-designer/src/index.tsx
index 19b4ba3..a39991f 100644
--- a/karavan-designer/src/index.tsx
+++ b/karavan-designer/src/index.tsx
@@ -15,9 +15,25 @@
* limitations under the License.
*/
import * as React from "react";
-import * as ReactDOM from "react-dom";
import "./index.css";
import "@patternfly/patternfly/patternfly.css";
import App from "./App";
+import {render} from "react-dom";
+import {
+ BrowserRouter,
+ Routes,
+ Route,
+} from "react-router-dom";
-ReactDOM.render(<App />, document.getElementById("root") as HTMLElement);
+const rootElement = document.getElementById("root");
+render(
+ <BrowserRouter>
+ <Routes>
+ <Route path="/" element={<App page="designer"/>} />
+ <Route path="kamelets-page" element={<App page="kamelets"/>} />
+ <Route path="components-page" element={<App page="components"/>} />
+ <Route path="eip-page" element={<App page="eip"/>} />
+ </Routes>
+ </BrowserRouter>,
+ rootElement
+);
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx b/karavan-designer/src/kamelets/KameletCard.tsx
similarity index 54%
copy from karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
copy to karavan-designer/src/kamelets/KameletCard.tsx
index 8a9cd75..8e05901 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
+++ b/karavan-designer/src/kamelets/KameletCard.tsx
@@ -27,20 +27,21 @@ export class KameletCard extends React.Component<Props, State> {
}
render() {
+ const kamelet = this.state.kamelet;
return (
- <Card isHoverable isCompact key={this.state.kamelet.metadata.name} className="kamelet-card"
+ <Card isHoverable isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false" src={this.state.kamelet.icon()} className="kamelet-icon" alt=""></img>
- <CardActions>
- <Badge className="badge" isRead> {this.state.kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- </CardActions>
+ <img draggable="false" src={kamelet.icon()} className="kamelet-icon" alt=""></img>
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(this.state.kamelet.metadata.name)}</CardTitle>
- <CardBody>{this.state.kamelet.spec.definition.description}</CardBody>
+ <CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
-
+ {/*<div style={{justifyContent: "space-between"}}>*/}
+ <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ {/*</div>*/}
</CardFooter>
</Card>
);
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-designer/src/kamelets/KameletModal.tsx
similarity index 98%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-designer/src/kamelets/KameletModal.tsx
index 3213a87..738c68a 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-designer/src/kamelets/KameletModal.tsx
@@ -57,7 +57,7 @@ export class KameletModal extends Component<Props, State> {
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-designer/src/kamelets/KameletsPage.tsx
similarity index 84%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-designer/src/kamelets/KameletsPage.tsx
index 6b2a251..a3e0cd4 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-designer/src/kamelets/KameletsPage.tsx
@@ -14,6 +14,7 @@ import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
interface Props {
+ dark: boolean
}
interface State {
@@ -53,14 +54,14 @@ export class KameletsPage extends React.Component<Props, State> {
render() {
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
<KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Kamelet Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,7 +79,7 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{this.state.kamelets.map(k => (
<KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
diff --git a/karavan-vscode/package-lock.json b/karavan-vscode/package-lock.json
index 15acf60..d5a82a7 100644
--- a/karavan-vscode/package-lock.json
+++ b/karavan-vscode/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "karavan",
- "version": "0.0.14",
+ "version": "0.0.15",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "karavan",
- "version": "0.0.14",
+ "version": "0.0.15",
"license": "Apache-2.0",
"dependencies": {
"@patternfly/patternfly": "4.171.1",
"@patternfly/react-core": "4.192.7",
+ "@patternfly/react-table": "^4.71.16",
"@reactour/tour": "^2.10.2",
"@types/js-yaml": "4.0.5",
"@types/uuid": "8.3.4",
@@ -56,7 +57,7 @@
}
},
"../karavan-core": {
- "version": "0.0.14",
+ "version": "0.0.15",
"license": "Apache-2.0",
"dependencies": {
"@types/js-yaml": "^4.0.5",
@@ -2058,23 +2059,58 @@
}
},
"node_modules/@patternfly/react-icons": {
- "version": "4.43.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.43.15.tgz",
- "integrity": "sha512-b1fcPpIsQVJBGG1onpNTDiGqVJ60BVNy3qvzUu4Ea+lOwP83oIlhODtS792wx1B284a4wxP3uMc6uXCfdULD/w==",
+ "version": "4.53.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.53.16.tgz",
+ "integrity": "sha512-QQOZwl9MR71uNaKUPKJUm2qjvol28evN7GgyiqGn7fr0p4FnPopm9F5GsnKMsE/764/HGwGLjYHulUo3Eb06dQ==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
}
},
"node_modules/@patternfly/react-styles": {
- "version": "4.42.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.42.15.tgz",
- "integrity": "sha512-7E6NmaB3b+OOAqIBlS7nJ74Plq+n76VVTH5zxCyUFkrbjo31TRArwLU2dlO/tZr77Z3MiUjGBcoLLEv0R6BZBg=="
+ "version": "4.52.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.52.16.tgz",
+ "integrity": "sha512-i/xj+r0qVlhSoxrFOePxXoC8BudDPsEma0qwP+3Ry4hSZhN6XhSRSqjA5xmaLkgbfWCAiT/+mR9ilCaguxoLTA=="
+ },
+ "node_modules/@patternfly/react-table": {
+ "version": "4.71.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.71.16.tgz",
+ "integrity": "sha512-HF//Sk1nnF7phAOjglC8zndRfJ3/3oe8Bkxbufhp3lSFdAyzjed6WBdV2dNIrsNj1UeO8MRSlYCbbDEZZlrO2A==",
+ "dependencies": {
+ "@patternfly/react-core": "^4.202.16",
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "lodash": "^4.17.19",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0"
+ }
+ },
+ "node_modules/@patternfly/react-table/node_modules/@patternfly/react-core": {
+ "version": "4.202.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.202.16.tgz",
+ "integrity": "sha512-yWDf0x+YFFVxm72RC/BUaSOn2UsIirT77qif6DfAWdSODhdxTfaLCeBZ08uWgxJ1YZNCrankj60va+G5L+LVrg==",
+ "dependencies": {
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "focus-trap": "6.2.2",
+ "react-dropzone": "9.0.0",
+ "tippy.js": "5.1.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0"
+ }
},
"node_modules/@patternfly/react-tokens": {
- "version": "4.44.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.44.15.tgz",
- "integrity": "sha512-Xp82baZURMISkvpNaWNu3w4cMfc2NIsDYh9K5QpVMQ94vphQrAd54UoO5NQI574+/QY2IPGKWadfvix8324J0Q=="
+ "version": "4.54.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.54.16.tgz",
+ "integrity": "sha512-BBVg40L4gx0Gew2kDdGNxP+EtDwGeBuJwXewKrTjXlCa4uhOOj7TqJ5rxhS4GULfYiYbUGdYe7UMFVb+mKDVVg=="
},
"node_modules/@react-aria/focus": {
"version": "3.5.0",
@@ -5691,6 +5727,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"node_modules/lodash.assignin": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
@@ -10065,20 +10106,49 @@
}
},
"@patternfly/react-icons": {
- "version": "4.43.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.43.15.tgz",
- "integrity": "sha512-b1fcPpIsQVJBGG1onpNTDiGqVJ60BVNy3qvzUu4Ea+lOwP83oIlhODtS792wx1B284a4wxP3uMc6uXCfdULD/w==",
+ "version": "4.53.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.53.16.tgz",
+ "integrity": "sha512-QQOZwl9MR71uNaKUPKJUm2qjvol28evN7GgyiqGn7fr0p4FnPopm9F5GsnKMsE/764/HGwGLjYHulUo3Eb06dQ==",
"requires": {}
},
"@patternfly/react-styles": {
- "version": "4.42.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.42.15.tgz",
- "integrity": "sha512-7E6NmaB3b+OOAqIBlS7nJ74Plq+n76VVTH5zxCyUFkrbjo31TRArwLU2dlO/tZr77Z3MiUjGBcoLLEv0R6BZBg=="
+ "version": "4.52.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.52.16.tgz",
+ "integrity": "sha512-i/xj+r0qVlhSoxrFOePxXoC8BudDPsEma0qwP+3Ry4hSZhN6XhSRSqjA5xmaLkgbfWCAiT/+mR9ilCaguxoLTA=="
+ },
+ "@patternfly/react-table": {
+ "version": "4.71.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.71.16.tgz",
+ "integrity": "sha512-HF//Sk1nnF7phAOjglC8zndRfJ3/3oe8Bkxbufhp3lSFdAyzjed6WBdV2dNIrsNj1UeO8MRSlYCbbDEZZlrO2A==",
+ "requires": {
+ "@patternfly/react-core": "^4.202.16",
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "lodash": "^4.17.19",
+ "tslib": "^2.0.0"
+ },
+ "dependencies": {
+ "@patternfly/react-core": {
+ "version": "4.202.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.202.16.tgz",
+ "integrity": "sha512-yWDf0x+YFFVxm72RC/BUaSOn2UsIirT77qif6DfAWdSODhdxTfaLCeBZ08uWgxJ1YZNCrankj60va+G5L+LVrg==",
+ "requires": {
+ "@patternfly/react-icons": "^4.53.16",
+ "@patternfly/react-styles": "^4.52.16",
+ "@patternfly/react-tokens": "^4.54.16",
+ "focus-trap": "6.2.2",
+ "react-dropzone": "9.0.0",
+ "tippy.js": "5.1.2",
+ "tslib": "^2.0.0"
+ }
+ }
+ }
},
"@patternfly/react-tokens": {
- "version": "4.44.15",
- "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.44.15.tgz",
- "integrity": "sha512-Xp82baZURMISkvpNaWNu3w4cMfc2NIsDYh9K5QpVMQ94vphQrAd54UoO5NQI574+/QY2IPGKWadfvix8324J0Q=="
+ "version": "4.54.16",
+ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.54.16.tgz",
+ "integrity": "sha512-BBVg40L4gx0Gew2kDdGNxP+EtDwGeBuJwXewKrTjXlCa4uhOOj7TqJ5rxhS4GULfYiYbUGdYe7UMFVb+mKDVVg=="
},
"@react-aria/focus": {
"version": "3.5.0",
@@ -12755,6 +12825,11 @@
"p-locate": "^5.0.0"
}
},
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"lodash.assignin": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 2dea45f..86eb137 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -47,7 +47,11 @@
"onCommand:karavan.open",
"onCommand:karavan.open-yaml",
"onCommand:karavan.jbang-run",
- "onView:integrations"
+ "onView:integrations",
+ "onCommand:karavan.openKamelets",
+ "onCommand:karavan.openComponents",
+ "onCommand:karavan.openEip",
+ "onCommand:karavan.reportIssue"
],
"main": "./dist/extension.js",
"contributes": {
@@ -144,28 +148,20 @@
}
},
{
- "command": "kamelets.refresh",
- "title": "Refresh",
- "icon": {
- "light": "icons/light/refresh.svg",
- "dark": "icons/dark/refresh.svg"
- }
+ "command": "karavan.openKamelets",
+ "title": "Open Kamelet Catalog"
},
{
- "command": "components.refresh",
- "title": "Refresh",
- "icon": {
- "light": "icons/light/refresh.svg",
- "dark": "icons/dark/refresh.svg"
- }
+ "command": "karavan.openComponents",
+ "title": "Open Component Catalog"
},
{
- "command": "eip.refresh",
- "title": "Refresh",
- "icon": {
- "light": "icons/light/refresh.svg",
- "dark": "icons/dark/refresh.svg"
- }
+ "command": "karavan.openEip",
+ "title": "Open EIP"
+ },
+ {
+ "command": "karavan.reportIssue",
+ "title": "Report Issue"
}
],
"menus": {
@@ -209,21 +205,6 @@
"command": "karavan.create-crd",
"when": "view == integrations",
"group": "navigation"
- },
- {
- "command": "kamelets.refresh",
- "when": "view == kamelets",
- "group": "navigation"
- },
- {
- "command": "components.refresh",
- "when": "view == components",
- "group": "navigation"
- },
- {
- "command": "eip.refresh",
- "when": "view == eip",
- "group": "navigation"
}
],
"view/item/context": [
@@ -257,22 +238,13 @@
"karavanView": [
{
"id": "integrations",
- "name": "Integrations"
- },
- {
- "id": "eip",
- "name": "Enterprise Integration Patterns",
- "visibility": "collapsed"
- },
- {
- "id": "kamelets",
- "name": "Kamelets",
- "visibility": "collapsed"
+ "name": "Integrations",
+ "visibility": "visible"
},
{
- "id": "components",
- "name": "Components",
- "visibility": "collapsed"
+ "id": "help",
+ "name": "Help & Feedback",
+ "visibility": "visible"
}
]
},
@@ -284,13 +256,14 @@
]
},
"scripts": {
- "vscode:prepublish": "cp -r ../karavan-designer/src/designer webview && npm 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",
+ "copy-designer": "cp -r ../karavan-designer/src/designer webview && cp -r ../karavan-designer/src/kamelets webview && cp -r ../karavan-designer/src/components webview && cp -r ../karavan-designer/src/eip webview",
+ "vscode:prepublish": "npm run copy-designer && npm run package",
+ "compile": "npm run copy-designer && cross-env NODE_ENV=development webpack --progress",
+ "watch": "npm run copy-designer && cross-env NODE_ENV=development webpack --progress --watch",
+ "package": "npm run copy-designer && cross-env NODE_ENV=production webpack --progress",
"test-compile": "tsc -p ./",
"test-watch": "tsc -watch -p ./",
- "pretest": "cp -r ../karavan-designer/src/designer webview && npm run test-compile && npm run lint",
+ "pretest": "npm run copy-designer && npm run test-compile && npm run lint",
"lint": "eslint src webview --ext .ts,.tsx",
"lint:fix": "eslint --fix src webview --ext .ts,.tsx",
"test": "node ./out/test/runTest.js"
@@ -328,6 +301,7 @@
"dependencies": {
"@patternfly/patternfly": "4.171.1",
"@patternfly/react-core": "4.192.7",
+ "@patternfly/react-table": "^4.71.16",
"@reactour/tour": "^2.10.2",
"@types/js-yaml": "4.0.5",
"@types/uuid": "8.3.4",
diff --git a/karavan-vscode/src/componentView.ts b/karavan-vscode/src/componentView.ts
deleted file mode 100644
index 1d45778..0000000
--- a/karavan-vscode/src/componentView.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 * as vscode from "vscode";
-import * as path from "path";
-import * as utils from "./utils";
-import * as fs from "fs";
-import { ComponentApi } from "karavan-core/lib/api/ComponentApi";
-import { Component } from "karavan-core/lib/model/ComponentModels";
-import { ThemeIcon } from "vscode";
-
-export class ComponentView implements vscode.TreeDataProvider<ComponentItem> {
-
- constructor(private context: vscode.ExtensionContext, private rootPath: string | undefined) {
-
- }
- private _onDidChangeTreeData: vscode.EventEmitter<ComponentItem | undefined | void> = new vscode.EventEmitter<ComponentItem | undefined | void>();
- readonly onDidChangeTreeData: vscode.Event<ComponentItem | undefined | void> = this._onDidChangeTreeData.event;
-
- getTreeItem(element: ComponentItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
- return element;
- }
- getChildren(element?: ComponentItem): vscode.ProviderResult<ComponentItem[]> {
- const kamelets: ComponentItem[] = [];
- if (this.rootPath){
- utils.readComponents(this.context).forEach(s => {
- const c:Component = ComponentApi.jsonToComponent(s);
- if (!c.component.deprecated)
- kamelets.push(new ComponentItem(c.component.title, c.component.description, c.component.label));
- })
- }
- return Promise.resolve(kamelets);
- }
-
- refresh(): void {
- this._onDidChangeTreeData.fire();
- }
-}
-
-export class ComponentItem extends vscode.TreeItem {
-
- constructor(
- public readonly title: string,
- public readonly description: string,
- private readonly type: string,
- public readonly command?: vscode.Command
- ) {
- super(title, vscode.TreeItemCollapsibleState.None);
-
- this.tooltip = this.description;
- this.description = this.type;
- }
-
- iconPath = ThemeIcon.File;
-
- contextValue = 'component';
-}
\ No newline at end of file
diff --git a/karavan-vscode/src/designerView.ts b/karavan-vscode/src/designerView.ts
index 0fe96d2..12feb95 100644
--- a/karavan-vscode/src/designerView.ts
+++ b/karavan-vscode/src/designerView.ts
@@ -165,7 +165,7 @@ export class DesignerView {
}
// Send integration
- panel.webview.postMessage({ command: 'open', filename: filename, relativePath: relativePath, yaml: yaml });
+ panel.webview.postMessage({ command: 'open', page: "designer", filename: filename, relativePath: relativePath, yaml: yaml });
}
diff --git a/karavan-vscode/src/eipView.ts b/karavan-vscode/src/eipView.ts
deleted file mode 100644
index 380c4e3..0000000
--- a/karavan-vscode/src/eipView.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 * as vscode from "vscode";
-import * as utils from "./utils";
-import { CamelModelMetadata, ElementMeta } from "karavan-core/lib/model/CamelMetadata";
-import { ThemeIcon } from "vscode";
-
-export class EipView implements vscode.TreeDataProvider<EipItem> {
-
- constructor(private context: vscode.ExtensionContext, private rootPath: string | undefined) {
-
- }
- private _onDidChangeTreeData: vscode.EventEmitter<EipItem | undefined | void> = new vscode.EventEmitter<EipItem | undefined | void>();
- readonly onDidChangeTreeData: vscode.Event<EipItem | undefined | void> = this._onDidChangeTreeData.event;
-
- getTreeItem(element: EipItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
- return element;
- }
- getChildren(element?: EipItem): vscode.ProviderResult<EipItem[]> {
- const kamelets: EipItem[] = [];
- if (this.rootPath){
- CamelModelMetadata.sort((a, b) => {
- if (a.title.toLowerCase() < b.title.toLowerCase()) {
- return -1;
- }
- return a.title.toLowerCase() > b.title.toLowerCase() ? 1 : 0;
- }).forEach((e:ElementMeta) => {
- kamelets.push(new EipItem(e.title, e.description, e.labels));
- })
- }
- return Promise.resolve(kamelets);
- }
-
- refresh(): void {
- this._onDidChangeTreeData.fire();
- }
-}
-
-export class EipItem extends vscode.TreeItem {
-
- constructor(
- public readonly title: string,
- public readonly description: string,
- private readonly type: string,
- public readonly command?: vscode.Command
- ) {
- super(title, vscode.TreeItemCollapsibleState.None);
-
- this.tooltip = this.description;
- this.description = this.type;
- }
-
- iconPath = ThemeIcon.File;
-
- contextValue = 'eip';
-}
\ No newline at end of file
diff --git a/karavan-vscode/src/extension.ts b/karavan-vscode/src/extension.ts
index b1a73bc..a871147 100644
--- a/karavan-vscode/src/extension.ts
+++ b/karavan-vscode/src/extension.ts
@@ -18,9 +18,7 @@ import * as vscode from "vscode";
import * as fs from "fs";
import { DesignerView } from "./designerView";
import {IntegrationView} from "./integrationView";
-import { KameletView } from "./kameletView";
-import { ComponentView } from "./componentView";
-import { EipView } from "./eipView";
+import { HelpView } from "./helpView";
const KARAVAN_LOADED = "karavan:loaded";
@@ -80,19 +78,15 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.registerTreeDataProvider('integrations', integrationView);
vscode.commands.registerCommand('integrations.refresh', () => integrationView.refresh());
- const kameletView = new KameletView(context, rootPath);
- vscode.window.registerTreeDataProvider('kamelets', kameletView);
- vscode.commands.registerCommand('kamelets.refresh', () => kameletView.refresh());
+ const helpView = new HelpView(context, webviewContent);
+ vscode.window.registerTreeDataProvider('help', helpView);
+ vscode.commands.registerCommand('karavan.openKamelets', () => helpView.openKaravanWebView("kamelets"));
+ vscode.commands.registerCommand('karavan.openComponents', () => helpView.openKaravanWebView("components"));
+ vscode.commands.registerCommand('karavan.openEip', () => helpView.openKaravanWebView("eip"));
- const componentView = new ComponentView(context, rootPath);
- vscode.window.registerTreeDataProvider('components', componentView);
- vscode.commands.registerCommand('components.refresh', () => componentView.refresh());
-
- const eipView = new EipView(context, rootPath);
- vscode.window.registerTreeDataProvider('eip', eipView);
- vscode.commands.registerCommand('eip.refresh', () => eipView.refresh());
-
- // vscode.commands.onDidChangeActiveView
+ vscode.commands.registerCommand('karavan.reportIssue', () => {
+ vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://github.com/apache/camel-karavan/issues/new?title=[VS+Code]New+report&template=issue_template.md'));
+ });
}
export function deactivate() {
diff --git a/karavan-vscode/src/helpView.ts b/karavan-vscode/src/helpView.ts
new file mode 100644
index 0000000..4bf321b
--- /dev/null
+++ b/karavan-vscode/src/helpView.ts
@@ -0,0 +1,126 @@
+/*
+ * 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 * as vscode from "vscode";
+import * as utils from "./utils";
+import { ThemeIcon } from "vscode";
+
+const KARAVAN_PANELS: Map<string, vscode.WebviewPanel> = new Map<string, vscode.WebviewPanel>();
+
+export class HelpView implements vscode.TreeDataProvider<HelpItem> {
+
+ constructor(private context: vscode.ExtensionContext, private webviewContent: string) {
+
+ }
+ private _onDidChangeTreeData: vscode.EventEmitter<HelpItem | undefined | void> = new vscode.EventEmitter<HelpItem | undefined | void>();
+ readonly onDidChangeTreeData: vscode.Event<HelpItem | undefined | void> = this._onDidChangeTreeData.event;
+
+ getTreeItem(element: HelpItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
+ return element;
+ }
+ getChildren(element?: HelpItem): vscode.ProviderResult<HelpItem[]> {
+ const helpItems: HelpItem[] = [];
+ helpItems.push(new HelpItem("Enterprise Integration Patterns", "Enterprise Integration Patterns", "eip", 'combine', { command: 'karavan.openEip' , title: ''}));
+ helpItems.push(new HelpItem("Kamelet catalog", "Kamelet Catalog", "kamelets", 'extensions', { command: 'karavan.openKamelets', title: '' }));
+ helpItems.push(new HelpItem("Component catalog", "Component Catalog", "component", 'extensions', { command: 'karavan.openComponents', title: '' }));
+ helpItems.push(new HelpItem("Report issue", "Report Issue", "issue", 'comment', { command: 'karavan.reportIssue' , title: ''}));
+ return Promise.resolve(helpItems);
+ }
+
+ refresh(): void {
+ this._onDidChangeTreeData.fire();
+ }
+
+ openKaravanWebView(page: string) {
+ if (!KARAVAN_PANELS.has(page)) {
+ // Karavan webview
+ const panel = vscode.window.createWebviewPanel(
+ "karavan",
+ page.toUpperCase(),
+ vscode.ViewColumn.One,
+ {
+ enableScripts: true,
+ retainContextWhenHidden: true,
+ localResourceRoots: [
+ vscode.Uri.joinPath(this.context.extensionUri, "dist"),
+ ],
+ }
+ );
+ panel.webview.html = this.webviewContent;
+ panel.iconPath = vscode.Uri.joinPath(
+ this.context.extensionUri,
+ "icons/karavan.svg"
+ );
+
+ // Handle messages from the webview
+ panel.webview.onDidReceiveMessage(
+ message => {
+ switch (message.command) {
+ case 'getData':
+ this.sendData(panel, page);
+ break;
+ }
+ },
+ undefined,
+ this.context.subscriptions
+ );
+ // Handle close event
+ panel.onDidDispose(() => {
+ KARAVAN_PANELS.delete(page);
+ }, null, this.context.subscriptions);
+
+ // Handle reopen
+ panel.onDidChangeViewState((e: vscode.WebviewPanelOnDidChangeViewStateEvent) => {
+ if (e.webviewPanel.active) {
+ e.webviewPanel.webview.postMessage({ command: 'reread' })
+ }
+ });
+
+ KARAVAN_PANELS.set(page, panel);
+ } else {
+ KARAVAN_PANELS.get(page)?.reveal(undefined, true);
+ }
+ }
+
+ sendData(panel: vscode.WebviewPanel, page: string) {
+ // Read and send Kamelets
+ if (page === 'kamelets') panel.webview.postMessage({ command: 'kamelets', kamelets: utils.readKamelets(this.context) });
+
+ // Read and send Components
+ if (page === 'components') panel.webview.postMessage({ command: 'components', components: utils.readComponents(this.context) });
+
+ // Send integration
+ panel.webview.postMessage({ command: 'open', page: page });
+ }
+}
+
+export class HelpItem extends vscode.TreeItem {
+
+ constructor(
+ public readonly title: string,
+ public readonly tooltip: string,
+ public readonly page: string,
+ public readonly icon: string,
+ public readonly command?: vscode.Command
+ ) {
+ super(title, vscode.TreeItemCollapsibleState.None);
+ this.tooltip = this.tooltip;
+ }
+
+ iconPath = new ThemeIcon(this.icon);
+
+ contextValue = 'help';
+}
\ No newline at end of file
diff --git a/karavan-vscode/src/kameletView.ts b/karavan-vscode/src/kameletView.ts
deleted file mode 100644
index c1e3ab6..0000000
--- a/karavan-vscode/src/kameletView.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 * as vscode from "vscode";
-import * as path from "path";
-import * as utils from "./utils";
-import * as fs from "fs";
-import { KameletApi } from "karavan-core/lib/api/KameletApi";
-import { KameletModel } from "karavan-core/lib/model/KameletModels";
-import { ThemeIcon } from "vscode";
-
-export class KameletView implements vscode.TreeDataProvider<KameletItem> {
-
- constructor(private context: vscode.ExtensionContext, private rootPath: string | undefined) {
-
- }
- private _onDidChangeTreeData: vscode.EventEmitter<KameletItem | undefined | void> = new vscode.EventEmitter<KameletItem | undefined | void>();
- readonly onDidChangeTreeData: vscode.Event<KameletItem | undefined | void> = this._onDidChangeTreeData.event;
-
- getTreeItem(element: KameletItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
- return element;
- }
- getChildren(element?: KameletItem): vscode.ProviderResult<KameletItem[]> {
- const kamelets: KameletItem[] = [];
- if (this.rootPath){
- utils.readKamelets(this.context).forEach(s => {
- const k:KameletModel = KameletApi.yamlToKamelet(s);
- kamelets.push(new KameletItem(k.spec.definition.title, k.spec.definition.description, k.type()));
- })
- }
- return Promise.resolve(kamelets);
- }
-
- refresh(): void {
- this._onDidChangeTreeData.fire();
- }
-}
-
-export class KameletItem extends vscode.TreeItem {
-
- constructor(
- public readonly title: string,
- public readonly description: string,
- private readonly type: string,
- public readonly command?: vscode.Command
- ) {
- super(title, vscode.TreeItemCollapsibleState.None);
-
- this.tooltip = this.description;
- this.description = this.type;
- }
-
- iconPath = ThemeIcon.File;
-
- contextValue = 'kamelet';
-}
\ No newline at end of file
diff --git a/karavan-vscode/src/utils.ts b/karavan-vscode/src/utils.ts
index fb83026..f6649fe 100644
--- a/karavan-vscode/src/utils.ts
+++ b/karavan-vscode/src/utils.ts
@@ -68,11 +68,8 @@ export function parceYaml(filename: string, yaml: string): [boolean, string?] {
}
export function disableStartHelp(){
- console.log("!!!! 3");
const config = vscode.workspace.getConfiguration();
- console.log(config);
config.update("Karavan.showStartHelp", false);
- console.log("!!!! 4", vscode.workspace.getConfiguration().get("Karavan.showStartHelp"));
}
export function runCamelJbang(filename: string) {
diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx
index 2ccb61e..7d070c0 100644
--- a/karavan-vscode/webview/App.tsx
+++ b/karavan-vscode/webview/App.tsx
@@ -22,6 +22,9 @@ 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";
+import { KameletsPage } from "./kamelets/KameletsPage";
+import { ComponentsPage } from "./components/ComponentsPage";
+import { EipPage } from "./eip/EipPage";
interface Props {
dark: boolean
@@ -37,6 +40,7 @@ interface State {
scheduledYaml: string
hasChanges: boolean
showStartHelp: boolean
+ page: "designer" | "kamelets" | "components" | "eip";
}
class App extends React.Component<Props, State> {
@@ -49,7 +53,8 @@ class App extends React.Component<Props, State> {
loaded: false,
scheduledYaml: '',
hasChanges: false,
- showStartHelp: false
+ showStartHelp: false,
+ page: "designer"
};
saveScheduledChanges = () => {
@@ -73,19 +78,27 @@ class App extends React.Component<Props, State> {
const message = event.data;
switch (message.command) {
case 'kamelets':
- KameletApi.saveKamelets(message.kamelets);
+ KameletApi.saveKamelets(message.kamelets, true);
break;
case 'components':
- ComponentApi.saveComponents(message.components);
+ ComponentApi.saveComponents(message.components, true);
break;
case 'showStartHelp':
this.setState({showStartHelp: message.showStartHelp});
break;
case 'open':
if (this.state.filename === '' && this.state.key === '') {
- this.setState({ filename: message.filename, yaml: message.yaml, scheduledYaml: message.yaml, relativePath: message.relativePath, key: Math.random().toString(), loaded: true });
+ this.setState({
+ page: message.page,
+ filename: message.filename,
+ yaml: message.yaml,
+ scheduledYaml: message.yaml,
+ relativePath: message.relativePath,
+ key: Math.random().toString(),
+ loaded: true
+ });
}
- break;
+ break;
case 'reread':
this.setState({ loaded: false, filename: '', key: '' });
vscode.postMessage({ command: 'getData', reread: true});
@@ -114,7 +127,7 @@ class App extends React.Component<Props, State> {
<Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>
</PageSection>
}
- {this.state.loaded &&
+ {this.state.loaded && this.state.page === "designer" &&
<KaravanDesigner
showStartHelp={this.state.showStartHelp}
key={this.state.key}
@@ -124,6 +137,9 @@ class App extends React.Component<Props, State> {
onDisableHelp={this.disableStartHelp}
dark={this.props.dark} />
}
+ {this.state.loaded && this.state.page === "kamelets" && <KameletsPage dark={this.props.dark}/>}
+ {this.state.loaded && this.state.page === "components" && <ComponentsPage dark={this.props.dark}/>}
+ {this.state.loaded && this.state.page === "eip" && <EipPage dark={this.props.dark}/>}
</Page>
)
}
diff --git a/karavan-vscode/webview/components/ComponentCard.tsx b/karavan-vscode/webview/components/ComponentCard.tsx
new file mode 100644
index 0000000..e1adb01
--- /dev/null
+++ b/karavan-vscode/webview/components/ComponentCard.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardActions, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+
+interface Props {
+ component: Component,
+ onClickCard: any
+}
+
+interface State {
+ component: Component,
+}
+
+export class ComponentCard extends React.Component<Props, State> {
+
+ public state: State = {
+ component: this.props.component
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.component);
+ }
+
+ render() {
+ const component = this.state.component;
+ return (
+ <Card isHoverable isCompact key={component.component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardBody>{component.component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.component.label}</Badge>
+ <Badge isRead className="version">{component.component.version}</Badge>
+ </CardFooter>
+ </Card>
+ );
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-vscode/webview/components/ComponentModal.tsx
similarity index 51%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-vscode/webview/components/ComponentModal.tsx
index 3213a87..25e72cc 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-vscode/webview/components/ComponentModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,27 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {camelIcon} from "../designer/utils/CamelUi";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {ComponentProperty} from "karavan-core/src/core/model/ComponentModels";
interface Props {
- kamelet?: KameletModel,
+ component?: Component,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ component?: Component,
}
-export class KameletModal extends Component<Props, State> {
+export class ComponentModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ component: this.props.component,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +42,67 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.component;
+ const props = new Map<string, ComponentProperty>();
+ if (component){
+ ComponentApi.getComponentProperties(component?.component.name, "consumer").forEach(cp => props.set(cp.name, cp));
+ ComponentApi.getComponentProperties(component?.component.name, "producer").forEach(cp => props.set(cp.name, cp));
+ }
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.component.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.component.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={camelIcon} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.component.label}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.component.description}</Text>
+ {props.size !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {Array.from(props.values()).map((p: ComponentProperty, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +111,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-vscode/webview/components/ComponentsPage.tsx
similarity index 54%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-vscode/webview/components/ComponentsPage.tsx
index 6b2a251..203a789 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-vscode/webview/components/ComponentsPage.tsx
@@ -8,59 +8,62 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {ComponentCard} from "./ComponentCard";
+import {ComponentModal} from "./ComponentModal";
+import {Component} from "karavan-core/lib/model/ComponentModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ component?: Component;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ components: Component[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class ComponentsPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ components: [],
filter: ''
};
componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
+ this.setState({components: ComponentApi.getComponents()})
}
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (c: Component)=> {
+ this.setState({component: c, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ components: ComponentApi.getComponents().filter(c => c.component.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const component = this.state.component;
+ const components = this.state.components;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <ComponentModal key={component?.component.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} component={component}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Component Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +81,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {components.map(c => (
+ <ComponentCard key={c.component.name} component={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-vscode/webview/eip/EipCard.tsx b/karavan-vscode/webview/eip/EipCard.tsx
new file mode 100644
index 0000000..34d745e
--- /dev/null
+++ b/karavan-vscode/webview/eip/EipCard.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import {
+ CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
+
+interface Props {
+ element: ElementMeta,
+ onClickCard: any
+}
+
+interface State {
+ element: ElementMeta,
+}
+
+export class EipCard extends React.Component<Props, State> {
+
+ public state: State = {
+ element: this.props.element
+ };
+
+ click = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ this.props.onClickCard.call(this, this.state.element);
+ }
+
+ render() {
+ const component = this.state.element;
+ return (
+ <Card isHoverable isCompact key={component.name} className="kamelet-card"
+ onClick={event => this.click(event)}
+ >
+ <CardHeader>
+ <img draggable="false" src={CamelUi.getIconForName(component.className)} className="kamelet-icon" alt=""></img>
+ </CardHeader>
+ <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardBody>{component.description}</CardBody>
+ <CardFooter>
+ <Badge isRead className="labels">{component.labels}</Badge>
+ </CardFooter>
+ </Card>
+ )
+ }
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-vscode/webview/eip/EipModal.tsx
similarity index 57%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-vscode/webview/eip/EipModal.tsx
index 3213a87..ea5e325 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-vscode/webview/eip/EipModal.tsx
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React from 'react';
import {
Button,
Modal,
@@ -9,24 +9,25 @@ import {
Badge, Flex, CardTitle,
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {CamelUi} from "../designer/utils/CamelUi";
+import {ElementMeta, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
- kamelet?: KameletModel,
+ element?: ElementMeta,
isOpen: boolean;
}
interface State {
isOpen: boolean;
- kamelet?: KameletModel,
+ element?: ElementMeta,
}
-export class KameletModal extends Component<Props, State> {
+export class EipModal extends React.Component<Props, State> {
public state: State = {
isOpen: this.props.isOpen,
- kamelet: this.props.kamelet,
+ element: this.props.element,
};
setModalOpen = (open: boolean) => {
@@ -39,61 +40,62 @@ export class KameletModal extends Component<Props, State> {
}
}
- getKameletProperties = (properties: any): any[] => {
- return properties
- ? Array.from(new Map(Object.entries(properties)), ([name, value]) => (value))
- : [];
- }
-
render() {
+ const component = this.state.element;
return (
<Modal
aria-label={"Kamelet"}
width={'fit-content'}
maxLength={200}
- title={this.state.kamelet?.spec.definition.title}
+ title={component?.title}
isOpen={this.state.isOpen}
onClose={() => this.setModalOpen(false)}
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
]}
>
- <Flex direction={{default: 'column'}} key={this.state.kamelet?.metadata.name}
+ <Flex direction={{default: 'column'}} key={component?.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ <img draggable="false" src={CamelUi.getIconForName(component?.name || '')} className="kamelet-icon" alt=""></img>
<CardActions>
<Badge className="badge"
- isRead> {this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ isRead> {component?.labels}</Badge>
</CardActions>
</CardHeader>
- <Text className="description">{this.state.kamelet?.spec.definition.description}</Text>
- {this.state.kamelet?.spec.definition.properties && this.state.kamelet?.spec.definition.properties.length !== 0 &&
+ <Text className="description">{component?.description}</Text>
+ {component?.properties.length !== 0 &&
<div>
<CardTitle>Properties</CardTitle>
<TableComposable aria-label="Simple table" variant='compact'>
<Thead>
<Tr>
- <Th key='title'>Title</Th>
- <Th key='type'>Type</Th>
+ <Th key='name'>Display Name / Name</Th>
<Th key='desc'>Description</Th>
- <Th key='format'>Format</Th>
- <Th key='example'>Example</Th>
+ <Th key='type'>Type</Th>
+ <Th key='label'>Label</Th>
</Tr>
</Thead>
<Tbody>
- {this.getKameletProperties(this.state.kamelet?.spec.definition.properties).map((p: Property, idx: number) => (
+ {component?.properties.map((p: PropertyMeta, idx: number) => (
<Tr key={idx}>
- <Td key={`${idx}_title`}>{p.title}</Td>
+ <Td key={`${idx}_name`}>
+ <div>
+ <b>{p.displayName}</b>
+ <div>{p.name}</div>
+ </div>
+ </Td>
+ <Td key={`${idx}_desc`}><div>
+ <div>{p.description}</div>
+ {p.defaultValue && p.defaultValue.toString().length > 0 && <div>{"Default value: " + p.defaultValue}</div>}
+ </div></Td>
<Td key={`${idx}_type`}>{p.type}</Td>
- <Td key={`${idx}_desc`}>{p.description}</Td>
- <Td key={`${idx}_format`}>{p.format}</Td>
- <Td key={`${idx}_example`}>{p.example}</Td>
+ <Td key={`${idx}_label`}>{p.label}</Td>
</Tr>
))}
</Tbody>
@@ -102,6 +104,6 @@ export class KameletModal extends Component<Props, State> {
}
</Flex>
</Modal>
- );
+ )
}
}
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-vscode/webview/eip/EipPage.tsx
similarity index 56%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-vscode/webview/eip/EipPage.tsx
index 6b2a251..fe5fa2f 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-vscode/webview/eip/EipPage.tsx
@@ -8,59 +8,57 @@ import {
PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
-import {KameletCard} from "./KameletCard";
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {KameletModal} from "./KameletModal";
+import {EipCard} from "./EipCard";
+import {EipModal} from "./EipModal";
+import {CamelModelMetadata, ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
+ dark: boolean
}
interface State {
- kamelet?: KameletModel;
+ element?: ElementMeta;
isModalOpen: boolean;
repository: string,
path: string,
- kamelets: KameletModel[],
+ elements: ElementMeta[],
filter: string
}
-export class KameletsPage extends React.Component<Props, State> {
+export class EipPage extends React.Component<Props, State> {
public state: State = {
isModalOpen: false,
repository: '',
path: '',
- kamelets: [],
+ elements: CamelModelMetadata.sort((a: ElementMeta,b: ElementMeta) => a.name > b.name ? 1 : -1),
filter: ''
};
- componentDidMount() {
- this.setState({kamelets: KameletApi.getKamelets()})
- }
-
- select = (k: KameletModel)=> {
- this.setState({kamelet: k, isModalOpen: true})
+ select = (e: ElementMeta)=> {
+ this.setState({element: e, isModalOpen: true})
}
search(filter: string){
this.setState({
filter: filter,
isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
+ elements: CamelModelMetadata.filter(c => c.name.toLowerCase().includes(filter.toLowerCase()))
})
}
render() {
+ const element = this.state.element;
+ const elements = this.state.elements;
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
+ <EipModal key={element?.name + this.state.isModalOpen.toString()}
+ isOpen={this.state.isModalOpen} element={element}/>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Enterprise Integration Patterns</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,10 +76,10 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
+ {elements.map(c => (
+ <EipCard key={c.name} element={c} onClickCard={this.select}/>
))}
</Gallery>
</PageSection>
diff --git a/karavan-vscode/webview/index.css b/karavan-vscode/webview/index.css
index aff3a4b..bfe00cc 100644
--- a/karavan-vscode/webview/index.css
+++ b/karavan-vscode/webview/index.css
@@ -291,3 +291,41 @@ body, :root, #root, .karavan {
.vscode-dark .reactour__mask {
color: var(--vscode-input-placeholderForeground);
}
+
+
+/* Kamelets page */
+
+.vscode-dark .karavan .kamelet-section,
+.vscode-dark .karavan .tools-section,
+.vscode-dark .karavan .tools-section .pf-c-toolbar,
+.vscode-dark .karavan .kamelets-page {
+ background-color: transparent;
+ border: none;
+}
+
+.vscode-dark .karavan .tools-section h1 {
+color: var(--vscode-editor-foreground);
+}
+
+.vscode-dark .karavan .kamelets-page .kamelet-card {
+ background-color: var(--vscode-badge-background);
+}
+
+.vscode-dark .karavan .tools-section .text-field {
+ background-color: var(--vscode-editor-background);
+ border-color: var(--vscode-input-foreground);
+ color: var(--vscode-input-foreground);
+}
+
+.vscode-dark .kamelet-modal-card .pf-c-table {
+ background-color: transparent;
+ color: var(--vscode-input-foreground);
+}
+
+.vscode-dark .pf-c-table {
+ --pf-c-table--cell--Color: var(--vscode-input-foreground);
+ color: var(--vscode-input-foreground);
+}
+
+
+
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx b/karavan-vscode/webview/kamelets/KameletCard.tsx
similarity index 54%
copy from karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
copy to karavan-vscode/webview/kamelets/KameletCard.tsx
index 8a9cd75..8e05901 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
+++ b/karavan-vscode/webview/kamelets/KameletCard.tsx
@@ -27,20 +27,21 @@ export class KameletCard extends React.Component<Props, State> {
}
render() {
+ const kamelet = this.state.kamelet;
return (
- <Card isHoverable isCompact key={this.state.kamelet.metadata.name} className="kamelet-card"
+ <Card isHoverable isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false" src={this.state.kamelet.icon()} className="kamelet-icon" alt=""></img>
- <CardActions>
- <Badge className="badge" isRead> {this.state.kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- </CardActions>
+ <img draggable="false" src={kamelet.icon()} className="kamelet-icon" alt=""></img>
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(this.state.kamelet.metadata.name)}</CardTitle>
- <CardBody>{this.state.kamelet.spec.definition.description}</CardBody>
+ <CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
-
+ {/*<div style={{justifyContent: "space-between"}}>*/}
+ <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ {/*</div>*/}
</CardFooter>
</Card>
);
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx b/karavan-vscode/webview/kamelets/KameletModal.tsx
similarity index 98%
copy from karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
copy to karavan-vscode/webview/kamelets/KameletModal.tsx
index 3213a87..738c68a 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletModal.tsx
+++ b/karavan-vscode/webview/kamelets/KameletModal.tsx
@@ -57,7 +57,7 @@ export class KameletModal extends Component<Props, State> {
actions={[
<div className="modal-footer">
<ActionGroup className="deploy-buttons">
- <Button key="cancel" variant="secondary"
+ <Button key="cancel" variant="primary"
onClick={e => this.setModalOpen(false)}>Close</Button>
</ActionGroup>
</div>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx b/karavan-vscode/webview/kamelets/KameletsPage.tsx
similarity index 84%
copy from karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
copy to karavan-vscode/webview/kamelets/KameletsPage.tsx
index 6b2a251..a3e0cd4 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletsPage.tsx
+++ b/karavan-vscode/webview/kamelets/KameletsPage.tsx
@@ -14,6 +14,7 @@ import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
interface Props {
+ dark: boolean
}
interface State {
@@ -53,14 +54,14 @@ export class KameletsPage extends React.Component<Props, State> {
render() {
return (
- <PageSection padding={{ default: 'noPadding' }} className="kamelet-section">
+ <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} padding={{ default: 'noPadding' }} className="kamelet-section">
<KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
- <PageSection className="tools-section" variant={PageSectionVariants.light}>
+ <PageSection className="tools-section" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent>
- <Text component="h1">Kamelets</Text>
+ <Text component="h1">Kamelet Catalog</Text>
</TextContent>
</FlexItem>
<FlexItem>
@@ -78,7 +79,7 @@ export class KameletsPage extends React.Component<Props, State> {
</FlexItem>
</Flex>
</PageSection>
- <PageSection isFilled className="kamelets-page">
+ <PageSection isFilled className="kamelets-page" variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{this.state.kamelets.map(k => (
<KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>