Skip to content

Commit a983bd1

Browse files
committed
Fix #1449
1 parent db73c76 commit a983bd1

File tree

26 files changed

+608
-394
lines changed

26 files changed

+608
-394
lines changed

karavan-app/src/main/webui/src/designer/icons/EipIcons.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ export function AggregateIcon() {
5050
);
5151
}
5252

53-
export function ToIcon() {
53+
export function ToIcon(classname: string = '') {
5454
return (
5555
<svg
5656
xmlns="http://www.w3.org/2000/svg"
5757
width={800}
5858
height={800}
5959
viewBox="0 0 32 32"
60-
className="icon"
60+
className={classname ? "icon " + classname : "icon"}
6161
>
6262
<path d="m12.103 11.923 2.58 2.59H2.513v2h12.17l-2.58 2.59 1.41 1.41 5-5-5-5z"/>
6363
<path

karavan-app/src/main/webui/src/designer/property/DslProperties.css

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,22 @@
2424
width: 100%;
2525
display: flex;
2626
flex-direction: row;
27+
/*justify-content: space-between;*/
28+
gap: 10px;
2729
}
2830

2931
.karavan .properties .headers .top h1 {
30-
width: 100%;
32+
/*width: 100%;*/
3133
margin-top: auto;
3234
margin-bottom: auto;
35+
text-wrap: nowrap;
36+
}
37+
38+
.karavan .properties .headers .top .pf-v5-c-switch {
39+
column-gap: 6px;
3340
}
3441

42+
3543
.karavan .properties .footer {
3644
height: 100%;
3745
display: contents;

karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx

Lines changed: 151 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ import {
2525
MenuToggle,
2626
DropdownList,
2727
DropdownItem, Flex, Popover, FlexItem, Badge, ClipboardCopy,
28-
Switch,
28+
Switch, Radio, Tooltip,
2929
} from '@patternfly/react-core';
3030
import '../karavan.css';
3131
import './DslProperties.css';
3232
import "@patternfly/patternfly/patternfly.css";
3333
import {CamelUi} from "../utils/CamelUi";
34-
import {useDesignerStore, useSelectorStore} from "../DesignerStore";
34+
import {useDesignerStore} from "../DesignerStore";
3535
import {shallow} from "zustand/shallow";
3636
import {usePropertiesHook} from "./usePropertiesHook";
3737
import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
@@ -56,7 +56,13 @@ export function PropertiesHeader(props: Props) {
5656
const [isHeadersExpanded, setIsHeadersExpanded] = useState<boolean>(false);
5757
const [isExchangePropertiesExpanded, setIsExchangePropertiesExpanded] = useState<boolean>(false);
5858
const [isMenuOpen, setMenuOpen] = useState<boolean>(false);
59-
const [isStepTypeOpen, setIsStepTypeOpen] = React.useState(false);
59+
const [stepIsPoll, setStepIsPoll] = React.useState(false);
60+
const [stepDynamic, setStepDynamic] = React.useState(false);
61+
62+
useEffect(() => {
63+
setStepDynamic(selectedStep?.dslName === 'ToDynamicDefinition')
64+
setStepIsPoll(selectedStep?.dslName === 'PollDefinition')
65+
}, [])
6066

6167
useEffect(() => {
6268
setMenuOpen(false)
@@ -68,67 +74,70 @@ export function PropertiesHeader(props: Props) {
6874
const targetDslTitle = targetDsl?.replace("Definition", "");
6975
const showMenu = hasSteps || targetDsl !== undefined;
7076
return showMenu ?
71-
<Dropdown
72-
popperProps={{position: "end"}}
73-
isOpen={isMenuOpen}
74-
onSelect={() => {
75-
}}
76-
onOpenChange={(isOpen: boolean) => setMenuOpen(isOpen)}
77-
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
78-
<MenuToggle
79-
className="header-menu-toggle"
80-
ref={toggleRef}
81-
aria-label="menu"
82-
variant="plain"
83-
onClick={() => setMenuOpen(!isMenuOpen)}
84-
isExpanded={isMenuOpen}
85-
>
86-
<EllipsisVIcon/>
87-
</MenuToggle>
88-
)}
89-
>
90-
<DropdownList>
91-
{isFrom &&
92-
<DropdownItem key="changeFrom" onClick={(ev) => {
93-
ev.preventDefault()
94-
openSelectorToReplaceFrom((selectedStep as any).id)
95-
setMenuOpen(false);
96-
}}>
97-
Change From...
98-
</DropdownItem>}
99-
{hasSteps &&
100-
<DropdownItem key="saveStepsRoute" onClick={(ev) => {
101-
ev.preventDefault()
102-
if (selectedStep) {
103-
saveAsRoute(selectedStep, true);
104-
setMenuOpen(false);
105-
}
106-
}}>
107-
Save Steps to Route
108-
</DropdownItem>}
109-
{hasSteps && !isFrom &&
110-
<DropdownItem key="saveElementRoute" onClick={(ev) => {
111-
ev.preventDefault()
112-
if (selectedStep) {
113-
saveAsRoute(selectedStep, false);
77+
<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', width: '100%'}}>
78+
<Dropdown
79+
popperProps={{position: "end"}}
80+
isOpen={isMenuOpen}
81+
onSelect={() => {
82+
}}
83+
onOpenChange={(isOpen: boolean) => setMenuOpen(isOpen)}
84+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
85+
<MenuToggle
86+
className="header-menu-toggle"
87+
ref={toggleRef}
88+
aria-label="menu"
89+
variant="plain"
90+
onClick={() => setMenuOpen(!isMenuOpen)}
91+
isExpanded={isMenuOpen}
92+
>
93+
<EllipsisVIcon/>
94+
</MenuToggle>
95+
)}
96+
>
97+
<DropdownList>
98+
{isFrom &&
99+
<DropdownItem key="changeFrom" onClick={(ev) => {
100+
ev.preventDefault()
101+
openSelectorToReplaceFrom((selectedStep as any).id)
114102
setMenuOpen(false);
115-
}
116-
}}>
117-
Save Element to Route
118-
</DropdownItem>}
119-
{targetDsl &&
120-
<DropdownItem key="convert"
121-
onClick={(ev) => {
122-
ev.preventDefault()
123-
if (selectedStep) {
124-
convertStep(selectedStep, targetDsl);
125-
setMenuOpen(false);
126-
}
127-
}}>
128-
Convert to {targetDslTitle}
129-
</DropdownItem>}
130-
</DropdownList>
131-
</Dropdown> : <></>;
103+
}}>
104+
Change From...
105+
</DropdownItem>}
106+
{hasSteps &&
107+
<DropdownItem key="saveStepsRoute" onClick={(ev) => {
108+
ev.preventDefault()
109+
if (selectedStep) {
110+
saveAsRoute(selectedStep, true);
111+
setMenuOpen(false);
112+
}
113+
}}>
114+
Save Steps to Route
115+
</DropdownItem>}
116+
{hasSteps && !isFrom &&
117+
<DropdownItem key="saveElementRoute" onClick={(ev) => {
118+
ev.preventDefault()
119+
if (selectedStep) {
120+
saveAsRoute(selectedStep, false);
121+
setMenuOpen(false);
122+
}
123+
}}>
124+
Save Element to Route
125+
</DropdownItem>}
126+
{targetDsl &&
127+
<DropdownItem key="convert"
128+
onClick={(ev) => {
129+
ev.preventDefault()
130+
if (selectedStep) {
131+
convertStep(selectedStep, targetDsl);
132+
setMenuOpen(false);
133+
}
134+
}}>
135+
Convert to {targetDslTitle}
136+
</DropdownItem>}
137+
</DropdownList>
138+
</Dropdown>
139+
</div>
140+
: <></>;
132141
}
133142

134143
function getExchangePropertiesSection(): React.JSX.Element {
@@ -138,35 +147,35 @@ export function PropertiesHeader(props: Props) {
138147
isExpanded={isExchangePropertiesExpanded}>
139148
<Flex className='component-headers' direction={{default: "column"}}>
140149
{exchangeProperties.map((header, index, array) =>
141-
<Flex key={index}>
142-
<ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
143-
isCode>
144-
{header.name}
145-
</ClipboardCopy>
146-
<FlexItem align={{default: 'alignRight'}}>
147-
<Popover
148-
position={"left"}
149-
headerContent={header.name}
150-
bodyContent={header.description}
151-
footerContent={
152-
<Flex>
153-
<Text component={TextVariants.p}>{header.javaType}</Text>
154-
<FlexItem align={{default: 'alignRight'}}>
155-
<Badge isRead>{header.label}</Badge>
156-
</FlexItem>
157-
</Flex>
158-
}
159-
>
160-
<button type="button" aria-label="More info" onClick={e => {
161-
e.preventDefault();
162-
e.stopPropagation();
163-
}} className="pf-v5-c-form__group-label-help">
164-
<HelpIcon/>
165-
</button>
166-
</Popover>
167-
</FlexItem>
168-
</Flex>
169-
)}
150+
<Flex key={index}>
151+
<ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
152+
isCode>
153+
{header.name}
154+
</ClipboardCopy>
155+
<FlexItem align={{default: 'alignRight'}}>
156+
<Popover
157+
position={"left"}
158+
headerContent={header.name}
159+
bodyContent={header.description}
160+
footerContent={
161+
<Flex>
162+
<Text component={TextVariants.p}>{header.javaType}</Text>
163+
<FlexItem align={{default: 'alignRight'}}>
164+
<Badge isRead>{header.label}</Badge>
165+
</FlexItem>
166+
</Flex>
167+
}
168+
>
169+
<button type="button" aria-label="More info" onClick={e => {
170+
e.preventDefault();
171+
e.stopPropagation();
172+
}} className="pf-v5-c-form__group-label-help">
173+
<HelpIcon/>
174+
</button>
175+
</Popover>
176+
</FlexItem>
177+
</Flex>
178+
)}
170179
</Flex>
171180
</ExpandableSection>
172181
)
@@ -235,24 +244,58 @@ export function PropertiesHeader(props: Props) {
235244
const component = ComponentApi.findStepComponent(selectedStep);
236245
const groups = (isFrom || isPoll) ? ['consumer', 'common'] : ['producer', 'common'];
237246
const isKamelet = CamelUi.isKamelet(selectedStep);
238-
const isStepComponent = !isFrom && selectedStep !== undefined && !isKamelet && ['ToDefinition', 'PollDefinition'].includes(selectedStep?.dslName);
247+
const isStepComponent = !isFrom && selectedStep !== undefined && !isKamelet && ['ToDefinition', 'PollDefinition', 'ToDynamicDefinition'].includes(selectedStep?.dslName);
248+
249+
function changeStepType(poll: boolean, dynamic: boolean) {
250+
if (selectedStep) {
251+
if (poll) {
252+
convertStep(selectedStep, 'PollDefinition');
253+
setStepIsPoll(true);
254+
setStepDynamic(false);
255+
} else if (dynamic) {
256+
convertStep(selectedStep, 'ToDynamicDefinition');
257+
setStepIsPoll(false);
258+
setStepDynamic(true);
259+
} else {
260+
convertStep(selectedStep, 'ToDefinition');
261+
setStepIsPoll(false);
262+
setStepDynamic(false);
263+
}
264+
}
265+
}
239266

240267
function getComponentStepTypeSwitch() {
241-
return (component?.component.producerOnly
242-
? <></>
243-
: <Switch
244-
id="step-type-switch"
245-
label="Poll"
246-
isChecked={isStepTypeOpen}
247-
onChange={(event, checked) => {
248-
if (selectedStep) {
249-
convertStep(selectedStep, checked ? 'PollDefinition' : 'ToDefinition');
250-
setIsStepTypeOpen(checked);
251-
}
252-
}}
253-
ouiaId="step-type-switch"
254-
isReversed
255-
/>
268+
const pollSupported = !component?.component.producerOnly;
269+
return (<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', width: '100%', gap: '10px'}}>
270+
<Tooltip content='Send messages to a dynamic endpoint evaluated on-demand' position='top-end'>
271+
<Switch
272+
id="step-type-dynamic"
273+
label="Dynamic"
274+
isChecked={stepDynamic}
275+
onChange={(event, checked) => {
276+
changeStepType(stepIsPoll, checked)
277+
}}
278+
ouiaId="step-type-switch"
279+
isDisabled={stepIsPoll}
280+
isReversed
281+
/>
282+
</Tooltip>
283+
{pollSupported &&
284+
<Tooltip content='Simple Polling Consumer to obtain the additional data' position='top-end'>
285+
<Switch
286+
id="step-type-poll"
287+
label="Poll"
288+
isChecked={stepIsPoll}
289+
onChange={(event, checked) => {
290+
changeStepType(checked, stepDynamic)
291+
}}
292+
ouiaId="step-type-switch"
293+
isDisabled={stepDynamic}
294+
isReversed
295+
/>
296+
</Tooltip>
297+
}
298+
</div>
256299
)
257300
}
258301

karavan-app/src/main/webui/src/designer/property/usePropertiesHook.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export function usePropertiesHook(designerType: 'routes' | 'rest' | 'beans' = 'r
177177
}
178178

179179
const convertStep = (step: CamelElement, targetDslName: string) => {
180+
console.log(targetDslName)
180181
try {
181182
// setSelectedStep(undefined);
182183
if (targetDslName === 'ChoiceDefinition' && step.dslName === 'FilterDefinition') {

karavan-app/src/main/webui/src/designer/route/DslConnections.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@
5454
fill: transparent;
5555
}
5656

57+
.karavan .dsl-page .graph .connections .path-dynamic {
58+
stroke-dasharray: 5;
59+
-webkit-animation: dashdrawR 0.5s linear infinite;
60+
animation: dashdrawR 0.5s linear infinite;
61+
stroke: var(--pf-v5-global--Color--200);
62+
stroke-width: 1;
63+
fill: transparent;
64+
}
65+
5766
.karavan .dsl-page .graph .connections .path-poll {
5867
stroke-dasharray: 5;
5968
-webkit-animation: dashdrawL 0.5s linear infinite;

0 commit comments

Comments
 (0)