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 a86356a8 Change for the issue - #979, to configure allowed components
and kamelets (#1113)
a86356a8 is described below
commit a86356a84b6c003927778297483180bcd82ea429
Author: Vidhya Sagar <[email protected]>
AuthorDate: Tue Feb 20 05:32:50 2024 +0800
Change for the issue - #979, to configure allowed components and kamelets
(#1113)
* fix#979 - implementation of blocked components and kamelets
* fix#979 -removed debugger
* Block list save in file implemented
* removed space changes by format.
* space changes reverted
* infinispan spaces reverted
* Vs code changes to save blocked lists in file .
* review comments fixed in designer and space
* block lists moved to settings folder
---------
Co-authored-by: induja <[email protected]>
---
karavan-core/src/core/api/ComponentApi.ts | 25 ++++++++++++-
karavan-core/src/core/api/KameletApi.ts | 22 +++++++++++-
karavan-designer/src/App.tsx | 21 +++++++----
karavan-designer/src/KnowledgebaseHome.tsx | 23 ++++++++++++
karavan-designer/src/designer/karavan.css | 9 +++--
.../src/designer/route/DslSelector.tsx | 9 ++++-
.../src/knowledgebase/KnowledgebasePage.tsx | 5 +--
.../src/knowledgebase/components/ComponentCard.tsx | 28 +++++++++++----
.../src/knowledgebase/components/ComponentsTab.tsx | 3 +-
.../src/knowledgebase/kamelets/KameletCard.tsx | 26 ++++++++++----
.../src/knowledgebase/kamelets/KameletsTab.tsx | 8 ++---
karavan-space/src/App.tsx | 22 ++++++++++--
karavan-space/src/designer/karavan.css | 11 +++++-
karavan-space/src/designer/route/DslSelector.tsx | 9 ++++-
.../src/knowledgebase/KnowledgebasePage.tsx | 5 +--
.../src/knowledgebase/components/ComponentCard.tsx | 28 +++++++++++----
.../src/knowledgebase/components/ComponentsTab.tsx | 3 +-
.../src/knowledgebase/kamelets/KameletCard.tsx | 26 ++++++++++----
.../src/knowledgebase/kamelets/KameletsTab.tsx | 8 ++---
karavan-vscode/package.json | 13 +++++--
karavan-vscode/settings/components-blocklist.txt | 0
karavan-vscode/settings/kamelets-blocklist.txt | 0
karavan-vscode/src/designerView.ts | 4 +++
karavan-vscode/src/helpView.ts | 9 ++++-
karavan-vscode/src/utils.ts | 25 ++++++++++++-
karavan-vscode/webview/App.tsx | 27 +++++++++++++-
.../camel/karavan/api/ComponentResources.java | 2 +-
.../org/apache/camel/karavan/code/CodeService.java | 2 ++
.../resources/snippets/components-blocklist.txt | 0
.../main/resources/snippets/kamelets-blocklist.txt | 0
.../src/main/webui/src/api/ProjectService.ts | 17 +++++++--
.../src/main/webui/src/designer/karavan.css | 11 +++++-
.../main/webui/src/designer/route/DslSelector.tsx | 9 ++++-
.../webui/src/knowledgebase/KnowledgebaseHome.tsx | 41 ++++++++++++++++++++++
.../webui/src/knowledgebase/KnowledgebasePage.tsx | 5 +--
.../src/knowledgebase/components/ComponentCard.tsx | 28 +++++++++++----
.../src/knowledgebase/components/ComponentsTab.tsx | 3 +-
.../src/knowledgebase/kamelets/KameletCard.tsx | 26 ++++++++++----
.../src/knowledgebase/kamelets/KameletsTab.tsx | 8 ++---
.../src/main/webui/src/main/MainRoutes.tsx | 4 +--
.../src/main/webui/src/main/useMainHook.tsx | 4 ++-
41 files changed, 434 insertions(+), 95 deletions(-)
diff --git a/karavan-core/src/core/api/ComponentApi.ts
b/karavan-core/src/core/api/ComponentApi.ts
index da9b9be1..3a390c6c 100644
--- a/karavan-core/src/core/api/ComponentApi.ts
+++ b/karavan-core/src/core/api/ComponentApi.ts
@@ -20,7 +20,7 @@ import { CamelElement } from '../model/IntegrationDefinition';
const Components: Component[] = [];
const SupportedComponents: SupportedComponent[] = [];
let SupportedOnly: boolean = false;
-
+const BlockedComponents: string[] = [];
export class ComponentApi {
private constructor() {}
@@ -339,4 +339,27 @@ export class ComponentApi {
}
return Array.from(new Map(properties.map(item => [item.name,
item])).values());
};
+
+
+ static saveBlockedComponentNames = (componentNames: string[]) => {
+ BlockedComponents.length = 0;
+ BlockedComponents.push(...componentNames);
+ }
+
+
+ static saveBlockedComponentName = (componentName: string, checked
:boolean) => {
+ const index = BlockedComponents.indexOf(componentName);
+ if (!checked && index === -1) {
+ BlockedComponents.push(componentName);
+ }
+ else if (checked && index > -1) {
+ BlockedComponents.splice(index, 1);
+ }
+ return BlockedComponents;
+ }
+
+
+ static getBlockedComponentNames = () => {
+ return BlockedComponents;
+ }
}
diff --git a/karavan-core/src/core/api/KameletApi.ts
b/karavan-core/src/core/api/KameletApi.ts
index 62ecb4f2..acccea33 100644
--- a/karavan-core/src/core/api/KameletApi.ts
+++ b/karavan-core/src/core/api/KameletApi.ts
@@ -19,7 +19,7 @@ import * as yaml from 'js-yaml';
const Kamelets: KameletModel[] = [];
const CustomNames: string[] = [];
-
+const BlockedKamelets: string[] = [];
export class KameletApi {
private constructor() {}
@@ -99,4 +99,24 @@ export class KameletApi {
Kamelets.push(kamelet);
}
};
+
+ static saveBlockedKameletNames = (names: string[]): void => {
+ BlockedKamelets.length = 0;
+ BlockedKamelets.push(...names);
+ }
+
+ static saveBlockedKameletName = (name: string, checked: boolean) => {
+ const index = BlockedKamelets.indexOf(name);
+ if ( !checked && index === -1) {
+ BlockedKamelets.push(name);
+ }
+ else if ( checked && index > -1) {
+ BlockedKamelets.splice(index, 1);
+ }
+ return BlockedKamelets;
+ }
+
+ static getBlockedKameletNames = () => {
+ return BlockedKamelets;
+ }
}
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 46894d94..e2d9803c 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -37,10 +37,10 @@ import {KaravanIcon} from "./designer/icons/KaravanIcons";
import './designer/karavan.css';
import {DesignerPage} from "./DesignerPage";
import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
-import {KnowledgebasePage} from "./knowledgebase/KnowledgebasePage";
import {Notification} from "./designer/utils/Notification";
import {EventBus} from "./designer/utils/EventBus";
import {TopologyTab} from "./topology/TopologyTab";
+import {KnowledgebaseHome} from "./KnowledgebaseHome";
import {useEffect, useState} from "react";
import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
@@ -70,10 +70,13 @@ export function App() {
fetch("components/components.json"),
fetch("snippets/org.apache.camel.AggregationStrategy"),
fetch("snippets/org.apache.camel.Processor"),
- fetch("example/demo.camel.yaml")
+ fetch("example/demo.camel.yaml"),
+ fetch("components/blocked-components.properties"),
+ fetch("kamelets/blocked-kamelets.properties")
// fetch("example/aws-cloudwatch-sink.kamelet.yaml")
// fetch("example/aws-s3-cdc-source.kamelet.yaml")
- // fetch("components/supported-components.json"),
+ //fetch("components/supported-components.json"),
+
]).then(responses =>
Promise.all(responses.map(response => response.text()))
).then(data => {
@@ -94,11 +97,17 @@ export function App() {
setYaml(data[4]);
setName("demo.camel.yaml");
}
-
if (data[5]) {
- ComponentApi.saveSupportedComponents(data[4]);
+ ComponentApi.saveBlockedComponentNames(data[5].split('\r\n'));
+ }
+ if (data[6]) {
+ KameletApi.saveBlockedKameletNames(data[6].split('\n'));
+ }
+ if (data[7]) {
+ ComponentApi.saveSupportedComponents(data[7]);
ComponentApi.setSupportedOnly(true);
}
+
}).catch(err =>
EventBus.sendAlert("Error", err.text, 'danger')
);
@@ -159,7 +168,7 @@ export function App() {
)
case "knowledgebase":
return (
- <KnowledgebasePage dark={dark}/>
+ <KnowledgebaseHome dark={dark}/>
)
case "topology":
return (
diff --git a/karavan-designer/src/KnowledgebaseHome.tsx
b/karavan-designer/src/KnowledgebaseHome.tsx
new file mode 100644
index 00000000..7c8719ca
--- /dev/null
+++ b/karavan-designer/src/KnowledgebaseHome.tsx
@@ -0,0 +1,23 @@
+import { useEffect, useState } from "react";
+import { KnowledgebasePage } from "./knowledgebase/KnowledgebasePage"
+import { ComponentApi } from "karavan-core/lib/api/ComponentApi";
+import { KameletApi } from "karavan-core/lib/api/KameletApi";
+interface Props {
+ dark: boolean,
+}
+export const KnowledgebaseHome = (props: Props) => {
+
+
+ const onchangeBlockedList = (type: string, name: string, checked: boolean)
=> {
+ if (type === 'kamelet') {
+
+ const blockedKamelet = KameletApi.saveBlockedKameletName(name,
checked);
+ }
+ else if (type === 'component') {
+ const blockedComponent =
ComponentApi.saveBlockedComponentName(name, checked);
+ }
+ }
+ return (
+ <KnowledgebasePage dark={props.dark} changeBlockList={(type: string,
name: string, checked: boolean) => onchangeBlockedList(type, name, checked)} />
+ );
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/karavan.css
b/karavan-designer/src/designer/karavan.css
index 4d9a7162..78b2a135 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -189,7 +189,12 @@
padding: 5px;
display: flex;
flex-direction: row;
- justify-content: flex-end;
+ justify-content:flex-end;
+}
+.kamelets-page .kamelet-card .header-labels .pf-v5-c-card__header-main{
+ display: flex;
+ flex-direction: row;
+ justify-content:space-between;
}
.kamelets-page .kamelet-card .footer-labels {
@@ -813,4 +818,4 @@
}
.karavan .knowledbase-eip-section .pf-v5-c-toggle-group{
margin:16px;
-}
\ No newline at end of file
+}
diff --git a/karavan-designer/src/designer/route/DslSelector.tsx
b/karavan-designer/src/designer/route/DslSelector.tsx
index a80525ba..27093f25 100644
--- a/karavan-designer/src/designer/route/DslSelector.tsx
+++ b/karavan-designer/src/designer/route/DslSelector.tsx
@@ -27,6 +27,8 @@ import {DslMetaModel} from "../utils/DslMetaModel";
import {useDesignerStore, useIntegrationStore, useSelectorStore} from
"../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
+import { KameletApi } from 'karavan-core/lib/api/KameletApi';
interface Props {
tabIndex?: string | number
@@ -119,9 +121,14 @@ export function DslSelector (props: Props) {
const isEip = selectorTabIndex === 'eip';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
+ const blockedComponents = ComponentApi.getBlockedComponentNames();
+ const blockedKamelets = KameletApi.getBlockedKameletNames();
const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl,
navigation, showSteps);
+ const allowedElements = selectorTabIndex === 'component' ?
+ elements.filter(dsl => (!blockedComponents.includes(dsl.uri ||
dsl.name))) :
+ (selectorTabIndex === 'kamelet' ? elements.filter(dsl =>
(!blockedKamelets.includes(dsl.name))) : elements);
const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- const filteredElement = elements
+ const filteredElement = allowedElements
.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, filter))
.filter((dsl: DslMetaModel) => {
if (!isEip || selectedLabels.length === 0) {
diff --git a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
index 02c6b641..66eae532 100644
--- a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
@@ -24,6 +24,7 @@ import {ComponentsTab} from "./components/ComponentsTab";
interface Props {
dark: boolean,
+ changeBlockList: (type: string, name: string, checked: boolean) => void,
}
export const KnowledgebasePage = (props: Props) => {
@@ -76,9 +77,9 @@ export const KnowledgebasePage = (props: Props) => {
</Flex>
</PageSection>
<>
- {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly}/>}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly} onChange={(name: string, checked:
boolean) => props.changeBlockList('kamelet', name, checked)} />}
{tab === 'eip' && <EipTab dark={props.dark} filter={filter}/>}
- {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter}/>}
+ {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
</>
</PageSection>
)
diff --git a/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
b/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
index 338dc3b9..f99d8136 100644
--- a/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
+++ b/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
@@ -14,32 +14,45 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
import {Component} from "karavan-core/lib/model/ComponentModels";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
interface Props {
component: Component,
+ onChange: (name: string, checked: boolean) => void
}
export function ComponentCard(props: Props) {
const [setComponent, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setComponent, s.setModalOpen], shallow)
-
const component = props.component;
+ const [blockedComponents, setBlockedComponents] = useState<string[]>();
+ useEffect(() => {
+ setBlockedComponents(ComponentApi.getBlockedComponentNames());
+ }, []);
+
- function click (event: React.MouseEvent) {
- setComponent(component)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setComponent(component)
+ setModalOpen(true);
+ }
}
-
+ function selectComponent(event: React.FormEvent, checked: boolean) {
+ props.onChange(component.component.name, checked);
+ setBlockedComponents([...ComponentApi.getBlockedComponentNames()]);
+ }
+ const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
return (
<Card isCompact key={component.component.name} className="kamelet-card"
onClick={event => click(event)}
@@ -47,6 +60,7 @@ export function ComponentCard(props: Props) {
<CardHeader className="header-labels">
{component.component.supportType === 'Supported' && <Badge
isRead className="support-type
labels">{component.component.supportType}</Badge>}
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
+ <Checkbox id={component.component.name}
className="block-checkbox labels" isChecked={!isBlockedComponent} onChange={(_,
checked) => selectComponent(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
diff --git a/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
index 708b04bd..9e9fb470 100644
--- a/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
+++ b/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
@@ -29,6 +29,7 @@ import {useKnowledgebaseStore} from "../KnowledgebaseStore";
interface Props {
dark: boolean,
filter: string,
+ onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
@@ -49,7 +50,7 @@ export function ComponentsTab(props: Props) {
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{components.map(c => (
- <ComponentCard key={c.component.name} component={c}/>
+ <ComponentCard key={c.component.name} component={c}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git a/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
index 045846e9..1dff9f2c 100644
--- a/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
+++ b/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
@@ -27,21 +27,34 @@ import {shallow} from "zustand/shallow";
interface Props {
kamelet: KameletModel,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletCard(props: Props) {
const [setKamelet, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setKamelet, s.setModalOpen], shallow)
-
+ const [blockedKamelets, setBlockedKamelets] = useState<string[]>();
+ useEffect(() => {
+ setBlockedKamelets(KameletApi.getBlockedKameletNames());
+ }, []);
+
const kamelet = props.kamelet;
const isCustom =
KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
- function click (event: React.MouseEvent) {
- setKamelet(kamelet)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setKamelet(kamelet)
+ setModalOpen(true);
+ }
}
+ function selectKamelet(event: React.FormEvent, checked: boolean) {
+ props.onChange(kamelet.metadata.name, checked );
+ setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
+ }
+ const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
return (
<Card isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => click(event)}
@@ -49,6 +62,7 @@ export function KameletCard(props: Props) {
<CardHeader className="header-labels">
{isCustom && <Badge className="custom">custom</Badge>}
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
+ <Checkbox id={kamelet.metadata.name} className="block-checkbox
labels" isChecked={!isblockedKamelet} onChange={(_, checked) =>
selectKamelet(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
diff --git a/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
index fb8df6df..353819e4 100644
--- a/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
+++ b/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -31,11 +31,7 @@ interface Props {
dark: boolean,
filter: string,
customOnly: boolean,
-}
-
-interface Props {
- dark: boolean,
- filter: string,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
@@ -55,7 +51,7 @@ export function KameletsTab(props: Props) {
variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
{kameletList.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k}/>
+ <KameletCard key={k.metadata.name} kamelet={k}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git a/karavan-space/src/App.tsx b/karavan-space/src/App.tsx
index 2adec90f..5a723404 100644
--- a/karavan-space/src/App.tsx
+++ b/karavan-space/src/App.tsx
@@ -74,7 +74,9 @@ class App extends React.Component<Props, State> {
fetch("kamelets/kamelets.yaml"),
fetch("components/components.json"),
fetch("snippets/org.apache.camel.AggregationStrategy"),
- fetch("snippets/org.apache.camel.Processor")
+ fetch("snippets/org.apache.camel.Processor"),
+ fetch("components/blocked-components.properties"),
+ fetch("kamelets/blocked-kamelets.properties")
]).then(responses =>
Promise.all(responses.map(response => response.text()))
).then(data => {
@@ -91,6 +93,12 @@ class App extends React.Component<Props, State> {
TemplateApi.saveTemplate("org.apache.camel.AggregationStrategy",
data[2]);
TemplateApi.saveTemplate("org.apache.camel.Processor", data[3]);
+ if (data[4]) {
+ ComponentApi.saveBlockedComponentNames(data[4].split('\r\n'));
+ }
+ if (data[5]) {
+ KameletApi.saveBlockedKameletNames(data[5].split('\n'));
+ }
}).catch(err =>
EventBus.sendAlert("Error", err.text, 'danger')
);
@@ -100,6 +108,16 @@ class App extends React.Component<Props, State> {
this.setState({name: filename, yaml: yaml});
// console.log(yaml);
}
+
+ onchangeBlockedList(type: string, name: string, checked: boolean){
+ if (type === 'kamelet') {
+
+ const blockedKamelet = KameletApi.saveBlockedKameletName(name,
checked);
+ }
+ else if (type === 'component') {
+ const blockedComponent =
ComponentApi.saveBlockedComponentName(name, checked);
+ }
+ }
closeGithubModal() {
this.setState({githubModalIsOpen: false})
@@ -167,7 +185,7 @@ class App extends React.Component<Props, State> {
)
case "knowledgebase":
return (
- <KnowledgebasePage dark={dark}/>
+ <KnowledgebasePage dark={dark} changeBlockList={(type:
string, name: string, checked: boolean) => this.onchangeBlockedList(type, name,
checked)}/>
)
case "topology":
return (
diff --git a/karavan-space/src/designer/karavan.css
b/karavan-space/src/designer/karavan.css
index 4d9a7162..82f75a51 100644
--- a/karavan-space/src/designer/karavan.css
+++ b/karavan-space/src/designer/karavan.css
@@ -189,7 +189,12 @@
padding: 5px;
display: flex;
flex-direction: row;
- justify-content: flex-end;
+ justify-content:flex-end;
+}
+.kamelets-page .kamelet-card .header-labels .pf-v5-c-card__header-main{
+ display: flex;
+ flex-direction: row;
+ justify-content:space-between;
}
.kamelets-page .kamelet-card .footer-labels {
@@ -813,4 +818,8 @@
}
.karavan .knowledbase-eip-section .pf-v5-c-toggle-group{
margin:16px;
+}
+.karavan .kamelet-section .kamelet-card .block-checkbox input{
+ width:18px;
+ height:18px
}
\ No newline at end of file
diff --git a/karavan-space/src/designer/route/DslSelector.tsx
b/karavan-space/src/designer/route/DslSelector.tsx
index a80525ba..27093f25 100644
--- a/karavan-space/src/designer/route/DslSelector.tsx
+++ b/karavan-space/src/designer/route/DslSelector.tsx
@@ -27,6 +27,8 @@ import {DslMetaModel} from "../utils/DslMetaModel";
import {useDesignerStore, useIntegrationStore, useSelectorStore} from
"../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
+import { KameletApi } from 'karavan-core/lib/api/KameletApi';
interface Props {
tabIndex?: string | number
@@ -119,9 +121,14 @@ export function DslSelector (props: Props) {
const isEip = selectorTabIndex === 'eip';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
+ const blockedComponents = ComponentApi.getBlockedComponentNames();
+ const blockedKamelets = KameletApi.getBlockedKameletNames();
const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl,
navigation, showSteps);
+ const allowedElements = selectorTabIndex === 'component' ?
+ elements.filter(dsl => (!blockedComponents.includes(dsl.uri ||
dsl.name))) :
+ (selectorTabIndex === 'kamelet' ? elements.filter(dsl =>
(!blockedKamelets.includes(dsl.name))) : elements);
const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- const filteredElement = elements
+ const filteredElement = allowedElements
.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, filter))
.filter((dsl: DslMetaModel) => {
if (!isEip || selectedLabels.length === 0) {
diff --git a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
index 02c6b641..66eae532 100644
--- a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
@@ -24,6 +24,7 @@ import {ComponentsTab} from "./components/ComponentsTab";
interface Props {
dark: boolean,
+ changeBlockList: (type: string, name: string, checked: boolean) => void,
}
export const KnowledgebasePage = (props: Props) => {
@@ -76,9 +77,9 @@ export const KnowledgebasePage = (props: Props) => {
</Flex>
</PageSection>
<>
- {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly}/>}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly} onChange={(name: string, checked:
boolean) => props.changeBlockList('kamelet', name, checked)} />}
{tab === 'eip' && <EipTab dark={props.dark} filter={filter}/>}
- {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter}/>}
+ {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
</>
</PageSection>
)
diff --git a/karavan-space/src/knowledgebase/components/ComponentCard.tsx
b/karavan-space/src/knowledgebase/components/ComponentCard.tsx
index 338dc3b9..f99d8136 100644
--- a/karavan-space/src/knowledgebase/components/ComponentCard.tsx
+++ b/karavan-space/src/knowledgebase/components/ComponentCard.tsx
@@ -14,32 +14,45 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
import {Component} from "karavan-core/lib/model/ComponentModels";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
interface Props {
component: Component,
+ onChange: (name: string, checked: boolean) => void
}
export function ComponentCard(props: Props) {
const [setComponent, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setComponent, s.setModalOpen], shallow)
-
const component = props.component;
+ const [blockedComponents, setBlockedComponents] = useState<string[]>();
+ useEffect(() => {
+ setBlockedComponents(ComponentApi.getBlockedComponentNames());
+ }, []);
+
- function click (event: React.MouseEvent) {
- setComponent(component)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setComponent(component)
+ setModalOpen(true);
+ }
}
-
+ function selectComponent(event: React.FormEvent, checked: boolean) {
+ props.onChange(component.component.name, checked);
+ setBlockedComponents([...ComponentApi.getBlockedComponentNames()]);
+ }
+ const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
return (
<Card isCompact key={component.component.name} className="kamelet-card"
onClick={event => click(event)}
@@ -47,6 +60,7 @@ export function ComponentCard(props: Props) {
<CardHeader className="header-labels">
{component.component.supportType === 'Supported' && <Badge
isRead className="support-type
labels">{component.component.supportType}</Badge>}
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
+ <Checkbox id={component.component.name}
className="block-checkbox labels" isChecked={!isBlockedComponent} onChange={(_,
checked) => selectComponent(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
diff --git a/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
index 708b04bd..9e9fb470 100644
--- a/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
+++ b/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
@@ -29,6 +29,7 @@ import {useKnowledgebaseStore} from "../KnowledgebaseStore";
interface Props {
dark: boolean,
filter: string,
+ onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
@@ -49,7 +50,7 @@ export function ComponentsTab(props: Props) {
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{components.map(c => (
- <ComponentCard key={c.component.name} component={c}/>
+ <ComponentCard key={c.component.name} component={c}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git a/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
index 045846e9..1dff9f2c 100644
--- a/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
+++ b/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
@@ -27,21 +27,34 @@ import {shallow} from "zustand/shallow";
interface Props {
kamelet: KameletModel,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletCard(props: Props) {
const [setKamelet, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setKamelet, s.setModalOpen], shallow)
-
+ const [blockedKamelets, setBlockedKamelets] = useState<string[]>();
+ useEffect(() => {
+ setBlockedKamelets(KameletApi.getBlockedKameletNames());
+ }, []);
+
const kamelet = props.kamelet;
const isCustom =
KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
- function click (event: React.MouseEvent) {
- setKamelet(kamelet)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setKamelet(kamelet)
+ setModalOpen(true);
+ }
}
+ function selectKamelet(event: React.FormEvent, checked: boolean) {
+ props.onChange(kamelet.metadata.name, checked );
+ setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
+ }
+ const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
return (
<Card isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => click(event)}
@@ -49,6 +62,7 @@ export function KameletCard(props: Props) {
<CardHeader className="header-labels">
{isCustom && <Badge className="custom">custom</Badge>}
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
+ <Checkbox id={kamelet.metadata.name} className="block-checkbox
labels" isChecked={!isblockedKamelet} onChange={(_, checked) =>
selectKamelet(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
diff --git a/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
index fb8df6df..353819e4 100644
--- a/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
+++ b/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -31,11 +31,7 @@ interface Props {
dark: boolean,
filter: string,
customOnly: boolean,
-}
-
-interface Props {
- dark: boolean,
- filter: string,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
@@ -55,7 +51,7 @@ export function KameletsTab(props: Props) {
variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
{kameletList.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k}/>
+ <KameletCard key={k.metadata.name} kamelet={k}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 2ac85771..c9e24eb3 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -457,6 +457,13 @@
"description": "application.properties template for camel-main on
Kubernetes",
"scope": "machine",
"order": 95
+ },
+ "Karavan.settingsPath": {
+ "type": "string",
+ "default": "settings",
+ "description": "Blocked kamelets/components Path",
+ "scope": "machine",
+ "order": 96
}
}
},
@@ -719,7 +726,7 @@
"replace-import": "run-script-os",
"replace-import:darwin": "find webview -type f -name '*.ts*' -exec sed -i
'' 's!karavan-core/lib!core!g' {} +",
"replace-import:linux": "find webview -type f -name '*.ts*' -exec sed -i
's!karavan-core/lib!core!g' {} +",
- "copy-karavan": "npm run copy-core && npm run copy-designer && npm run
replace-import",
+ "copy-karavan": "npm run copy-core && npm run copy-designer && npm run
replace-import",
"vscode:prepublish": "npm run copy-karavan && npm run package",
"compile": "npm run copy-karavan && cross-env NODE_ENV=development webpack
--progress --stats-error-details",
"watch": "npm run copy-karavan && cross-env NODE_ENV=development webpack
--progress --watch",
@@ -742,9 +749,9 @@
"@types/js-yaml": "4.0.9",
"@types/node": "20.11.16",
"@types/uuid": "9.0.8",
- "html-to-image": "1.11.11",
+ "html-to-image": "1.11.11",
"js-yaml": "^4.1.0",
- "path-browserify": "^1.0.1",
+ "path-browserify": "^1.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"rxjs": "7.8.1",
diff --git a/karavan-vscode/settings/components-blocklist.txt
b/karavan-vscode/settings/components-blocklist.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/karavan-vscode/settings/kamelets-blocklist.txt
b/karavan-vscode/settings/kamelets-blocklist.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/karavan-vscode/src/designerView.ts
b/karavan-vscode/src/designerView.ts
index 822ef7dc..612a093c 100644
--- a/karavan-vscode/src/designerView.ts
+++ b/karavan-vscode/src/designerView.ts
@@ -189,6 +189,8 @@ export class DesignerView {
utils.readPropertyPlaceholders(this.context),
// Read beans
utils.readBeans(fullPath),
+ //Read BlockList
+ utils.readBlockTemplates(this.context),
// Read integration
utils.readCamelYamlFiles(path.dirname(fullPath))
]).then(results => {
@@ -206,6 +208,8 @@ export class DesignerView {
// Send integration
panel.webview.postMessage({ command: 'files', files: results[8] });
this.sendIntegrationData(panel, filename, relativePath, fullPath,
reread, yaml, tab, results[6], results[7]);
+ // Send block list
+ panel.webview.postMessage({ command: 'blockList', blockList:
Object.fromEntries(results[8]) });
}).catch(err => console.log(err));
}
diff --git a/karavan-vscode/src/helpView.ts b/karavan-vscode/src/helpView.ts
index c1d11236..435281d5 100644
--- a/karavan-vscode/src/helpView.ts
+++ b/karavan-vscode/src/helpView.ts
@@ -71,6 +71,10 @@ export class HelpView implements
vscode.TreeDataProvider<HelpItem> {
case 'getData':
this.sendData(panel,
page);
break;
+
+ case 'saveBlockedList':
+
utils.saveBlockList(message.key,message.value);
+ break;
}
},
undefined,
@@ -102,7 +106,10 @@ export class HelpView implements
vscode.TreeDataProvider<HelpItem> {
utils.readComponents(this.context).then(components => {
// Read and send Components
panel.webview.postMessage({ command:
'components', components: components });
- }).finally(() => {
+ }).finally(() =>
{utils.readBlockTemplates(this.context).then(list => {
+ // Read and send block lists
+ panel.webview.postMessage({ command:
'blockList', blockList: Object.fromEntries(list) });
+ }) }).finally(() => {
// Send integration
panel.webview.postMessage({ command: 'open',
page: page });
})
diff --git a/karavan-vscode/src/utils.ts b/karavan-vscode/src/utils.ts
index 17e999a0..985544b0 100644
--- a/karavan-vscode/src/utils.ts
+++ b/karavan-vscode/src/utils.ts
@@ -49,6 +49,16 @@ export async function savePropertyPlaceholder(key: string,
value: string) {
}
}
+export function saveBlockList(key: string, value: string) {
+ if (workspace.workspaceFolders) {
+ const uriFolder: Uri = workspace.workspaceFolders[0].uri;
+ const settingsPath: string | undefined =
workspace.getConfiguration().get("Karavan.settingsPath");
+ const name = key+"s-blocklist.txt";
+ write(path.join(uriFolder.path, settingsPath+"/"+name), value);
+ }
+}
+
+
export function deleteFile(fullPath: string) {
if (workspace.workspaceFolders) {
const uriFile: Uri = Uri.file(path.resolve(fullPath));
@@ -64,7 +74,7 @@ export function getRalativePath(fullPath: string): string {
}
export async function readKamelets(context: ExtensionContext) {
- const yamls: string[] = await readBuildInKamelets(context);
+ const yamls: string[] = await readBuildInKamelets(context);
const kameletsPath: string | undefined =
workspace.getConfiguration().get("Karavan.kameletsPath");
if (kameletsPath && kameletsPath.trim().length > 0) {
const kameletsDir = path.isAbsolute(kameletsPath) ? kameletsPath :
path.resolve(kameletsPath);
@@ -179,6 +189,19 @@ export async function readTemplates(context:
ExtensionContext) {
})
return result;
}
+export async function readBlockTemplates(context: ExtensionContext) {
+ const result = new Map<string, string>();
+
+ const blockedListDir: string | undefined =
workspace.getConfiguration().get("Karavan.settingsPath");
+ if (blockedListDir && blockedListDir.trim().length > 0) {
+ const files = await
readFilesInDirByExtension(path.join(context.extensionPath, blockedListDir),
"txt");
+ files.forEach((v, k) => {
+ result.set(k,v);
+ })
+ }
+ return result;
+}
+
export async function readJavaCode(fullPath: string) {
const result = new Map<string, string>();
diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx
index dec9683b..f46b71d0 100644
--- a/karavan-vscode/webview/App.tsx
+++ b/karavan-vscode/webview/App.tsx
@@ -173,6 +173,21 @@ class App extends React.Component<Props, State> {
case 'downloadImage':
EventBus.sendCommand("downloadImage");
break;
+ case 'blockList':
+ const blockList = message.blockList;
+ const blockListMap = new Map(Object.keys(blockList).map(key => [key,
blockList[key]])).forEach((list,key) => {
+ if (key === 'components-blocklist.txt') {
+ ComponentApi.saveBlockedComponentNames(list.split(/\r?\n/));
+ }
+ else if (key === 'kamelets-blocklist.txt') {
+ KameletApi.saveBlockedKameletNames(list.split(/\r?\n/));
+ }
+ });
+ this.setState((prevState: State) => {
+ prevState.loadingMessages.push("block lists loaded");
+ return { loadingMessages: prevState.loadingMessages }
+ });
+ break;
}
};
@@ -202,6 +217,16 @@ class App extends React.Component<Props, State> {
}
+ onchangeBlockedList(type: string, name: string, checked: boolean) {
+ let fileContent = '';
+ if (type === "component") {
+ fileContent = ComponentApi.saveBlockedComponentName(name,
checked).join('\n');
+ } else {
+ fileContent =KameletApi.saveBlockedKameletName(name, checked).join('\n');
+ }
+ vscode.postMessage({ command: 'saveBlockedList', key: type, value:
fileContent });
+ }
+
public render() {
const { loadingMessages, filename, key, yaml, page, loaded, tab } =
this.state;
const { dark } = this.props;
@@ -238,7 +263,7 @@ class App extends React.Component<Props, State> {
files={this.state.files.map(f => new IntegrationFile(f.name,
f.code))}
/>
}
- {loaded && page === "knowledgebase" && <KnowledgebasePage dark={dark}
/>}
+ {loaded && page === "knowledgebase" && <KnowledgebasePage dark={dark}
changeBlockList={(type: string, name: string, checked: boolean) =>
this.onchangeBlockedList(type, name, checked)}/>}
{loaded && page === "topology" &&
<TopologyTab
hideToolbar={true}
diff --git
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java
index 4388b4e4..d763fefb 100644
---
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java
+++
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java
@@ -25,7 +25,7 @@ import org.apache.camel.karavan.code.CodeService;
@Path("/api/component")
public class ComponentResources {
-
+
@Inject
CodeService codeService;
diff --git
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
index de039b83..eece054f 100644
---
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
+++
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
@@ -87,6 +87,7 @@ public class CodeService {
@Inject
Vertx vertx;
+ List<String> blockList = List.of("components-blocklist.txt",
"kamelets-blocklist.txt");
List<String> beansTemplates = List.of("database", "messaging");
List<String> targets = List.of("openshift", "kubernetes", "docker");
List<String> interfaces =
List.of("org.apache.camel.AggregationStrategy.java",
"org.apache.camel.Processor.java");
@@ -197,6 +198,7 @@ public class CodeService {
List<String> files = new ArrayList<>(interfaces);
files.addAll(targets.stream().map(target -> target + "-" +
APPLICATION_PROPERTIES_FILENAME).toList());
files.addAll(targets.stream().map(target -> target + "-" +
BUILD_SCRIPT_FILENAME).toList());
+ files.addAll(blockList);
files.addAll(getBeanTemplateNames());
diff --git
a/karavan-web/karavan-app/src/main/resources/snippets/components-blocklist.txt
b/karavan-web/karavan-app/src/main/resources/snippets/components-blocklist.txt
new file mode 100644
index 00000000..e69de29b
diff --git
a/karavan-web/karavan-app/src/main/resources/snippets/kamelets-blocklist.txt
b/karavan-web/karavan-app/src/main/resources/snippets/kamelets-blocklist.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
index 9a1b5f21..df52aa72 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
@@ -30,6 +30,7 @@ import {
import {ProjectEventBus} from './ProjectEventBus';
import {EventBus} from "../designer/utils/EventBus";
import {KameletApi} from "karavan-core/lib/api/KameletApi";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
export class ProjectService {
@@ -129,14 +130,13 @@ export class ProjectService {
public static reloadKamelets() {
KaravanApi.getKamelets(yamls => {
const kamelets: string[] = [];
- yamls.split("\n---\n").map(c => c.trim()).forEach(z =>
kamelets.push(z));
+ yamls.split(/\n?---\n?/).map(c => c.trim()).forEach(z =>
kamelets.push(z));
KameletApi.saveKamelets(kamelets, true);
})
KaravanApi.getCustomKameletNames(names => {
KameletApi.saveCustomKameletNames(names);
})
}
-
public static updateFile(file: ProjectFile, active: boolean) {
KaravanApi.putProjectFile(file, res => {
if (res.status === 200) {
@@ -297,4 +297,17 @@ export class ProjectService {
useProjectStore.setState({images: images})
});
}
+
+ public static reloadBlockedTemplates() {
+ KaravanApi.getTemplatesFiles((files: ProjectFile[]) => {
+ files.filter(f => f.name.endsWith('blocklist.txt')).forEach(file
=> {
+ if (file.name === 'components-blocklist.txt') {
+
ComponentApi.saveBlockedComponentNames(file.code.split(/\r?\n/));
+ }
+ else if (file.name === "kamelets-blocklist.txt") {
+
KameletApi.saveBlockedKameletNames(file.code.split(/\r?\n/));
+ }
+ });
+ });
+ }
}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
index 4d9a7162..82f75a51 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
@@ -189,7 +189,12 @@
padding: 5px;
display: flex;
flex-direction: row;
- justify-content: flex-end;
+ justify-content:flex-end;
+}
+.kamelets-page .kamelet-card .header-labels .pf-v5-c-card__header-main{
+ display: flex;
+ flex-direction: row;
+ justify-content:space-between;
}
.kamelets-page .kamelet-card .footer-labels {
@@ -813,4 +818,8 @@
}
.karavan .knowledbase-eip-section .pf-v5-c-toggle-group{
margin:16px;
+}
+.karavan .kamelet-section .kamelet-card .block-checkbox input{
+ width:18px;
+ height:18px
}
\ No newline at end of file
diff --git
a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
index a80525ba..27093f25 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx
@@ -27,6 +27,8 @@ import {DslMetaModel} from "../utils/DslMetaModel";
import {useDesignerStore, useIntegrationStore, useSelectorStore} from
"../DesignerStore";
import {shallow} from "zustand/shallow";
import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
+import { KameletApi } from 'karavan-core/lib/api/KameletApi';
interface Props {
tabIndex?: string | number
@@ -119,9 +121,14 @@ export function DslSelector (props: Props) {
const isEip = selectorTabIndex === 'eip';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
+ const blockedComponents = ComponentApi.getBlockedComponentNames();
+ const blockedKamelets = KameletApi.getBlockedKameletNames();
const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl,
navigation, showSteps);
+ const allowedElements = selectorTabIndex === 'component' ?
+ elements.filter(dsl => (!blockedComponents.includes(dsl.uri ||
dsl.name))) :
+ (selectorTabIndex === 'kamelet' ? elements.filter(dsl =>
(!blockedKamelets.includes(dsl.name))) : elements);
const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- const filteredElement = elements
+ const filteredElement = allowedElements
.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, filter))
.filter((dsl: DslMetaModel) => {
if (!isEip || selectedLabels.length === 0) {
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebaseHome.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebaseHome.tsx
new file mode 100644
index 00000000..d9a50a9a
--- /dev/null
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebaseHome.tsx
@@ -0,0 +1,41 @@
+import { KameletApi } from "karavan-core/lib/api/KameletApi";
+import { KnowledgebasePage } from "./KnowledgebasePage"
+import { ComponentApi } from "karavan-core/lib/api/ComponentApi";
+import { KaravanApi } from "../api/KaravanApi";
+import { useState, useEffect } from "react";
+import { ProjectFile } from "../api/ProjectModels";
+import { ProjectService } from "../api/ProjectService";
+interface Props {
+ dark: boolean,
+}
+export const KnowledgebaseHome = (props: Props) => {
+
+ const [blockList, setBlockList] = useState<ProjectFile[]>();
+
+ useEffect(() => {
+ KaravanApi.getTemplatesFiles((files:ProjectFile[]) => {
+ setBlockList([...(files.filter(f =>
f.name.endsWith('blocklist.txt')))]);
+ });
+ }, []);
+
+ const onChangeBlockedList = async (type: string, name: string, checked:
boolean) => {
+
+ let file: ProjectFile | undefined;
+ let fileContent = '';
+ if (type === "component") {
+ file = blockList?.find(obj => obj.name ===
'components-blocklist.txt');
+ fileContent = ComponentApi.saveBlockedComponentName(name,
checked).join('\n');
+ } else {
+ file = blockList?.find(obj => obj.name ===
'kamelets-blocklist.txt');
+ fileContent = KameletApi.saveBlockedKameletName(name,
checked).join('\n');
+ }
+ if (file) {
+ file.code = fileContent;
+ ProjectService.updateFile(file, false);
+ }
+ }
+
+ return (
+ <KnowledgebasePage dark={props.dark} changeBlockList={(type: string,
name: string, checked: boolean) => onChangeBlockedList(type, name, checked)} />
+ );
+}
\ No newline at end of file
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
index 02c6b641..66eae532 100644
---
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
@@ -24,6 +24,7 @@ import {ComponentsTab} from "./components/ComponentsTab";
interface Props {
dark: boolean,
+ changeBlockList: (type: string, name: string, checked: boolean) => void,
}
export const KnowledgebasePage = (props: Props) => {
@@ -76,9 +77,9 @@ export const KnowledgebasePage = (props: Props) => {
</Flex>
</PageSection>
<>
- {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly}/>}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
filter={filter} customOnly={customOnly} onChange={(name: string, checked:
boolean) => props.changeBlockList('kamelet', name, checked)} />}
{tab === 'eip' && <EipTab dark={props.dark} filter={filter}/>}
- {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter}/>}
+ {tab === 'components' && <ComponentsTab dark={props.dark}
filter={filter} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
</>
</PageSection>
)
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
index 338dc3b9..f99d8136 100644
---
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
@@ -14,32 +14,45 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
import {Component} from "karavan-core/lib/model/ComponentModels";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import { ComponentApi } from 'karavan-core/lib/api/ComponentApi';
interface Props {
component: Component,
+ onChange: (name: string, checked: boolean) => void
}
export function ComponentCard(props: Props) {
const [setComponent, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setComponent, s.setModalOpen], shallow)
-
const component = props.component;
+ const [blockedComponents, setBlockedComponents] = useState<string[]>();
+ useEffect(() => {
+ setBlockedComponents(ComponentApi.getBlockedComponentNames());
+ }, []);
+
- function click (event: React.MouseEvent) {
- setComponent(component)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setComponent(component)
+ setModalOpen(true);
+ }
}
-
+ function selectComponent(event: React.FormEvent, checked: boolean) {
+ props.onChange(component.component.name, checked);
+ setBlockedComponents([...ComponentApi.getBlockedComponentNames()]);
+ }
+ const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
return (
<Card isCompact key={component.component.name} className="kamelet-card"
onClick={event => click(event)}
@@ -47,6 +60,7 @@ export function ComponentCard(props: Props) {
<CardHeader className="header-labels">
{component.component.supportType === 'Supported' && <Badge
isRead className="support-type
labels">{component.component.supportType}</Badge>}
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
+ <Checkbox id={component.component.name}
className="block-checkbox labels" isChecked={!isBlockedComponent} onChange={(_,
checked) => selectComponent(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
index 708b04bd..9e9fb470 100644
---
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
@@ -29,6 +29,7 @@ import {useKnowledgebaseStore} from "../KnowledgebaseStore";
interface Props {
dark: boolean,
filter: string,
+ onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
@@ -49,7 +50,7 @@ export function ComponentsTab(props: Props) {
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
{components.map(c => (
- <ComponentCard key={c.component.name} component={c}/>
+ <ComponentCard key={c.component.name} component={c}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
index 045846e9..1dff9f2c 100644
---
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
@@ -27,21 +27,34 @@ import {shallow} from "zustand/shallow";
interface Props {
kamelet: KameletModel,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletCard(props: Props) {
const [setKamelet, setModalOpen] = useKnowledgebaseStore((s) =>
[s.setKamelet, s.setModalOpen], shallow)
-
+ const [blockedKamelets, setBlockedKamelets] = useState<string[]>();
+ useEffect(() => {
+ setBlockedKamelets(KameletApi.getBlockedKameletNames());
+ }, []);
+
const kamelet = props.kamelet;
const isCustom =
KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
- function click (event: React.MouseEvent) {
- setKamelet(kamelet)
- setModalOpen(true);
+ function click(event: React.MouseEvent) {
+ const { target } = event;
+ if (!(target as
HTMLElement).parentElement?.className.includes("block-checkbox")) {
+ setKamelet(kamelet)
+ setModalOpen(true);
+ }
}
+ function selectKamelet(event: React.FormEvent, checked: boolean) {
+ props.onChange(kamelet.metadata.name, checked );
+ setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
+ }
+ const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
return (
<Card isCompact key={kamelet.metadata.name} className="kamelet-card"
onClick={event => click(event)}
@@ -49,6 +62,7 @@ export function KameletCard(props: Props) {
<CardHeader className="header-labels">
{isCustom && <Badge className="custom">custom</Badge>}
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
+ <Checkbox id={kamelet.metadata.name} className="block-checkbox
labels" isChecked={!isblockedKamelet} onChange={(_, checked) =>
selectKamelet(_, checked)} />
</CardHeader>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
diff --git
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
index fb8df6df..353819e4 100644
---
a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
+++
b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -31,11 +31,7 @@ interface Props {
dark: boolean,
filter: string,
customOnly: boolean,
-}
-
-interface Props {
- dark: boolean,
- filter: string,
+ onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
@@ -55,7 +51,7 @@ export function KameletsTab(props: Props) {
variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
{kameletList.map(k => (
- <KameletCard key={k.metadata.name} kamelet={k}/>
+ <KameletCard key={k.metadata.name} kamelet={k}
onChange={props.onChange} />
))}
</Gallery>
</PageSection>
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainRoutes.tsx
b/karavan-web/karavan-app/src/main/webui/src/main/MainRoutes.tsx
index 0434dcef..91956b2c 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/MainRoutes.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/MainRoutes.tsx
@@ -21,9 +21,9 @@ import {ProjectsPage} from "../projects/ProjectsPage";
import {ProjectPage} from "../project/ProjectPage";
import {ServicesPage} from "../services/ServicesPage";
import {ContainersPage} from "../containers/ContainersPage";
-import {KnowledgebasePage} from "../knowledgebase/KnowledgebasePage";
import {TemplatesPage} from "../templates/TemplatesPage";
import {ConfigurationPage} from "../config/ConfigurationPage";
+import { KnowledgebaseHome } from '../knowledgebase/KnowledgebaseHome';
export function MainRoutes() {
@@ -34,7 +34,7 @@ export function MainRoutes() {
<Route path="/templates" element={<TemplatesPage
key={'templates'}/>}/>
<Route path="/services" element={<ServicesPage key="services"/>}/>
<Route path="/containers" element={<ContainersPage
key="services"/>}/>
- <Route path="/knowledgebase" element={<KnowledgebasePage
dark={false}/>}/>
+ <Route path="/knowledgebase" element={<KnowledgebaseHome
dark={false}/>}/>
<Route path="/configuration" element={<ConfigurationPage
dark={false}/>}/>
<Route path="*" element={<Navigate to="/projects" replace/>}/>
</Routes>
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
b/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
index ed8b5fce..5508002f 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
@@ -50,6 +50,7 @@ export function useMainHook () {
});
updateKamelets();
updateComponents();
+ ProjectService.reloadBlockedTemplates();
// updateSupportedComponents(); // not implemented yet
}
}
@@ -59,7 +60,8 @@ export function useMainHook () {
ProjectService.reloadKamelets();
});
}
-
+
+
async function updateComponents(): Promise<void> {
await new Promise(resolve => {
KaravanApi.getComponents(code => {