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
commit 6c642c7a4d4b6d418368395b3164e8cfaf2f33de Author: Marat Gubaidullin <[email protected]> AuthorDate: Tue Aug 8 19:31:25 2023 -0400 Simplified picker #844 --- karavan-designer/src/designer/karavan.css | 2 +- .../src/designer/route/DslSelector.tsx | 112 +++++++++++++-------- karavan-designer/src/designer/utils/CamelUi.tsx | 11 +- .../src/knowledgebase/KnowledgebasePage.tsx | 4 +- karavan-space/src/designer/karavan.css | 2 +- karavan-space/src/designer/route/DslSelector.tsx | 112 +++++++++++++-------- karavan-space/src/designer/utils/CamelUi.tsx | 11 +- .../src/knowledgebase/KnowledgebasePage.tsx | 4 +- .../src/main/webui/src/designer/karavan.css | 2 +- .../main/webui/src/designer/route/DslSelector.tsx | 112 +++++++++++++-------- .../src/main/webui/src/designer/utils/CamelUi.tsx | 11 +- .../webui/src/knowledgebase/KnowledgebasePage.tsx | 4 +- 12 files changed, 243 insertions(+), 144 deletions(-) diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css index f8f9f634..5bfd3fef 100644 --- a/karavan-designer/src/designer/karavan.css +++ b/karavan-designer/src/designer/karavan.css @@ -940,7 +940,7 @@ padding: 5px; display: flex; flex-direction: row; - justify-content: flex-end; + justify-content: space-between; } .dsl-modal .pf-c-card.pf-m-compact .footer-labels { diff --git a/karavan-designer/src/designer/route/DslSelector.tsx b/karavan-designer/src/designer/route/DslSelector.tsx index 8c6d741a..3baca8d8 100644 --- a/karavan-designer/src/designer/route/DslSelector.tsx +++ b/karavan-designer/src/designer/route/DslSelector.tsx @@ -17,14 +17,13 @@ import React from 'react'; import { Badge, - Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Modal, PageSection, + Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Label, Modal, PageSection, Tab, Tabs, TabTitleText, - Text, TextInput, + Text, TextInput, ToggleGroup, ToggleGroupItem, } from '@patternfly/react-core'; import '../karavan.css'; import {CamelUi} from "../utils/CamelUi"; import {DslMetaModel} from "../utils/DslMetaModel"; -import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; interface Props { onDslSelect: (dsl: DslMetaModel, parentId: string, position?: number | undefined) => void, @@ -41,23 +40,19 @@ interface Props { interface State { tabIndex: string | number filter: string; + selectedLabels: string [] } export class DslSelector extends React.Component<Props, State> { - getDefaultTabIndex = () => { - const x = CamelUi.getSelectorModelTypes(this.props.parentDsl, this.props.showSteps); - if (x.length > 0) return x[0][0] - else return ''; - } - public state: State = { - tabIndex: this.props.tabIndex ? this.props.tabIndex : this.getDefaultTabIndex(), - filter: '' + tabIndex: this.props.tabIndex ? this.props.tabIndex : (this.props.parentDsl ? 'eip' : 'kamelet'), + filter: '', + selectedLabels: [] } selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => { - this.setState({tabIndex: eventKey}) + this.setState({tabIndex: eventKey}); } componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => { @@ -68,7 +63,7 @@ export class DslSelector extends React.Component<Props, State> { selectDsl = (evt: React.MouseEvent, dsl: any) => { evt.stopPropagation(); - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onDslSelect.call(this, dsl, this.props.parentId, this.props.position); } @@ -85,12 +80,15 @@ export class DslSelector extends React.Component<Props, State> { } getCard(dsl: DslMetaModel, index: number) { + const labels = dsl.labels !== undefined ? dsl.labels.split(",").filter(label => label !== 'eip') : []; return ( - <Card key={dsl.dsl + index} isHoverable isCompact className="dsl-card" + <Card key={dsl.dsl + index} isCompact className="dsl-card" onClick={event => this.selectDsl(event, dsl)}> <CardHeader className="header-labels"> - {dsl.supportType === 'Supported' && <Badge isRead className="support-type labels">{dsl.supportType}</Badge>} <Badge isRead className="support-level labels">{dsl.supportLevel}</Badge> + {['kamelet', 'component'].includes(dsl.navigation.toLowerCase()) && + <Badge isRead className="version labels">{dsl.version}</Badge> + } </CardHeader> <CardHeader> {CamelUi.getIconForDsl(dsl)} @@ -99,30 +97,53 @@ export class DslSelector extends React.Component<Props, State> { <CardBody> <Text>{dsl.description}</Text> </CardBody> - {dsl.navigation.toLowerCase() === "kamelet" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter>} - {dsl.navigation.toLowerCase() === "component" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter> - } + <CardFooter className="footer-labels"> + <div style={{display: "flex", flexDirection: "row", justifyContent: "start"}}> + {labels.map(label => <Badge isRead className="labels">{label}</Badge>)} + </div> + + </CardFooter> </Card> ) } close = () => { - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onClose?.call(this); } + selectLabel = (eipLabel: string) => { + if (!this.state.selectedLabels.includes(eipLabel)) { + this.setState((state) => { + state.selectedLabels.push(eipLabel); + return state + }) + } else { + this.setState((state) => { + const index = state.selectedLabels.findIndex((label) => label === eipLabel); + state.selectedLabels.splice(index, 1); + return state; + }) + } + } + render() { + const isEip = this.state.tabIndex === 'eip'; const {parentDsl, isOpen} = this.props; const title = parentDsl === undefined ? "Select source" : "Select step"; - const labelText: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const navigation: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, navigation, this.props.showSteps); + const eipLabels = [...new Set(elements.map(e => e.labels).join(",").split(",").filter(e => e !== 'eip'))]; + const filteredElement = elements + .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) + .filter((dsl: DslMetaModel) => { + if (!isEip || this.state.selectedLabels.length === 0) { + return true; + } else { + return dsl.labels.split(",").some(r => this.state.selectedLabels.includes(r)); + } + }); + return ( <Modal aria-label={title} @@ -139,26 +160,33 @@ export class DslSelector extends React.Component<Props, State> { <FlexItem> <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - {CamelUi.getSelectorModelTypes(parentDsl, this.props.showSteps,this.state.filter).map((label: [string, number], index: number) => { - const labelText = label[0]; - const count = label[1]; - const title = ['kamelet', 'component'].includes(labelText.toLowerCase()) ? labelText + "s (" + count + ")" : labelText; - return ( - <Tab eventKey={labelText} key={"tab-" + labelText} - title={<TabTitleText>{CamelUtil.capitalizeName(title)}</TabTitleText>}> - </Tab> - ) - })} + {parentDsl !== undefined && + <Tab eventKey={"eip"} key={"tab-eip"} + title={<TabTitleText>Integration Patterns</TabTitleText>}> + </Tab> + } + <Tab eventKey={'kamelet'} key={"tab-kamelet"} + title={<TabTitleText>Kamelets</TabTitleText>}> + </Tab> + <Tab eventKey={'component'} key={'tab-component'} + title={<TabTitleText>Components</TabTitleText>}> + </Tab> </Tabs> </FlexItem> </Flex> } actions={{}}> <PageSection variant={this.props.dark ? "darker" : "light"}> - <Gallery key={"gallery-" + labelText} hasGutter className="dsl-gallery"> - {isOpen && CamelUi.getSelectorModelsForParentFiltered(parentDsl, labelText, this.props.showSteps) - .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) - .map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} + {isEip && <ToggleGroup aria-label="Labels" isCompact> + {eipLabels.map(eipLabel => <ToggleGroupItem + text={eipLabel} + buttonId={eipLabel} + isSelected={this.state.selectedLabels.includes(eipLabel)} + onChange={selected => this.selectLabel(eipLabel)} + />)} + </ToggleGroup>} + <Gallery key={"gallery-" + navigation} hasGutter className="dsl-gallery"> + {isOpen && filteredElement.map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} </Gallery> </PageSection> </Modal> diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx index 9749fe68..a94ed0ac 100644 --- a/karavan-designer/src/designer/utils/CamelUi.tsx +++ b/karavan-designer/src/designer/utils/CamelUi.tsx @@ -157,6 +157,9 @@ export class RouteToCreate { } } +const INTEGRATION_PATTERNS = 'Integration Patterns'; +const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + export class CamelUi { static getSelectorModelTypes = (parentDsl: string | undefined, showSteps: boolean = true, filter: string | undefined = undefined): [string, number][] => { @@ -164,7 +167,8 @@ export class CamelUi { .reduce((accumulator, value) => accumulator.concat(value), []) .filter((nav, i, arr) => arr.findIndex(l => l === nav) === i) .filter((nav, i, arr) => !['dataformat'].includes(nav)); - const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + console.log(navs); + const connectorNavs = [INTEGRATION_PATTERNS, "kamelet", "component"]; const eipLabels = connectorNavs.filter(n => navs.includes(n)); return eipLabels.map(label => [label, this.getSelectorModelsForParentFiltered(parentDsl, label, true) .filter((dsl: DslMetaModel) => filter === undefined ? true : CamelUi.checkFilter(dsl, filter)).length]); @@ -173,7 +177,8 @@ export class CamelUi { static checkFilter = (dsl: DslMetaModel, filter: string | undefined = undefined): boolean => { if (filter !== undefined && filter !== "") { return dsl.title.toLowerCase().includes(filter.toLowerCase()) - || dsl.description.toLowerCase().includes(filter.toLowerCase()); + || dsl.description.toLowerCase().includes(filter.toLowerCase()) + || dsl.labels.toLowerCase().includes(filter.toLowerCase()); } else { return true; } @@ -229,7 +234,7 @@ export class CamelUi { title: el?.title, description: el?.description, labels: el?.labels, - navigation: el?.labels, + navigation: 'eip', type: "DSL" }) } diff --git a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx index 7af978d2..d7856f55 100644 --- a/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx +++ b/karavan-designer/src/knowledgebase/KnowledgebasePage.tsx @@ -28,7 +28,7 @@ interface Props { export const KnowledgebasePage = (props: Props) => { - const [tab, setTab] = useState<string | number>("kamelets"); + const [tab, setTab] = useState<string | number>("eip"); const [filter, setFilter] = useState<string>(""); const [customOnly, setCustomOnly] = useState<boolean>(false); @@ -68,7 +68,7 @@ export const KnowledgebasePage = (props: Props) => { <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}> <FlexItem className="knowledge-tabs"> <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}> - <Tab eventKey="eip" title="Enterprise Integration Patterns"/> + <Tab eventKey="eip" title="Integration Patterns"/> <Tab eventKey="kamelets" title="Kamelets"/> <Tab eventKey="components" title="Components"/> </Tabs> diff --git a/karavan-space/src/designer/karavan.css b/karavan-space/src/designer/karavan.css index f8f9f634..5bfd3fef 100644 --- a/karavan-space/src/designer/karavan.css +++ b/karavan-space/src/designer/karavan.css @@ -940,7 +940,7 @@ padding: 5px; display: flex; flex-direction: row; - justify-content: flex-end; + justify-content: space-between; } .dsl-modal .pf-c-card.pf-m-compact .footer-labels { diff --git a/karavan-space/src/designer/route/DslSelector.tsx b/karavan-space/src/designer/route/DslSelector.tsx index 8c6d741a..3baca8d8 100644 --- a/karavan-space/src/designer/route/DslSelector.tsx +++ b/karavan-space/src/designer/route/DslSelector.tsx @@ -17,14 +17,13 @@ import React from 'react'; import { Badge, - Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Modal, PageSection, + Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Label, Modal, PageSection, Tab, Tabs, TabTitleText, - Text, TextInput, + Text, TextInput, ToggleGroup, ToggleGroupItem, } from '@patternfly/react-core'; import '../karavan.css'; import {CamelUi} from "../utils/CamelUi"; import {DslMetaModel} from "../utils/DslMetaModel"; -import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; interface Props { onDslSelect: (dsl: DslMetaModel, parentId: string, position?: number | undefined) => void, @@ -41,23 +40,19 @@ interface Props { interface State { tabIndex: string | number filter: string; + selectedLabels: string [] } export class DslSelector extends React.Component<Props, State> { - getDefaultTabIndex = () => { - const x = CamelUi.getSelectorModelTypes(this.props.parentDsl, this.props.showSteps); - if (x.length > 0) return x[0][0] - else return ''; - } - public state: State = { - tabIndex: this.props.tabIndex ? this.props.tabIndex : this.getDefaultTabIndex(), - filter: '' + tabIndex: this.props.tabIndex ? this.props.tabIndex : (this.props.parentDsl ? 'eip' : 'kamelet'), + filter: '', + selectedLabels: [] } selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => { - this.setState({tabIndex: eventKey}) + this.setState({tabIndex: eventKey}); } componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => { @@ -68,7 +63,7 @@ export class DslSelector extends React.Component<Props, State> { selectDsl = (evt: React.MouseEvent, dsl: any) => { evt.stopPropagation(); - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onDslSelect.call(this, dsl, this.props.parentId, this.props.position); } @@ -85,12 +80,15 @@ export class DslSelector extends React.Component<Props, State> { } getCard(dsl: DslMetaModel, index: number) { + const labels = dsl.labels !== undefined ? dsl.labels.split(",").filter(label => label !== 'eip') : []; return ( - <Card key={dsl.dsl + index} isHoverable isCompact className="dsl-card" + <Card key={dsl.dsl + index} isCompact className="dsl-card" onClick={event => this.selectDsl(event, dsl)}> <CardHeader className="header-labels"> - {dsl.supportType === 'Supported' && <Badge isRead className="support-type labels">{dsl.supportType}</Badge>} <Badge isRead className="support-level labels">{dsl.supportLevel}</Badge> + {['kamelet', 'component'].includes(dsl.navigation.toLowerCase()) && + <Badge isRead className="version labels">{dsl.version}</Badge> + } </CardHeader> <CardHeader> {CamelUi.getIconForDsl(dsl)} @@ -99,30 +97,53 @@ export class DslSelector extends React.Component<Props, State> { <CardBody> <Text>{dsl.description}</Text> </CardBody> - {dsl.navigation.toLowerCase() === "kamelet" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter>} - {dsl.navigation.toLowerCase() === "component" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter> - } + <CardFooter className="footer-labels"> + <div style={{display: "flex", flexDirection: "row", justifyContent: "start"}}> + {labels.map(label => <Badge isRead className="labels">{label}</Badge>)} + </div> + + </CardFooter> </Card> ) } close = () => { - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onClose?.call(this); } + selectLabel = (eipLabel: string) => { + if (!this.state.selectedLabels.includes(eipLabel)) { + this.setState((state) => { + state.selectedLabels.push(eipLabel); + return state + }) + } else { + this.setState((state) => { + const index = state.selectedLabels.findIndex((label) => label === eipLabel); + state.selectedLabels.splice(index, 1); + return state; + }) + } + } + render() { + const isEip = this.state.tabIndex === 'eip'; const {parentDsl, isOpen} = this.props; const title = parentDsl === undefined ? "Select source" : "Select step"; - const labelText: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const navigation: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, navigation, this.props.showSteps); + const eipLabels = [...new Set(elements.map(e => e.labels).join(",").split(",").filter(e => e !== 'eip'))]; + const filteredElement = elements + .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) + .filter((dsl: DslMetaModel) => { + if (!isEip || this.state.selectedLabels.length === 0) { + return true; + } else { + return dsl.labels.split(",").some(r => this.state.selectedLabels.includes(r)); + } + }); + return ( <Modal aria-label={title} @@ -139,26 +160,33 @@ export class DslSelector extends React.Component<Props, State> { <FlexItem> <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - {CamelUi.getSelectorModelTypes(parentDsl, this.props.showSteps,this.state.filter).map((label: [string, number], index: number) => { - const labelText = label[0]; - const count = label[1]; - const title = ['kamelet', 'component'].includes(labelText.toLowerCase()) ? labelText + "s (" + count + ")" : labelText; - return ( - <Tab eventKey={labelText} key={"tab-" + labelText} - title={<TabTitleText>{CamelUtil.capitalizeName(title)}</TabTitleText>}> - </Tab> - ) - })} + {parentDsl !== undefined && + <Tab eventKey={"eip"} key={"tab-eip"} + title={<TabTitleText>Integration Patterns</TabTitleText>}> + </Tab> + } + <Tab eventKey={'kamelet'} key={"tab-kamelet"} + title={<TabTitleText>Kamelets</TabTitleText>}> + </Tab> + <Tab eventKey={'component'} key={'tab-component'} + title={<TabTitleText>Components</TabTitleText>}> + </Tab> </Tabs> </FlexItem> </Flex> } actions={{}}> <PageSection variant={this.props.dark ? "darker" : "light"}> - <Gallery key={"gallery-" + labelText} hasGutter className="dsl-gallery"> - {isOpen && CamelUi.getSelectorModelsForParentFiltered(parentDsl, labelText, this.props.showSteps) - .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) - .map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} + {isEip && <ToggleGroup aria-label="Labels" isCompact> + {eipLabels.map(eipLabel => <ToggleGroupItem + text={eipLabel} + buttonId={eipLabel} + isSelected={this.state.selectedLabels.includes(eipLabel)} + onChange={selected => this.selectLabel(eipLabel)} + />)} + </ToggleGroup>} + <Gallery key={"gallery-" + navigation} hasGutter className="dsl-gallery"> + {isOpen && filteredElement.map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} </Gallery> </PageSection> </Modal> diff --git a/karavan-space/src/designer/utils/CamelUi.tsx b/karavan-space/src/designer/utils/CamelUi.tsx index 9749fe68..a94ed0ac 100644 --- a/karavan-space/src/designer/utils/CamelUi.tsx +++ b/karavan-space/src/designer/utils/CamelUi.tsx @@ -157,6 +157,9 @@ export class RouteToCreate { } } +const INTEGRATION_PATTERNS = 'Integration Patterns'; +const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + export class CamelUi { static getSelectorModelTypes = (parentDsl: string | undefined, showSteps: boolean = true, filter: string | undefined = undefined): [string, number][] => { @@ -164,7 +167,8 @@ export class CamelUi { .reduce((accumulator, value) => accumulator.concat(value), []) .filter((nav, i, arr) => arr.findIndex(l => l === nav) === i) .filter((nav, i, arr) => !['dataformat'].includes(nav)); - const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + console.log(navs); + const connectorNavs = [INTEGRATION_PATTERNS, "kamelet", "component"]; const eipLabels = connectorNavs.filter(n => navs.includes(n)); return eipLabels.map(label => [label, this.getSelectorModelsForParentFiltered(parentDsl, label, true) .filter((dsl: DslMetaModel) => filter === undefined ? true : CamelUi.checkFilter(dsl, filter)).length]); @@ -173,7 +177,8 @@ export class CamelUi { static checkFilter = (dsl: DslMetaModel, filter: string | undefined = undefined): boolean => { if (filter !== undefined && filter !== "") { return dsl.title.toLowerCase().includes(filter.toLowerCase()) - || dsl.description.toLowerCase().includes(filter.toLowerCase()); + || dsl.description.toLowerCase().includes(filter.toLowerCase()) + || dsl.labels.toLowerCase().includes(filter.toLowerCase()); } else { return true; } @@ -229,7 +234,7 @@ export class CamelUi { title: el?.title, description: el?.description, labels: el?.labels, - navigation: el?.labels, + navigation: 'eip', type: "DSL" }) } diff --git a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx index 4d3ccd8e..d7856f55 100644 --- a/karavan-space/src/knowledgebase/KnowledgebasePage.tsx +++ b/karavan-space/src/knowledgebase/KnowledgebasePage.tsx @@ -28,7 +28,7 @@ interface Props { export const KnowledgebasePage = (props: Props) => { - const [tab, setTab] = useState<string | number>("kamelets"); + const [tab, setTab] = useState<string | number>("eip"); const [filter, setFilter] = useState<string>(""); const [customOnly, setCustomOnly] = useState<boolean>(false); @@ -68,8 +68,8 @@ export const KnowledgebasePage = (props: Props) => { <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}> <FlexItem className="knowledge-tabs"> <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}> + <Tab eventKey="eip" title="Integration Patterns"/> <Tab eventKey="kamelets" title="Kamelets"/> - <Tab eventKey="eip" title="Enterprise Integration Patterns"/> <Tab eventKey="components" title="Components"/> </Tabs> </FlexItem> diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css index f8f9f634..5bfd3fef 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css +++ b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css @@ -940,7 +940,7 @@ padding: 5px; display: flex; flex-direction: row; - justify-content: flex-end; + justify-content: space-between; } .dsl-modal .pf-c-card.pf-m-compact .footer-labels { diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx index 8c6d741a..3baca8d8 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx @@ -17,14 +17,13 @@ import React from 'react'; import { Badge, - Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Modal, PageSection, + Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Label, Modal, PageSection, Tab, Tabs, TabTitleText, - Text, TextInput, + Text, TextInput, ToggleGroup, ToggleGroupItem, } from '@patternfly/react-core'; import '../karavan.css'; import {CamelUi} from "../utils/CamelUi"; import {DslMetaModel} from "../utils/DslMetaModel"; -import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; interface Props { onDslSelect: (dsl: DslMetaModel, parentId: string, position?: number | undefined) => void, @@ -41,23 +40,19 @@ interface Props { interface State { tabIndex: string | number filter: string; + selectedLabels: string [] } export class DslSelector extends React.Component<Props, State> { - getDefaultTabIndex = () => { - const x = CamelUi.getSelectorModelTypes(this.props.parentDsl, this.props.showSteps); - if (x.length > 0) return x[0][0] - else return ''; - } - public state: State = { - tabIndex: this.props.tabIndex ? this.props.tabIndex : this.getDefaultTabIndex(), - filter: '' + tabIndex: this.props.tabIndex ? this.props.tabIndex : (this.props.parentDsl ? 'eip' : 'kamelet'), + filter: '', + selectedLabels: [] } selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => { - this.setState({tabIndex: eventKey}) + this.setState({tabIndex: eventKey}); } componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => { @@ -68,7 +63,7 @@ export class DslSelector extends React.Component<Props, State> { selectDsl = (evt: React.MouseEvent, dsl: any) => { evt.stopPropagation(); - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onDslSelect.call(this, dsl, this.props.parentId, this.props.position); } @@ -85,12 +80,15 @@ export class DslSelector extends React.Component<Props, State> { } getCard(dsl: DslMetaModel, index: number) { + const labels = dsl.labels !== undefined ? dsl.labels.split(",").filter(label => label !== 'eip') : []; return ( - <Card key={dsl.dsl + index} isHoverable isCompact className="dsl-card" + <Card key={dsl.dsl + index} isCompact className="dsl-card" onClick={event => this.selectDsl(event, dsl)}> <CardHeader className="header-labels"> - {dsl.supportType === 'Supported' && <Badge isRead className="support-type labels">{dsl.supportType}</Badge>} <Badge isRead className="support-level labels">{dsl.supportLevel}</Badge> + {['kamelet', 'component'].includes(dsl.navigation.toLowerCase()) && + <Badge isRead className="version labels">{dsl.version}</Badge> + } </CardHeader> <CardHeader> {CamelUi.getIconForDsl(dsl)} @@ -99,30 +97,53 @@ export class DslSelector extends React.Component<Props, State> { <CardBody> <Text>{dsl.description}</Text> </CardBody> - {dsl.navigation.toLowerCase() === "kamelet" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter>} - {dsl.navigation.toLowerCase() === "component" - && <CardFooter className="footer-labels"> - <Badge isRead className="labels">{dsl.labels}</Badge> - <Badge isRead className="version labels">{dsl.version}</Badge> - </CardFooter> - } + <CardFooter className="footer-labels"> + <div style={{display: "flex", flexDirection: "row", justifyContent: "start"}}> + {labels.map(label => <Badge isRead className="labels">{label}</Badge>)} + </div> + + </CardFooter> </Card> ) } close = () => { - this.setState({filter:""}); + this.setState({filter: ""}); this.props.onClose?.call(this); } + selectLabel = (eipLabel: string) => { + if (!this.state.selectedLabels.includes(eipLabel)) { + this.setState((state) => { + state.selectedLabels.push(eipLabel); + return state + }) + } else { + this.setState((state) => { + const index = state.selectedLabels.findIndex((label) => label === eipLabel); + state.selectedLabels.splice(index, 1); + return state; + }) + } + } + render() { + const isEip = this.state.tabIndex === 'eip'; const {parentDsl, isOpen} = this.props; const title = parentDsl === undefined ? "Select source" : "Select step"; - const labelText: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const navigation: string = this.state.tabIndex ? this.state.tabIndex.toString() : ""; + const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, navigation, this.props.showSteps); + const eipLabels = [...new Set(elements.map(e => e.labels).join(",").split(",").filter(e => e !== 'eip'))]; + const filteredElement = elements + .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) + .filter((dsl: DslMetaModel) => { + if (!isEip || this.state.selectedLabels.length === 0) { + return true; + } else { + return dsl.labels.split(",").some(r => this.state.selectedLabels.includes(r)); + } + }); + return ( <Modal aria-label={title} @@ -139,26 +160,33 @@ export class DslSelector extends React.Component<Props, State> { <FlexItem> <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - {CamelUi.getSelectorModelTypes(parentDsl, this.props.showSteps,this.state.filter).map((label: [string, number], index: number) => { - const labelText = label[0]; - const count = label[1]; - const title = ['kamelet', 'component'].includes(labelText.toLowerCase()) ? labelText + "s (" + count + ")" : labelText; - return ( - <Tab eventKey={labelText} key={"tab-" + labelText} - title={<TabTitleText>{CamelUtil.capitalizeName(title)}</TabTitleText>}> - </Tab> - ) - })} + {parentDsl !== undefined && + <Tab eventKey={"eip"} key={"tab-eip"} + title={<TabTitleText>Integration Patterns</TabTitleText>}> + </Tab> + } + <Tab eventKey={'kamelet'} key={"tab-kamelet"} + title={<TabTitleText>Kamelets</TabTitleText>}> + </Tab> + <Tab eventKey={'component'} key={'tab-component'} + title={<TabTitleText>Components</TabTitleText>}> + </Tab> </Tabs> </FlexItem> </Flex> } actions={{}}> <PageSection variant={this.props.dark ? "darker" : "light"}> - <Gallery key={"gallery-" + labelText} hasGutter className="dsl-gallery"> - {isOpen && CamelUi.getSelectorModelsForParentFiltered(parentDsl, labelText, this.props.showSteps) - .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter)) - .map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} + {isEip && <ToggleGroup aria-label="Labels" isCompact> + {eipLabels.map(eipLabel => <ToggleGroupItem + text={eipLabel} + buttonId={eipLabel} + isSelected={this.state.selectedLabels.includes(eipLabel)} + onChange={selected => this.selectLabel(eipLabel)} + />)} + </ToggleGroup>} + <Gallery key={"gallery-" + navigation} hasGutter className="dsl-gallery"> + {isOpen && filteredElement.map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))} </Gallery> </PageSection> </Modal> diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx index 9749fe68..a94ed0ac 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx @@ -157,6 +157,9 @@ export class RouteToCreate { } } +const INTEGRATION_PATTERNS = 'Integration Patterns'; +const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + export class CamelUi { static getSelectorModelTypes = (parentDsl: string | undefined, showSteps: boolean = true, filter: string | undefined = undefined): [string, number][] => { @@ -164,7 +167,8 @@ export class CamelUi { .reduce((accumulator, value) => accumulator.concat(value), []) .filter((nav, i, arr) => arr.findIndex(l => l === nav) === i) .filter((nav, i, arr) => !['dataformat'].includes(nav)); - const connectorNavs = ['routing', "transformation", "error", "configuration", "endpoint", "kamelet", "component"]; + console.log(navs); + const connectorNavs = [INTEGRATION_PATTERNS, "kamelet", "component"]; const eipLabels = connectorNavs.filter(n => navs.includes(n)); return eipLabels.map(label => [label, this.getSelectorModelsForParentFiltered(parentDsl, label, true) .filter((dsl: DslMetaModel) => filter === undefined ? true : CamelUi.checkFilter(dsl, filter)).length]); @@ -173,7 +177,8 @@ export class CamelUi { static checkFilter = (dsl: DslMetaModel, filter: string | undefined = undefined): boolean => { if (filter !== undefined && filter !== "") { return dsl.title.toLowerCase().includes(filter.toLowerCase()) - || dsl.description.toLowerCase().includes(filter.toLowerCase()); + || dsl.description.toLowerCase().includes(filter.toLowerCase()) + || dsl.labels.toLowerCase().includes(filter.toLowerCase()); } else { return true; } @@ -229,7 +234,7 @@ export class CamelUi { title: el?.title, description: el?.description, labels: el?.labels, - navigation: el?.labels, + navigation: 'eip', type: "DSL" }) } diff --git a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx index 4d3ccd8e..d7856f55 100644 --- a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx @@ -28,7 +28,7 @@ interface Props { export const KnowledgebasePage = (props: Props) => { - const [tab, setTab] = useState<string | number>("kamelets"); + const [tab, setTab] = useState<string | number>("eip"); const [filter, setFilter] = useState<string>(""); const [customOnly, setCustomOnly] = useState<boolean>(false); @@ -68,8 +68,8 @@ export const KnowledgebasePage = (props: Props) => { <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}> <FlexItem className="knowledge-tabs"> <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}> + <Tab eventKey="eip" title="Integration Patterns"/> <Tab eventKey="kamelets" title="Kamelets"/> - <Tab eventKey="eip" title="Enterprise Integration Patterns"/> <Tab eventKey="components" title="Components"/> </Tabs> </FlexItem>
