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 56748121fad06f00e642a400ad1c8e31092d2376 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Mon Dec 18 20:34:54 2023 -0500 Fix #960 --- .../src/designer/property/DslProperties.tsx | 100 ++++++++++++++++----- .../src/designer/property/usePropertiesHook.tsx | 77 ++++++++++++---- .../src/designer/route/useRouteDesignerHook.tsx | 2 +- 3 files changed, 139 insertions(+), 40 deletions(-) diff --git a/karavan-designer/src/designer/property/DslProperties.tsx b/karavan-designer/src/designer/property/DslProperties.tsx index 212a5f68..a3212312 100644 --- a/karavan-designer/src/designer/property/DslProperties.tsx +++ b/karavan-designer/src/designer/property/DslProperties.tsx @@ -14,12 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import { Form, Text, Title, - TextVariants, ExpandableSection, Button, Tooltip, + TextVariants, + ExpandableSection, + Button, + Tooltip, + Dropdown, + MenuToggleElement, + MenuToggle, + DropdownList, + DropdownItem, } from '@patternfly/react-core'; import '../karavan.css'; import './DslProperties.css'; @@ -31,11 +39,11 @@ import {CamelUi} from "../utils/CamelUi"; import {CamelMetadataApi, DataFormats, PropertyMeta} from "karavan-core/lib/model/CamelMetadata"; import {IntegrationHeader} from "../utils/IntegrationHeader"; import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon"; -import ConvertIcon from "@patternfly/react-icons/dist/esm/icons/optimize-icon"; import {useDesignerStore, useIntegrationStore} from "../DesignerStore"; import {shallow} from "zustand/shallow"; import {usePropertiesHook} from "./usePropertiesHook"; import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil"; +import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; interface Props { designerType: 'routes' | 'rest' | 'beans' @@ -45,7 +53,7 @@ export function DslProperties(props: Props) { const [integration] = useIntegrationStore((s) => [s.integration], shallow) - const {convertStep, cloneElement, onDataFormatChange, onPropertyChange, onParametersChange, onExpressionChange} = + const {saveAsRoute, convertStep, cloneElement, onDataFormatChange, onPropertyChange, onParametersChange, onExpressionChange} = usePropertiesHook(props.designerType); const [selectedStep, dark] @@ -53,31 +61,83 @@ export function DslProperties(props: Props) { const [showAdvanced, setShowAdvanced] = useState<boolean>(false); const [isDescriptionExpanded, setIsDescriptionExpanded] = useState<boolean>(false); + const [isMenuOpen, setMenuOpen] = useState<boolean>(false); + + useEffect(()=> { + setMenuOpen(false) + }, [selectedStep]) + + function getHeaderMenu(): JSX.Element { + const hasSteps = selectedStep?.hasSteps(); + const targetDsl = CamelUi.getConvertTargetDsl(selectedStep?.dslName); + const targetDslTitle = targetDsl?.replace("Definition", ""); + const showMenu = hasSteps || targetDsl !== undefined; + return showMenu ? + <Dropdown + style={{inset: "0px auto auto -70px important!"}} + className={"xxx"} + isOpen={isMenuOpen} + onSelect={() => {}} + onOpenChange={(isOpen: boolean) => setMenuOpen(isOpen)} + toggle={(toggleRef: React.Ref<MenuToggleElement>) => ( + <MenuToggle + style={{width: "240px", display: "flex", flexDirection: "row", justifyContent: "end"}} + className={"zzzz"} + ref={toggleRef} + aria-label="kebab dropdown toggle" + variant="plain" + onClick={() => setMenuOpen(!isMenuOpen)} + isExpanded={isMenuOpen} + > + <EllipsisVIcon /> + </MenuToggle> + )} + > + <DropdownList > + {hasSteps && + <DropdownItem key="saveRoute" onClick={(ev) => { + ev.preventDefault() + if (selectedStep) { + saveAsRoute(selectedStep, true); + setMenuOpen(false); + } + }}> + Save Steps to Route + </DropdownItem>} + {hasSteps && + <DropdownItem key="saveRoute" onClick={(ev) => { + ev.preventDefault() + if (selectedStep) { + saveAsRoute(selectedStep, false); + setMenuOpen(false); + } + }}> + Save Element to Route + </DropdownItem>} + {targetDsl && + <DropdownItem key="convert" + onClick={(ev) => { + ev.preventDefault() + if (selectedStep) { + convertStep(selectedStep, targetDsl); + setMenuOpen(false); + } + }}> + Convert to {targetDslTitle} + </DropdownItem>} + </DropdownList> + </Dropdown> : <></>; + } function getRouteHeader(): JSX.Element { const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep) const description = selectedStep && CamelUi.getDescription(selectedStep); const descriptionLines: string [] = description ? description?.split("\n") : [""]; - const targetDsl = CamelUi.getConvertTargetDsl(selectedStep?.dslName); - const targetDslTitle = targetDsl?.replace("Definition", ""); return ( <div className="headers"> <div className="top"> <Title headingLevel="h1" size="md">{title}</Title> - {targetDsl && - <Button - variant={"link"} - icon={<ConvertIcon/>} - iconPosition={"right"} - onClick={event => { - if (selectedStep) { - convertStep(selectedStep, targetDsl); - } - }} - > - Convert to {targetDslTitle} - </Button> - } + {getHeaderMenu()} </div> <Text component={TextVariants.p}>{descriptionLines.at(0)}</Text> {descriptionLines.length > 1 && diff --git a/karavan-designer/src/designer/property/usePropertiesHook.tsx b/karavan-designer/src/designer/property/usePropertiesHook.tsx index f8b94498..a0b6d445 100644 --- a/karavan-designer/src/designer/property/usePropertiesHook.tsx +++ b/karavan-designer/src/designer/property/usePropertiesHook.tsx @@ -17,7 +17,7 @@ import '../karavan.css'; import {CamelUtil} from "karavan-core/lib/api/CamelUtil"; import { - DataFormatDefinition, ExpressionDefinition, ToDefinition, + DataFormatDefinition, ExpressionDefinition, FromDefinition, ToDefinition, } from "karavan-core/lib/model/CamelDefinition"; import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"; @@ -28,13 +28,13 @@ import {shallow} from "zustand/shallow"; import {CamelMetadataApi} from "karavan-core/lib/model/CamelMetadata"; import {EventBus} from "../utils/EventBus"; -export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = 'routes') { +export function usePropertiesHook(designerType: 'routes' | 'rest' | 'beans' = 'routes') { const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow) - const [ selectedStep, setSelectedStep, setSelectedUuids] = useDesignerStore((s) => + const [selectedStep, setSelectedStep, setSelectedUuids] = useDesignerStore((s) => [s.selectedStep, s.setSelectedStep, s.setSelectedUuids], shallow) - function onPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) { + function onPropertyUpdate(element: CamelElement, newRoute?: RouteToCreate) { if (designerType === 'routes') { onRoutePropertyUpdate(element, newRoute); } else if (designerType === 'rest') { @@ -44,10 +44,13 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onRoutePropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) { + function onRoutePropertyUpdate(element: CamelElement, newRoute?: RouteToCreate) { if (newRoute) { let i = CamelDefinitionApiExt.updateIntegrationRouteElement(integration, element); - const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}}); + const f = CamelDefinitionApi.createFromDefinition({ + uri: newRoute.componentName, + parameters: {name: newRoute.name} + }); const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name}) i = CamelDefinitionApiExt.addStepToIntegration(i, r, ''); const clone = CamelUtil.cloneIntegration(i); @@ -61,10 +64,13 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onRestPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) { + function onRestPropertyUpdate(element: CamelElement, newRoute?: RouteToCreate) { if (newRoute) { let i = CamelDefinitionApiExt.updateIntegrationRestElement(integration, element); - const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}}); + const f = CamelDefinitionApi.createFromDefinition({ + uri: newRoute.componentName, + parameters: {name: newRoute.name} + }); const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name}) i = CamelDefinitionApiExt.addStepToIntegration(i, r, ''); const clone = CamelUtil.cloneIntegration(i); @@ -78,10 +84,13 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onBeanPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) { + function onBeanPropertyUpdate(element: CamelElement, newRoute?: RouteToCreate) { if (newRoute) { let i = CamelDefinitionApiExt.updateIntegrationBeanElement(integration, element); - const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}}); + const f = CamelDefinitionApi.createFromDefinition({ + uri: newRoute.componentName, + parameters: {name: newRoute.name} + }); const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name}) i = CamelDefinitionApiExt.addStepToIntegration(i, r, ''); const clone = CamelUtil.cloneIntegration(i); @@ -95,7 +104,7 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onPropertyChange (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate){ + function onPropertyChange(fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) { value = value === '' ? undefined : value; if (selectedStep) { const clone = CamelUtil.cloneStep(selectedStep); @@ -105,13 +114,13 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onDataFormatChange (value: DataFormatDefinition) { + function onDataFormatChange(value: DataFormatDefinition) { value.uuid = selectedStep?.uuid ? selectedStep?.uuid : value.uuid; setSelectedStep(value); onPropertyUpdate(value); } - function onExpressionChange (propertyName: string, exp: ExpressionDefinition) { + function onExpressionChange(propertyName: string, exp: ExpressionDefinition) { if (selectedStep) { const clone = (CamelUtil.cloneStep(selectedStep)); (clone as any)[propertyName] = exp; @@ -120,7 +129,7 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function onParametersChange (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) { + function onParametersChange(parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) { value = value === '' ? undefined : value; if (selectedStep) { const clone = (CamelUtil.cloneStep(selectedStep)); @@ -143,11 +152,28 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - function cloneElement () { + function cloneElement() { // TODO: } - const convertStep = (step: CamelElement, targetDslName: string ) => { + function saveAsRoute(step: CamelElement, stepsOnly: boolean) { + if (step && step.hasSteps()) { + const stepClone = CamelUtil.cloneStep(step, true); + const from = CamelDefinitionApi.createFromDefinition({uri: "direct", parameters: {name: (step as any).id}}); + if (stepsOnly) { + from.steps = (stepClone as any).steps; + } else { + from.steps = [stepClone] + } + const route = CamelDefinitionApi.createRouteDefinition({from: from, nodePrefixId: (step as any).id}); + const clone = CamelUtil.cloneIntegration(integration); + clone.spec.flows?.push(route) + setIntegration(clone, false); + // setSelectedStep(element); + } + } + + const convertStep = (step: CamelElement, targetDslName: string) => { try { // setSelectedStep(undefined); if (targetDslName === 'ChoiceDefinition' && step.dslName === 'FilterDefinition') { @@ -156,7 +182,11 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' delete (clone as any).stepName; const when = CamelDefinitionApi.createWhenDefinition(clone); const otherwise = CamelDefinitionApi.createOtherwiseDefinition(undefined); - const choice = CamelDefinitionApi.createChoiceDefinition({uuid: step.uuid, when: [when], otherwise: otherwise}); + const choice = CamelDefinitionApi.createChoiceDefinition({ + uuid: step.uuid, + when: [when], + otherwise: otherwise + }); onPropertyUpdate(choice); setSelectedStep(choice); } else { @@ -171,7 +201,7 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' }) delete (clone as any).dslName; delete (clone as any).stepName; - const converted= CamelDefinitionApi.createStep(targetDslName, clone, true); + const converted = CamelDefinitionApi.createStep(targetDslName, clone, true); onPropertyUpdate(converted); setSelectedStep(converted); } @@ -180,5 +210,14 @@ export function usePropertiesHook (designerType: 'routes' | 'rest' | 'beans' = ' } } - return {convertStep, cloneElement, onPropertyChange, onParametersChange, onDataFormatChange, onExpressionChange, getInternalComponentName} + return { + saveAsRoute, + convertStep, + cloneElement, + onPropertyChange, + onParametersChange, + onDataFormatChange, + onExpressionChange, + getInternalComponentName + } } \ No newline at end of file diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx index 192988ab..543f2a00 100644 --- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx +++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx @@ -220,7 +220,7 @@ export function useRouteDesignerHook () { } } - const openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => { + const openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined) => { setShowSelector(true); setParentId(parentId || ''); setParentDsl(parentDsl);