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 5e889e62 Fix #1180
5e889e62 is described below
commit 5e889e6290662aa1a8acd92dcb7e288b093689b0
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Fri Mar 15 18:14:44 2024 -0400
Fix #1180
---
.../main/webui/src/designer/KaravanDesigner.tsx | 62 +++++-----
.../main/webui/src/designer/selector/DslCard.tsx | 71 +++++++++++
.../webui/src/designer/selector/DslFastCard.tsx | 58 +++++++++
.../webui/src/designer/selector/DslPreferences.tsx | 13 +++
.../webui/src/designer/selector/DslSelector.css | 40 ++++++-
.../webui/src/designer/selector/DslSelector.tsx | 130 ++++++++-------------
karavan-designer/public/example/demo.camel.yaml | 2 -
karavan-designer/src/designer/selector/DslCard.tsx | 71 +++++++++++
.../src/designer/selector/DslFastCard.tsx | 58 +++++++++
.../src/designer/selector/DslPreferences.tsx | 13 +++
.../src/designer/selector/DslSelector.css | 40 ++++++-
.../src/designer/selector/DslSelector.tsx | 130 ++++++++-------------
karavan-space/src/designer/selector/DslCard.tsx | 71 +++++++++++
.../src/designer/selector/DslFastCard.tsx | 58 +++++++++
.../src/designer/selector/DslPreferences.tsx | 13 +++
.../src/designer/selector/DslSelector.css | 40 ++++++-
.../src/designer/selector/DslSelector.tsx | 130 ++++++++-------------
17 files changed, 708 insertions(+), 292 deletions(-)
diff --git a/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
b/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
index 8e49e054..36b65118 100644
--- a/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
+++ b/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx
@@ -73,30 +73,35 @@ export function KaravanDesigner(props: Props) {
useEffect(() => {
const sub = EventBus.onIntegrationUpdate()?.subscribe((update:
IntegrationUpdate) =>
save(update.integration, update.propertyOnly));
- InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
- InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
- InfrastructureAPI.setOnSave(props.onSave);
-
InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder);
-
InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick);
+ try {
+ InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
+ InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
+ InfrastructureAPI.setOnSave(props.onSave);
+
InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder);
+
InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick);
- setSelectedStep(undefined);
- const i = makeIntegration(props.yaml, props.filename);
- setIntegration(i, false);
- let designerTab = i.kind === 'Kamelet' ? 'kamelet' : props.tab;
- if (designerTab === undefined) {
- const counts = CamelUi.getFlowCounts(i);
- designerTab = (counts.get('routes') || 0) > 0 ? 'routes' :
designerTab;
- designerTab = (counts.get('rest') || 0) > 0 ? 'rest' : designerTab;
- designerTab = (counts.get('beans') || 0) > 0 ? 'beans' :
designerTab;
+ setSelectedStep(undefined);
+ const i = makeIntegration(props.yaml, props.filename);
+ setIntegration(i, false);
+ let designerTab = i.kind === 'Kamelet' ? 'kamelet' : props.tab;
+ if (designerTab === undefined) {
+ const counts = CamelUi.getFlowCounts(i);
+ designerTab = (counts.get('routes') || 0) > 0 ? 'routes' :
designerTab;
+ designerTab = (counts.get('rest') || 0) > 0 ? 'rest' :
designerTab;
+ designerTab = (counts.get('beans') || 0) > 0 ? 'beans' :
designerTab;
+ }
+ setTab(designerTab || 'routes')
+ reset();
+ setDark(props.dark);
+ setPropertyPlaceholders(props.propertyPlaceholders)
+ setVariables(VariableUtil.findVariables(props.files))
+ setBeans(props.beans)
+ resetFiles(props.files)
+ setHideLogDSL(props.hideLogDSL === true);
+ } catch (e: any) {
+ console.log(e)
+ EventBus.sendAlert(' ' + e?.name, '' + e?.message, 'danger');
}
- setTab(designerTab || 'routes')
- reset();
- setDark(props.dark);
- setPropertyPlaceholders(props.propertyPlaceholders)
- setVariables(VariableUtil.findVariables(props.files))
- setBeans(props.beans)
- resetFiles(props.files)
- setHideLogDSL(props.hideLogDSL === true);
return () => {
sub?.unsubscribe();
setSelectedStep(undefined);
@@ -169,19 +174,6 @@ export function KaravanDesigner(props: Props) {
<Tab eventKey='beans' title={getTab("Beans", "Beans
Configuration", "beans")}></Tab>
{props.showCodeTab && <Tab eventKey='code'
title={getTab("YAML", "YAML Code", "code", true)}></Tab>}
</Tabs>
- {/*{tab === 'routes' && <Tooltip content={"Hide Log
elements"}>*/}
- {/* <Switch*/}
- {/* isReversed*/}
- {/* isChecked={hideLogDSL}*/}
- {/* onChange={(_, checked) => {*/}
- {/* setHideLogDSL(checked)*/}
- {/* }}*/}
- {/* aria-label={"Hide Log"}*/}
- {/* id="hideLogDSL"*/}
- {/* name="hideLogDSL"*/}
- {/* className={"hide-log"}*/}
- {/* />*/}
- {/*</Tooltip>}*/}
</div>
{tab === 'kamelet' && <KameletDesigner/>}
{tab === 'routes' && <RouteDesigner/>}
diff --git a/karavan-app/src/main/webui/src/designer/selector/DslCard.tsx
b/karavan-app/src/main/webui/src/designer/selector/DslCard.tsx
new file mode 100644
index 00000000..1e0b9a3f
--- /dev/null
+++ b/karavan-app/src/main/webui/src/designer/selector/DslCard.tsx
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Badge,
+ Card, CardBody, CardFooter,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+ const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
+ const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <CardHeader className="header-labels">
+ <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
+ {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
+ <Badge isRead className="version
labels">{dsl.version}</Badge>
+ }
+ {isCustom && <Badge className="custom">custom</Badge>}
+ </CardHeader>
+ <CardHeader>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ <CardBody>
+ {/*<Text>{dsl.description}</Text>*/}
+ <Text className="pf-v5-u-color-200">{dsl.description}</Text>
+ </CardBody>
+ <CardFooter className="footer-labels">
+ <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
+ {labels.map((label, index) => <Badge key={label + "-" +
index} isRead
+
className="labels">{label}</Badge>)}
+ </div>
+
+ </CardFooter>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/designer/selector/DslFastCard.tsx
b/karavan-app/src/main/webui/src/designer/selector/DslFastCard.tsx
new file mode 100644
index 00000000..26bb8dfb
--- /dev/null
+++ b/karavan-app/src/main/webui/src/designer/selector/DslFastCard.tsx
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Card,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import TimesIcon from
"@patternfly/react-icons/dist/esm/icons/outlined-times-circle-icon";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+ onDeleteFast: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslFastCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ function deleteFast(evt: React.MouseEvent) {
+ props.onDeleteFast(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card dsl-fast-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <Button className='fast-delete' variant='link' icon={<TimesIcon/>}
onClick={deleteFast}/>
+ <CardHeader className='header'>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-fast-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git
a/karavan-app/src/main/webui/src/designer/selector/DslPreferences.tsx
b/karavan-app/src/main/webui/src/designer/selector/DslPreferences.tsx
index 87844b5a..9464b813 100644
--- a/karavan-app/src/main/webui/src/designer/selector/DslPreferences.tsx
+++ b/karavan-app/src/main/webui/src/designer/selector/DslPreferences.tsx
@@ -74,3 +74,16 @@ export function addPreferredElement(type: 'eip' |
'components' | 'kamelets', dsl
console.log(e);
}
}
+
+export function deletePreferredElement(type: 'eip' | 'components' |
'kamelets', dsl: DslMetaModel) {
+ try {
+ const dslKey = type === 'eip' ? dsl.dsl : (type === 'components' ?
dsl.uri : dsl.name);
+ const local = localStorage.getItem(PREFERRED_ELEMENTS_STORAGE_NAME);
+ const pes = local !== null ? new PreferredElements(JSON.parse(local))
: new PreferredElements();
+ let list: PreferredElement[] = (pes as any)[type];
+ (pes as any)[type] = [...list.filter(l => l.dslKey !== dslKey)];
+ localStorage.setItem(PREFERRED_ELEMENTS_STORAGE_NAME,
JSON.stringify(pes));
+ } catch (e) {
+ console.log(e);
+ }
+}
diff --git a/karavan-app/src/main/webui/src/designer/selector/DslSelector.css
b/karavan-app/src/main/webui/src/designer/selector/DslSelector.css
index 279c1f41..4c54ffa3 100644
--- a/karavan-app/src/main/webui/src/designer/selector/DslSelector.css
+++ b/karavan-app/src/main/webui/src/designer/selector/DslSelector.css
@@ -27,6 +27,8 @@
.dsl-modal .dsl-card .pf-v5-c-card__header-main {
display: flex;
flex-direction: row;
+ justify-content: start;
+ overflow-x: hidden;
}
.dsl-modal .dsl-card .header-labels .pf-v5-c-card__header-main {
@@ -120,15 +122,23 @@
.dsl-modal .labels {
opacity: 0.5;
font-weight: 200;
- text-wrap: nowrap;
+ text-wrap: none;
}
-.dsl-modal .dsl-card:hover .labels {
- opacity: 1;
+.dsl-modal .dsl-card:hover .pf-v5-c-badge {
+ margin-right: 1px;
+}
+
+.dsl-modal .dsl-card:hover {
+ background-color: var(--pf-v5-global--palette--black-200);
+}
+
+.dsl-modal .dsl-card:hover .pf-v5-c-badge.pf-m-read {
+ --pf-v5-c-badge--BackgroundColor: var(--pf-v5-global--palette--black-150);
}
.dsl-modal .dsl-card:hover p {
- color: var(--pf-v5-global--Color--100);
+ /*color: var(--pf-v5-global--Color--200);*/
}
.dsl-modal .dsl-fast-card .header p {
@@ -140,3 +150,25 @@
.dsl-modal .dsl-fast-card .header {
padding: 10px;
}
+
+.dsl-modal .dsl-fast-card .fast-delete {
+ padding: 0;
+ margin: 0;
+ width: 16px;
+ height: 16px;
+ vertical-align: text-bottom;
+ position: absolute;
+ right: 0;
+ top: -1px;
+ visibility: hidden;
+}
+
+.dsl-modal .dsl-fast-card .fast-delete .pf-v5-svg {
+ fill: var(--pf-v5-global--danger-color--100);
+ width: 16px;
+ height: 16px;
+}
+
+.dsl-modal .dsl-fast-card:hover .fast-delete {
+ visibility: visible;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/designer/selector/DslSelector.tsx
b/karavan-app/src/main/webui/src/designer/selector/DslSelector.tsx
index 9e366515..50424e8c 100644
--- a/karavan-app/src/main/webui/src/designer/selector/DslSelector.tsx
+++ b/karavan-app/src/main/webui/src/designer/selector/DslSelector.tsx
@@ -16,12 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- Badge,
Button,
- Card,
- CardBody,
- CardFooter,
- CardHeader,
Flex,
FlexItem,
Gallery,
@@ -31,7 +26,6 @@ import {
Tab,
Tabs,
TabTitleText,
- Text,
TextInputGroup,
TextInputGroupMain,
TextInputGroupUtilities,
@@ -47,13 +41,15 @@ import {useRouteDesignerHook} from
"../route/useRouteDesignerHook";
import {ComponentApi} from 'karavan-core/lib/api/ComponentApi';
import {KameletApi} from 'karavan-core/lib/api/KameletApi';
import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
-import {addPreferredElement, getPreferredElements} from "./DslPreferences";
+import {addPreferredElement, deletePreferredElement, getPreferredElements}
from "./DslPreferences";
+import {DslFastCard} from "./DslFastCard";
+import {DslCard} from "./DslCard";
interface Props {
tabIndex?: string | number
}
-export function DslSelector (props: Props) {
+export function DslSelector(props: Props) {
const [showSelector, showSteps, parentId, parentDsl, selectorTabIndex,
setShowSelector, setSelectorTabIndex,
selectedPosition, selectedLabels, addSelectedLabel,
deleteSelectedLabel, clearSelectedLabels] =
@@ -72,11 +68,14 @@ export function DslSelector (props: Props) {
const [preferredKamelets, setPreferredKamelets] = useState<string[]>([]);
useEffect(() => {
+ setPreferences();
+ }, [selectedLabels]);
+
+ function setPreferences() {
setPreferredEip(getPreferredElements('eip'));
setPreferredComponents(getPreferredElements('components'));
setPreferredKamelets(getPreferredElements('kamelets'));
- }, [selectedLabels]);
-
+ }
function selectTab(evt: React.MouseEvent<HTMLElement, MouseEvent>,
eventKey: string | number) {
setSelectorTabIndex(eventKey);
@@ -87,9 +86,13 @@ export function DslSelector (props: Props) {
setFilter('');
setShowSelector(false);
onDslSelect(dsl, parentId, selectedPosition);
- const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
addPreferredElement(type, dsl)
}
+ function deleteFast(evt: React.MouseEvent, dsl: DslMetaModel) {
+ evt.stopPropagation();
+ deletePreferredElement(type, dsl);
+ setPreferences();
+ }
function searchInput() {
return (
@@ -105,11 +108,11 @@ export function DslSelector (props: Props) {
<FlexItem>
<TextInputGroup>
<TextInputGroupMain className="text-field" type="text"
autoComplete={"off"}
- value={filter}
- onChange={(_, value) => setFilter(value)}/>
+ value={filter}
+ onChange={(_, value) =>
setFilter(value)}/>
<TextInputGroupUtilities>
<Button variant="plain" onClick={_ =>
setFilter('')}>
- <TimesIcon />
+ <TimesIcon/>
</Button>
</TextInputGroupUtilities>
</TextInputGroup>
@@ -118,50 +121,6 @@ export function DslSelector (props: Props) {
)
}
- function getCard(dsl: DslMetaModel, index: number) {
- const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
- const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className="header-labels">
- <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
- {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
- <Badge isRead className="version
labels">{dsl.version}</Badge>
- }
- {isCustom && <Badge className="custom">custom</Badge>}
- </CardHeader>
- <CardHeader>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-card-title'>{dsl.title}</Text>
- </CardHeader>
- <CardBody>
- {/*<Text>{dsl.description}</Text>*/}
- <Text
className="pf-v5-u-color-200">{dsl.description}</Text>
- </CardBody>
- <CardFooter className="footer-labels">
- <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
- {labels.map((label, index) => <Badge key={label + "-"
+ index} isRead
-
className="labels">{label}</Badge>)}
- </div>
-
- </CardFooter>
- </Card>
- )
- }
-
- function getFastCard(dsl: DslMetaModel, index: number) {
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card
dsl-fast-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className='header'>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-fast-card-title'>{dsl.title}</Text>
- </CardHeader>
- </Card>
- )
- }
-
function close() {
setFilter('');
setShowSelector(false);
@@ -175,7 +134,7 @@ export function DslSelector (props: Props) {
}
}
- function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'):DslMetaModel[] {
+ function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'): DslMetaModel[] {
return elements.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl,
filter))
.filter((dsl: DslMetaModel) => {
if (type !== 'eip' || selectedLabels.length === 0) {
@@ -187,6 +146,7 @@ export function DslSelector (props: Props) {
}
const isEip = selectorTabIndex === 'eip';
+ const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
const isRouteConfig = parentDsl === 'RouteConfigurationDefinition';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
@@ -219,6 +179,17 @@ export function DslSelector (props: Props) {
? filteredComponentElements
: (navigation === 'kamelets' ? filteredKameletElements :
filteredEipElements);
+ const fastElements = elements.filter((d: DslMetaModel) => {
+ if (isEip) {
+ return preferredElements.includes(d.dsl);
+ } else if (navigation === 'components') {
+ return d.uri && preferredElements.includes(d.uri)
+ } else {
+ return preferredElements.includes(d.name)
+ }
+ }).filter((_, i) => i < 7)
+
+
return (
<Modal
aria-label={title}
@@ -237,7 +208,8 @@ export function DslSelector (props: Props) {
onSelect={selectTab}>
{parentDsl !== undefined &&
<Tab eventKey={"eip"} key={"tab-eip"}
- title={<TabTitleText>{`Integration
Patterns (${filteredEipElements?.length})`}</TabTitleText>}>
+ title={
+ <TabTitleText>{`Integration Patterns
(${filteredEipElements?.length})`}</TabTitleText>}>
</Tab>
}
{!isRouteConfig &&
@@ -259,30 +231,26 @@ export function DslSelector (props: Props) {
actions={{}}>
<PageSection padding={{default: "noPadding"}} variant={dark ?
"darker" : "light"}>
{isEip && <ToggleGroup aria-label="Labels" isCompact>
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels} icon={<TimesIcon/>}/>
+ {eipLabels.map(eipLabel =>
+ <ToggleGroupItem key={eipLabel}
+ text={eipLabel}
+ buttonId={eipLabel}
+
isSelected={selectedLabels.includes(eipLabel)}
+ onChange={selected =>
selectLabel(eipLabel)}
+ />)}
+ <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels}
+ icon={<TimesIcon/>}/>
</ToggleGroup>}
- <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '150px'}}>
- {showSelector && elements
- .filter((d: DslMetaModel) => {
- if (isEip) {
- return preferredElements.includes(d.dsl);
- } else if (navigation === 'components') {
- return d.uri &&
preferredElements.includes(d.uri)
- } else {
- return preferredElements.includes(d.name)
- }
- })
- .filter((_, i) => i < 7).map((dsl: DslMetaModel,
index: number) => getFastCard(dsl, index))}
+ <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery"
+ minWidths={{default: '150px'}}>
+ {showSelector && fastElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslFastCard dsl={dsl} index={index}
onDslSelect={selectDsl} onDeleteFast={deleteFast}/>
+ )}
</Gallery>
<Gallery key={"gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '200px'}}>
- {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) => getCard(dsl, index))}
+ {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslCard dsl={dsl} index={index}
onDslSelect={selectDsl}/>
+ )}
</Gallery>
</PageSection>
</Modal>
diff --git a/karavan-designer/public/example/demo.camel.yaml
b/karavan-designer/public/example/demo.camel.yaml
index facfc3d1..b751e86b 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -59,5 +59,3 @@
Beer battle: ${jq(variable:beer1,.name)}
(${variable.alc1}%) is weaker than
${jq(variable:beer2,.name)} (${variable.alc2}%)
- otherwise:
- id: otherwise-03ac
\ No newline at end of file
diff --git a/karavan-designer/src/designer/selector/DslCard.tsx
b/karavan-designer/src/designer/selector/DslCard.tsx
new file mode 100644
index 00000000..1e0b9a3f
--- /dev/null
+++ b/karavan-designer/src/designer/selector/DslCard.tsx
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Badge,
+ Card, CardBody, CardFooter,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+ const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
+ const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <CardHeader className="header-labels">
+ <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
+ {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
+ <Badge isRead className="version
labels">{dsl.version}</Badge>
+ }
+ {isCustom && <Badge className="custom">custom</Badge>}
+ </CardHeader>
+ <CardHeader>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ <CardBody>
+ {/*<Text>{dsl.description}</Text>*/}
+ <Text className="pf-v5-u-color-200">{dsl.description}</Text>
+ </CardBody>
+ <CardFooter className="footer-labels">
+ <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
+ {labels.map((label, index) => <Badge key={label + "-" +
index} isRead
+
className="labels">{label}</Badge>)}
+ </div>
+
+ </CardFooter>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/selector/DslFastCard.tsx
b/karavan-designer/src/designer/selector/DslFastCard.tsx
new file mode 100644
index 00000000..26bb8dfb
--- /dev/null
+++ b/karavan-designer/src/designer/selector/DslFastCard.tsx
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Card,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import TimesIcon from
"@patternfly/react-icons/dist/esm/icons/outlined-times-circle-icon";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+ onDeleteFast: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslFastCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ function deleteFast(evt: React.MouseEvent) {
+ props.onDeleteFast(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card dsl-fast-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <Button className='fast-delete' variant='link' icon={<TimesIcon/>}
onClick={deleteFast}/>
+ <CardHeader className='header'>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-fast-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/selector/DslPreferences.tsx
b/karavan-designer/src/designer/selector/DslPreferences.tsx
index 87844b5a..9464b813 100644
--- a/karavan-designer/src/designer/selector/DslPreferences.tsx
+++ b/karavan-designer/src/designer/selector/DslPreferences.tsx
@@ -74,3 +74,16 @@ export function addPreferredElement(type: 'eip' |
'components' | 'kamelets', dsl
console.log(e);
}
}
+
+export function deletePreferredElement(type: 'eip' | 'components' |
'kamelets', dsl: DslMetaModel) {
+ try {
+ const dslKey = type === 'eip' ? dsl.dsl : (type === 'components' ?
dsl.uri : dsl.name);
+ const local = localStorage.getItem(PREFERRED_ELEMENTS_STORAGE_NAME);
+ const pes = local !== null ? new PreferredElements(JSON.parse(local))
: new PreferredElements();
+ let list: PreferredElement[] = (pes as any)[type];
+ (pes as any)[type] = [...list.filter(l => l.dslKey !== dslKey)];
+ localStorage.setItem(PREFERRED_ELEMENTS_STORAGE_NAME,
JSON.stringify(pes));
+ } catch (e) {
+ console.log(e);
+ }
+}
diff --git a/karavan-designer/src/designer/selector/DslSelector.css
b/karavan-designer/src/designer/selector/DslSelector.css
index 279c1f41..4c54ffa3 100644
--- a/karavan-designer/src/designer/selector/DslSelector.css
+++ b/karavan-designer/src/designer/selector/DslSelector.css
@@ -27,6 +27,8 @@
.dsl-modal .dsl-card .pf-v5-c-card__header-main {
display: flex;
flex-direction: row;
+ justify-content: start;
+ overflow-x: hidden;
}
.dsl-modal .dsl-card .header-labels .pf-v5-c-card__header-main {
@@ -120,15 +122,23 @@
.dsl-modal .labels {
opacity: 0.5;
font-weight: 200;
- text-wrap: nowrap;
+ text-wrap: none;
}
-.dsl-modal .dsl-card:hover .labels {
- opacity: 1;
+.dsl-modal .dsl-card:hover .pf-v5-c-badge {
+ margin-right: 1px;
+}
+
+.dsl-modal .dsl-card:hover {
+ background-color: var(--pf-v5-global--palette--black-200);
+}
+
+.dsl-modal .dsl-card:hover .pf-v5-c-badge.pf-m-read {
+ --pf-v5-c-badge--BackgroundColor: var(--pf-v5-global--palette--black-150);
}
.dsl-modal .dsl-card:hover p {
- color: var(--pf-v5-global--Color--100);
+ /*color: var(--pf-v5-global--Color--200);*/
}
.dsl-modal .dsl-fast-card .header p {
@@ -140,3 +150,25 @@
.dsl-modal .dsl-fast-card .header {
padding: 10px;
}
+
+.dsl-modal .dsl-fast-card .fast-delete {
+ padding: 0;
+ margin: 0;
+ width: 16px;
+ height: 16px;
+ vertical-align: text-bottom;
+ position: absolute;
+ right: 0;
+ top: -1px;
+ visibility: hidden;
+}
+
+.dsl-modal .dsl-fast-card .fast-delete .pf-v5-svg {
+ fill: var(--pf-v5-global--danger-color--100);
+ width: 16px;
+ height: 16px;
+}
+
+.dsl-modal .dsl-fast-card:hover .fast-delete {
+ visibility: visible;
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/selector/DslSelector.tsx
b/karavan-designer/src/designer/selector/DslSelector.tsx
index 9e366515..50424e8c 100644
--- a/karavan-designer/src/designer/selector/DslSelector.tsx
+++ b/karavan-designer/src/designer/selector/DslSelector.tsx
@@ -16,12 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- Badge,
Button,
- Card,
- CardBody,
- CardFooter,
- CardHeader,
Flex,
FlexItem,
Gallery,
@@ -31,7 +26,6 @@ import {
Tab,
Tabs,
TabTitleText,
- Text,
TextInputGroup,
TextInputGroupMain,
TextInputGroupUtilities,
@@ -47,13 +41,15 @@ import {useRouteDesignerHook} from
"../route/useRouteDesignerHook";
import {ComponentApi} from 'karavan-core/lib/api/ComponentApi';
import {KameletApi} from 'karavan-core/lib/api/KameletApi';
import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
-import {addPreferredElement, getPreferredElements} from "./DslPreferences";
+import {addPreferredElement, deletePreferredElement, getPreferredElements}
from "./DslPreferences";
+import {DslFastCard} from "./DslFastCard";
+import {DslCard} from "./DslCard";
interface Props {
tabIndex?: string | number
}
-export function DslSelector (props: Props) {
+export function DslSelector(props: Props) {
const [showSelector, showSteps, parentId, parentDsl, selectorTabIndex,
setShowSelector, setSelectorTabIndex,
selectedPosition, selectedLabels, addSelectedLabel,
deleteSelectedLabel, clearSelectedLabels] =
@@ -72,11 +68,14 @@ export function DslSelector (props: Props) {
const [preferredKamelets, setPreferredKamelets] = useState<string[]>([]);
useEffect(() => {
+ setPreferences();
+ }, [selectedLabels]);
+
+ function setPreferences() {
setPreferredEip(getPreferredElements('eip'));
setPreferredComponents(getPreferredElements('components'));
setPreferredKamelets(getPreferredElements('kamelets'));
- }, [selectedLabels]);
-
+ }
function selectTab(evt: React.MouseEvent<HTMLElement, MouseEvent>,
eventKey: string | number) {
setSelectorTabIndex(eventKey);
@@ -87,9 +86,13 @@ export function DslSelector (props: Props) {
setFilter('');
setShowSelector(false);
onDslSelect(dsl, parentId, selectedPosition);
- const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
addPreferredElement(type, dsl)
}
+ function deleteFast(evt: React.MouseEvent, dsl: DslMetaModel) {
+ evt.stopPropagation();
+ deletePreferredElement(type, dsl);
+ setPreferences();
+ }
function searchInput() {
return (
@@ -105,11 +108,11 @@ export function DslSelector (props: Props) {
<FlexItem>
<TextInputGroup>
<TextInputGroupMain className="text-field" type="text"
autoComplete={"off"}
- value={filter}
- onChange={(_, value) => setFilter(value)}/>
+ value={filter}
+ onChange={(_, value) =>
setFilter(value)}/>
<TextInputGroupUtilities>
<Button variant="plain" onClick={_ =>
setFilter('')}>
- <TimesIcon />
+ <TimesIcon/>
</Button>
</TextInputGroupUtilities>
</TextInputGroup>
@@ -118,50 +121,6 @@ export function DslSelector (props: Props) {
)
}
- function getCard(dsl: DslMetaModel, index: number) {
- const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
- const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className="header-labels">
- <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
- {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
- <Badge isRead className="version
labels">{dsl.version}</Badge>
- }
- {isCustom && <Badge className="custom">custom</Badge>}
- </CardHeader>
- <CardHeader>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-card-title'>{dsl.title}</Text>
- </CardHeader>
- <CardBody>
- {/*<Text>{dsl.description}</Text>*/}
- <Text
className="pf-v5-u-color-200">{dsl.description}</Text>
- </CardBody>
- <CardFooter className="footer-labels">
- <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
- {labels.map((label, index) => <Badge key={label + "-"
+ index} isRead
-
className="labels">{label}</Badge>)}
- </div>
-
- </CardFooter>
- </Card>
- )
- }
-
- function getFastCard(dsl: DslMetaModel, index: number) {
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card
dsl-fast-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className='header'>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-fast-card-title'>{dsl.title}</Text>
- </CardHeader>
- </Card>
- )
- }
-
function close() {
setFilter('');
setShowSelector(false);
@@ -175,7 +134,7 @@ export function DslSelector (props: Props) {
}
}
- function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'):DslMetaModel[] {
+ function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'): DslMetaModel[] {
return elements.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl,
filter))
.filter((dsl: DslMetaModel) => {
if (type !== 'eip' || selectedLabels.length === 0) {
@@ -187,6 +146,7 @@ export function DslSelector (props: Props) {
}
const isEip = selectorTabIndex === 'eip';
+ const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
const isRouteConfig = parentDsl === 'RouteConfigurationDefinition';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
@@ -219,6 +179,17 @@ export function DslSelector (props: Props) {
? filteredComponentElements
: (navigation === 'kamelets' ? filteredKameletElements :
filteredEipElements);
+ const fastElements = elements.filter((d: DslMetaModel) => {
+ if (isEip) {
+ return preferredElements.includes(d.dsl);
+ } else if (navigation === 'components') {
+ return d.uri && preferredElements.includes(d.uri)
+ } else {
+ return preferredElements.includes(d.name)
+ }
+ }).filter((_, i) => i < 7)
+
+
return (
<Modal
aria-label={title}
@@ -237,7 +208,8 @@ export function DslSelector (props: Props) {
onSelect={selectTab}>
{parentDsl !== undefined &&
<Tab eventKey={"eip"} key={"tab-eip"}
- title={<TabTitleText>{`Integration
Patterns (${filteredEipElements?.length})`}</TabTitleText>}>
+ title={
+ <TabTitleText>{`Integration Patterns
(${filteredEipElements?.length})`}</TabTitleText>}>
</Tab>
}
{!isRouteConfig &&
@@ -259,30 +231,26 @@ export function DslSelector (props: Props) {
actions={{}}>
<PageSection padding={{default: "noPadding"}} variant={dark ?
"darker" : "light"}>
{isEip && <ToggleGroup aria-label="Labels" isCompact>
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels} icon={<TimesIcon/>}/>
+ {eipLabels.map(eipLabel =>
+ <ToggleGroupItem key={eipLabel}
+ text={eipLabel}
+ buttonId={eipLabel}
+
isSelected={selectedLabels.includes(eipLabel)}
+ onChange={selected =>
selectLabel(eipLabel)}
+ />)}
+ <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels}
+ icon={<TimesIcon/>}/>
</ToggleGroup>}
- <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '150px'}}>
- {showSelector && elements
- .filter((d: DslMetaModel) => {
- if (isEip) {
- return preferredElements.includes(d.dsl);
- } else if (navigation === 'components') {
- return d.uri &&
preferredElements.includes(d.uri)
- } else {
- return preferredElements.includes(d.name)
- }
- })
- .filter((_, i) => i < 7).map((dsl: DslMetaModel,
index: number) => getFastCard(dsl, index))}
+ <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery"
+ minWidths={{default: '150px'}}>
+ {showSelector && fastElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslFastCard dsl={dsl} index={index}
onDslSelect={selectDsl} onDeleteFast={deleteFast}/>
+ )}
</Gallery>
<Gallery key={"gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '200px'}}>
- {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) => getCard(dsl, index))}
+ {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslCard dsl={dsl} index={index}
onDslSelect={selectDsl}/>
+ )}
</Gallery>
</PageSection>
</Modal>
diff --git a/karavan-space/src/designer/selector/DslCard.tsx
b/karavan-space/src/designer/selector/DslCard.tsx
new file mode 100644
index 00000000..1e0b9a3f
--- /dev/null
+++ b/karavan-space/src/designer/selector/DslCard.tsx
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Badge,
+ Card, CardBody, CardFooter,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+ const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
+ const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <CardHeader className="header-labels">
+ <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
+ {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
+ <Badge isRead className="version
labels">{dsl.version}</Badge>
+ }
+ {isCustom && <Badge className="custom">custom</Badge>}
+ </CardHeader>
+ <CardHeader>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ <CardBody>
+ {/*<Text>{dsl.description}</Text>*/}
+ <Text className="pf-v5-u-color-200">{dsl.description}</Text>
+ </CardBody>
+ <CardFooter className="footer-labels">
+ <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
+ {labels.map((label, index) => <Badge key={label + "-" +
index} isRead
+
className="labels">{label}</Badge>)}
+ </div>
+
+ </CardFooter>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-space/src/designer/selector/DslFastCard.tsx
b/karavan-space/src/designer/selector/DslFastCard.tsx
new file mode 100644
index 00000000..26bb8dfb
--- /dev/null
+++ b/karavan-space/src/designer/selector/DslFastCard.tsx
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Card,
+ CardHeader,
+ Text,
+} from '@patternfly/react-core';
+import './DslSelector.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
+import TimesIcon from
"@patternfly/react-icons/dist/esm/icons/outlined-times-circle-icon";
+
+interface Props {
+ dsl: DslMetaModel,
+ index: number
+ onDslSelect: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+ onDeleteFast: (evt: React.MouseEvent, dsl: DslMetaModel) => void
+}
+
+export function DslFastCard (props: Props) {
+
+ function selectDsl(evt: React.MouseEvent, dsl: DslMetaModel) {
+ props.onDslSelect(evt, dsl);
+ }
+
+ function deleteFast(evt: React.MouseEvent) {
+ props.onDeleteFast(evt, dsl);
+ }
+
+ const {dsl, index} = props;
+
+ return (
+ <Card key={dsl.dsl + index} isCompact isPlain isFlat isRounded
className="dsl-card dsl-fast-card"
+ onClick={event => selectDsl(event, dsl)}>
+ <Button className='fast-delete' variant='link' icon={<TimesIcon/>}
onClick={deleteFast}/>
+ <CardHeader className='header'>
+ {CamelUi.getIconForDsl(dsl)}
+ <Text className='dsl-fast-card-title'>{dsl.title}</Text>
+ </CardHeader>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-space/src/designer/selector/DslPreferences.tsx
b/karavan-space/src/designer/selector/DslPreferences.tsx
index 87844b5a..9464b813 100644
--- a/karavan-space/src/designer/selector/DslPreferences.tsx
+++ b/karavan-space/src/designer/selector/DslPreferences.tsx
@@ -74,3 +74,16 @@ export function addPreferredElement(type: 'eip' |
'components' | 'kamelets', dsl
console.log(e);
}
}
+
+export function deletePreferredElement(type: 'eip' | 'components' |
'kamelets', dsl: DslMetaModel) {
+ try {
+ const dslKey = type === 'eip' ? dsl.dsl : (type === 'components' ?
dsl.uri : dsl.name);
+ const local = localStorage.getItem(PREFERRED_ELEMENTS_STORAGE_NAME);
+ const pes = local !== null ? new PreferredElements(JSON.parse(local))
: new PreferredElements();
+ let list: PreferredElement[] = (pes as any)[type];
+ (pes as any)[type] = [...list.filter(l => l.dslKey !== dslKey)];
+ localStorage.setItem(PREFERRED_ELEMENTS_STORAGE_NAME,
JSON.stringify(pes));
+ } catch (e) {
+ console.log(e);
+ }
+}
diff --git a/karavan-space/src/designer/selector/DslSelector.css
b/karavan-space/src/designer/selector/DslSelector.css
index 279c1f41..4c54ffa3 100644
--- a/karavan-space/src/designer/selector/DslSelector.css
+++ b/karavan-space/src/designer/selector/DslSelector.css
@@ -27,6 +27,8 @@
.dsl-modal .dsl-card .pf-v5-c-card__header-main {
display: flex;
flex-direction: row;
+ justify-content: start;
+ overflow-x: hidden;
}
.dsl-modal .dsl-card .header-labels .pf-v5-c-card__header-main {
@@ -120,15 +122,23 @@
.dsl-modal .labels {
opacity: 0.5;
font-weight: 200;
- text-wrap: nowrap;
+ text-wrap: none;
}
-.dsl-modal .dsl-card:hover .labels {
- opacity: 1;
+.dsl-modal .dsl-card:hover .pf-v5-c-badge {
+ margin-right: 1px;
+}
+
+.dsl-modal .dsl-card:hover {
+ background-color: var(--pf-v5-global--palette--black-200);
+}
+
+.dsl-modal .dsl-card:hover .pf-v5-c-badge.pf-m-read {
+ --pf-v5-c-badge--BackgroundColor: var(--pf-v5-global--palette--black-150);
}
.dsl-modal .dsl-card:hover p {
- color: var(--pf-v5-global--Color--100);
+ /*color: var(--pf-v5-global--Color--200);*/
}
.dsl-modal .dsl-fast-card .header p {
@@ -140,3 +150,25 @@
.dsl-modal .dsl-fast-card .header {
padding: 10px;
}
+
+.dsl-modal .dsl-fast-card .fast-delete {
+ padding: 0;
+ margin: 0;
+ width: 16px;
+ height: 16px;
+ vertical-align: text-bottom;
+ position: absolute;
+ right: 0;
+ top: -1px;
+ visibility: hidden;
+}
+
+.dsl-modal .dsl-fast-card .fast-delete .pf-v5-svg {
+ fill: var(--pf-v5-global--danger-color--100);
+ width: 16px;
+ height: 16px;
+}
+
+.dsl-modal .dsl-fast-card:hover .fast-delete {
+ visibility: visible;
+}
\ No newline at end of file
diff --git a/karavan-space/src/designer/selector/DslSelector.tsx
b/karavan-space/src/designer/selector/DslSelector.tsx
index 9e366515..50424e8c 100644
--- a/karavan-space/src/designer/selector/DslSelector.tsx
+++ b/karavan-space/src/designer/selector/DslSelector.tsx
@@ -16,12 +16,7 @@
*/
import React, {useEffect, useState} from 'react';
import {
- Badge,
Button,
- Card,
- CardBody,
- CardFooter,
- CardHeader,
Flex,
FlexItem,
Gallery,
@@ -31,7 +26,6 @@ import {
Tab,
Tabs,
TabTitleText,
- Text,
TextInputGroup,
TextInputGroupMain,
TextInputGroupUtilities,
@@ -47,13 +41,15 @@ import {useRouteDesignerHook} from
"../route/useRouteDesignerHook";
import {ComponentApi} from 'karavan-core/lib/api/ComponentApi';
import {KameletApi} from 'karavan-core/lib/api/KameletApi';
import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
-import {addPreferredElement, getPreferredElements} from "./DslPreferences";
+import {addPreferredElement, deletePreferredElement, getPreferredElements}
from "./DslPreferences";
+import {DslFastCard} from "./DslFastCard";
+import {DslCard} from "./DslCard";
interface Props {
tabIndex?: string | number
}
-export function DslSelector (props: Props) {
+export function DslSelector(props: Props) {
const [showSelector, showSteps, parentId, parentDsl, selectorTabIndex,
setShowSelector, setSelectorTabIndex,
selectedPosition, selectedLabels, addSelectedLabel,
deleteSelectedLabel, clearSelectedLabels] =
@@ -72,11 +68,14 @@ export function DslSelector (props: Props) {
const [preferredKamelets, setPreferredKamelets] = useState<string[]>([]);
useEffect(() => {
+ setPreferences();
+ }, [selectedLabels]);
+
+ function setPreferences() {
setPreferredEip(getPreferredElements('eip'));
setPreferredComponents(getPreferredElements('components'));
setPreferredKamelets(getPreferredElements('kamelets'));
- }, [selectedLabels]);
-
+ }
function selectTab(evt: React.MouseEvent<HTMLElement, MouseEvent>,
eventKey: string | number) {
setSelectorTabIndex(eventKey);
@@ -87,9 +86,13 @@ export function DslSelector (props: Props) {
setFilter('');
setShowSelector(false);
onDslSelect(dsl, parentId, selectedPosition);
- const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
addPreferredElement(type, dsl)
}
+ function deleteFast(evt: React.MouseEvent, dsl: DslMetaModel) {
+ evt.stopPropagation();
+ deletePreferredElement(type, dsl);
+ setPreferences();
+ }
function searchInput() {
return (
@@ -105,11 +108,11 @@ export function DslSelector (props: Props) {
<FlexItem>
<TextInputGroup>
<TextInputGroupMain className="text-field" type="text"
autoComplete={"off"}
- value={filter}
- onChange={(_, value) => setFilter(value)}/>
+ value={filter}
+ onChange={(_, value) =>
setFilter(value)}/>
<TextInputGroupUtilities>
<Button variant="plain" onClick={_ =>
setFilter('')}>
- <TimesIcon />
+ <TimesIcon/>
</Button>
</TextInputGroupUtilities>
</TextInputGroup>
@@ -118,50 +121,6 @@ export function DslSelector (props: Props) {
)
}
- function getCard(dsl: DslMetaModel, index: number) {
- const labels = dsl.labels !== undefined ?
dsl.labels.split(",").filter(label => label !== 'eip') : [];
- const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name);
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className="header-labels">
- <Badge isRead className="support-level
labels">{dsl.supportLevel}</Badge>
- {['kamelet',
'component'].includes(dsl.navigation.toLowerCase()) &&
- <Badge isRead className="version
labels">{dsl.version}</Badge>
- }
- {isCustom && <Badge className="custom">custom</Badge>}
- </CardHeader>
- <CardHeader>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-card-title'>{dsl.title}</Text>
- </CardHeader>
- <CardBody>
- {/*<Text>{dsl.description}</Text>*/}
- <Text
className="pf-v5-u-color-200">{dsl.description}</Text>
- </CardBody>
- <CardFooter className="footer-labels">
- <div style={{display: "flex", flexDirection: "row",
justifyContent: "start"}}>
- {labels.map((label, index) => <Badge key={label + "-"
+ index} isRead
-
className="labels">{label}</Badge>)}
- </div>
-
- </CardFooter>
- </Card>
- )
- }
-
- function getFastCard(dsl: DslMetaModel, index: number) {
- return (
- <Card key={dsl.dsl + index} isCompact className="dsl-card
dsl-fast-card"
- onClick={event => selectDsl(event, dsl)}>
- <CardHeader className='header'>
- {CamelUi.getIconForDsl(dsl)}
- <Text className='dsl-fast-card-title'>{dsl.title}</Text>
- </CardHeader>
- </Card>
- )
- }
-
function close() {
setFilter('');
setShowSelector(false);
@@ -175,7 +134,7 @@ export function DslSelector (props: Props) {
}
}
- function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'):DslMetaModel[] {
+ function filterElements(elements: DslMetaModel[], type: 'eip' |
'components' | 'kamelets'): DslMetaModel[] {
return elements.filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl,
filter))
.filter((dsl: DslMetaModel) => {
if (type !== 'eip' || selectedLabels.length === 0) {
@@ -187,6 +146,7 @@ export function DslSelector (props: Props) {
}
const isEip = selectorTabIndex === 'eip';
+ const type = isEip ? 'eip' : (selectorTabIndex === 'components' ?
'components' : 'kamelets');
const isRouteConfig = parentDsl === 'RouteConfigurationDefinition';
const title = parentDsl === undefined ? "Select source" : "Select step";
const navigation: string = selectorTabIndex ? selectorTabIndex.toString()
: '';
@@ -219,6 +179,17 @@ export function DslSelector (props: Props) {
? filteredComponentElements
: (navigation === 'kamelets' ? filteredKameletElements :
filteredEipElements);
+ const fastElements = elements.filter((d: DslMetaModel) => {
+ if (isEip) {
+ return preferredElements.includes(d.dsl);
+ } else if (navigation === 'components') {
+ return d.uri && preferredElements.includes(d.uri)
+ } else {
+ return preferredElements.includes(d.name)
+ }
+ }).filter((_, i) => i < 7)
+
+
return (
<Modal
aria-label={title}
@@ -237,7 +208,8 @@ export function DslSelector (props: Props) {
onSelect={selectTab}>
{parentDsl !== undefined &&
<Tab eventKey={"eip"} key={"tab-eip"}
- title={<TabTitleText>{`Integration
Patterns (${filteredEipElements?.length})`}</TabTitleText>}>
+ title={
+ <TabTitleText>{`Integration Patterns
(${filteredEipElements?.length})`}</TabTitleText>}>
</Tab>
}
{!isRouteConfig &&
@@ -259,30 +231,26 @@ export function DslSelector (props: Props) {
actions={{}}>
<PageSection padding={{default: "noPadding"}} variant={dark ?
"darker" : "light"}>
{isEip && <ToggleGroup aria-label="Labels" isCompact>
- {eipLabels.map(eipLabel => <ToggleGroupItem
- key={eipLabel}
- text={eipLabel}
- buttonId={eipLabel}
- isSelected={selectedLabels.includes(eipLabel)}
- onChange={selected => selectLabel(eipLabel)}
- />)}
- <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels} icon={<TimesIcon/>}/>
+ {eipLabels.map(eipLabel =>
+ <ToggleGroupItem key={eipLabel}
+ text={eipLabel}
+ buttonId={eipLabel}
+
isSelected={selectedLabels.includes(eipLabel)}
+ onChange={selected =>
selectLabel(eipLabel)}
+ />)}
+ <ToggleGroupItem key='clean' buttonId='clean'
isSelected={false} onChange={clearSelectedLabels}
+ icon={<TimesIcon/>}/>
</ToggleGroup>}
- <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '150px'}}>
- {showSelector && elements
- .filter((d: DslMetaModel) => {
- if (isEip) {
- return preferredElements.includes(d.dsl);
- } else if (navigation === 'components') {
- return d.uri &&
preferredElements.includes(d.uri)
- } else {
- return preferredElements.includes(d.name)
- }
- })
- .filter((_, i) => i < 7).map((dsl: DslMetaModel,
index: number) => getFastCard(dsl, index))}
+ <Gallery key={"fast-gallery-" + navigation} hasGutter
className="dsl-gallery"
+ minWidths={{default: '150px'}}>
+ {showSelector && fastElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslFastCard dsl={dsl} index={index}
onDslSelect={selectDsl} onDeleteFast={deleteFast}/>
+ )}
</Gallery>
<Gallery key={"gallery-" + navigation} hasGutter
className="dsl-gallery" minWidths={{default: '200px'}}>
- {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) => getCard(dsl, index))}
+ {showSelector && filteredElements.map((dsl: DslMetaModel,
index: number) =>
+ <DslCard dsl={dsl} index={index}
onDslSelect={selectDsl}/>
+ )}
</Gallery>
</PageSection>
</Modal>