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 70ce664a Fix #1421
70ce664a is described below
commit 70ce664adcd89c1c22040001096b091ec5898ade
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Tue Sep 17 10:57:24 2024 -0400
Fix #1421
---
.../src/main/webui/src/designer/DesignerStore.ts | 21 ----
.../src/designer/property/PropertiesHeader.tsx | 2 +-
.../webui/src/knowledgebase/KnowledgebasePage.tsx | 55 +++++++--
.../src/knowledgebase/components/ComponentCard.tsx | 11 +-
.../src/knowledgebase/components/ComponentsTab.tsx | 15 +--
.../main/webui/src/knowledgebase/eip/EipCard.tsx | 10 +-
.../main/webui/src/knowledgebase/eip/EipTab.tsx | 45 ++------
.../src/knowledgebase/kamelets/KameletCard.tsx | 6 +-
.../src/knowledgebase/kamelets/KameletsTab.tsx | 14 +--
.../main/webui/src/knowledgebase/knowledgebase.css | 124 ++++++++++++++++++++-
karavan-designer/src/designer/DesignerStore.ts | 21 ----
.../src/designer/property/PropertiesHeader.tsx | 2 +-
.../src/knowledgebase/KnowledgebasePage.tsx | 55 +++++++--
.../src/knowledgebase/components/ComponentCard.tsx | 11 +-
.../src/knowledgebase/components/ComponentsTab.tsx | 15 +--
karavan-designer/src/knowledgebase/eip/EipCard.tsx | 10 +-
karavan-designer/src/knowledgebase/eip/EipTab.tsx | 45 ++------
.../src/knowledgebase/kamelets/KameletCard.tsx | 6 +-
.../src/knowledgebase/kamelets/KameletsTab.tsx | 14 +--
.../src/knowledgebase/knowledgebase.css | 124 ++++++++++++++++++++-
karavan-space/src/designer/DesignerStore.ts | 21 ----
.../src/designer/property/PropertiesHeader.tsx | 2 +-
.../src/knowledgebase/KnowledgebasePage.tsx | 55 +++++++--
.../src/knowledgebase/components/ComponentCard.tsx | 11 +-
.../src/knowledgebase/components/ComponentsTab.tsx | 15 +--
karavan-space/src/knowledgebase/eip/EipCard.tsx | 10 +-
karavan-space/src/knowledgebase/eip/EipTab.tsx | 45 ++------
.../src/knowledgebase/kamelets/KameletCard.tsx | 6 +-
.../src/knowledgebase/kamelets/KameletsTab.tsx | 14 +--
karavan-space/src/knowledgebase/knowledgebase.css | 124 ++++++++++++++++++++-
30 files changed, 609 insertions(+), 300 deletions(-)
diff --git a/karavan-app/src/main/webui/src/designer/DesignerStore.ts
b/karavan-app/src/main/webui/src/designer/DesignerStore.ts
index 9c855c5f..e207c546 100644
--- a/karavan-app/src/main/webui/src/designer/DesignerStore.ts
+++ b/karavan-app/src/main/webui/src/designer/DesignerStore.ts
@@ -105,10 +105,6 @@ interface SelectorStateState {
setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
selectedPosition?: number;
setSelectedPosition: (selectedPosition?: number) => void;
- selectedLabels: string [];
- addSelectedLabel: (label: string) => void;
- deleteSelectedLabel: (label: string) => void;
- clearSelectedLabels: () => void;
selectedToggles: string [];
addSelectedToggle: (label: string) => void;
deleteSelectedToggle: (label: string) => void;
@@ -121,24 +117,7 @@ export const useSelectorStore =
createWithEqualityFn<SelectorStateState>((set) =
deleteMessage: '',
parentId: '',
showSteps: true,
- selectedLabels: [],
selectedToggles: ['eip', 'components', 'kamelets'],
- addSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels, label]
- }))
- },
- deleteSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels.filter(x => x !== label)]
- }))
- },
- clearSelectedLabels: () => {
- set((state: SelectorStateState) => {
- state.selectedLabels.length = 0;
- return {selectedLabels : [...state.selectedLabels]};
- })
- },
addSelectedToggle: (toggle: string) => {
set(state => ({
selectedToggles: [...state.selectedToggles, toggle]
diff --git
a/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
b/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
index 30b0034b..b8aca6b4 100644
--- a/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
@@ -94,7 +94,7 @@ export function PropertiesHeader(props: Props) {
openSelectorToReplaceFrom((selectedStep as any).id)
setMenuOpen(false);
}}>
- Change From Element
+ Change From...
</DropdownItem>}
{hasSteps &&
<DropdownItem key="saveStepsRoute" onClick={(ev) => {
diff --git a/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
index a7c1d514..cb2e7158 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
@@ -16,13 +16,30 @@
*/
import React, {useState} from 'react';
import '../designer/karavan.css';
-import {Flex, FlexItem, PageSection, Switch, Tab, Tabs, Text, TextContent,
TextInput, Toolbar, ToolbarContent} from "@patternfly/react-core";
+import {
+ Badge,
+ Flex,
+ FlexItem,
+ PageSection,
+ Switch,
+ Tab,
+ Tabs,
+ Text,
+ TextContent,
+ TextInput,
+ Toolbar,
+ ToolbarContent
+} from "@patternfly/react-core";
import {MainToolbar} from "../designer/MainToolbar";
import {KameletsTab} from "./kamelets/KameletsTab";
import {EipTab} from "./eip/EipTab";
import {ComponentsTab} from "./components/ComponentsTab";
import {useKnowledgebaseStore} from "./KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
@@ -33,7 +50,7 @@ interface Props {
export const KnowledgebasePage = (props: Props) => {
const [setShowBlockCheckbox] = useKnowledgebaseStore((s) =>
[s.setShowBlockCheckbox], shallow)
- const [tab, setTab] = useState<string | number>("eip");
+ const [tab, setTab] = useState<string | number>("components");
const [filter, setFilter] = useState<string>("");
const [customOnly, setCustomOnly] = useState<boolean>(false);
@@ -71,8 +88,21 @@ export const KnowledgebasePage = (props: Props) => {
</Toolbar>
}
+ let kameletList: KameletModel[] = KameletApi.getKamelets().filter(kamelet
=>
+
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
+
+ const components = ComponentApi.getComponents().filter(c => {
+ return c.component.name.toLowerCase().includes(filter.toLowerCase())
+ || c.component.title.toLowerCase().includes(filter.toLowerCase())
+ ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
+ }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+
+ const elements= CamelModelMetadata
+ .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).sort((a: ElementMeta, b:
ElementMeta) => a.name > b.name ? 1 : -1);
+
return (
- <PageSection className="kamelet-section" padding={{default:
'noPadding'}}>
+ <PageSection className="knowledgebase-section" padding={{default:
'noPadding'}}>
<PageSection className="tools-section" padding={{default:
'noPadding'}}>
<MainToolbar title={title()} tools={getTools()}/>
</PageSection>
@@ -80,17 +110,24 @@ export const KnowledgebasePage = (props: Props) => {
<Flex direction={{default: "column"}} spaceItems={{default:
"spaceItemsNone"}}>
<FlexItem>
<Tabs activeKey={tab} onSelect={(event, tabIndex) =>
setTab(tabIndex)}>
- <Tab eventKey="eip" title="Integration Patterns"/>
- <Tab eventKey="kamelets" title="Kamelets"/>
- <Tab eventKey="components" title="Components"/>
+ <Tab eventKey="components" title={<div
style={{display: 'flex', gap:'6px'}}>Components<Badge
className='label-component'>{components.length}</Badge></div>}/>
+ <Tab eventKey="eip" title={<div style={{display:
'flex', gap:'6px'}}>Integration Patterns<Badge
className='label-eip'>{elements.length}</Badge></div>}/>
+ <Tab eventKey="kamelets" title={<div
style={{display: 'flex', gap:'6px'}}>Kamelets<Badge
className='label-kamelet'>{kameletList.length}</Badge></div>}/>
</Tabs>
</FlexItem>
</Flex>
</PageSection>
<>
- {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} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
+ kameletList={kameletList}
+ onChange={(name: string,
checked: boolean) => props.changeBlockList('kamelet', name, checked)} />
+ }
+ {tab === 'eip' && <EipTab dark={props.dark}
elements={elements}/>
+ }
+ {tab === 'components' && <ComponentsTab dark={props.dark}
+ components={components}
+ onChange={(name:
string, checked: boolean) => props.changeBlockList('component', name, checked)}
/>
+ }
</>
</PageSection>
)
diff --git
a/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
b/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
index c9f39d04..80d298c5 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/components/ComponentCard.tsx
@@ -16,7 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex,
Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -56,14 +56,15 @@ export function ComponentCard(props: Props) {
const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
const isRemote = component.component.remote;
+ const classNameBadge = 'label-component' +
(component.component.supportLevel !== 'Stable' ? '-preview' : '')
return (
- <Card isCompact key={component.component.name} className="kamelet-card"
+ <Card isCompact key={component.component.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width: '100%'}} gap={{default: 'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Component</Badge>
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
- <Badge isRead className="version
labels">{component.component.version}</Badge>
</Flex>
{showBlockCheckbox &&
<Checkbox id={component.component.name}
@@ -77,7 +78,9 @@ export function ComponentCard(props: Props) {
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
<CardTitle>{component.component.title}</CardTitle>
</CardHeader>
- <CardBody>{component.component.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{component.component.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<Badge isRead
className="labels">{component.component.label}</Badge>
<Badge isRead className="labels">{isRemote ? 'remote' :
'internal'}</Badge>
diff --git
a/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
index 9e9fb470..c4fdb592 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/components/ComponentsTab.tsx
@@ -22,28 +22,21 @@ import {
import '../../designer/karavan.css';
import {ComponentCard} from "./ComponentCard";
import {ComponentModal} from "./ComponentModal";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {shallow} from "zustand/shallow";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
+import { Component } from 'karavan-core/lib/model/ComponentModels';
interface Props {
dark: boolean,
- filter: string,
+ components: Component[],
onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
-
- const {filter} = props;
- const components = ComponentApi.getComponents().filter(c => {
- return c.component.name.toLowerCase().includes(filter.toLowerCase())
- || c.component.title.toLowerCase().includes(filter.toLowerCase())
- ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
- }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+ const {components} = props;
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light} padding={{ default: 'noPadding' }}
className="kamelet-section">
{isModalOpen && <ComponentModal/>}
diff --git a/karavan-app/src/main/webui/src/knowledgebase/eip/EipCard.tsx
b/karavan-app/src/main/webui/src/knowledgebase/eip/EipCard.tsx
index fb47a932..bac46590 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/eip/EipCard.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/eip/EipCard.tsx
@@ -16,7 +16,7 @@
*/
import React from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -39,18 +39,20 @@ export function EipCard(props: Props) {
setElement(element)
setModalOpen(true);
}
-
return (
- <Card isCompact key={element.name} className="kamelet-card"
+ <Card isCompact key={element.name} className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader>
+ <Badge className='label-eip'>EIP</Badge>
</CardHeader>
<CardHeader>
{CamelUi.getIconForDslName(element.className)}
<CardTitle>{element.title}</CardTitle>
</CardHeader>
- <CardBody>{element.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{element.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<div>
{element.labels.split(',').map((s: string, i: number) =>
<Badge key={s + i} isRead
diff --git a/karavan-app/src/main/webui/src/knowledgebase/eip/EipTab.tsx
b/karavan-app/src/main/webui/src/knowledgebase/eip/EipTab.tsx
index 35cc9741..7720bd29 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/eip/EipTab.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/eip/EipTab.tsx
@@ -17,66 +17,35 @@
import React from 'react';
import {
Gallery,
- PageSection, PageSectionVariants,ToggleGroup,ToggleGroupItem
+ PageSection, PageSectionVariants
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {EipCard} from "./EipCard";
import {EipModal} from "./EipModal";
-import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
-import { useSelectorStore } from '../../designer/DesignerStore';
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
- filter: string,
+ elements: ElementMeta[],
}
export function EipTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const { elements } = props;
- const [ selectedLabels, addSelectedLabel, deleteSelectedLabel] =
- useSelectorStore((s) =>
- [s.selectedLabels, s.addSelectedLabel, s.deleteSelectedLabel],
shallow)
- const { filter } = props;
- const elements = CamelModelMetadata;
- const filteredElements=CamelModelMetadata
- .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).filter((dsl: ElementMeta)
=> {
- if (selectedLabels.length === 0) {
- return true;
- } else {
- return dsl.labels.split(",").some(r =>
selectedLabels.includes(r));
- }
- })
- .sort((a: ElementMeta, b: ElementMeta) => a.name > b.name ? 1 : -1);
- const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- function selectLabel(eipLabel: string) {
- if (!selectedLabels.includes(eipLabel)) {
- addSelectedLabel(eipLabel);
- } else {
- deleteSelectedLabel(eipLabel);
- }
- }
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{ default: 'noPadding' }} className="kamelet-section
knowledbase-eip-section">
- <ToggleGroup aria-label="Labels" isCompact >
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- </ToggleGroup>
{isModalOpen && <EipModal/>}
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
- {filteredElements.map(c => (
+ {elements.map(c => (
<EipCard key={c.name} element={c}/>
))}
</Gallery>
diff --git
a/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
index a1a0f903..4fb6e662 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletCard.tsx
@@ -56,14 +56,16 @@ export function KameletCard(props: Props) {
setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
}
const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
+ const supportLevel =
kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"];
+ const classNameBadge = 'label-kamelet' + (supportLevel !== 'Stable' ?
'-preview' : '')
return (
- <Card isCompact key={kamelet.metadata.name} className="kamelet-card"
+ <Card isCompact key={kamelet.metadata.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width:'100%'}} gap={{default:'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Kamelet</Badge>
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
- <Badge isRead className="version
labels">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
</Flex>
{showBlockCheckbox && <Checkbox id={kamelet.metadata.name}
className="block-checkbox labels" isChecked={!isblockedKamelet}
onChange={(_, checked) =>
selectKamelet(_, checked)}/>}
diff --git
a/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
index 353819e4..83db2eb5 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
+++ b/karavan-app/src/main/webui/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -22,27 +22,23 @@ import {
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletCard} from "./KameletCard";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
interface Props {
dark: boolean,
- filter: string,
- customOnly: boolean,
+ kameletList: KameletModel[],
onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const {kameletList, dark} = props;
- const {filter, customOnly, dark} = props;
- let kameletList = KameletApi.getKamelets().filter(kamelet =>
-
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
- if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
<PageSection variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{default: 'noPadding'}}
className="kamelet-section">
diff --git a/karavan-app/src/main/webui/src/knowledgebase/knowledgebase.css
b/karavan-app/src/main/webui/src/knowledgebase/knowledgebase.css
index 6fb889de..b0caf549 100644
--- a/karavan-app/src/main/webui/src/knowledgebase/knowledgebase.css
+++ b/karavan-app/src/main/webui/src/knowledgebase/knowledgebase.css
@@ -15,7 +15,129 @@
* limitations under the License.
*/
-.kamelets-page .kamelet-card .block-checkbox {
+.karavan .knowledgebase-section {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card {
+ cursor: pointer;
+ height: 160px;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header {
+ padding-top: var(--pf-v5-global--spacer--sm);
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.custom {
+ margin-left: auto;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ overflow: hidden;
+ position: relative;
+ line-height: 1.6em;
+}
+
+.knowledgebase-section .knowledgebase-card .icon {
+ height: 24px;
+ max-width: 24px;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-right: 5px;
+ border: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .footer-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .version,
+.karavan .knowledgebase-section .knowledgebase-card .support-type,
+.karavan .knowledgebase-section .knowledgebase-card .support-level {
+ white-space: nowrap;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .labels {
+ opacity: 0.5;
+ font-weight: 200;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card:hover .labels {
+ opacity: 1;
+}
+
+.knowledgebase-section .knowledgebase-card .block-checkbox {
align-self: center;
margin-left: 6px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card p {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ color: var(--pf-v5-global--Color--200);
+}
+
+.knowledgebase-section {
+ .label-eip {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--orange-200);
+ }
+ .label-component {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--blue-300);
+ }
+ .label-kamelet {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--green-300);
+ }
+ .label-component-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--blue-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
+ .label-kamelet-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--green-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/DesignerStore.ts
b/karavan-designer/src/designer/DesignerStore.ts
index 9c855c5f..e207c546 100644
--- a/karavan-designer/src/designer/DesignerStore.ts
+++ b/karavan-designer/src/designer/DesignerStore.ts
@@ -105,10 +105,6 @@ interface SelectorStateState {
setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
selectedPosition?: number;
setSelectedPosition: (selectedPosition?: number) => void;
- selectedLabels: string [];
- addSelectedLabel: (label: string) => void;
- deleteSelectedLabel: (label: string) => void;
- clearSelectedLabels: () => void;
selectedToggles: string [];
addSelectedToggle: (label: string) => void;
deleteSelectedToggle: (label: string) => void;
@@ -121,24 +117,7 @@ export const useSelectorStore =
createWithEqualityFn<SelectorStateState>((set) =
deleteMessage: '',
parentId: '',
showSteps: true,
- selectedLabels: [],
selectedToggles: ['eip', 'components', 'kamelets'],
- addSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels, label]
- }))
- },
- deleteSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels.filter(x => x !== label)]
- }))
- },
- clearSelectedLabels: () => {
- set((state: SelectorStateState) => {
- state.selectedLabels.length = 0;
- return {selectedLabels : [...state.selectedLabels]};
- })
- },
addSelectedToggle: (toggle: string) => {
set(state => ({
selectedToggles: [...state.selectedToggles, toggle]
diff --git a/karavan-designer/src/designer/property/PropertiesHeader.tsx
b/karavan-designer/src/designer/property/PropertiesHeader.tsx
index 30b0034b..b8aca6b4 100644
--- a/karavan-designer/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-designer/src/designer/property/PropertiesHeader.tsx
@@ -94,7 +94,7 @@ export function PropertiesHeader(props: Props) {
openSelectorToReplaceFrom((selectedStep as any).id)
setMenuOpen(false);
}}>
- Change From Element
+ Change From...
</DropdownItem>}
{hasSteps &&
<DropdownItem key="saveStepsRoute" onClick={(ev) => {
diff --git a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
index a7c1d514..cb2e7158 100644
--- a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx
@@ -16,13 +16,30 @@
*/
import React, {useState} from 'react';
import '../designer/karavan.css';
-import {Flex, FlexItem, PageSection, Switch, Tab, Tabs, Text, TextContent,
TextInput, Toolbar, ToolbarContent} from "@patternfly/react-core";
+import {
+ Badge,
+ Flex,
+ FlexItem,
+ PageSection,
+ Switch,
+ Tab,
+ Tabs,
+ Text,
+ TextContent,
+ TextInput,
+ Toolbar,
+ ToolbarContent
+} from "@patternfly/react-core";
import {MainToolbar} from "../designer/MainToolbar";
import {KameletsTab} from "./kamelets/KameletsTab";
import {EipTab} from "./eip/EipTab";
import {ComponentsTab} from "./components/ComponentsTab";
import {useKnowledgebaseStore} from "./KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
@@ -33,7 +50,7 @@ interface Props {
export const KnowledgebasePage = (props: Props) => {
const [setShowBlockCheckbox] = useKnowledgebaseStore((s) =>
[s.setShowBlockCheckbox], shallow)
- const [tab, setTab] = useState<string | number>("eip");
+ const [tab, setTab] = useState<string | number>("components");
const [filter, setFilter] = useState<string>("");
const [customOnly, setCustomOnly] = useState<boolean>(false);
@@ -71,8 +88,21 @@ export const KnowledgebasePage = (props: Props) => {
</Toolbar>
}
+ let kameletList: KameletModel[] = KameletApi.getKamelets().filter(kamelet
=>
+
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
+
+ const components = ComponentApi.getComponents().filter(c => {
+ return c.component.name.toLowerCase().includes(filter.toLowerCase())
+ || c.component.title.toLowerCase().includes(filter.toLowerCase())
+ ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
+ }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+
+ const elements= CamelModelMetadata
+ .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).sort((a: ElementMeta, b:
ElementMeta) => a.name > b.name ? 1 : -1);
+
return (
- <PageSection className="kamelet-section" padding={{default:
'noPadding'}}>
+ <PageSection className="knowledgebase-section" padding={{default:
'noPadding'}}>
<PageSection className="tools-section" padding={{default:
'noPadding'}}>
<MainToolbar title={title()} tools={getTools()}/>
</PageSection>
@@ -80,17 +110,24 @@ export const KnowledgebasePage = (props: Props) => {
<Flex direction={{default: "column"}} spaceItems={{default:
"spaceItemsNone"}}>
<FlexItem>
<Tabs activeKey={tab} onSelect={(event, tabIndex) =>
setTab(tabIndex)}>
- <Tab eventKey="eip" title="Integration Patterns"/>
- <Tab eventKey="kamelets" title="Kamelets"/>
- <Tab eventKey="components" title="Components"/>
+ <Tab eventKey="components" title={<div
style={{display: 'flex', gap:'6px'}}>Components<Badge
className='label-component'>{components.length}</Badge></div>}/>
+ <Tab eventKey="eip" title={<div style={{display:
'flex', gap:'6px'}}>Integration Patterns<Badge
className='label-eip'>{elements.length}</Badge></div>}/>
+ <Tab eventKey="kamelets" title={<div
style={{display: 'flex', gap:'6px'}}>Kamelets<Badge
className='label-kamelet'>{kameletList.length}</Badge></div>}/>
</Tabs>
</FlexItem>
</Flex>
</PageSection>
<>
- {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} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
+ kameletList={kameletList}
+ onChange={(name: string,
checked: boolean) => props.changeBlockList('kamelet', name, checked)} />
+ }
+ {tab === 'eip' && <EipTab dark={props.dark}
elements={elements}/>
+ }
+ {tab === 'components' && <ComponentsTab dark={props.dark}
+ components={components}
+ 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 c9f39d04..80d298c5 100644
--- a/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
+++ b/karavan-designer/src/knowledgebase/components/ComponentCard.tsx
@@ -16,7 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex,
Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -56,14 +56,15 @@ export function ComponentCard(props: Props) {
const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
const isRemote = component.component.remote;
+ const classNameBadge = 'label-component' +
(component.component.supportLevel !== 'Stable' ? '-preview' : '')
return (
- <Card isCompact key={component.component.name} className="kamelet-card"
+ <Card isCompact key={component.component.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width: '100%'}} gap={{default: 'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Component</Badge>
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
- <Badge isRead className="version
labels">{component.component.version}</Badge>
</Flex>
{showBlockCheckbox &&
<Checkbox id={component.component.name}
@@ -77,7 +78,9 @@ export function ComponentCard(props: Props) {
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
<CardTitle>{component.component.title}</CardTitle>
</CardHeader>
- <CardBody>{component.component.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{component.component.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<Badge isRead
className="labels">{component.component.label}</Badge>
<Badge isRead className="labels">{isRemote ? 'remote' :
'internal'}</Badge>
diff --git a/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
index 9e9fb470..c4fdb592 100644
--- a/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
+++ b/karavan-designer/src/knowledgebase/components/ComponentsTab.tsx
@@ -22,28 +22,21 @@ import {
import '../../designer/karavan.css';
import {ComponentCard} from "./ComponentCard";
import {ComponentModal} from "./ComponentModal";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {shallow} from "zustand/shallow";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
+import { Component } from 'karavan-core/lib/model/ComponentModels';
interface Props {
dark: boolean,
- filter: string,
+ components: Component[],
onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
-
- const {filter} = props;
- const components = ComponentApi.getComponents().filter(c => {
- return c.component.name.toLowerCase().includes(filter.toLowerCase())
- || c.component.title.toLowerCase().includes(filter.toLowerCase())
- ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
- }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+ const {components} = props;
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light} padding={{ default: 'noPadding' }}
className="kamelet-section">
{isModalOpen && <ComponentModal/>}
diff --git a/karavan-designer/src/knowledgebase/eip/EipCard.tsx
b/karavan-designer/src/knowledgebase/eip/EipCard.tsx
index fb47a932..bac46590 100644
--- a/karavan-designer/src/knowledgebase/eip/EipCard.tsx
+++ b/karavan-designer/src/knowledgebase/eip/EipCard.tsx
@@ -16,7 +16,7 @@
*/
import React from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -39,18 +39,20 @@ export function EipCard(props: Props) {
setElement(element)
setModalOpen(true);
}
-
return (
- <Card isCompact key={element.name} className="kamelet-card"
+ <Card isCompact key={element.name} className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader>
+ <Badge className='label-eip'>EIP</Badge>
</CardHeader>
<CardHeader>
{CamelUi.getIconForDslName(element.className)}
<CardTitle>{element.title}</CardTitle>
</CardHeader>
- <CardBody>{element.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{element.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<div>
{element.labels.split(',').map((s: string, i: number) =>
<Badge key={s + i} isRead
diff --git a/karavan-designer/src/knowledgebase/eip/EipTab.tsx
b/karavan-designer/src/knowledgebase/eip/EipTab.tsx
index 35cc9741..7720bd29 100644
--- a/karavan-designer/src/knowledgebase/eip/EipTab.tsx
+++ b/karavan-designer/src/knowledgebase/eip/EipTab.tsx
@@ -17,66 +17,35 @@
import React from 'react';
import {
Gallery,
- PageSection, PageSectionVariants,ToggleGroup,ToggleGroupItem
+ PageSection, PageSectionVariants
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {EipCard} from "./EipCard";
import {EipModal} from "./EipModal";
-import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
-import { useSelectorStore } from '../../designer/DesignerStore';
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
- filter: string,
+ elements: ElementMeta[],
}
export function EipTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const { elements } = props;
- const [ selectedLabels, addSelectedLabel, deleteSelectedLabel] =
- useSelectorStore((s) =>
- [s.selectedLabels, s.addSelectedLabel, s.deleteSelectedLabel],
shallow)
- const { filter } = props;
- const elements = CamelModelMetadata;
- const filteredElements=CamelModelMetadata
- .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).filter((dsl: ElementMeta)
=> {
- if (selectedLabels.length === 0) {
- return true;
- } else {
- return dsl.labels.split(",").some(r =>
selectedLabels.includes(r));
- }
- })
- .sort((a: ElementMeta, b: ElementMeta) => a.name > b.name ? 1 : -1);
- const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- function selectLabel(eipLabel: string) {
- if (!selectedLabels.includes(eipLabel)) {
- addSelectedLabel(eipLabel);
- } else {
- deleteSelectedLabel(eipLabel);
- }
- }
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{ default: 'noPadding' }} className="kamelet-section
knowledbase-eip-section">
- <ToggleGroup aria-label="Labels" isCompact >
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- </ToggleGroup>
{isModalOpen && <EipModal/>}
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
- {filteredElements.map(c => (
+ {elements.map(c => (
<EipCard key={c.name} element={c}/>
))}
</Gallery>
diff --git a/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
index a1a0f903..4fb6e662 100644
--- a/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
+++ b/karavan-designer/src/knowledgebase/kamelets/KameletCard.tsx
@@ -56,14 +56,16 @@ export function KameletCard(props: Props) {
setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
}
const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
+ const supportLevel =
kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"];
+ const classNameBadge = 'label-kamelet' + (supportLevel !== 'Stable' ?
'-preview' : '')
return (
- <Card isCompact key={kamelet.metadata.name} className="kamelet-card"
+ <Card isCompact key={kamelet.metadata.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width:'100%'}} gap={{default:'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Kamelet</Badge>
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
- <Badge isRead className="version
labels">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
</Flex>
{showBlockCheckbox && <Checkbox id={kamelet.metadata.name}
className="block-checkbox labels" isChecked={!isblockedKamelet}
onChange={(_, checked) =>
selectKamelet(_, checked)}/>}
diff --git a/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
index 353819e4..83db2eb5 100644
--- a/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
+++ b/karavan-designer/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -22,27 +22,23 @@ import {
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletCard} from "./KameletCard";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
interface Props {
dark: boolean,
- filter: string,
- customOnly: boolean,
+ kameletList: KameletModel[],
onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const {kameletList, dark} = props;
- const {filter, customOnly, dark} = props;
- let kameletList = KameletApi.getKamelets().filter(kamelet =>
-
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
- if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
<PageSection variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{default: 'noPadding'}}
className="kamelet-section">
diff --git a/karavan-designer/src/knowledgebase/knowledgebase.css
b/karavan-designer/src/knowledgebase/knowledgebase.css
index 6fb889de..b0caf549 100644
--- a/karavan-designer/src/knowledgebase/knowledgebase.css
+++ b/karavan-designer/src/knowledgebase/knowledgebase.css
@@ -15,7 +15,129 @@
* limitations under the License.
*/
-.kamelets-page .kamelet-card .block-checkbox {
+.karavan .knowledgebase-section {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card {
+ cursor: pointer;
+ height: 160px;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header {
+ padding-top: var(--pf-v5-global--spacer--sm);
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.custom {
+ margin-left: auto;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ overflow: hidden;
+ position: relative;
+ line-height: 1.6em;
+}
+
+.knowledgebase-section .knowledgebase-card .icon {
+ height: 24px;
+ max-width: 24px;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-right: 5px;
+ border: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .footer-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .version,
+.karavan .knowledgebase-section .knowledgebase-card .support-type,
+.karavan .knowledgebase-section .knowledgebase-card .support-level {
+ white-space: nowrap;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .labels {
+ opacity: 0.5;
+ font-weight: 200;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card:hover .labels {
+ opacity: 1;
+}
+
+.knowledgebase-section .knowledgebase-card .block-checkbox {
align-self: center;
margin-left: 6px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card p {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ color: var(--pf-v5-global--Color--200);
+}
+
+.knowledgebase-section {
+ .label-eip {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--orange-200);
+ }
+ .label-component {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--blue-300);
+ }
+ .label-kamelet {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--green-300);
+ }
+ .label-component-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--blue-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
+ .label-kamelet-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--green-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
}
\ No newline at end of file
diff --git a/karavan-space/src/designer/DesignerStore.ts
b/karavan-space/src/designer/DesignerStore.ts
index 9c855c5f..e207c546 100644
--- a/karavan-space/src/designer/DesignerStore.ts
+++ b/karavan-space/src/designer/DesignerStore.ts
@@ -105,10 +105,6 @@ interface SelectorStateState {
setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
selectedPosition?: number;
setSelectedPosition: (selectedPosition?: number) => void;
- selectedLabels: string [];
- addSelectedLabel: (label: string) => void;
- deleteSelectedLabel: (label: string) => void;
- clearSelectedLabels: () => void;
selectedToggles: string [];
addSelectedToggle: (label: string) => void;
deleteSelectedToggle: (label: string) => void;
@@ -121,24 +117,7 @@ export const useSelectorStore =
createWithEqualityFn<SelectorStateState>((set) =
deleteMessage: '',
parentId: '',
showSteps: true,
- selectedLabels: [],
selectedToggles: ['eip', 'components', 'kamelets'],
- addSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels, label]
- }))
- },
- deleteSelectedLabel: (label: string) => {
- set(state => ({
- selectedLabels: [...state.selectedLabels.filter(x => x !== label)]
- }))
- },
- clearSelectedLabels: () => {
- set((state: SelectorStateState) => {
- state.selectedLabels.length = 0;
- return {selectedLabels : [...state.selectedLabels]};
- })
- },
addSelectedToggle: (toggle: string) => {
set(state => ({
selectedToggles: [...state.selectedToggles, toggle]
diff --git a/karavan-space/src/designer/property/PropertiesHeader.tsx
b/karavan-space/src/designer/property/PropertiesHeader.tsx
index 30b0034b..b8aca6b4 100644
--- a/karavan-space/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-space/src/designer/property/PropertiesHeader.tsx
@@ -94,7 +94,7 @@ export function PropertiesHeader(props: Props) {
openSelectorToReplaceFrom((selectedStep as any).id)
setMenuOpen(false);
}}>
- Change From Element
+ Change From...
</DropdownItem>}
{hasSteps &&
<DropdownItem key="saveStepsRoute" onClick={(ev) => {
diff --git a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
index a7c1d514..cb2e7158 100644
--- a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx
@@ -16,13 +16,30 @@
*/
import React, {useState} from 'react';
import '../designer/karavan.css';
-import {Flex, FlexItem, PageSection, Switch, Tab, Tabs, Text, TextContent,
TextInput, Toolbar, ToolbarContent} from "@patternfly/react-core";
+import {
+ Badge,
+ Flex,
+ FlexItem,
+ PageSection,
+ Switch,
+ Tab,
+ Tabs,
+ Text,
+ TextContent,
+ TextInput,
+ Toolbar,
+ ToolbarContent
+} from "@patternfly/react-core";
import {MainToolbar} from "../designer/MainToolbar";
import {KameletsTab} from "./kamelets/KameletsTab";
import {EipTab} from "./eip/EipTab";
import {ComponentsTab} from "./components/ComponentsTab";
import {useKnowledgebaseStore} from "./KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
@@ -33,7 +50,7 @@ interface Props {
export const KnowledgebasePage = (props: Props) => {
const [setShowBlockCheckbox] = useKnowledgebaseStore((s) =>
[s.setShowBlockCheckbox], shallow)
- const [tab, setTab] = useState<string | number>("eip");
+ const [tab, setTab] = useState<string | number>("components");
const [filter, setFilter] = useState<string>("");
const [customOnly, setCustomOnly] = useState<boolean>(false);
@@ -71,8 +88,21 @@ export const KnowledgebasePage = (props: Props) => {
</Toolbar>
}
+ let kameletList: KameletModel[] = KameletApi.getKamelets().filter(kamelet
=>
+
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
+
+ const components = ComponentApi.getComponents().filter(c => {
+ return c.component.name.toLowerCase().includes(filter.toLowerCase())
+ || c.component.title.toLowerCase().includes(filter.toLowerCase())
+ ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
+ }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+
+ const elements= CamelModelMetadata
+ .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).sort((a: ElementMeta, b:
ElementMeta) => a.name > b.name ? 1 : -1);
+
return (
- <PageSection className="kamelet-section" padding={{default:
'noPadding'}}>
+ <PageSection className="knowledgebase-section" padding={{default:
'noPadding'}}>
<PageSection className="tools-section" padding={{default:
'noPadding'}}>
<MainToolbar title={title()} tools={getTools()}/>
</PageSection>
@@ -80,17 +110,24 @@ export const KnowledgebasePage = (props: Props) => {
<Flex direction={{default: "column"}} spaceItems={{default:
"spaceItemsNone"}}>
<FlexItem>
<Tabs activeKey={tab} onSelect={(event, tabIndex) =>
setTab(tabIndex)}>
- <Tab eventKey="eip" title="Integration Patterns"/>
- <Tab eventKey="kamelets" title="Kamelets"/>
- <Tab eventKey="components" title="Components"/>
+ <Tab eventKey="components" title={<div
style={{display: 'flex', gap:'6px'}}>Components<Badge
className='label-component'>{components.length}</Badge></div>}/>
+ <Tab eventKey="eip" title={<div style={{display:
'flex', gap:'6px'}}>Integration Patterns<Badge
className='label-eip'>{elements.length}</Badge></div>}/>
+ <Tab eventKey="kamelets" title={<div
style={{display: 'flex', gap:'6px'}}>Kamelets<Badge
className='label-kamelet'>{kameletList.length}</Badge></div>}/>
</Tabs>
</FlexItem>
</Flex>
</PageSection>
<>
- {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} onChange={(name: string, checked: boolean) =>
props.changeBlockList('component', name, checked)} />}
+ {tab === 'kamelets' && <KameletsTab dark={props.dark}
+ kameletList={kameletList}
+ onChange={(name: string,
checked: boolean) => props.changeBlockList('kamelet', name, checked)} />
+ }
+ {tab === 'eip' && <EipTab dark={props.dark}
elements={elements}/>
+ }
+ {tab === 'components' && <ComponentsTab dark={props.dark}
+ components={components}
+ 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 c9f39d04..80d298c5 100644
--- a/karavan-space/src/knowledgebase/components/ComponentCard.tsx
+++ b/karavan-space/src/knowledgebase/components/ComponentCard.tsx
@@ -16,7 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Checkbox, Flex,
Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -56,14 +56,15 @@ export function ComponentCard(props: Props) {
const isBlockedComponent = blockedComponents ?
blockedComponents.findIndex(r => r === component.component.name) > -1 : false;
const isRemote = component.component.remote;
+ const classNameBadge = 'label-component' +
(component.component.supportLevel !== 'Stable' ? '-preview' : '')
return (
- <Card isCompact key={component.component.name} className="kamelet-card"
+ <Card isCompact key={component.component.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width: '100%'}} gap={{default: 'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Component</Badge>
<Badge isRead className="support-level
labels">{component.component.supportLevel}</Badge>
- <Badge isRead className="version
labels">{component.component.version}</Badge>
</Flex>
{showBlockCheckbox &&
<Checkbox id={component.component.name}
@@ -77,7 +78,9 @@ export function ComponentCard(props: Props) {
{CamelUi.getIconForComponent(component.component.title,
component.component.label)}
<CardTitle>{component.component.title}</CardTitle>
</CardHeader>
- <CardBody>{component.component.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{component.component.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<Badge isRead
className="labels">{component.component.label}</Badge>
<Badge isRead className="labels">{isRemote ? 'remote' :
'internal'}</Badge>
diff --git a/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
b/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
index 9e9fb470..c4fdb592 100644
--- a/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
+++ b/karavan-space/src/knowledgebase/components/ComponentsTab.tsx
@@ -22,28 +22,21 @@ import {
import '../../designer/karavan.css';
import {ComponentCard} from "./ComponentCard";
import {ComponentModal} from "./ComponentModal";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {shallow} from "zustand/shallow";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
+import { Component } from 'karavan-core/lib/model/ComponentModels';
interface Props {
dark: boolean,
- filter: string,
+ components: Component[],
onChange: (name: string, checked: boolean) => void,
}
export function ComponentsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
-
- const {filter} = props;
- const components = ComponentApi.getComponents().filter(c => {
- return c.component.name.toLowerCase().includes(filter.toLowerCase())
- || c.component.title.toLowerCase().includes(filter.toLowerCase())
- ||
c.component.description.toLowerCase().includes(filter.toLowerCase())
- }).sort((a, b) => (a.component.title?.toLowerCase() >
b.component.title?.toLowerCase() ? 1 : -1)) ;
+ const {components} = props;
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light} padding={{ default: 'noPadding' }}
className="kamelet-section">
{isModalOpen && <ComponentModal/>}
diff --git a/karavan-space/src/knowledgebase/eip/EipCard.tsx
b/karavan-space/src/knowledgebase/eip/EipCard.tsx
index fb47a932..bac46590 100644
--- a/karavan-space/src/knowledgebase/eip/EipCard.tsx
+++ b/karavan-space/src/knowledgebase/eip/EipCard.tsx
@@ -16,7 +16,7 @@
*/
import React from 'react';
import {
- CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
+ CardHeader, Card, CardTitle, CardBody, CardFooter, Badge, Text
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {CamelUi} from "../../designer/utils/CamelUi";
@@ -39,18 +39,20 @@ export function EipCard(props: Props) {
setElement(element)
setModalOpen(true);
}
-
return (
- <Card isCompact key={element.name} className="kamelet-card"
+ <Card isCompact key={element.name} className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader>
+ <Badge className='label-eip'>EIP</Badge>
</CardHeader>
<CardHeader>
{CamelUi.getIconForDslName(element.className)}
<CardTitle>{element.title}</CardTitle>
</CardHeader>
- <CardBody>{element.description}</CardBody>
+ <CardBody>
+ <Text
className="pf-v5-u-color-200">{element.description}</Text>
+ </CardBody>
<CardFooter className="footer-labels">
<div>
{element.labels.split(',').map((s: string, i: number) =>
<Badge key={s + i} isRead
diff --git a/karavan-space/src/knowledgebase/eip/EipTab.tsx
b/karavan-space/src/knowledgebase/eip/EipTab.tsx
index 35cc9741..7720bd29 100644
--- a/karavan-space/src/knowledgebase/eip/EipTab.tsx
+++ b/karavan-space/src/knowledgebase/eip/EipTab.tsx
@@ -17,66 +17,35 @@
import React from 'react';
import {
Gallery,
- PageSection, PageSectionVariants,ToggleGroup,ToggleGroupItem
+ PageSection, PageSectionVariants
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {EipCard} from "./EipCard";
import {EipModal} from "./EipModal";
-import {CamelModelMetadata, ElementMeta} from
"karavan-core/lib/model/CamelMetadata";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
-import { useSelectorStore } from '../../designer/DesignerStore';
+import {ElementMeta} from "karavan-core/lib/model/CamelMetadata";
interface Props {
dark: boolean,
- filter: string,
+ elements: ElementMeta[],
}
export function EipTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const { elements } = props;
- const [ selectedLabels, addSelectedLabel, deleteSelectedLabel] =
- useSelectorStore((s) =>
- [s.selectedLabels, s.addSelectedLabel, s.deleteSelectedLabel],
shallow)
- const { filter } = props;
- const elements = CamelModelMetadata;
- const filteredElements=CamelModelMetadata
- .filter(c =>
c.name.toLowerCase().includes(filter.toLowerCase())).filter((dsl: ElementMeta)
=> {
- if (selectedLabels.length === 0) {
- return true;
- } else {
- return dsl.labels.split(",").some(r =>
selectedLabels.includes(r));
- }
- })
- .sort((a: ElementMeta, b: ElementMeta) => a.name > b.name ? 1 : -1);
- const eipLabels = [...new Set(elements.map(e =>
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
- function selectLabel(eipLabel: string) {
- if (!selectedLabels.includes(eipLabel)) {
- addSelectedLabel(eipLabel);
- } else {
- deleteSelectedLabel(eipLabel);
- }
- }
return (
<PageSection variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{ default: 'noPadding' }} className="kamelet-section
knowledbase-eip-section">
- <ToggleGroup aria-label="Labels" isCompact >
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- </ToggleGroup>
{isModalOpen && <EipModal/>}
<PageSection isFilled className="kamelets-page"
variant={props.dark ? PageSectionVariants.darker :
PageSectionVariants.light}>
<Gallery hasGutter>
- {filteredElements.map(c => (
+ {elements.map(c => (
<EipCard key={c.name} element={c}/>
))}
</Gallery>
diff --git a/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
b/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
index a1a0f903..4fb6e662 100644
--- a/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
+++ b/karavan-space/src/knowledgebase/kamelets/KameletCard.tsx
@@ -56,14 +56,16 @@ export function KameletCard(props: Props) {
setBlockedKamelets([...KameletApi.getBlockedKameletNames()]);
}
const isblockedKamelet = blockedKamelets ? blockedKamelets.findIndex(r =>
r === kamelet.metadata.name) > -1 : false;
+ const supportLevel =
kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"];
+ const classNameBadge = 'label-kamelet' + (supportLevel !== 'Stable' ?
'-preview' : '')
return (
- <Card isCompact key={kamelet.metadata.name} className="kamelet-card"
+ <Card isCompact key={kamelet.metadata.name}
className="knowledgebase-card"
onClick={event => click(event)}
>
<CardHeader className="header-labels">
<Flex style={{width:'100%'}} gap={{default:'gapSm'}}
justifyContent={{default: 'justifyContentSpaceBetween'}}>
+ <Badge className={classNameBadge}>Kamelet</Badge>
<Badge isRead className="support-level
labels">{kamelet.metadata.annotations["camel.apache.org/kamelet.support.level"]}</Badge>
- <Badge isRead className="version
labels">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
</Flex>
{showBlockCheckbox && <Checkbox id={kamelet.metadata.name}
className="block-checkbox labels" isChecked={!isblockedKamelet}
onChange={(_, checked) =>
selectKamelet(_, checked)}/>}
diff --git a/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
b/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
index 353819e4..83db2eb5 100644
--- a/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
+++ b/karavan-space/src/knowledgebase/kamelets/KameletsTab.tsx
@@ -22,27 +22,23 @@ import {
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {KameletCard} from "./KameletCard";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
import {KameletModal} from "./KameletModal";
import {useKnowledgebaseStore} from "../KnowledgebaseStore";
import {shallow} from "zustand/shallow";
+import {KameletModel} from "karavan-core/lib/model/KameletModels";
interface Props {
dark: boolean,
- filter: string,
- customOnly: boolean,
+ kameletList: KameletModel[],
onChange: (name: string, checked: boolean) => void
}
export function KameletsTab(props: Props) {
- const [isModalOpen] = useKnowledgebaseStore((s) =>
- [s.isModalOpen], shallow)
+ const [isModalOpen] = useKnowledgebaseStore((s) => [s.isModalOpen],
shallow)
+
+ const {kameletList, dark} = props;
- const {filter, customOnly, dark} = props;
- let kameletList = KameletApi.getKamelets().filter(kamelet =>
-
kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
- if (customOnly) kameletList = kameletList.filter(k =>
KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
<PageSection variant={dark ? PageSectionVariants.darker :
PageSectionVariants.light}
padding={{default: 'noPadding'}}
className="kamelet-section">
diff --git a/karavan-space/src/knowledgebase/knowledgebase.css
b/karavan-space/src/knowledgebase/knowledgebase.css
index 6fb889de..b0caf549 100644
--- a/karavan-space/src/knowledgebase/knowledgebase.css
+++ b/karavan-space/src/knowledgebase/knowledgebase.css
@@ -15,7 +15,129 @@
* limitations under the License.
*/
-.kamelets-page .kamelet-card .block-checkbox {
+.karavan .knowledgebase-section {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card {
+ cursor: pointer;
+ height: 160px;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header {
+ padding-top: var(--pf-v5-global--spacer--sm);
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.custom {
+ margin-left: auto;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__header
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ overflow: hidden;
+ position: relative;
+ line-height: 1.6em;
+}
+
+.knowledgebase-section .knowledgebase-card .icon {
+ height: 24px;
+ max-width: 24px;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-right: 5px;
+ border: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .header-labels
.pf-v5-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .footer-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .version,
+.karavan .knowledgebase-section .knowledgebase-card .support-type,
+.karavan .knowledgebase-section .knowledgebase-card .support-level {
+ white-space: nowrap;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card .labels {
+ opacity: 0.5;
+ font-weight: 200;
+}
+
+.karavan .knowledgebase-section .knowledgebase-card:hover .labels {
+ opacity: 1;
+}
+
+.knowledgebase-section .knowledgebase-card .block-checkbox {
align-self: center;
margin-left: 6px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card .pf-v5-c-card__body {
+ padding-bottom: 0;
+ height: 54px;
+}
+
+.knowledgebase-section .knowledgebase-card p {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ color: var(--pf-v5-global--Color--200);
+}
+
+.knowledgebase-section {
+ .label-eip {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--orange-200);
+ }
+ .label-component {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--blue-300);
+ }
+ .label-kamelet {
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-global--palette--green-300);
+ }
+ .label-component-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--blue-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
+ .label-kamelet-preview {
+ --pf-v5-c-badge--Color: var(--pf-v5-global--palette--green-300);
+ --pf-v5-c-badge--BackgroundColor:
var(--pf-v5-c-badge--m-read--BackgroundColor);
+ }
}
\ No newline at end of file